toolchain-layer: move binutils and gcc from meta-oe into here

Acked-by: Martin Jansa <Martin.Jansa@gmail.com>
Acked-by: Eric Bénard <eric@eukrea.com>
Acked-by: Khem Raj <raj.khem@gmail.com>
Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
This commit is contained in:
Koen Kooi
2012-03-23 08:22:26 +01:00
parent 6b22bd198a
commit ff0f815593
382 changed files with 0 additions and 0 deletions
@@ -0,0 +1,45 @@
Index: gcc-4_6-branch/gcc/config/arm/arm.c
===================================================================
--- gcc-4_6-branch.orig/gcc/config/arm/arm.c 2012-03-05 17:14:09.901129286 -0800
+++ gcc-4_6-branch/gcc/config/arm/arm.c 2012-03-05 17:18:23.061141606 -0800
@@ -17525,6 +17525,13 @@
}
return;
+ case 'v':
+ {
+ gcc_assert (GET_CODE (x) == CONST_DOUBLE);
+ fprintf (stream, "#%d", vfp3_const_double_for_fract_bits (x));
+ return;
+ }
+
/* Register specifier for vld1.16/vst1.16. Translate the S register
number into a D register number and element index. */
case 'z':
@@ -24925,4 +24932,26 @@
return 4;
}
+int
+vfp3_const_double_for_fract_bits (rtx operand)
+{
+ REAL_VALUE_TYPE r0;
+
+ if (GET_CODE (operand) != CONST_DOUBLE)
+ return 0;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r0, operand);
+ if (exact_real_inverse (DFmode, &r0))
+ {
+ if (exact_real_truncate (DFmode, &r0))
+ {
+ HOST_WIDE_INT value = real_to_integer (&r0);
+ value = value & 0xffffffff;
+ if ((value != 0) && ( (value & (value - 1)) == 0))
+ return int_log2 (value);
+ }
+ }
+ return 0;
+}
+
#include "gt-arm.h"
@@ -0,0 +1,51 @@
2011-02-21 Andrew Stubbs <ams@codesourcery.com>
Julian Brown <julian@codesourcery.com>
Mark Shinwell <shinwell@codesourcery.com>
Forward-ported from Linaro GCC 4.5 (bzr99324).
gcc/
* config/arm/arm.h (arm_class_likely_spilled_p): Check against
LO_REGS only for Thumb-1.
(MODE_BASE_REG_CLASS): Restrict base registers to those which can
be used in short instructions when optimising for size on Thumb-2.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-01-29 03:20:57 +0000
+++ new/gcc/config/arm/arm.c 2011-02-21 14:04:51 +0000
@@ -22304,14 +22304,16 @@
/* Implement TARGET_CLASS_LIKELY_SPILLED_P.
- We need to define this for LO_REGS on thumb. Otherwise we can end up
- using r0-r4 for function arguments, r7 for the stack frame and don't
- have enough left over to do doubleword arithmetic. */
-
+ We need to define this for LO_REGS on Thumb-1. Otherwise we can end up
+ using r0-r4 for function arguments, r7 for the stack frame and don't have
+ enough left over to do doubleword arithmetic. For Thumb-2 all the
+ potentially problematic instructions accept high registers so this is not
+ necessary. Care needs to be taken to avoid adding new Thumb-2 patterns
+ that require many low registers. */
static bool
arm_class_likely_spilled_p (reg_class_t rclass)
{
- if ((TARGET_THUMB && rclass == LO_REGS)
+ if ((TARGET_THUMB1 && rclass == LO_REGS)
|| rclass == CC_REG)
return true;
=== modified file 'gcc/config/arm/arm.h'
--- old/gcc/config/arm/arm.h 2011-01-29 03:20:57 +0000
+++ new/gcc/config/arm/arm.h 2011-02-21 14:04:51 +0000
@@ -1185,7 +1185,7 @@
when addressing quantities in QI or HI mode; if we don't know the
mode, then we must be conservative. */
#define MODE_BASE_REG_CLASS(MODE) \
- (TARGET_32BIT ? CORE_REGS : \
+ (TARGET_ARM || (TARGET_THUMB2 && !optimize_size) ? CORE_REGS : \
(((MODE) == SImode) ? BASE_REGS : LO_REGS))
/* For Thumb we can not support SP+reg addressing, so we return LO_REGS
@@ -0,0 +1,653 @@
2011-03-27 Ira Rosen <ira.rosen@linaro.org>
gcc/
* doc/invoke.texi (max-stores-to-sink): Document.
* params.h (MAX_STORES_TO_SINK): Define.
* opts.c (finish_options): Set MAX_STORES_TO_SINK to 0
if either vectorization or if-conversion is disabled.
* tree-data-ref.c (dr_equal_offsets_p1): Moved and renamed from
tree-vect-data-refs.c vect_equal_offsets.
(dr_equal_offsets_p): New function.
(find_data_references_in_bb): Remove static.
* tree-data-ref.h (find_data_references_in_bb): Declare.
(dr_equal_offsets_p): Likewise.
* tree-vect-data-refs.c (vect_equal_offsets): Move to tree-data-ref.c.
(vect_drs_dependent_in_basic_block): Update calls to
vect_equal_offsets.
(vect_check_interleaving): Likewise.
* tree-ssa-phiopt.c: Include cfgloop.h and tree-data-ref.h.
(cond_if_else_store_replacement): Rename to...
(cond_if_else_store_replacement_1): ... this. Change arguments and
documentation.
(cond_if_else_store_replacement): New function.
* Makefile.in (tree-ssa-phiopt.o): Adjust dependencies.
* params.def (PARAM_MAX_STORES_TO_SINK): Define.
gcc/testsuite/
* gcc.dg/vect/vect-cselim-1.c: New test.
* gcc.dg/vect/vect-cselim-2.c: New test.
=== modified file 'gcc/Makefile.in'
--- old/gcc/Makefile.in 2011-03-26 09:20:34 +0000
+++ new/gcc/Makefile.in 2011-04-18 11:31:29 +0000
@@ -2422,7 +2422,8 @@
tree-ssa-phiopt.o : tree-ssa-phiopt.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(GGC_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) \
$(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) langhooks.h $(FLAGS_H) \
- $(DIAGNOSTIC_H) $(TIMEVAR_H) pointer-set.h domwalk.h
+ $(DIAGNOSTIC_H) $(TIMEVAR_H) pointer-set.h domwalk.h $(CFGLOOP_H) \
+ $(TREE_DATA_REF_H)
tree-nrv.o : tree-nrv.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(TREE_H) $(FUNCTION_H) $(BASIC_BLOCK_H) $(FLAGS_H) \
$(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TIMEVAR_H) $(TREE_DUMP_H) $(TREE_PASS_H) \
=== modified file 'gcc/doc/invoke.texi'
--- old/gcc/doc/invoke.texi 2011-03-29 14:24:42 +0000
+++ new/gcc/doc/invoke.texi 2011-04-18 11:31:29 +0000
@@ -8909,6 +8909,11 @@
The maximum number of namespaces to consult for suggestions when C++
name lookup fails for an identifier. The default is 1000.
+@item max-stores-to-sink
+The maximum number of conditional stores paires that can be sunk. Set to 0
+if either vectorization (@option{-ftree-vectorize}) or if-conversion
+(@option{-ftree-loop-if-convert}) is disabled. The default is 2.
+
@end table
@end table
=== modified file 'gcc/opts.c'
--- old/gcc/opts.c 2011-02-17 22:51:57 +0000
+++ new/gcc/opts.c 2011-03-27 09:38:18 +0000
@@ -823,6 +823,12 @@
opts->x_flag_split_stack = 0;
}
}
+
+ /* Set PARAM_MAX_STORES_TO_SINK to 0 if either vectorization or if-conversion
+ is disabled. */
+ if (!opts->x_flag_tree_vectorize || !opts->x_flag_tree_loop_if_convert)
+ maybe_set_param_value (PARAM_MAX_STORES_TO_SINK, 0,
+ opts->x_param_values, opts_set->x_param_values);
}
#define LEFT_COLUMN 27
=== modified file 'gcc/params.def'
--- old/gcc/params.def 2011-03-26 09:20:34 +0000
+++ new/gcc/params.def 2011-04-18 11:31:29 +0000
@@ -883,6 +883,13 @@
"name lookup fails",
1000, 0, 0)
+/* Maximum number of conditional store pairs that can be sunk. */
+DEFPARAM (PARAM_MAX_STORES_TO_SINK,
+ "max-stores-to-sink",
+ "Maximum number of conditional store pairs that can be sunk",
+ 2, 0, 0)
+
+
/*
Local variables:
mode:c
=== modified file 'gcc/params.h'
--- old/gcc/params.h 2011-01-13 13:41:03 +0000
+++ new/gcc/params.h 2011-03-27 09:38:18 +0000
@@ -206,4 +206,6 @@
PARAM_VALUE (PARAM_PREFETCH_MIN_INSN_TO_MEM_RATIO)
#define MIN_NONDEBUG_INSN_UID \
PARAM_VALUE (PARAM_MIN_NONDEBUG_INSN_UID)
+#define MAX_STORES_TO_SINK \
+ PARAM_VALUE (PARAM_MAX_STORES_TO_SINK)
#endif /* ! GCC_PARAMS_H */
=== added file 'gcc/testsuite/gcc.dg/vect/vect-cselim-1.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-cselim-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-cselim-1.c 2011-03-27 09:38:18 +0000
@@ -0,0 +1,86 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 50
+
+typedef struct {
+ short a;
+ short b;
+} data;
+
+data in1[N], in2[N], out[N];
+short result[N*2] = {7,-7,9,-6,11,-5,13,-4,15,-3,17,-2,19,-1,21,0,23,1,25,2,27,3,29,4,31,5,33,6,35,7,37,8,39,9,41,10,43,11,45,12,47,13,49,14,51,15,53,16,55,17,57,18,59,19,61,20,63,21,65,22,67,23,69,24,71,25,73,26,75,27,77,28,79,29,81,30,83,31,85,32,87,33,89,34,91,35,93,36,95,37,97,38,99,39,101,40,103,41,105,42};
+short out1[N], out2[N];
+
+__attribute__ ((noinline)) void
+foo ()
+{
+ int i;
+ short c, d;
+
+ /* Vectorizable with conditional store sinking. */
+ for (i = 0; i < N; i++)
+ {
+ c = in1[i].b;
+ d = in2[i].b;
+
+ if (c >= d)
+ {
+ out[i].b = c;
+ out[i].a = d + 5;
+ }
+ else
+ {
+ out[i].b = d - 12;
+ out[i].a = c + d;
+ }
+ }
+
+ /* Not vectorizable. */
+ for (i = 0; i < N; i++)
+ {
+ c = in1[i].b;
+ d = in2[i].b;
+
+ if (c >= d)
+ {
+ out1[i] = c;
+ }
+ else
+ {
+ out2[i] = c + d;
+ }
+ }
+}
+
+int
+main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ in1[i].a = i;
+ in1[i].b = i + 2;
+ in2[i].a = 5;
+ in2[i].b = i + 5;
+ __asm__ volatile ("");
+ }
+
+ foo ();
+
+ for (i = 0; i < N; i++)
+ {
+ if (out[i].a != result[2*i] || out[i].b != result[2*i+1])
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail { vect_no_align || {! vect_strided } } } } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== added file 'gcc/testsuite/gcc.dg/vect/vect-cselim-2.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-cselim-2.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-cselim-2.c 2011-03-27 09:38:18 +0000
@@ -0,0 +1,65 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 50
+
+int a[N], b[N], in1[N], in2[N];
+int result[2*N] = {5,-7,7,-6,9,-5,11,-4,13,-3,15,-2,17,-1,19,0,21,1,23,2,25,3,27,4,29,5,31,6,33,7,35,8,37,9,39,10,41,11,43,12,45,13,47,14,49,15,51,16,53,17,55,18,57,19,59,20,61,21,63,22,65,23,67,24,69,25,71,26,73,27,75,28,77,29,79,30,81,31,83,32,85,33,87,34,89,35,91,36,93,37,95,38,97,39,99,40,101,41,103,42};
+
+__attribute__ ((noinline)) void
+foo (int *pa, int *pb)
+{
+ int i;
+ int c, d;
+
+ /* Store sinking should not work here since the pointers may alias. */
+ for (i = 0; i < N; i++)
+ {
+ c = in1[i];
+ d = in2[i];
+
+ if (c >= d)
+ {
+ *pa = c;
+ *pb = d + 5;
+ }
+ else
+ {
+ *pb = d - 12;
+ *pa = c + d;
+ }
+
+ pa++;
+ pb++;
+ }
+}
+
+int
+main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ in1[i] = i;
+ in2[i] = i + 5;
+ __asm__ volatile ("");
+ }
+
+ foo (a, b);
+
+ for (i = 0; i < N; i++)
+ {
+ if (a[i] != result[2*i] || b[i] != result[2*i+1])
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/tree-data-ref.c'
--- old/gcc/tree-data-ref.c 2011-02-05 01:39:20 +0000
+++ new/gcc/tree-data-ref.c 2011-03-27 09:38:18 +0000
@@ -991,6 +991,48 @@
return dr;
}
+/* Check if OFFSET1 and OFFSET2 (DR_OFFSETs of some data-refs) are identical
+ expressions. */
+static bool
+dr_equal_offsets_p1 (tree offset1, tree offset2)
+{
+ bool res;
+
+ STRIP_NOPS (offset1);
+ STRIP_NOPS (offset2);
+
+ if (offset1 == offset2)
+ return true;
+
+ if (TREE_CODE (offset1) != TREE_CODE (offset2)
+ || (!BINARY_CLASS_P (offset1) && !UNARY_CLASS_P (offset1)))
+ return false;
+
+ res = dr_equal_offsets_p1 (TREE_OPERAND (offset1, 0),
+ TREE_OPERAND (offset2, 0));
+
+ if (!res || !BINARY_CLASS_P (offset1))
+ return res;
+
+ res = dr_equal_offsets_p1 (TREE_OPERAND (offset1, 1),
+ TREE_OPERAND (offset2, 1));
+
+ return res;
+}
+
+/* Check if DRA and DRB have equal offsets. */
+bool
+dr_equal_offsets_p (struct data_reference *dra,
+ struct data_reference *drb)
+{
+ tree offset1, offset2;
+
+ offset1 = DR_OFFSET (dra);
+ offset2 = DR_OFFSET (drb);
+
+ return dr_equal_offsets_p1 (offset1, offset2);
+}
+
/* Returns true if FNA == FNB. */
static bool
@@ -4294,7 +4336,7 @@
DATAREFS. Returns chrec_dont_know when failing to analyze a
difficult case, returns NULL_TREE otherwise. */
-static tree
+tree
find_data_references_in_bb (struct loop *loop, basic_block bb,
VEC (data_reference_p, heap) **datarefs)
{
=== modified file 'gcc/tree-data-ref.h'
--- old/gcc/tree-data-ref.h 2011-01-25 21:24:23 +0000
+++ new/gcc/tree-data-ref.h 2011-03-27 09:38:18 +0000
@@ -426,10 +426,14 @@
extern void compute_all_dependences (VEC (data_reference_p, heap) *,
VEC (ddr_p, heap) **, VEC (loop_p, heap) *,
bool);
+extern tree find_data_references_in_bb (struct loop *, basic_block,
+ VEC (data_reference_p, heap) **);
extern void create_rdg_vertices (struct graph *, VEC (gimple, heap) *);
extern bool dr_may_alias_p (const struct data_reference *,
const struct data_reference *);
+extern bool dr_equal_offsets_p (struct data_reference *,
+ struct data_reference *);
/* Return true when the base objects of data references A and B are
=== modified file 'gcc/tree-ssa-phiopt.c'
--- old/gcc/tree-ssa-phiopt.c 2010-11-03 15:18:50 +0000
+++ new/gcc/tree-ssa-phiopt.c 2011-03-27 09:38:18 +0000
@@ -34,6 +34,8 @@
#include "langhooks.h"
#include "pointer-set.h"
#include "domwalk.h"
+#include "cfgloop.h"
+#include "tree-data-ref.h"
static unsigned int tree_ssa_phiopt (void);
static unsigned int tree_ssa_phiopt_worker (bool);
@@ -1292,35 +1294,18 @@
return true;
}
-/* Do the main work of conditional store replacement. We already know
- that the recognized pattern looks like so:
-
- split:
- if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
- THEN_BB:
- X = Y;
- goto JOIN_BB;
- ELSE_BB:
- X = Z;
- fallthrough (edge E0)
- JOIN_BB:
- some more
-
- We check that THEN_BB and ELSE_BB contain only one store
- that the stores have a "simple" RHS. */
+/* Do the main work of conditional store replacement. */
static bool
-cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb,
- basic_block join_bb)
+cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
+ basic_block join_bb, gimple then_assign,
+ gimple else_assign)
{
- gimple then_assign = last_and_only_stmt (then_bb);
- gimple else_assign = last_and_only_stmt (else_bb);
tree lhs_base, lhs, then_rhs, else_rhs;
source_location then_locus, else_locus;
gimple_stmt_iterator gsi;
gimple newphi, new_stmt;
- /* Check if then_bb and else_bb contain only one store each. */
if (then_assign == NULL
|| !gimple_assign_single_p (then_assign)
|| else_assign == NULL
@@ -1385,6 +1370,190 @@
return true;
}
+/* Conditional store replacement. We already know
+ that the recognized pattern looks like so:
+
+ split:
+ if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
+ THEN_BB:
+ ...
+ X = Y;
+ ...
+ goto JOIN_BB;
+ ELSE_BB:
+ ...
+ X = Z;
+ ...
+ fallthrough (edge E0)
+ JOIN_BB:
+ some more
+
+ We check that it is safe to sink the store to JOIN_BB by verifying that
+ there are no read-after-write or write-after-write dependencies in
+ THEN_BB and ELSE_BB. */
+
+static bool
+cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb,
+ basic_block join_bb)
+{
+ gimple then_assign = last_and_only_stmt (then_bb);
+ gimple else_assign = last_and_only_stmt (else_bb);
+ VEC (data_reference_p, heap) *then_datarefs, *else_datarefs;
+ VEC (ddr_p, heap) *then_ddrs, *else_ddrs;
+ gimple then_store, else_store;
+ bool found, ok = false, res;
+ struct data_dependence_relation *ddr;
+ data_reference_p then_dr, else_dr;
+ int i, j;
+ tree then_lhs, else_lhs;
+ VEC (gimple, heap) *then_stores, *else_stores;
+ basic_block blocks[3];
+
+ if (MAX_STORES_TO_SINK == 0)
+ return false;
+
+ /* Handle the case with single statement in THEN_BB and ELSE_BB. */
+ if (then_assign && else_assign)
+ return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
+ then_assign, else_assign);
+
+ /* Find data references. */
+ then_datarefs = VEC_alloc (data_reference_p, heap, 1);
+ else_datarefs = VEC_alloc (data_reference_p, heap, 1);
+ if ((find_data_references_in_bb (NULL, then_bb, &then_datarefs)
+ == chrec_dont_know)
+ || !VEC_length (data_reference_p, then_datarefs)
+ || (find_data_references_in_bb (NULL, else_bb, &else_datarefs)
+ == chrec_dont_know)
+ || !VEC_length (data_reference_p, else_datarefs))
+ {
+ free_data_refs (then_datarefs);
+ free_data_refs (else_datarefs);
+ return false;
+ }
+
+ /* Find pairs of stores with equal LHS. */
+ then_stores = VEC_alloc (gimple, heap, 1);
+ else_stores = VEC_alloc (gimple, heap, 1);
+ FOR_EACH_VEC_ELT (data_reference_p, then_datarefs, i, then_dr)
+ {
+ if (DR_IS_READ (then_dr))
+ continue;
+
+ then_store = DR_STMT (then_dr);
+ then_lhs = gimple_assign_lhs (then_store);
+ found = false;
+
+ FOR_EACH_VEC_ELT (data_reference_p, else_datarefs, j, else_dr)
+ {
+ if (DR_IS_READ (else_dr))
+ continue;
+
+ else_store = DR_STMT (else_dr);
+ else_lhs = gimple_assign_lhs (else_store);
+
+ if (operand_equal_p (then_lhs, else_lhs, 0))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ continue;
+
+ VEC_safe_push (gimple, heap, then_stores, then_store);
+ VEC_safe_push (gimple, heap, else_stores, else_store);
+ }
+
+ /* No pairs of stores found. */
+ if (!VEC_length (gimple, then_stores)
+ || VEC_length (gimple, then_stores) > (unsigned) MAX_STORES_TO_SINK)
+ {
+ free_data_refs (then_datarefs);
+ free_data_refs (else_datarefs);
+ VEC_free (gimple, heap, then_stores);
+ VEC_free (gimple, heap, else_stores);
+ return false;
+ }
+
+ /* Compute and check data dependencies in both basic blocks. */
+ then_ddrs = VEC_alloc (ddr_p, heap, 1);
+ else_ddrs = VEC_alloc (ddr_p, heap, 1);
+ compute_all_dependences (then_datarefs, &then_ddrs, NULL, false);
+ compute_all_dependences (else_datarefs, &else_ddrs, NULL, false);
+ blocks[0] = then_bb;
+ blocks[1] = else_bb;
+ blocks[2] = join_bb;
+ renumber_gimple_stmt_uids_in_blocks (blocks, 3);
+
+ /* Check that there are no read-after-write or write-after-write dependencies
+ in THEN_BB. */
+ FOR_EACH_VEC_ELT (ddr_p, then_ddrs, i, ddr)
+ {
+ struct data_reference *dra = DDR_A (ddr);
+ struct data_reference *drb = DDR_B (ddr);
+
+ if (DDR_ARE_DEPENDENT (ddr) != chrec_known
+ && ((DR_IS_READ (dra) && DR_IS_WRITE (drb)
+ && gimple_uid (DR_STMT (dra)) > gimple_uid (DR_STMT (drb)))
+ || (DR_IS_READ (drb) && DR_IS_WRITE (dra)
+ && gimple_uid (DR_STMT (drb)) > gimple_uid (DR_STMT (dra)))
+ || (DR_IS_WRITE (dra) && DR_IS_WRITE (drb))))
+ {
+ free_dependence_relations (then_ddrs);
+ free_dependence_relations (else_ddrs);
+ free_data_refs (then_datarefs);
+ free_data_refs (else_datarefs);
+ VEC_free (gimple, heap, then_stores);
+ VEC_free (gimple, heap, else_stores);
+ return false;
+ }
+ }
+
+ /* Check that there are no read-after-write or write-after-write dependencies
+ in ELSE_BB. */
+ FOR_EACH_VEC_ELT (ddr_p, else_ddrs, i, ddr)
+ {
+ struct data_reference *dra = DDR_A (ddr);
+ struct data_reference *drb = DDR_B (ddr);
+
+ if (DDR_ARE_DEPENDENT (ddr) != chrec_known
+ && ((DR_IS_READ (dra) && DR_IS_WRITE (drb)
+ && gimple_uid (DR_STMT (dra)) > gimple_uid (DR_STMT (drb)))
+ || (DR_IS_READ (drb) && DR_IS_WRITE (dra)
+ && gimple_uid (DR_STMT (drb)) > gimple_uid (DR_STMT (dra)))
+ || (DR_IS_WRITE (dra) && DR_IS_WRITE (drb))))
+ {
+ free_dependence_relations (then_ddrs);
+ free_dependence_relations (else_ddrs);
+ free_data_refs (then_datarefs);
+ free_data_refs (else_datarefs);
+ VEC_free (gimple, heap, then_stores);
+ VEC_free (gimple, heap, else_stores);
+ return false;
+ }
+ }
+
+ /* Sink stores with same LHS. */
+ FOR_EACH_VEC_ELT (gimple, then_stores, i, then_store)
+ {
+ else_store = VEC_index (gimple, else_stores, i);
+ res = cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
+ then_store, else_store);
+ ok = ok || res;
+ }
+
+ free_dependence_relations (then_ddrs);
+ free_dependence_relations (else_ddrs);
+ free_data_refs (then_datarefs);
+ free_data_refs (else_datarefs);
+ VEC_free (gimple, heap, then_stores);
+ VEC_free (gimple, heap, else_stores);
+
+ return ok;
+}
+
/* Always do these optimizations if we have SSA
trees to work on. */
static bool
=== modified file 'gcc/tree-vect-data-refs.c'
--- old/gcc/tree-vect-data-refs.c 2011-02-25 11:18:14 +0000
+++ new/gcc/tree-vect-data-refs.c 2011-03-27 09:38:18 +0000
@@ -289,39 +289,6 @@
}
}
-
-/* Function vect_equal_offsets.
-
- Check if OFFSET1 and OFFSET2 are identical expressions. */
-
-static bool
-vect_equal_offsets (tree offset1, tree offset2)
-{
- bool res;
-
- STRIP_NOPS (offset1);
- STRIP_NOPS (offset2);
-
- if (offset1 == offset2)
- return true;
-
- if (TREE_CODE (offset1) != TREE_CODE (offset2)
- || (!BINARY_CLASS_P (offset1) && !UNARY_CLASS_P (offset1)))
- return false;
-
- res = vect_equal_offsets (TREE_OPERAND (offset1, 0),
- TREE_OPERAND (offset2, 0));
-
- if (!res || !BINARY_CLASS_P (offset1))
- return res;
-
- res = vect_equal_offsets (TREE_OPERAND (offset1, 1),
- TREE_OPERAND (offset2, 1));
-
- return res;
-}
-
-
/* Check dependence between DRA and DRB for basic block vectorization.
If the accesses share same bases and offsets, we can compare their initial
constant offsets to decide whether they differ or not. In case of a read-
@@ -352,7 +319,7 @@
|| TREE_CODE (DR_BASE_ADDRESS (drb)) != ADDR_EXPR
|| TREE_OPERAND (DR_BASE_ADDRESS (dra), 0)
!= TREE_OPERAND (DR_BASE_ADDRESS (drb),0)))
- || !vect_equal_offsets (DR_OFFSET (dra), DR_OFFSET (drb)))
+ || !dr_equal_offsets_p (dra, drb))
return true;
/* Check the types. */
@@ -402,7 +369,7 @@
|| TREE_CODE (DR_BASE_ADDRESS (drb)) != ADDR_EXPR
|| TREE_OPERAND (DR_BASE_ADDRESS (dra), 0)
!= TREE_OPERAND (DR_BASE_ADDRESS (drb),0)))
- || !vect_equal_offsets (DR_OFFSET (dra), DR_OFFSET (drb))
+ || !dr_equal_offsets_p (dra, drb)
|| !tree_int_cst_compare (DR_INIT (dra), DR_INIT (drb))
|| DR_IS_READ (dra) != DR_IS_READ (drb))
return false;
@@ -0,0 +1,126 @@
2011-04-21 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF:
2008-12-03 Daniel Jacobowitz <dan@codesourcery.com>
gcc/testsuite/
* gcc.dg/vect/vect-shift-3.c, gcc.dg/vect/vect-shift-4.c: New.
* lib/target-supports.exp (check_effective_target_vect_shift_char): New
function.
=== added file 'gcc/testsuite/gcc.dg/vect/vect-shift-3.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-shift-3.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-shift-3.c 2011-04-21 13:51:06 +0000
@@ -0,0 +1,37 @@
+/* { dg-require-effective-target vect_shift } */
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+
+#define N 32
+
+unsigned short dst[N] __attribute__((aligned(N)));
+unsigned short src[N] __attribute__((aligned(N)));
+
+__attribute__ ((noinline))
+void array_shift(void)
+{
+ int i;
+ for (i = 0; i < N; i++)
+ dst[i] = src[i] >> 3;
+}
+
+int main()
+{
+ volatile int i;
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ src[i] = i << 3;
+
+ array_shift ();
+
+ for (i = 0; i < N; i++)
+ if (dst[i] != i)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== added file 'gcc/testsuite/gcc.dg/vect/vect-shift-4.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-shift-4.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-shift-4.c 2011-04-21 13:51:06 +0000
@@ -0,0 +1,37 @@
+/* { dg-require-effective-target vect_shift_char } */
+/* { dg-require-effective-target vect_int } */
+
+#include "tree-vect.h"
+
+#define N 32
+
+unsigned char dst[N] __attribute__((aligned(N)));
+unsigned char src[N] __attribute__((aligned(N)));
+
+__attribute__ ((noinline))
+void array_shift(void)
+{
+ int i;
+ for (i = 0; i < N; i++)
+ dst[i] = src[i] >> 3;
+}
+
+int main()
+{
+ volatile int i;
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ src[i] = i << 3;
+
+ array_shift ();
+
+ for (i = 0; i < N; i++)
+ if (dst[i] != i)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/lib/target-supports.exp'
--- old/gcc/testsuite/lib/target-supports.exp 2011-02-19 15:31:15 +0000
+++ new/gcc/testsuite/lib/target-supports.exp 2011-04-21 13:51:06 +0000
@@ -2308,6 +2308,26 @@
}
+# Return 1 if the target supports hardware vector shift operation for char.
+
+proc check_effective_target_vect_shift_char { } {
+ global et_vect_shift_char_saved
+
+ if [info exists et_vect_shift_char_saved] {
+ verbose "check_effective_target_vect_shift_char: using cached result" 2
+ } else {
+ set et_vect_shift_char_saved 0
+ if { ([istarget powerpc*-*-*]
+ && ![istarget powerpc-*-linux*paired*])
+ || [check_effective_target_arm32] } {
+ set et_vect_shift_char_saved 1
+ }
+ }
+
+ verbose "check_effective_target_vect_shift_char: returning $et_vect_shift_char_saved" 2
+ return $et_vect_shift_char_saved
+}
+
# Return 1 if the target supports hardware vectors of long, 0 otherwise.
#
# This can change for different subtargets so do not cache the result.
@@ -0,0 +1,177 @@
2011-04-27 Ira Rosen <ira.rosen@linaro.org>
Backport from FSF:
2011-04-03 Richard Guenther <rguenther@suse.de>
Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-if-conv.c (memrefs_read_or_written_unconditionally): Strip all
non-variable offsets and compare the remaining bases of the two
accesses instead of looking for exact same data-ref.
gcc/testsuite/
* gcc.dg/vect/if-cvt-stores-vect-ifcvt-18.c: New test.
* gcc.dg/vect/vect.exp: Run if-cvt-stores-vect* tests with
-ftree-loop-if-convert-stores.
=== added file 'gcc/testsuite/gcc.dg/vect/if-cvt-stores-vect-ifcvt-18.c'
--- old/gcc/testsuite/gcc.dg/vect/if-cvt-stores-vect-ifcvt-18.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/if-cvt-stores-vect-ifcvt-18.c 2011-04-24 07:45:49 +0000
@@ -0,0 +1,69 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 50
+
+typedef struct {
+ short a;
+ short b;
+} data;
+
+data in1[N], in2[N], out[N];
+short result[N*2] = {10,-7,11,-6,12,-5,13,-4,14,-3,15,-2,16,-1,17,0,18,1,19,2,20,3,21,4,22,5,23,6,24,7,25,8,26,9,27,10,28,11,29,12,30,13,31,14,32,15,33,16,34,17,35,18,36,19,37,20,38,21,39,22,40,23,41,24,42,25,43,26,44,27,45,28,46,29,47,30,48,31,49,32,50,33,51,34,52,35,53,36,54,37,55,38,56,39,57,40,58,41,59,42};
+short out1[N], out2[N];
+
+__attribute__ ((noinline)) void
+foo ()
+{
+ int i;
+ short c, d;
+
+ for (i = 0; i < N; i++)
+ {
+ c = in1[i].b;
+ d = in2[i].b;
+
+ if (c >= d)
+ {
+ out[i].b = in1[i].a;
+ out[i].a = d + 5;
+ }
+ else
+ {
+ out[i].b = d - 12;
+ out[i].a = in2[i].a + d;
+ }
+ }
+}
+
+int
+main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ in1[i].a = i;
+ in1[i].b = i + 2;
+ in2[i].a = 5;
+ in2[i].b = i + 5;
+ __asm__ volatile ("");
+ }
+
+ foo ();
+
+ for (i = 0; i < N; i++)
+ {
+ if (out[i].a != result[2*i] || out[i].b != result[2*i+1])
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail { vect_no_align || {! vect_strided } } } } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect.exp'
--- old/gcc/testsuite/gcc.dg/vect/vect.exp 2010-11-22 21:49:19 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect.exp 2011-04-24 07:45:49 +0000
@@ -210,6 +210,12 @@
dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/ggc-*.\[cS\]]] \
"" $DEFAULT_VECTCFLAGS
+# -ftree-loop-if-convert-stores
+set DEFAULT_VECTCFLAGS $SAVED_DEFAULT_VECTCFLAGS
+lappend DEFAULT_VECTCFLAGS "-ftree-loop-if-convert-stores"
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/if-cvt-stores-vect-*.\[cS\]]] \
+ "" $DEFAULT_VECTCFLAGS
+
# With -O3.
# Don't allow IPA cloning, because it throws our counts out of whack.
set DEFAULT_VECTCFLAGS $SAVED_DEFAULT_VECTCFLAGS
=== modified file 'gcc/tree-if-conv.c'
--- old/gcc/tree-if-conv.c 2011-02-23 16:49:52 +0000
+++ new/gcc/tree-if-conv.c 2011-04-24 07:45:49 +0000
@@ -464,8 +464,8 @@
/* Returns true when the memory references of STMT are read or written
unconditionally. In other words, this function returns true when
for every data reference A in STMT there exist other accesses to
- the same data reference with predicates that add up (OR-up) to the
- true predicate: this ensures that the data reference A is touched
+ a data reference with the same base with predicates that add up (OR-up) to
+ the true predicate: this ensures that the data reference A is touched
(read or written) on every iteration of the if-converted loop. */
static bool
@@ -489,21 +489,38 @@
continue;
for (j = 0; VEC_iterate (data_reference_p, drs, j, b); j++)
- if (DR_STMT (b) != stmt
- && same_data_refs (a, b))
- {
- tree cb = bb_predicate (gimple_bb (DR_STMT (b)));
-
- if (DR_RW_UNCONDITIONALLY (b) == 1
- || is_true_predicate (cb)
- || is_true_predicate (ca = fold_or_predicates (EXPR_LOCATION (cb),
- ca, cb)))
- {
- DR_RW_UNCONDITIONALLY (a) = 1;
- DR_RW_UNCONDITIONALLY (b) = 1;
- found = true;
- break;
- }
+ {
+ tree ref_base_a = DR_REF (a);
+ tree ref_base_b = DR_REF (b);
+
+ if (DR_STMT (b) == stmt)
+ continue;
+
+ while (TREE_CODE (ref_base_a) == COMPONENT_REF
+ || TREE_CODE (ref_base_a) == IMAGPART_EXPR
+ || TREE_CODE (ref_base_a) == REALPART_EXPR)
+ ref_base_a = TREE_OPERAND (ref_base_a, 0);
+
+ while (TREE_CODE (ref_base_b) == COMPONENT_REF
+ || TREE_CODE (ref_base_b) == IMAGPART_EXPR
+ || TREE_CODE (ref_base_b) == REALPART_EXPR)
+ ref_base_b = TREE_OPERAND (ref_base_b, 0);
+
+ if (!operand_equal_p (ref_base_a, ref_base_b, 0))
+ {
+ tree cb = bb_predicate (gimple_bb (DR_STMT (b)));
+
+ if (DR_RW_UNCONDITIONALLY (b) == 1
+ || is_true_predicate (cb)
+ || is_true_predicate (ca
+ = fold_or_predicates (EXPR_LOCATION (cb), ca, cb)))
+ {
+ DR_RW_UNCONDITIONALLY (a) = 1;
+ DR_RW_UNCONDITIONALLY (b) = 1;
+ found = true;
+ break;
+ }
+ }
}
if (!found)
@@ -0,0 +1,140 @@
2011-05-02 Ira Rosen <ira.rosen@linaro.org>
Backport from FSF:
2011-03-27 Ira Rosen <ira.rosen@linaro.org>
gcc/
* config/arm/arm.c (arm_autovectorize_vector_sizes): New function.
(TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES): Define.
gcc/testsuite/
* gcc.dg/vect/vect-outer-5.c: Reduce the distance between data
accesses to preserve the meaning of the test for doubleword vectors.
* gcc.dg/vect/no-vfa-pr29145.c: Likewise.
* gcc.dg/vect/slp-3.c: Reduce the loop bound for the same reason.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-03-02 11:38:43 +0000
+++ new/gcc/config/arm/arm.c 2011-04-28 11:46:58 +0000
@@ -250,6 +250,7 @@
bool is_packed);
static void arm_conditional_register_usage (void);
static reg_class_t arm_preferred_rename_class (reg_class_t rclass);
+static unsigned int arm_autovectorize_vector_sizes (void);
/* Table of machine attributes. */
@@ -395,6 +396,9 @@
#define TARGET_VECTOR_MODE_SUPPORTED_P arm_vector_mode_supported_p
#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE arm_preferred_simd_mode
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES \
+ arm_autovectorize_vector_sizes
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG arm_reorg
@@ -23511,6 +23515,12 @@
}
}
+static unsigned int
+arm_autovectorize_vector_sizes (void)
+{
+ return TARGET_NEON_VECTORIZE_QUAD ? 16 | 8 : 0;
+}
+
static bool
arm_vector_alignment_reachable (const_tree type, bool is_packed)
{
=== modified file 'gcc/testsuite/gcc.dg/vect/no-vfa-pr29145.c'
--- old/gcc/testsuite/gcc.dg/vect/no-vfa-pr29145.c 2010-10-04 14:59:30 +0000
+++ new/gcc/testsuite/gcc.dg/vect/no-vfa-pr29145.c 2011-04-28 11:46:58 +0000
@@ -8,7 +8,7 @@
void with_restrict(int * __restrict p)
{
int i;
- int *q = p - 2;
+ int *q = p - 1;
for (i = 0; i < 1000; ++i) {
p[i] = q[i];
@@ -19,7 +19,7 @@
void without_restrict(int * p)
{
int i;
- int *q = p - 2;
+ int *q = p - 1;
for (i = 0; i < 1000; ++i) {
p[i] = q[i];
@@ -38,8 +38,8 @@
a[i] = b[i] = i;
}
- with_restrict(a + 2);
- without_restrict(b + 2);
+ with_restrict(a + 1);
+ without_restrict(b + 1);
for (i = 0; i < 1002; ++i) {
if (a[i] != b[i])
=== modified file 'gcc/testsuite/gcc.dg/vect/slp-3.c'
--- old/gcc/testsuite/gcc.dg/vect/slp-3.c 2010-11-22 12:16:52 +0000
+++ new/gcc/testsuite/gcc.dg/vect/slp-3.c 2011-04-28 11:46:58 +0000
@@ -4,9 +4,9 @@
#include <stdarg.h>
#include "tree-vect.h"
-#define N 8
+#define N 12
-unsigned short in[N*8] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63};
+unsigned short in[N*8] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
int
main1 ()
@@ -101,7 +101,7 @@
}
/* SLP with unrolling by 8. */
- for (i = 0; i < N/2; i++)
+ for (i = 0; i < N/4; i++)
{
out[i*9] = in[i*9];
out[i*9 + 1] = in[i*9 + 1];
@@ -115,7 +115,7 @@
}
/* check results: */
- for (i = 0; i < N/2; i++)
+ for (i = 0; i < N/4; i++)
{
if (out[i*9] != in[i*9]
|| out[i*9 + 1] != in[i*9 + 1]
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-outer-5.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-outer-5.c 2010-11-22 12:16:52 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-outer-5.c 2011-04-28 11:46:58 +0000
@@ -17,7 +17,7 @@
float B[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
float C[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
float D[N] __attribute__ ((__aligned__(__BIGGEST_ALIGNMENT__)));
- float E[4] = {0,1,2,480};
+ float E[4] = {0,480,960,1440};
float s;
int i, j;
@@ -55,7 +55,7 @@
s = 0;
for (j=0; j<N; j+=4)
s += C[j];
- B[i+3] = B[i] + s;
+ B[i+1] = B[i] + s;
}
/* check results: */
@@ -0,0 +1,255 @@
2011-04-26 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF:
2011-04-15 Maxim Kuvyrkov <maxim@codesourcery.com>
gcc/
* combine.c (subst, combine_simlify_rtx): Add new argument, use it
to track processing of conditionals. Update all callers.
(try_combine, simplify_if_then_else): Update.
2011-04-25 Maxim Kuvyrkov <maxim@codesourcery.com>
Eric Botcazou <ebotcazou@adacore.com>
gcc/
* combine.c (combine_simplify_rtx): Avoid mis-simplifying conditionals
for STORE_FLAG_VALUE==-1 case.
=== modified file 'gcc/combine.c'
Index: gcc-4_6-branch/gcc/combine.c
===================================================================
--- gcc-4_6-branch.orig/gcc/combine.c 2012-03-05 00:16:20.000000000 -0800
+++ gcc-4_6-branch/gcc/combine.c 2012-03-05 16:05:01.212928507 -0800
@@ -391,8 +391,8 @@
static void undo_all (void);
static void undo_commit (void);
static rtx *find_split_point (rtx *, rtx, bool);
-static rtx subst (rtx, rtx, rtx, int, int);
-static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
+static rtx subst (rtx, rtx, rtx, int, int, int);
+static rtx combine_simplify_rtx (rtx, enum machine_mode, int, int);
static rtx simplify_if_then_else (rtx);
static rtx simplify_set (rtx);
static rtx simplify_logical (rtx);
@@ -3119,12 +3119,12 @@
if (i1)
{
subst_low_luid = DF_INSN_LUID (i1);
- i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0);
+ i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0, 0);
}
else
{
subst_low_luid = DF_INSN_LUID (i2);
- i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
+ i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
}
}
@@ -3136,7 +3136,7 @@
self-referential RTL when we will be substituting I1SRC for I1DEST
later. Likewise if I0 feeds into I2, either directly or indirectly
through I1, and I0DEST is in I0SRC. */
- newpat = subst (PATTERN (i3), i2dest, i2src, 0,
+ newpat = subst (PATTERN (i3), i2dest, i2src, 0, 0,
(i1_feeds_i2_n && i1dest_in_i1src)
|| ((i0_feeds_i2_n || (i0_feeds_i1_n && i1_feeds_i2_n))
&& i0dest_in_i0src));
@@ -3180,7 +3180,7 @@
copy of I1SRC each time we substitute it, in order to avoid creating
self-referential RTL when we will be substituting I0SRC for I0DEST
later. */
- newpat = subst (newpat, i1dest, i1src, 0,
+ newpat = subst (newpat, i1dest, i1src, 0, 0,
i0_feeds_i1_n && i0dest_in_i0src);
substed_i1 = 1;
@@ -3214,7 +3214,7 @@
n_occurrences = 0;
subst_low_luid = DF_INSN_LUID (i0);
- newpat = subst (newpat, i0dest, i0src, 0, 0);
+ newpat = subst (newpat, i0dest, i0src, 0, 0, 0);
substed_i0 = 1;
}
@@ -3276,7 +3276,7 @@
{
rtx t = i1pat;
if (i0_feeds_i1_n)
- t = subst (t, i0dest, i0src_copy ? i0src_copy : i0src, 0, 0);
+ t = subst (t, i0dest, i0src_copy ? i0src_copy : i0src, 0, 0, 0);
XVECEXP (newpat, 0, --total_sets) = t;
}
@@ -3284,10 +3284,10 @@
{
rtx t = i2pat;
if (i1_feeds_i2_n)
- t = subst (t, i1dest, i1src_copy ? i1src_copy : i1src, 0,
+ t = subst (t, i1dest, i1src_copy ? i1src_copy : i1src, 0, 0,
i0_feeds_i1_n && i0dest_in_i0src);
if ((i0_feeds_i1_n && i1_feeds_i2_n) || i0_feeds_i2_n)
- t = subst (t, i0dest, i0src_copy2 ? i0src_copy2 : i0src, 0, 0);
+ t = subst (t, i0dest, i0src_copy2 ? i0src_copy2 : i0src, 0, 0, 0);
XVECEXP (newpat, 0, --total_sets) = t;
}
@@ -4959,11 +4959,13 @@
IN_DEST is nonzero if we are processing the SET_DEST of a SET.
+ IN_COND is nonzero if we are on top level of the condition.
+
UNIQUE_COPY is nonzero if each substitution must be unique. We do this
by copying if `n_occurrences' is nonzero. */
static rtx
-subst (rtx x, rtx from, rtx to, int in_dest, int unique_copy)
+subst (rtx x, rtx from, rtx to, int in_dest, int in_cond, int unique_copy)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode op0_mode = VOIDmode;
@@ -5024,7 +5026,7 @@
&& GET_CODE (XVECEXP (x, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
{
- new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
+ new_rtx = subst (XVECEXP (x, 0, 0), from, to, 0, 0, unique_copy);
/* If this substitution failed, this whole thing fails. */
if (GET_CODE (new_rtx) == CLOBBER
@@ -5041,7 +5043,7 @@
&& GET_CODE (dest) != CC0
&& GET_CODE (dest) != PC)
{
- new_rtx = subst (dest, from, to, 0, unique_copy);
+ new_rtx = subst (dest, from, to, 0, 0, unique_copy);
/* If this substitution failed, this whole thing fails. */
if (GET_CODE (new_rtx) == CLOBBER
@@ -5087,8 +5089,8 @@
}
else
{
- new_rtx = subst (XVECEXP (x, i, j), from, to, 0,
- unique_copy);
+ new_rtx = subst (XVECEXP (x, i, j), from, to, 0, 0,
+ unique_copy);
/* If this substitution failed, this whole thing
fails. */
@@ -5165,7 +5167,9 @@
&& (code == SUBREG || code == STRICT_LOW_PART
|| code == ZERO_EXTRACT))
|| code == SET)
- && i == 0), unique_copy);
+ && i == 0),
+ code == IF_THEN_ELSE && i == 0,
+ unique_copy);
/* If we found that we will have to reject this combination,
indicate that by returning the CLOBBER ourselves, rather than
@@ -5222,7 +5226,7 @@
/* If X is sufficiently simple, don't bother trying to do anything
with it. */
if (code != CONST_INT && code != REG && code != CLOBBER)
- x = combine_simplify_rtx (x, op0_mode, in_dest);
+ x = combine_simplify_rtx (x, op0_mode, in_dest, in_cond);
if (GET_CODE (x) == code)
break;
@@ -5242,10 +5246,12 @@
expression.
OP0_MODE is the original mode of XEXP (x, 0). IN_DEST is nonzero
- if we are inside a SET_DEST. */
+ if we are inside a SET_DEST. IN_COND is nonzero if we are on the top level
+ of a condition. */
static rtx
-combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
+combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest,
+ int in_cond)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
@@ -5300,8 +5306,8 @@
false arms to store-flag values. Be careful to use copy_rtx
here since true_rtx or false_rtx might share RTL with x as a
result of the if_then_else_cond call above. */
- true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0);
- false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0);
+ true_rtx = subst (copy_rtx (true_rtx), pc_rtx, pc_rtx, 0, 0, 0);
+ false_rtx = subst (copy_rtx (false_rtx), pc_rtx, pc_rtx, 0, 0, 0);
/* If true_rtx and false_rtx are not general_operands, an if_then_else
is unlikely to be simpler. */
@@ -5645,7 +5651,7 @@
{
/* Try to simplify the expression further. */
rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
- temp = combine_simplify_rtx (tor, VOIDmode, in_dest);
+ temp = combine_simplify_rtx (tor, VOIDmode, in_dest, 0);
/* If we could, great. If not, do not go ahead with the IOR
replacement, since PLUS appears in many special purpose
@@ -5738,7 +5744,16 @@
ZERO_EXTRACT is indeed appropriate, it will be placed back by
the call to make_compound_operation in the SET case. */
- if (STORE_FLAG_VALUE == 1
+ if (in_cond)
+ /* Don't apply below optimizations if the caller would
+ prefer a comparison rather than a value.
+ E.g., for the condition in an IF_THEN_ELSE most targets need
+ an explicit comparison. */
+ {
+ ;
+ }
+
+ else if (STORE_FLAG_VALUE == 1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
@@ -5784,7 +5799,10 @@
/* If STORE_FLAG_VALUE is -1, we have cases similar to
those above. */
- if (STORE_FLAG_VALUE == -1
+ if (in_cond)
+ ;
+
+ else if (STORE_FLAG_VALUE == -1
&& new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
@@ -5982,11 +6000,11 @@
if (reg_mentioned_p (from, true_rtx))
true_rtx = subst (known_cond (copy_rtx (true_rtx), true_code,
from, true_val),
- pc_rtx, pc_rtx, 0, 0);
+ pc_rtx, pc_rtx, 0, 0, 0);
if (reg_mentioned_p (from, false_rtx))
false_rtx = subst (known_cond (copy_rtx (false_rtx), false_code,
from, false_val),
- pc_rtx, pc_rtx, 0, 0);
+ pc_rtx, pc_rtx, 0, 0, 0);
SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx);
SUBST (XEXP (x, 2), swapped ? true_rtx : false_rtx);
@@ -6203,11 +6221,11 @@
{
temp = subst (simplify_gen_relational (true_code, m, VOIDmode,
cond_op0, cond_op1),
- pc_rtx, pc_rtx, 0, 0);
+ pc_rtx, pc_rtx, 0, 0, 0);
temp = simplify_gen_binary (MULT, m, temp,
simplify_gen_binary (MULT, m, c1,
const_true_rtx));
- temp = subst (temp, pc_rtx, pc_rtx, 0, 0);
+ temp = subst (temp, pc_rtx, pc_rtx, 0, 0, 0);
temp = simplify_gen_binary (op, m, gen_lowpart (m, z), temp);
if (extend_op != UNKNOWN)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,21 @@
2011-05-06 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
From Sergey Grechanik <mouseentity@ispras.ru>, approved for mainline
* config/arm/arm.c (coproc_secondary_reload_class): Return NO_REGS
for constant vectors.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-05-03 15:18:07 +0000
+++ new/gcc/config/arm/arm.c 2011-05-06 11:33:02 +0000
@@ -9193,7 +9193,7 @@
/* The neon move patterns handle all legitimate vector and struct
addresses. */
if (TARGET_NEON
- && MEM_P (x)
+ && (MEM_P (x) || GET_CODE (x) == CONST_VECTOR)
&& (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
|| GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
|| VALID_NEON_STRUCT_MODE (mode)))
@@ -0,0 +1,24 @@
2011-05-12 Michael Hope <michael.hope@linaro.org>
gcc/
Backport from mainline:
2011-05-05 Michael Hope <michael.hope@linaro.org>
PR pch/45979
* config/host-linux.c (TRY_EMPTY_VM_SPACE): Define for
__ARM_EABI__ hosts.
=== modified file 'gcc/config/host-linux.c'
--- old/gcc/config/host-linux.c 2010-11-29 14:09:41 +0000
+++ new/gcc/config/host-linux.c 2011-05-06 20:19:30 +0000
@@ -84,6 +84,8 @@
# define TRY_EMPTY_VM_SPACE 0x60000000
#elif defined(__mc68000__)
# define TRY_EMPTY_VM_SPACE 0x40000000
+#elif defined(__ARM_EABI__)
+# define TRY_EMPTY_VM_SPACE 0x60000000
#else
# define TRY_EMPTY_VM_SPACE 0
#endif
@@ -0,0 +1,640 @@
2011-05-13 Revital Eres <revital.eres@linaro.org>
gcc/
* loop-doloop.c (doloop_condition_get): Support new form of
doloop pattern and use prev_nondebug_insn instead of PREV_INSN.
* config/arm/thumb2.md (*thumb2_addsi3_compare0): Remove "*".
(doloop_end): New.
* config/arm/arm.md (*addsi3_compare0): Remove "*".
* params.def (sms-min-sc): New param flag.
* doc/invoke.texi (sms-min-sc): Document it.
* ddg.c (create_ddg_dep_from_intra_loop_link): If a true dep edge
enters the branch create an anti edge in the opposite direction
to prevent the creation of reg-moves.
* modulo-sched.c: Adjust comment to reflect the fact we are
scheduling closing branch.
(PS_STAGE_COUNT): Rename to CALC_STAGE_COUNT and redefine.
(stage_count): New field in struct partial_schedule.
(calculate_stage_count): New function.
(normalize_sched_times): Rename to reset_sched_times and handle
incrementing the sched time of the nodes by a constant value
passed as parameter.
(duplicate_insns_of_cycles): Skip closing branch.
(sms_schedule_by_order): Schedule closing branch.
(ps_insn_find_column): Handle closing branch.
(sms_schedule): Call reset_sched_times and adjust the code to
support scheduling of the closing branch. Use sms-min-sc.
Support new form of doloop pattern.
(ps_insert_empty_row): Update calls to normalize_sched_times
and rotate_partial_schedule functions.
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2011-05-06 11:28:27 +0000
+++ new/gcc/config/arm/arm.md 2011-05-13 13:42:39 +0000
@@ -791,7 +791,7 @@
""
)
-(define_insn "*addsi3_compare0"
+(define_insn "addsi3_compare0"
[(set (reg:CC_NOOV CC_REGNUM)
(compare:CC_NOOV
(plus:SI (match_operand:SI 1 "s_register_operand" "r, r")
=== modified file 'gcc/config/arm/thumb2.md'
--- old/gcc/config/arm/thumb2.md 2011-01-03 20:52:22 +0000
+++ new/gcc/config/arm/thumb2.md 2011-05-11 07:15:47 +0000
@@ -836,7 +836,7 @@
"operands[4] = GEN_INT (- INTVAL (operands[2]));"
)
-(define_insn "*thumb2_addsi3_compare0"
+(define_insn "thumb2_addsi3_compare0"
[(set (reg:CC_NOOV CC_REGNUM)
(compare:CC_NOOV
(plus:SI (match_operand:SI 1 "s_register_operand" "l, 0, r")
@@ -1118,3 +1118,54 @@
"
operands[2] = GEN_INT (32 - INTVAL (operands[2]));
")
+
+;; Define the subtract-one-and-jump insns so loop.c
+;; knows what to generate.
+(define_expand "doloop_end"
+ [(use (match_operand 0 "" "")) ; loop pseudo
+ (use (match_operand 1 "" "")) ; iterations; zero if unknown
+ (use (match_operand 2 "" "")) ; max iterations
+ (use (match_operand 3 "" "")) ; loop level
+ (use (match_operand 4 "" ""))] ; label
+ "TARGET_32BIT"
+ "
+ {
+ /* Currently SMS relies on the do-loop pattern to recognize loops
+ where (1) the control part consists of all insns defining and/or
+ using a certain 'count' register and (2) the loop count can be
+ adjusted by modifying this register prior to the loop.
+ ??? The possible introduction of a new block to initialize the
+ new IV can potentially affect branch optimizations. */
+ if (optimize > 0 && flag_modulo_sched)
+ {
+ rtx s0;
+ rtx bcomp;
+ rtx loc_ref;
+ rtx cc_reg;
+ rtx insn;
+ rtx cmp;
+
+ /* Only use this on innermost loops. */
+ if (INTVAL (operands[3]) > 1)
+ FAIL;
+ if (GET_MODE (operands[0]) != SImode)
+ FAIL;
+
+ s0 = operands [0];
+ if (TARGET_THUMB2)
+ insn = emit_insn (gen_thumb2_addsi3_compare0 (s0, s0, GEN_INT (-1)));
+ else
+ insn = emit_insn (gen_addsi3_compare0 (s0, s0, GEN_INT (-1)));
+
+ cmp = XVECEXP (PATTERN (insn), 0, 0);
+ cc_reg = SET_DEST (cmp);
+ bcomp = gen_rtx_NE (VOIDmode, cc_reg, const0_rtx);
+ loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]);
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp,
+ loc_ref, pc_rtx)));
+ DONE;
+ }else
+ FAIL;
+}")
+
=== modified file 'gcc/ddg.c'
--- old/gcc/ddg.c 2010-11-30 11:41:24 +0000
+++ new/gcc/ddg.c 2011-05-11 07:15:47 +0000
@@ -197,6 +197,11 @@
}
}
+ /* If a true dep edge enters the branch create an anti edge in the
+ opposite direction to prevent the creation of reg-moves. */
+ if ((DEP_TYPE (link) == REG_DEP_TRUE) && JUMP_P (dest_node->insn))
+ create_ddg_dep_no_link (g, dest_node, src_node, ANTI_DEP, REG_DEP, 1);
+
latency = dep_cost (link);
e = create_ddg_edge (src_node, dest_node, t, dt, latency, distance);
add_edge_to_ddg (g, e);
=== modified file 'gcc/doc/invoke.texi'
--- old/gcc/doc/invoke.texi 2011-04-18 11:31:29 +0000
+++ new/gcc/doc/invoke.texi 2011-05-11 07:15:47 +0000
@@ -8730,6 +8730,10 @@
The maximum number of best instructions in the ready list that are considered
for renaming in the selective scheduler. The default value is 2.
+@item sms-min-sc
+The minimum value of stage count that swing modulo scheduler will
+generate. The default value is 2.
+
@item max-last-value-rtl
The maximum size measured as number of RTLs that can be recorded in an expression
in combiner for a pseudo register as last known value of that register. The default
=== modified file 'gcc/loop-doloop.c'
--- old/gcc/loop-doloop.c 2010-11-30 11:41:24 +0000
+++ new/gcc/loop-doloop.c 2011-05-11 07:15:47 +0000
@@ -78,6 +78,8 @@
rtx inc_src;
rtx condition;
rtx pattern;
+ rtx cc_reg = NULL_RTX;
+ rtx reg_orig = NULL_RTX;
/* The canonical doloop pattern we expect has one of the following
forms:
@@ -96,7 +98,16 @@
2) (set (reg) (plus (reg) (const_int -1))
(set (pc) (if_then_else (reg != 0)
(label_ref (label))
- (pc))). */
+ (pc))).
+
+ Some targets (ARM) do the comparison before the branch, as in the
+ following form:
+
+ 3) (parallel [(set (cc) (compare ((plus (reg) (const_int -1), 0)))
+ (set (reg) (plus (reg) (const_int -1)))])
+ (set (pc) (if_then_else (cc == NE)
+ (label_ref (label))
+ (pc))) */
pattern = PATTERN (doloop_pat);
@@ -104,19 +115,47 @@
{
rtx cond;
rtx prev_insn = prev_nondebug_insn (doloop_pat);
+ rtx cmp_arg1, cmp_arg2;
+ rtx cmp_orig;
- /* We expect the decrement to immediately precede the branch. */
+ /* In case the pattern is not PARALLEL we expect two forms
+ of doloop which are cases 2) and 3) above: in case 2) the
+ decrement immediately precedes the branch, while in case 3)
+ the compare and decrement instructions immediately precede
+ the branch. */
if (prev_insn == NULL_RTX || !INSN_P (prev_insn))
return 0;
cmp = pattern;
- inc = PATTERN (PREV_INSN (doloop_pat));
+ if (GET_CODE (PATTERN (prev_insn)) == PARALLEL)
+ {
+ /* The third case: the compare and decrement instructions
+ immediately precede the branch. */
+ cmp_orig = XVECEXP (PATTERN (prev_insn), 0, 0);
+ if (GET_CODE (cmp_orig) != SET)
+ return 0;
+ if (GET_CODE (SET_SRC (cmp_orig)) != COMPARE)
+ return 0;
+ cmp_arg1 = XEXP (SET_SRC (cmp_orig), 0);
+ cmp_arg2 = XEXP (SET_SRC (cmp_orig), 1);
+ if (cmp_arg2 != const0_rtx
+ || GET_CODE (cmp_arg1) != PLUS)
+ return 0;
+ reg_orig = XEXP (cmp_arg1, 0);
+ if (XEXP (cmp_arg1, 1) != GEN_INT (-1)
+ || !REG_P (reg_orig))
+ return 0;
+ cc_reg = SET_DEST (cmp_orig);
+
+ inc = XVECEXP (PATTERN (prev_insn), 0, 1);
+ }
+ else
+ inc = PATTERN (prev_insn);
/* We expect the condition to be of the form (reg != 0) */
cond = XEXP (SET_SRC (cmp), 0);
if (GET_CODE (cond) != NE || XEXP (cond, 1) != const0_rtx)
return 0;
-
}
else
{
@@ -162,11 +201,15 @@
return 0;
if ((XEXP (condition, 0) == reg)
+ /* For the third case: */
+ || ((cc_reg != NULL_RTX)
+ && (XEXP (condition, 0) == cc_reg)
+ && (reg_orig == reg))
|| (GET_CODE (XEXP (condition, 0)) == PLUS
- && XEXP (XEXP (condition, 0), 0) == reg))
+ && XEXP (XEXP (condition, 0), 0) == reg))
{
if (GET_CODE (pattern) != PARALLEL)
- /* The second form we expect:
+ /* For the second form we expect:
(set (reg) (plus (reg) (const_int -1))
(set (pc) (if_then_else (reg != 0)
@@ -181,7 +224,24 @@
(set (reg) (plus (reg) (const_int -1)))
(additional clobbers and uses)])
- So we return that form instead.
+ For the third form we expect:
+
+ (parallel [(set (cc) (compare ((plus (reg) (const_int -1)), 0))
+ (set (reg) (plus (reg) (const_int -1)))])
+ (set (pc) (if_then_else (cc == NE)
+ (label_ref (label))
+ (pc)))
+
+ which is equivalent to the following:
+
+ (parallel [(set (cc) (compare (reg, 1))
+ (set (reg) (plus (reg) (const_int -1)))
+ (set (pc) (if_then_else (NE == cc)
+ (label_ref (label))
+ (pc))))])
+
+ So we return the second form instead for the two cases.
+
*/
condition = gen_rtx_fmt_ee (NE, VOIDmode, inc_src, const1_rtx);
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-02-14 17:59:10 +0000
+++ new/gcc/modulo-sched.c 2011-05-11 07:15:47 +0000
@@ -84,14 +84,13 @@
II cycles (i.e. use register copies to prevent a def from overwriting
itself before reaching the use).
- SMS works with countable loops (1) whose control part can be easily
- decoupled from the rest of the loop and (2) whose loop count can
- be easily adjusted. This is because we peel a constant number of
- iterations into a prologue and epilogue for which we want to avoid
- emitting the control part, and a kernel which is to iterate that
- constant number of iterations less than the original loop. So the
- control part should be a set of insns clearly identified and having
- its own iv, not otherwise used in the loop (at-least for now), which
+ SMS works with countable loops whose loop count can be easily
+ adjusted. This is because we peel a constant number of iterations
+ into a prologue and epilogue for which we want to avoid emitting
+ the control part, and a kernel which is to iterate that constant
+ number of iterations less than the original loop. So the control
+ part should be a set of insns clearly identified and having its
+ own iv, not otherwise used in the loop (at-least for now), which
initializes a register before the loop to the number of iterations.
Currently SMS relies on the do-loop pattern to recognize such loops,
where (1) the control part comprises of all insns defining and/or
@@ -116,8 +115,10 @@
/* The number of different iterations the nodes in ps span, assuming
the stage boundaries are placed efficiently. */
-#define PS_STAGE_COUNT(ps) ((PS_MAX_CYCLE (ps) - PS_MIN_CYCLE (ps) \
- + 1 + (ps)->ii - 1) / (ps)->ii)
+#define CALC_STAGE_COUNT(max_cycle,min_cycle,ii) ((max_cycle - min_cycle \
+ + 1 + ii - 1) / ii)
+/* The stage count of ps. */
+#define PS_STAGE_COUNT(ps) (((partial_schedule_ptr)(ps))->stage_count)
/* A single instruction in the partial schedule. */
struct ps_insn
@@ -155,6 +156,8 @@
int max_cycle;
ddg_ptr g; /* The DDG of the insns in the partial schedule. */
+
+ int stage_count; /* The stage count of the partial schedule. */
};
/* We use this to record all the register replacements we do in
@@ -195,7 +198,7 @@
rtx, rtx);
static void duplicate_insns_of_cycles (partial_schedule_ptr,
int, int, int, rtx);
-
+static int calculate_stage_count (partial_schedule_ptr ps);
#define SCHED_ASAP(x) (((node_sched_params_ptr)(x)->aux.info)->asap)
#define SCHED_TIME(x) (((node_sched_params_ptr)(x)->aux.info)->time)
#define SCHED_FIRST_REG_MOVE(x) \
@@ -310,10 +313,10 @@
either a single (parallel) branch-on-count or a (non-parallel)
branch immediately preceded by a single (decrement) insn. */
first_insn_not_to_check = (GET_CODE (PATTERN (tail)) == PARALLEL ? tail
- : PREV_INSN (tail));
+ : prev_nondebug_insn (tail));
for (insn = head; insn != first_insn_not_to_check; insn = NEXT_INSN (insn))
- if (reg_mentioned_p (reg, insn))
+ if (reg_mentioned_p (reg, insn) && !DEBUG_INSN_P (insn))
{
if (dump_file)
{
@@ -569,13 +572,12 @@
}
}
-/* Bump the SCHED_TIMEs of all nodes to start from zero. Set the values
- of SCHED_ROW and SCHED_STAGE. */
+/* Bump the SCHED_TIMEs of all nodes by AMOUNT. Set the values of
+ SCHED_ROW and SCHED_STAGE. */
static void
-normalize_sched_times (partial_schedule_ptr ps)
+reset_sched_times (partial_schedule_ptr ps, int amount)
{
int row;
- int amount = PS_MIN_CYCLE (ps);
int ii = ps->ii;
ps_insn_ptr crr_insn;
@@ -584,19 +586,43 @@
{
ddg_node_ptr u = crr_insn->node;
int normalized_time = SCHED_TIME (u) - amount;
+ int new_min_cycle = PS_MIN_CYCLE (ps) - amount;
+ int sc_until_cycle_zero, stage;
- if (dump_file)
- fprintf (dump_file, "crr_insn->node=%d, crr_insn->cycle=%d,\
- min_cycle=%d\n", crr_insn->node->cuid, SCHED_TIME
- (u), ps->min_cycle);
+ if (dump_file)
+ {
+ /* Print the scheduling times after the rotation. */
+ fprintf (dump_file, "crr_insn->node=%d (insn id %d), "
+ "crr_insn->cycle=%d, min_cycle=%d", crr_insn->node->cuid,
+ INSN_UID (crr_insn->node->insn), SCHED_TIME (u),
+ normalized_time);
+ if (JUMP_P (crr_insn->node->insn))
+ fprintf (dump_file, " (branch)");
+ fprintf (dump_file, "\n");
+ }
+
gcc_assert (SCHED_TIME (u) >= ps->min_cycle);
gcc_assert (SCHED_TIME (u) <= ps->max_cycle);
SCHED_TIME (u) = normalized_time;
- SCHED_ROW (u) = normalized_time % ii;
- SCHED_STAGE (u) = normalized_time / ii;
+ SCHED_ROW (u) = SMODULO (normalized_time, ii);
+
+ /* The calculation of stage count is done adding the number
+ of stages before cycle zero and after cycle zero. */
+ sc_until_cycle_zero = CALC_STAGE_COUNT (-1, new_min_cycle, ii);
+
+ if (SCHED_TIME (u) < 0)
+ {
+ stage = CALC_STAGE_COUNT (-1, SCHED_TIME (u), ii);
+ SCHED_STAGE (u) = sc_until_cycle_zero - stage;
+ }
+ else
+ {
+ stage = CALC_STAGE_COUNT (SCHED_TIME (u), 0, ii);
+ SCHED_STAGE (u) = sc_until_cycle_zero + stage - 1;
+ }
}
}
-
+
/* Set SCHED_COLUMN of each node according to its position in PS. */
static void
set_columns_for_ps (partial_schedule_ptr ps)
@@ -646,9 +672,12 @@
/* Do not duplicate any insn which refers to count_reg as it
belongs to the control part.
+ The closing branch is scheduled as well and thus should
+ be ignored.
TODO: This should be done by analyzing the control part of
the loop. */
- if (reg_mentioned_p (count_reg, u_node->insn))
+ if (reg_mentioned_p (count_reg, u_node->insn)
+ || JUMP_P (ps_ij->node->insn))
continue;
if (for_prolog)
@@ -1009,9 +1038,11 @@
continue;
}
- /* Don't handle BBs with calls or barriers, or !single_set insns,
- or auto-increment insns (to avoid creating invalid reg-moves
- for the auto-increment insns).
+ /* Don't handle BBs with calls or barriers or auto-increment insns
+ (to avoid creating invalid reg-moves for the auto-increment insns),
+ or !single_set with the exception of instructions that include
+ count_reg---these instructions are part of the control part
+ that do-loop recognizes.
??? Should handle auto-increment insns.
??? Should handle insns defining subregs. */
for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
@@ -1021,7 +1052,8 @@
if (CALL_P (insn)
|| BARRIER_P (insn)
|| (NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
- && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE)
+ && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE
+ && !reg_mentioned_p (count_reg, insn))
|| (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
|| (INSN_P (insn) && (set = single_set (insn))
&& GET_CODE (SET_DEST (set)) == SUBREG))
@@ -1049,7 +1081,11 @@
continue;
}
- if (! (g = create_ddg (bb, 0)))
+ /* Always schedule the closing branch with the rest of the
+ instructions. The branch is rotated to be in row ii-1 at the
+ end of the scheduling procedure to make sure it's the last
+ instruction in the iteration. */
+ if (! (g = create_ddg (bb, 1)))
{
if (dump_file)
fprintf (dump_file, "SMS create_ddg failed\n");
@@ -1157,14 +1193,17 @@
ps = sms_schedule_by_order (g, mii, maxii, node_order);
- if (ps){
- stage_count = PS_STAGE_COUNT (ps);
- gcc_assert(stage_count >= 1);
- }
+ if (ps)
+ {
+ stage_count = calculate_stage_count (ps);
+ gcc_assert(stage_count >= 1);
+ PS_STAGE_COUNT(ps) = stage_count;
+ }
- /* Stage count of 1 means that there is no interleaving between
- iterations, let the scheduling passes do the job. */
- if (stage_count <= 1
+ /* The default value of PARAM_SMS_MIN_SC is 2 as stage count of
+ 1 means that there is no interleaving between iterations thus
+ we let the scheduling passes do the job in this case. */
+ if (stage_count < (unsigned) PARAM_VALUE (PARAM_SMS_MIN_SC)
|| (count_init && (loop_count <= stage_count))
|| (flag_branch_probabilities && (trip_count <= stage_count)))
{
@@ -1182,32 +1221,24 @@
else
{
struct undo_replace_buff_elem *reg_move_replaces;
-
- if (dump_file)
- {
+ int amount = SCHED_TIME (g->closing_branch) + 1;
+
+ /* Set the stage boundaries. The closing_branch was scheduled
+ and should appear in the last (ii-1) row. */
+ reset_sched_times (ps, amount);
+ rotate_partial_schedule (ps, amount);
+ set_columns_for_ps (ps);
+
+ canon_loop (loop);
+
+ if (dump_file)
+ {
fprintf (dump_file,
"SMS succeeded %d %d (with ii, sc)\n", ps->ii,
stage_count);
print_partial_schedule (ps, dump_file);
- fprintf (dump_file,
- "SMS Branch (%d) will later be scheduled at cycle %d.\n",
- g->closing_branch->cuid, PS_MIN_CYCLE (ps) - 1);
}
-
- /* Set the stage boundaries. If the DDG is built with closing_branch_deps,
- the closing_branch was scheduled and should appear in the last (ii-1)
- row. Otherwise, we are free to schedule the branch, and we let nodes
- that were scheduled at the first PS_MIN_CYCLE cycle appear in the first
- row; this should reduce stage_count to minimum.
- TODO: Revisit the issue of scheduling the insns of the
- control part relative to the branch when the control part
- has more than one insn. */
- normalize_sched_times (ps);
- rotate_partial_schedule (ps, PS_MIN_CYCLE (ps));
- set_columns_for_ps (ps);
-
- canon_loop (loop);
-
+
/* case the BCT count is not known , Do loop-versioning */
if (count_reg && ! count_init)
{
@@ -1760,12 +1791,6 @@
continue;
}
- if (JUMP_P (insn)) /* Closing branch handled later. */
- {
- RESET_BIT (tobe_scheduled, u);
- continue;
- }
-
if (TEST_BIT (sched_nodes, u))
continue;
@@ -1893,8 +1918,8 @@
if (dump_file)
fprintf (dump_file, "split_row=%d\n", split_row);
- normalize_sched_times (ps);
- rotate_partial_schedule (ps, ps->min_cycle);
+ reset_sched_times (ps, PS_MIN_CYCLE (ps));
+ rotate_partial_schedule (ps, PS_MIN_CYCLE (ps));
rows_new = (ps_insn_ptr *) xcalloc (new_ii, sizeof (ps_insn_ptr));
for (row = 0; row < split_row; row++)
@@ -2571,6 +2596,7 @@
ps_insn_ptr next_ps_i;
ps_insn_ptr first_must_follow = NULL;
ps_insn_ptr last_must_precede = NULL;
+ ps_insn_ptr last_in_row = NULL;
int row;
if (! ps_i)
@@ -2597,8 +2623,37 @@
else
last_must_precede = next_ps_i;
}
+ /* The closing branch must be the last in the row. */
+ if (must_precede
+ && TEST_BIT (must_precede, next_ps_i->node->cuid)
+ && JUMP_P (next_ps_i->node->insn))
+ return false;
+
+ last_in_row = next_ps_i;
}
+ /* The closing branch is scheduled as well. Make sure there is no
+ dependent instruction after it as the branch should be the last
+ instruction in the row. */
+ if (JUMP_P (ps_i->node->insn))
+ {
+ if (first_must_follow)
+ return false;
+ if (last_in_row)
+ {
+ /* Make the branch the last in the row. New instructions
+ will be inserted at the beginning of the row or after the
+ last must_precede instruction thus the branch is guaranteed
+ to remain the last instruction in the row. */
+ last_in_row->next_in_row = ps_i;
+ ps_i->prev_in_row = last_in_row;
+ ps_i->next_in_row = NULL;
+ }
+ else
+ ps->rows[row] = ps_i;
+ return true;
+ }
+
/* Now insert the node after INSERT_AFTER_PSI. */
if (! last_must_precede)
@@ -2820,6 +2875,24 @@
return ps_i;
}
+/* Calculate the stage count of the partial schedule PS. The calculation
+ takes into account the rotation to bring the closing branch to row
+ ii-1. */
+int
+calculate_stage_count (partial_schedule_ptr ps)
+{
+ int rotation_amount = (SCHED_TIME (ps->g->closing_branch)) + 1;
+ int new_min_cycle = PS_MIN_CYCLE (ps) - rotation_amount;
+ int new_max_cycle = PS_MAX_CYCLE (ps) - rotation_amount;
+ int stage_count = CALC_STAGE_COUNT (-1, new_min_cycle, ps->ii);
+
+ /* The calculation of stage count is done adding the number of stages
+ before cycle zero and after cycle zero. */
+ stage_count += CALC_STAGE_COUNT (new_max_cycle, 0, ps->ii);
+
+ return stage_count;
+}
+
/* Rotate the rows of PS such that insns scheduled at time
START_CYCLE will appear in row 0. Updates max/min_cycles. */
void
=== modified file 'gcc/params.def'
--- old/gcc/params.def 2011-04-18 11:31:29 +0000
+++ new/gcc/params.def 2011-05-11 07:15:47 +0000
@@ -344,6 +344,11 @@
"sms-max-ii-factor",
"A factor for tuning the upper bound that swing modulo scheduler uses for scheduling a loop",
100, 0, 0)
+/* The minimum value of stage count that swing modulo scheduler will generate. */
+DEFPARAM(PARAM_SMS_MIN_SC,
+ "sms-min-sc",
+ "The minimum value of stage count that swing modulo scheduler will generate.",
+ 2, 1, 1)
DEFPARAM(PARAM_SMS_DFA_HISTORY,
"sms-dfa-history",
"The number of cycles the swing modulo scheduler considers when checking conflicts using DFA",
@@ -0,0 +1,30 @@
2011-05-13 Revital Eres <revital.eres@linaro.org>
gcc/
* ddg.c (free_ddg_all_sccs): Free sccs field in struct ddg_all_sccs.
* modulo-sched.c (sms_schedule): Avoid unfreed memory when SMS fails.
=== modified file 'gcc/ddg.c'
--- old/gcc/ddg.c 2011-05-11 07:15:47 +0000
+++ new/gcc/ddg.c 2011-05-13 16:03:40 +0000
@@ -1016,6 +1016,7 @@
for (i = 0; i < all_sccs->num_sccs; i++)
free_scc (all_sccs->sccs[i]);
+ free (all_sccs->sccs);
free (all_sccs);
}
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-05-11 07:15:47 +0000
+++ new/gcc/modulo-sched.c 2011-05-13 16:03:40 +0000
@@ -1216,7 +1216,6 @@
fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, trip_count);
fprintf (dump_file, ")\n");
}
- continue;
}
else
{
@@ -0,0 +1,134 @@
2011-06-02 Chung-Lin Tang <cltang@codesourcery.com>
Backport from mainline:
2011-03-21 Chung-Lin Tang <cltang@codesourcery.com>
gcc/
* simplify-rtx.c (simplify_binary_operation_1): Handle
(xor (and A B) C) case when B and C are both constants.
gcc/testsuite/
* gcc.target/arm/xor-and.c: New.
2011-03-18 Chung-Lin Tang <cltang@codesourcery.com>
gcc/
* combine.c (try_combine): Do simplification only call of
subst() on i2 even when i1 is present. Update comments.
gcc/testsuite/
* gcc.target/arm/unsigned-extend-1.c: New.
=== modified file 'gcc/combine.c'
--- old/gcc/combine.c 2011-05-06 11:28:27 +0000
+++ new/gcc/combine.c 2011-05-27 14:31:18 +0000
@@ -3089,7 +3089,7 @@
/* It is possible that the source of I2 or I1 may be performing
an unneeded operation, such as a ZERO_EXTEND of something
that is known to have the high part zero. Handle that case
- by letting subst look at the innermost one of them.
+ by letting subst look at the inner insns.
Another way to do this would be to have a function that tries
to simplify a single insn instead of merging two or more
@@ -3114,11 +3114,9 @@
subst_low_luid = DF_INSN_LUID (i1);
i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0, 0);
}
- else
- {
- subst_low_luid = DF_INSN_LUID (i2);
- i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
- }
+
+ subst_low_luid = DF_INSN_LUID (i2);
+ i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
}
n_occurrences = 0; /* `subst' counts here */
=== modified file 'gcc/simplify-rtx.c'
--- old/gcc/simplify-rtx.c 2011-03-26 09:24:06 +0000
+++ new/gcc/simplify-rtx.c 2011-05-27 14:31:18 +0000
@@ -2484,6 +2484,46 @@
XEXP (op0, 1), mode),
op1);
+ /* Given (xor (and A B) C), using P^Q == (~P&Q) | (~Q&P),
+ we can transform like this:
+ (A&B)^C == ~(A&B)&C | ~C&(A&B)
+ == (~A|~B)&C | ~C&(A&B) * DeMorgan's Law
+ == ~A&C | ~B&C | A&(~C&B) * Distribute and re-order
+ Attempt a few simplifications when B and C are both constants. */
+ if (GET_CODE (op0) == AND
+ && CONST_INT_P (op1)
+ && CONST_INT_P (XEXP (op0, 1)))
+ {
+ rtx a = XEXP (op0, 0);
+ rtx b = XEXP (op0, 1);
+ rtx c = op1;
+ HOST_WIDE_INT bval = INTVAL (b);
+ HOST_WIDE_INT cval = INTVAL (c);
+
+ rtx na_c
+ = simplify_binary_operation (AND, mode,
+ simplify_gen_unary (NOT, mode, a, mode),
+ c);
+ if ((~cval & bval) == 0)
+ {
+ /* Try to simplify ~A&C | ~B&C. */
+ if (na_c != NULL_RTX)
+ return simplify_gen_binary (IOR, mode, na_c,
+ GEN_INT (~bval & cval));
+ }
+ else
+ {
+ /* If ~A&C is zero, simplify A&(~C&B) | ~B&C. */
+ if (na_c == const0_rtx)
+ {
+ rtx a_nc_b = simplify_gen_binary (AND, mode, a,
+ GEN_INT (~cval & bval));
+ return simplify_gen_binary (IOR, mode, a_nc_b,
+ GEN_INT (~bval & cval));
+ }
+ }
+ }
+
/* (xor (comparison foo bar) (const_int 1)) can become the reversed
comparison if STORE_FLAG_VALUE is 1. */
if (STORE_FLAG_VALUE == 1
=== added file 'gcc/testsuite/gcc.target/arm/unsigned-extend-1.c'
--- old/gcc/testsuite/gcc.target/arm/unsigned-extend-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/unsigned-extend-1.c 2011-05-27 14:31:18 +0000
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv6" } */
+
+unsigned char foo (unsigned char c)
+{
+ return (c >= '0') && (c <= '9');
+}
+
+/* { dg-final { scan-assembler-not "uxtb" } } */
=== added file 'gcc/testsuite/gcc.target/arm/xor-and.c'
--- old/gcc/testsuite/gcc.target/arm/xor-and.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/xor-and.c 2011-05-27 14:31:18 +0000
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -march=armv6" } */
+
+unsigned short foo (unsigned short x)
+{
+ x ^= 0x4002;
+ x >>= 1;
+ x |= 0x8000;
+ return x;
+}
+
+/* { dg-final { scan-assembler "orr" } } */
+/* { dg-final { scan-assembler-not "mvn" } } */
+/* { dg-final { scan-assembler-not "uxth" } } */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,329 @@
2011-06-07 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF:
2011-06-07 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm.md (*maddhidi4tb, *maddhidi4tt): New define_insns.
(*maddhisi4tb, *maddhisi4tt): New define_insns.
gcc/testsuite/
* gcc.target/arm/smlatb-1.c: New file.
* gcc.target/arm/smlatt-1.c: New file.
* gcc.target/arm/smlaltb-1.c: New file.
* gcc.target/arm/smlaltt-1.c: New file.
2011-06-07 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF:
2011-06-07 Bernd Schmidt <bernds@codesourcery.com>
Andrew Stubbs <ams@codesourcery.com>
gcc/
* simplify-rtx.c (simplify_unary_operation_1): Canonicalize widening
multiplies.
* doc/md.texi (Canonicalization of Instructions): Document widening
multiply canonicalization.
gcc/testsuite/
* gcc.target/arm/mla-2.c: New test.
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2011-05-13 13:42:39 +0000
+++ new/gcc/config/arm/arm.md 2011-06-02 15:58:33 +0000
@@ -1809,6 +1809,36 @@
(set_attr "predicable" "yes")]
)
+;; Note: there is no maddhisi4ibt because this one is canonical form
+(define_insn "*maddhisi4tb"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (mult:SI (ashiftrt:SI
+ (match_operand:SI 1 "s_register_operand" "r")
+ (const_int 16))
+ (sign_extend:SI
+ (match_operand:HI 2 "s_register_operand" "r")))
+ (match_operand:SI 3 "s_register_operand" "r")))]
+ "TARGET_DSP_MULTIPLY"
+ "smlatb%?\\t%0, %1, %2, %3"
+ [(set_attr "insn" "smlaxy")
+ (set_attr "predicable" "yes")]
+)
+
+(define_insn "*maddhisi4tt"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (plus:SI (mult:SI (ashiftrt:SI
+ (match_operand:SI 1 "s_register_operand" "r")
+ (const_int 16))
+ (ashiftrt:SI
+ (match_operand:SI 2 "s_register_operand" "r")
+ (const_int 16)))
+ (match_operand:SI 3 "s_register_operand" "r")))]
+ "TARGET_DSP_MULTIPLY"
+ "smlatt%?\\t%0, %1, %2, %3"
+ [(set_attr "insn" "smlaxy")
+ (set_attr "predicable" "yes")]
+)
+
(define_insn "*maddhidi4"
[(set (match_operand:DI 0 "s_register_operand" "=r")
(plus:DI
@@ -1822,6 +1852,39 @@
[(set_attr "insn" "smlalxy")
(set_attr "predicable" "yes")])
+;; Note: there is no maddhidi4ibt because this one is canonical form
+(define_insn "*maddhidi4tb"
+ [(set (match_operand:DI 0 "s_register_operand" "=r")
+ (plus:DI
+ (mult:DI (sign_extend:DI
+ (ashiftrt:SI
+ (match_operand:SI 1 "s_register_operand" "r")
+ (const_int 16)))
+ (sign_extend:DI
+ (match_operand:HI 2 "s_register_operand" "r")))
+ (match_operand:DI 3 "s_register_operand" "0")))]
+ "TARGET_DSP_MULTIPLY"
+ "smlaltb%?\\t%Q0, %R0, %1, %2"
+ [(set_attr "insn" "smlalxy")
+ (set_attr "predicable" "yes")])
+
+(define_insn "*maddhidi4tt"
+ [(set (match_operand:DI 0 "s_register_operand" "=r")
+ (plus:DI
+ (mult:DI (sign_extend:DI
+ (ashiftrt:SI
+ (match_operand:SI 1 "s_register_operand" "r")
+ (const_int 16)))
+ (sign_extend:DI
+ (ashiftrt:SI
+ (match_operand:SI 2 "s_register_operand" "r")
+ (const_int 16))))
+ (match_operand:DI 3 "s_register_operand" "0")))]
+ "TARGET_DSP_MULTIPLY"
+ "smlaltt%?\\t%Q0, %R0, %1, %2"
+ [(set_attr "insn" "smlalxy")
+ (set_attr "predicable" "yes")])
+
(define_expand "mulsf3"
[(set (match_operand:SF 0 "s_register_operand" "")
(mult:SF (match_operand:SF 1 "s_register_operand" "")
=== modified file 'gcc/doc/md.texi'
--- old/gcc/doc/md.texi 2011-05-05 15:43:06 +0000
+++ new/gcc/doc/md.texi 2011-06-07 11:18:20 +0000
@@ -5929,6 +5929,23 @@
will be written using @code{zero_extract} rather than the equivalent
@code{and} or @code{sign_extract} operations.
+@cindex @code{mult}, canonicalization of
+@item
+@code{(sign_extend:@var{m1} (mult:@var{m2} (sign_extend:@var{m2} @var{x})
+(sign_extend:@var{m2} @var{y})))} is converted to @code{(mult:@var{m1}
+(sign_extend:@var{m1} @var{x}) (sign_extend:@var{m1} @var{y}))}, and likewise
+for @code{zero_extend}.
+
+@item
+@code{(sign_extend:@var{m1} (mult:@var{m2} (ashiftrt:@var{m2}
+@var{x} @var{s}) (sign_extend:@var{m2} @var{y})))} is converted
+to @code{(mult:@var{m1} (sign_extend:@var{m1} (ashiftrt:@var{m2}
+@var{x} @var{s})) (sign_extend:@var{m1} @var{y}))}, and likewise for
+patterns using @code{zero_extend} and @code{lshiftrt}. If the second
+operand of @code{mult} is also a shift, then that is extended also.
+This transformation is only applied when it can be proven that the
+original operation had sufficient precision to prevent overflow.
+
@end itemize
Further canonicalization rules are defined in the function
=== modified file 'gcc/simplify-rtx.c'
--- old/gcc/simplify-rtx.c 2011-05-27 14:31:18 +0000
+++ new/gcc/simplify-rtx.c 2011-06-02 12:32:16 +0000
@@ -1000,6 +1000,48 @@
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
return XEXP (op, 0);
+ /* Extending a widening multiplication should be canonicalized to
+ a wider widening multiplication. */
+ if (GET_CODE (op) == MULT)
+ {
+ rtx lhs = XEXP (op, 0);
+ rtx rhs = XEXP (op, 1);
+ enum rtx_code lcode = GET_CODE (lhs);
+ enum rtx_code rcode = GET_CODE (rhs);
+
+ /* Widening multiplies usually extend both operands, but sometimes
+ they use a shift to extract a portion of a register. */
+ if ((lcode == SIGN_EXTEND
+ || (lcode == ASHIFTRT && CONST_INT_P (XEXP (lhs, 1))))
+ && (rcode == SIGN_EXTEND
+ || (rcode == ASHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
+ {
+ enum machine_mode lmode = GET_MODE (lhs);
+ enum machine_mode rmode = GET_MODE (rhs);
+ int bits;
+
+ if (lcode == ASHIFTRT)
+ /* Number of bits not shifted off the end. */
+ bits = GET_MODE_PRECISION (lmode) - INTVAL (XEXP (lhs, 1));
+ else /* lcode == SIGN_EXTEND */
+ /* Size of inner mode. */
+ bits = GET_MODE_PRECISION (GET_MODE (XEXP (lhs, 0)));
+
+ if (rcode == ASHIFTRT)
+ bits += GET_MODE_PRECISION (rmode) - INTVAL (XEXP (rhs, 1));
+ else /* rcode == SIGN_EXTEND */
+ bits += GET_MODE_PRECISION (GET_MODE (XEXP (rhs, 0)));
+
+ /* We can only widen multiplies if the result is mathematiclly
+ equivalent. I.e. if overflow was impossible. */
+ if (bits <= GET_MODE_PRECISION (GET_MODE (op)))
+ return simplify_gen_binary
+ (MULT, mode,
+ simplify_gen_unary (SIGN_EXTEND, mode, lhs, lmode),
+ simplify_gen_unary (SIGN_EXTEND, mode, rhs, rmode));
+ }
+ }
+
/* Check for a sign extension of a subreg of a promoted
variable, where the promotion is sign-extended, and the
target mode is the same as the variable's promotion. */
@@ -1071,6 +1113,48 @@
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
return rtl_hooks.gen_lowpart_no_emit (mode, op);
+ /* Extending a widening multiplication should be canonicalized to
+ a wider widening multiplication. */
+ if (GET_CODE (op) == MULT)
+ {
+ rtx lhs = XEXP (op, 0);
+ rtx rhs = XEXP (op, 1);
+ enum rtx_code lcode = GET_CODE (lhs);
+ enum rtx_code rcode = GET_CODE (rhs);
+
+ /* Widening multiplies usually extend both operands, but sometimes
+ they use a shift to extract a portion of a register. */
+ if ((lcode == ZERO_EXTEND
+ || (lcode == LSHIFTRT && CONST_INT_P (XEXP (lhs, 1))))
+ && (rcode == ZERO_EXTEND
+ || (rcode == LSHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
+ {
+ enum machine_mode lmode = GET_MODE (lhs);
+ enum machine_mode rmode = GET_MODE (rhs);
+ int bits;
+
+ if (lcode == LSHIFTRT)
+ /* Number of bits not shifted off the end. */
+ bits = GET_MODE_PRECISION (lmode) - INTVAL (XEXP (lhs, 1));
+ else /* lcode == ZERO_EXTEND */
+ /* Size of inner mode. */
+ bits = GET_MODE_PRECISION (GET_MODE (XEXP (lhs, 0)));
+
+ if (rcode == LSHIFTRT)
+ bits += GET_MODE_PRECISION (rmode) - INTVAL (XEXP (rhs, 1));
+ else /* rcode == ZERO_EXTEND */
+ bits += GET_MODE_PRECISION (GET_MODE (XEXP (rhs, 0)));
+
+ /* We can only widen multiplies if the result is mathematiclly
+ equivalent. I.e. if overflow was impossible. */
+ if (bits <= GET_MODE_PRECISION (GET_MODE (op)))
+ return simplify_gen_binary
+ (MULT, mode,
+ simplify_gen_unary (ZERO_EXTEND, mode, lhs, lmode),
+ simplify_gen_unary (ZERO_EXTEND, mode, rhs, rmode));
+ }
+ }
+
/* (zero_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>). */
if (GET_CODE (op) == ZERO_EXTEND)
return simplify_gen_unary (ZERO_EXTEND, mode, XEXP (op, 0),
=== added file 'gcc/testsuite/gcc.target/arm/mla-2.c'
--- old/gcc/testsuite/gcc.target/arm/mla-2.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/mla-2.c 2011-06-02 12:32:16 +0000
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv7-a" } */
+
+long long foolong (long long x, short *a, short *b)
+{
+ return x + *a * *b;
+}
+
+/* { dg-final { scan-assembler "smlalbb" } } */
=== added file 'gcc/testsuite/gcc.target/arm/smlaltb-1.c'
--- old/gcc/testsuite/gcc.target/arm/smlaltb-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/smlaltb-1.c 2011-06-02 15:58:33 +0000
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv7-a" } */
+
+long long int
+foo (long long x, int in)
+{
+ short a = in & 0xffff;
+ short b = (in & 0xffff0000) >> 16;
+
+ return x + b * a;
+}
+
+/* { dg-final { scan-assembler "smlaltb" } } */
=== added file 'gcc/testsuite/gcc.target/arm/smlaltt-1.c'
--- old/gcc/testsuite/gcc.target/arm/smlaltt-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/smlaltt-1.c 2011-06-02 15:58:33 +0000
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv7-a" } */
+
+long long int
+foo (long long x, int in1, int in2)
+{
+ short a = (in1 & 0xffff0000) >> 16;
+ short b = (in2 & 0xffff0000) >> 16;
+
+ return x + b * a;
+}
+
+/* { dg-final { scan-assembler "smlaltt" } } */
=== added file 'gcc/testsuite/gcc.target/arm/smlatb-1.c'
--- old/gcc/testsuite/gcc.target/arm/smlatb-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/smlatb-1.c 2011-06-02 15:58:33 +0000
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv7-a" } */
+
+int
+foo (int x, int in)
+{
+ short a = in & 0xffff;
+ short b = (in & 0xffff0000) >> 16;
+
+ return x + b * a;
+}
+
+/* { dg-final { scan-assembler "smlatb" } } */
=== added file 'gcc/testsuite/gcc.target/arm/smlatt-1.c'
--- old/gcc/testsuite/gcc.target/arm/smlatt-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/smlatt-1.c 2011-06-02 15:58:33 +0000
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv7-a" } */
+
+int
+foo (int x, int in1, int in2)
+{
+ short a = (in1 & 0xffff0000) >> 16;
+ short b = (in2 & 0xffff0000) >> 16;
+
+ return x + b * a;
+}
+
+/* { dg-final { scan-assembler "smlatt" } } */
@@ -0,0 +1,120 @@
2011-06-10 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline:
gcc/
2011-06-02 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
* config/arm/neon.md (orndi3_neon): Actually split it.
2011-06-10 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline.
gcc/
2011-05-26 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
* config/arm/neon.md ("orn<mode>3_neon"): Canonicalize not.
("orndi3_neon"): Likewise.
("bic<mode>3_neon"): Likewise.
gcc/testsuite
2011-05-26 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
* gcc.target/arm/neon-vorn-vbic.c: New test.
=== modified file 'gcc/config/arm/neon.md'
--- old/gcc/config/arm/neon.md 2011-06-02 12:12:00 +0000
+++ new/gcc/config/arm/neon.md 2011-06-04 00:04:47 +0000
@@ -783,30 +783,57 @@
(define_insn "orn<mode>3_neon"
[(set (match_operand:VDQ 0 "s_register_operand" "=w")
- (ior:VDQ (match_operand:VDQ 1 "s_register_operand" "w")
- (not:VDQ (match_operand:VDQ 2 "s_register_operand" "w"))))]
+ (ior:VDQ (not:VDQ (match_operand:VDQ 2 "s_register_operand" "w"))
+ (match_operand:VDQ 1 "s_register_operand" "w")))]
"TARGET_NEON"
"vorn\t%<V_reg>0, %<V_reg>1, %<V_reg>2"
[(set_attr "neon_type" "neon_int_1")]
)
-(define_insn "orndi3_neon"
- [(set (match_operand:DI 0 "s_register_operand" "=w,?=&r,?&r")
- (ior:DI (match_operand:DI 1 "s_register_operand" "w,r,0")
- (not:DI (match_operand:DI 2 "s_register_operand" "w,0,r"))))]
+;; TODO: investigate whether we should disable
+;; this and bicdi3_neon for the A8 in line with the other
+;; changes above.
+(define_insn_and_split "orndi3_neon"
+ [(set (match_operand:DI 0 "s_register_operand" "=w,?&r,?&r,?&r")
+ (ior:DI (not:DI (match_operand:DI 2 "s_register_operand" "w,0,0,r"))
+ (match_operand:DI 1 "s_register_operand" "w,r,r,0")))]
"TARGET_NEON"
"@
vorn\t%P0, %P1, %P2
#
+ #
#"
- [(set_attr "neon_type" "neon_int_1,*,*")
- (set_attr "length" "*,8,8")]
+ "reload_completed &&
+ (TARGET_NEON && !(IS_VFP_REGNUM (REGNO (operands[0]))))"
+ [(set (match_dup 0) (ior:SI (not:SI (match_dup 2)) (match_dup 1)))
+ (set (match_dup 3) (ior:SI (not:SI (match_dup 4)) (match_dup 5)))]
+ "
+ {
+ if (TARGET_THUMB2)
+ {
+ operands[3] = gen_highpart (SImode, operands[0]);
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_highpart (SImode, operands[2]);
+ operands[2] = gen_lowpart (SImode, operands[2]);
+ operands[5] = gen_highpart (SImode, operands[1]);
+ operands[1] = gen_lowpart (SImode, operands[1]);
+ }
+ else
+ {
+ emit_insn (gen_one_cmpldi2 (operands[0], operands[2]));
+ emit_insn (gen_iordi3 (operands[0], operands[1], operands[0]));
+ DONE;
+ }
+ }"
+ [(set_attr "neon_type" "neon_int_1,*,*,*")
+ (set_attr "length" "*,16,8,8")
+ (set_attr "arch" "any,a,t2,t2")]
)
(define_insn "bic<mode>3_neon"
[(set (match_operand:VDQ 0 "s_register_operand" "=w")
- (and:VDQ (match_operand:VDQ 1 "s_register_operand" "w")
- (not:VDQ (match_operand:VDQ 2 "s_register_operand" "w"))))]
+ (and:VDQ (not:VDQ (match_operand:VDQ 2 "s_register_operand" "w"))
+ (match_operand:VDQ 1 "s_register_operand" "w")))]
"TARGET_NEON"
"vbic\t%<V_reg>0, %<V_reg>1, %<V_reg>2"
[(set_attr "neon_type" "neon_int_1")]
=== added file 'gcc/testsuite/gcc.target/arm/neon-vorn-vbic.c'
--- old/gcc/testsuite/gcc.target/arm/neon-vorn-vbic.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/neon-vorn-vbic.c 2011-06-03 23:50:02 +0000
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 -ftree-vectorize" } */
+/* { dg-add-options arm_neon } */
+
+void bor (int *__restrict__ c, int *__restrict__ a, int *__restrict__ b)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ c[i] = b[i] | (~a[i]);
+}
+void bic (int *__restrict__ c, int *__restrict__ a, int *__restrict__ b)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ c[i] = b[i] & (~a[i]);
+}
+
+/* { dg-final { scan-assembler "vorn\\t" } } */
+/* { dg-final { scan-assembler "vbic\\t" } } */
@@ -0,0 +1,545 @@
2011-06-20 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline.
2011-06-03 Julian Brown <julian@codesourcery.com>
* config/arm/arm-cores.def (strongarm, strongarm110, strongarm1100)
(strongarm1110): Use strongarm tuning.
* config/arm/arm-protos.h (tune_params): Add max_insns_skipped
field.
* config/arm/arm.c (arm_strongarm_tune): New.
(arm_slowmul_tune, arm_fastmul_tune, arm_xscale_tune, arm_9e_tune)
(arm_v6t2_tune, arm_cortex_tune, arm_cortex_a5_tune)
(arm_cortex_a9_tune, arm_fa726te_tune): Add max_insns_skipped field
setting, using previous defaults or 1 for Cortex-A5.
(arm_option_override): Set max_insns_skipped from current tuning.
2011-06-14 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline.
2011-06-02 Julian Brown <julian@codesourcery.com>
* config/arm/arm-cores.def (cortex-a5): Use cortex_a5 tuning.
* config/arm/arm.c (arm_cortex_a5_branch_cost): New.
(arm_cortex_a5_tune): New.
2011-06-02 Julian Brown <julian@codesourcery.com>
* config/arm/arm-protos.h (tune_params): Add branch_cost hook.
* config/arm/arm.c (arm_default_branch_cost): New.
(arm_slowmul_tune, arm_fastmul_tune, arm_xscale_tune, arm_9e_tune)
(arm_v6t2_tune, arm_cortex_tune, arm_cortex_a9_tune)
(arm_fa726_tune): Set branch_cost field using
arm_default_branch_cost.
* config/arm/arm.h (BRANCH_COST): Use branch_cost hook from
current_tune structure.
* dojump.c (tm_p.h): Include file.
2011-06-02 Julian Brown <julian@codesourcery.com>
* config/arm/arm-cores.def (arm1156t2-s, arm1156t2f-s): Use v6t2
tuning.
(cortex-a5, cortex-a8, cortex-a15, cortex-r4, cortex-r4f, cortex-m4)
(cortex-m3, cortex-m1, cortex-m0): Use cortex tuning.
* config/arm/arm-protos.h (tune_params): Add prefer_constant_pool
field.
* config/arm/arm.c (arm_slowmul_tune, arm_fastmul_tune)
(arm_xscale_tune, arm_9e_tune, arm_cortex_a9_tune)
(arm_fa726te_tune): Add prefer_constant_pool setting.
(arm_v6t2_tune, arm_cortex_tune): New.
* config/arm/arm.h (TARGET_USE_MOVT): Make dependent on
prefer_constant_pool setting.
2011-06-14 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline
2011-06-01 Paul Brook <paul@cpodesourcery.com>
* config/arm/arm-cores.def: Add cortex-r5. Add DIV flags to
Cortex-A15.
* config/arm/arm-tune.md: Regenerate.
* config/arm/arm.c (FL_DIV): Rename...
(FL_THUMB_DIV): ... to this.
(FL_ARM_DIV): Define.
(FL_FOR_ARCH7R, FL_FOR_ARCH7M): Use FL_THUMB_DIV.
(arm_arch_hwdiv): Remove.
(arm_arch_thumb_hwdiv, arm_arch_arm_hwdiv): New variables.
(arm_issue_rate): Add cortexr5.
* config/arm/arm.h (TARGET_CPU_CPP_BUILTINS): Set
__ARM_ARCH_EXT_IDIV__.
(TARGET_IDIV): Define.
(arm_arch_hwdiv): Remove.
(arm_arch_arm_hwdiv, arm_arch_thumb_hwdiv): New prototypes.
* config/arm/arm.md (tune_cortexr4): Add cortexr5.
(divsi3, udivsi3): New patterns.
* config/arm/thumb2.md (divsi3, udivsi3): Remove.
* doc/invoke.texi: Document ARM -mcpu=cortex-r5
=== modified file 'gcc/config/arm/arm-cores.def'
--- old/gcc/config/arm/arm-cores.def 2011-01-03 20:52:22 +0000
+++ new/gcc/config/arm/arm-cores.def 2011-06-14 16:00:30 +0000
@@ -70,10 +70,10 @@
/* V4 Architecture Processors */
ARM_CORE("arm8", arm8, 4, FL_MODE26 | FL_LDSCHED, fastmul)
ARM_CORE("arm810", arm810, 4, FL_MODE26 | FL_LDSCHED, fastmul)
-ARM_CORE("strongarm", strongarm, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, fastmul)
-ARM_CORE("strongarm110", strongarm110, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, fastmul)
-ARM_CORE("strongarm1100", strongarm1100, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, fastmul)
-ARM_CORE("strongarm1110", strongarm1110, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, fastmul)
+ARM_CORE("strongarm", strongarm, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, strongarm)
+ARM_CORE("strongarm110", strongarm110, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, strongarm)
+ARM_CORE("strongarm1100", strongarm1100, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, strongarm)
+ARM_CORE("strongarm1110", strongarm1110, 4, FL_MODE26 | FL_LDSCHED | FL_STRONG, strongarm)
ARM_CORE("fa526", fa526, 4, FL_LDSCHED, fastmul)
ARM_CORE("fa626", fa626, 4, FL_LDSCHED, fastmul)
@@ -122,15 +122,16 @@
ARM_CORE("arm1176jzf-s", arm1176jzfs, 6ZK, FL_LDSCHED | FL_VFPV2, 9e)
ARM_CORE("mpcorenovfp", mpcorenovfp, 6K, FL_LDSCHED, 9e)
ARM_CORE("mpcore", mpcore, 6K, FL_LDSCHED | FL_VFPV2, 9e)
-ARM_CORE("arm1156t2-s", arm1156t2s, 6T2, FL_LDSCHED, 9e)
-ARM_CORE("arm1156t2f-s", arm1156t2fs, 6T2, FL_LDSCHED | FL_VFPV2, 9e)
-ARM_CORE("cortex-a5", cortexa5, 7A, FL_LDSCHED, 9e)
-ARM_CORE("cortex-a8", cortexa8, 7A, FL_LDSCHED, 9e)
+ARM_CORE("arm1156t2-s", arm1156t2s, 6T2, FL_LDSCHED, v6t2)
+ARM_CORE("arm1156t2f-s", arm1156t2fs, 6T2, FL_LDSCHED | FL_VFPV2, v6t2)
+ARM_CORE("cortex-a5", cortexa5, 7A, FL_LDSCHED, cortex_a5)
+ARM_CORE("cortex-a8", cortexa8, 7A, FL_LDSCHED, cortex)
ARM_CORE("cortex-a9", cortexa9, 7A, FL_LDSCHED, cortex_a9)
-ARM_CORE("cortex-a15", cortexa15, 7A, FL_LDSCHED, 9e)
-ARM_CORE("cortex-r4", cortexr4, 7R, FL_LDSCHED, 9e)
-ARM_CORE("cortex-r4f", cortexr4f, 7R, FL_LDSCHED, 9e)
-ARM_CORE("cortex-m4", cortexm4, 7EM, FL_LDSCHED, 9e)
-ARM_CORE("cortex-m3", cortexm3, 7M, FL_LDSCHED, 9e)
-ARM_CORE("cortex-m1", cortexm1, 6M, FL_LDSCHED, 9e)
-ARM_CORE("cortex-m0", cortexm0, 6M, FL_LDSCHED, 9e)
+ARM_CORE("cortex-a15", cortexa15, 7A, FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex)
+ARM_CORE("cortex-r4", cortexr4, 7R, FL_LDSCHED, cortex)
+ARM_CORE("cortex-r4f", cortexr4f, 7R, FL_LDSCHED, cortex)
+ARM_CORE("cortex-r5", cortexr5, 7R, FL_LDSCHED | FL_ARM_DIV, cortex)
+ARM_CORE("cortex-m4", cortexm4, 7EM, FL_LDSCHED, cortex)
+ARM_CORE("cortex-m3", cortexm3, 7M, FL_LDSCHED, cortex)
+ARM_CORE("cortex-m1", cortexm1, 6M, FL_LDSCHED, cortex)
+ARM_CORE("cortex-m0", cortexm0, 6M, FL_LDSCHED, cortex)
=== modified file 'gcc/config/arm/arm-protos.h'
--- old/gcc/config/arm/arm-protos.h 2011-05-03 15:17:25 +0000
+++ new/gcc/config/arm/arm-protos.h 2011-06-14 16:00:30 +0000
@@ -219,9 +219,14 @@
bool (*rtx_costs) (rtx, RTX_CODE, RTX_CODE, int *, bool);
bool (*sched_adjust_cost) (rtx, rtx, rtx, int *);
int constant_limit;
+ /* Maximum number of instructions to conditionalise in
+ arm_final_prescan_insn. */
+ int max_insns_skipped;
int num_prefetch_slots;
int l1_cache_size;
int l1_cache_line_size;
+ bool prefer_constant_pool;
+ int (*branch_cost) (bool, bool);
};
extern const struct tune_params *current_tune;
=== modified file 'gcc/config/arm/arm-tune.md'
--- old/gcc/config/arm/arm-tune.md 2010-12-20 17:48:51 +0000
+++ new/gcc/config/arm/arm-tune.md 2011-06-14 14:37:30 +0000
@@ -1,5 +1,5 @@
;; -*- buffer-read-only: t -*-
;; Generated automatically by gentune.sh from arm-cores.def
(define_attr "tune"
- "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,fa526,fa626,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,cortexa5,cortexa8,cortexa9,cortexa15,cortexr4,cortexr4f,cortexm4,cortexm3,cortexm1,cortexm0"
+ "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,fa526,fa626,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,cortexa5,cortexa8,cortexa9,cortexa15,cortexr4,cortexr4f,cortexr5,cortexm4,cortexm3,cortexm1,cortexm0"
(const (symbol_ref "((enum attr_tune) arm_tune)")))
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-05-11 14:49:48 +0000
+++ new/gcc/config/arm/arm.c 2011-06-14 16:00:30 +0000
@@ -255,6 +255,8 @@
static void arm_conditional_register_usage (void);
static reg_class_t arm_preferred_rename_class (reg_class_t rclass);
static unsigned int arm_autovectorize_vector_sizes (void);
+static int arm_default_branch_cost (bool, bool);
+static int arm_cortex_a5_branch_cost (bool, bool);
/* Table of machine attributes. */
@@ -672,12 +674,13 @@
#define FL_THUMB2 (1 << 16) /* Thumb-2. */
#define FL_NOTM (1 << 17) /* Instructions not present in the 'M'
profile. */
-#define FL_DIV (1 << 18) /* Hardware divide. */
+#define FL_THUMB_DIV (1 << 18) /* Hardware divide (Thumb mode). */
#define FL_VFPV3 (1 << 19) /* Vector Floating Point V3. */
#define FL_NEON (1 << 20) /* Neon instructions. */
#define FL_ARCH7EM (1 << 21) /* Instructions present in the ARMv7E-M
architecture. */
#define FL_ARCH7 (1 << 22) /* Architecture 7. */
+#define FL_ARM_DIV (1 << 23) /* Hardware divide (ARM mode). */
#define FL_IWMMXT (1 << 29) /* XScale v2 or "Intel Wireless MMX technology". */
@@ -704,8 +707,8 @@
#define FL_FOR_ARCH6M (FL_FOR_ARCH6 & ~FL_NOTM)
#define FL_FOR_ARCH7 ((FL_FOR_ARCH6T2 & ~FL_NOTM) | FL_ARCH7)
#define FL_FOR_ARCH7A (FL_FOR_ARCH7 | FL_NOTM | FL_ARCH6K)
-#define FL_FOR_ARCH7R (FL_FOR_ARCH7A | FL_DIV)
-#define FL_FOR_ARCH7M (FL_FOR_ARCH7 | FL_DIV)
+#define FL_FOR_ARCH7R (FL_FOR_ARCH7A | FL_THUMB_DIV)
+#define FL_FOR_ARCH7M (FL_FOR_ARCH7 | FL_THUMB_DIV)
#define FL_FOR_ARCH7EM (FL_FOR_ARCH7M | FL_ARCH7EM)
/* The bits in this mask specify which
@@ -791,7 +794,8 @@
int arm_arch_thumb2;
/* Nonzero if chip supports integer division instruction. */
-int arm_arch_hwdiv;
+int arm_arch_arm_hwdiv;
+int arm_arch_thumb_hwdiv;
/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference,
we must report the mode of the memory reference from
@@ -864,48 +868,117 @@
{
arm_slowmul_rtx_costs,
NULL,
- 3,
- ARM_PREFETCH_NOT_BENEFICIAL
+ 3, /* Constant limit. */
+ 5, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ true, /* Prefer constant pool. */
+ arm_default_branch_cost
};
const struct tune_params arm_fastmul_tune =
{
arm_fastmul_rtx_costs,
NULL,
- 1,
- ARM_PREFETCH_NOT_BENEFICIAL
+ 1, /* Constant limit. */
+ 5, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ true, /* Prefer constant pool. */
+ arm_default_branch_cost
+};
+
+/* StrongARM has early execution of branches, so a sequence that is worth
+ skipping is shorter. Set max_insns_skipped to a lower value. */
+
+const struct tune_params arm_strongarm_tune =
+{
+ arm_fastmul_rtx_costs,
+ NULL,
+ 1, /* Constant limit. */
+ 3, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ true, /* Prefer constant pool. */
+ arm_default_branch_cost
};
const struct tune_params arm_xscale_tune =
{
arm_xscale_rtx_costs,
xscale_sched_adjust_cost,
- 2,
- ARM_PREFETCH_NOT_BENEFICIAL
+ 2, /* Constant limit. */
+ 3, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ true, /* Prefer constant pool. */
+ arm_default_branch_cost
};
const struct tune_params arm_9e_tune =
{
arm_9e_rtx_costs,
NULL,
- 1,
- ARM_PREFETCH_NOT_BENEFICIAL
+ 1, /* Constant limit. */
+ 5, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ true, /* Prefer constant pool. */
+ arm_default_branch_cost
+};
+
+const struct tune_params arm_v6t2_tune =
+{
+ arm_9e_rtx_costs,
+ NULL,
+ 1, /* Constant limit. */
+ 5, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ false, /* Prefer constant pool. */
+ arm_default_branch_cost
+};
+
+/* Generic Cortex tuning. Use more specific tunings if appropriate. */
+const struct tune_params arm_cortex_tune =
+{
+ arm_9e_rtx_costs,
+ NULL,
+ 1, /* Constant limit. */
+ 5, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ false, /* Prefer constant pool. */
+ arm_default_branch_cost
+};
+
+/* Branches can be dual-issued on Cortex-A5, so conditional execution is
+ less appealing. Set max_insns_skipped to a low value. */
+
+const struct tune_params arm_cortex_a5_tune =
+{
+ arm_9e_rtx_costs,
+ NULL,
+ 1, /* Constant limit. */
+ 1, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ false, /* Prefer constant pool. */
+ arm_cortex_a5_branch_cost
};
const struct tune_params arm_cortex_a9_tune =
{
arm_9e_rtx_costs,
cortex_a9_sched_adjust_cost,
- 1,
- ARM_PREFETCH_BENEFICIAL(4,32,32)
+ 1, /* Constant limit. */
+ 5, /* Max cond insns. */
+ ARM_PREFETCH_BENEFICIAL(4,32,32),
+ false, /* Prefer constant pool. */
+ arm_default_branch_cost
};
const struct tune_params arm_fa726te_tune =
{
arm_9e_rtx_costs,
fa726te_sched_adjust_cost,
- 1,
- ARM_PREFETCH_NOT_BENEFICIAL
+ 1, /* Constant limit. */
+ 5, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL,
+ true, /* Prefer constant pool. */
+ arm_default_branch_cost
};
@@ -1711,7 +1784,8 @@
arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
- arm_arch_hwdiv = (insn_flags & FL_DIV) != 0;
+ arm_arch_thumb_hwdiv = (insn_flags & FL_THUMB_DIV) != 0;
+ arm_arch_arm_hwdiv = (insn_flags & FL_ARM_DIV) != 0;
arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0;
/* If we are not using the default (ARM mode) section anchor offset
@@ -1991,12 +2065,7 @@
max_insns_skipped = 6;
}
else
- {
- /* StrongARM has early execution of branches, so a sequence
- that is worth skipping is shorter. */
- if (arm_tune_strongarm)
- max_insns_skipped = 3;
- }
+ max_insns_skipped = current_tune->max_insns_skipped;
/* Hot/Cold partitioning is not currently supported, since we can't
handle literal pool placement in that case. */
@@ -8211,6 +8280,21 @@
return cost;
}
+static int
+arm_default_branch_cost (bool speed_p, bool predictable_p ATTRIBUTE_UNUSED)
+{
+ if (TARGET_32BIT)
+ return (TARGET_THUMB2 && !speed_p) ? 1 : 4;
+ else
+ return (optimize > 0) ? 2 : 0;
+}
+
+static int
+arm_cortex_a5_branch_cost (bool speed_p, bool predictable_p)
+{
+ return speed_p ? 0 : arm_default_branch_cost (speed_p, predictable_p);
+}
+
static int fp_consts_inited = 0;
/* Only zero is valid for VFP. Other values are also valid for FPA. */
@@ -23123,6 +23207,7 @@
{
case cortexr4:
case cortexr4f:
+ case cortexr5:
case cortexa5:
case cortexa8:
case cortexa9:
=== modified file 'gcc/config/arm/arm.h'
--- old/gcc/config/arm/arm.h 2011-06-02 12:12:00 +0000
+++ new/gcc/config/arm/arm.h 2011-06-14 14:53:07 +0000
@@ -101,6 +101,8 @@
builtin_define ("__ARM_PCS"); \
builtin_define ("__ARM_EABI__"); \
} \
+ if (TARGET_IDIV) \
+ builtin_define ("__ARM_ARCH_EXT_IDIV__"); \
} while (0)
/* The various ARM cores. */
@@ -282,7 +284,8 @@
(TARGET_32BIT && arm_arch6 && (arm_arch_notm || arm_arch7em))
/* Should MOVW/MOVT be used in preference to a constant pool. */
-#define TARGET_USE_MOVT (arm_arch_thumb2 && !optimize_size)
+#define TARGET_USE_MOVT \
+ (arm_arch_thumb2 && !optimize_size && !current_tune->prefer_constant_pool)
/* We could use unified syntax for arm mode, but for now we just use it
for Thumb-2. */
@@ -303,6 +306,10 @@
/* Nonzero if this chip supports ldrex{bhd} and strex{bhd}. */
#define TARGET_HAVE_LDREXBHD ((arm_arch6k && TARGET_ARM) || arm_arch7)
+/* Nonzero if integer division instructions supported. */
+#define TARGET_IDIV ((TARGET_ARM && arm_arch_arm_hwdiv) \
+ || (TARGET_THUMB2 && arm_arch_thumb_hwdiv))
+
/* True iff the full BPABI is being used. If TARGET_BPABI is true,
then TARGET_AAPCS_BASED must be true -- but the converse does not
hold. TARGET_BPABI implies the use of the BPABI runtime library,
@@ -487,8 +494,11 @@
/* Nonzero if chip supports Thumb 2. */
extern int arm_arch_thumb2;
-/* Nonzero if chip supports integer division instruction. */
-extern int arm_arch_hwdiv;
+/* Nonzero if chip supports integer division instruction in ARM mode. */
+extern int arm_arch_arm_hwdiv;
+
+/* Nonzero if chip supports integer division instruction in Thumb mode. */
+extern int arm_arch_thumb_hwdiv;
#ifndef TARGET_DEFAULT
#define TARGET_DEFAULT (MASK_APCS_FRAME)
@@ -2018,8 +2028,8 @@
/* Try to generate sequences that don't involve branches, we can then use
conditional instructions */
#define BRANCH_COST(speed_p, predictable_p) \
- (TARGET_32BIT ? (TARGET_THUMB2 && !speed_p ? 1 : 4) \
- : (optimize > 0 ? 2 : 0))
+ (current_tune->branch_cost (speed_p, predictable_p))
+
/* Position Independent Code. */
/* We decide which register to use based on the compilation options and
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2011-06-02 15:58:33 +0000
+++ new/gcc/config/arm/arm.md 2011-06-14 14:37:30 +0000
@@ -490,7 +490,7 @@
(define_attr "tune_cortexr4" "yes,no"
(const (if_then_else
- (eq_attr "tune" "cortexr4,cortexr4f")
+ (eq_attr "tune" "cortexr4,cortexr4f,cortexr5")
(const_string "yes")
(const_string "no"))))
@@ -3738,6 +3738,28 @@
(set_attr "predicable" "yes")]
)
+
+;; Division instructions
+(define_insn "divsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (div:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "s_register_operand" "r")))]
+ "TARGET_IDIV"
+ "sdiv%?\t%0, %1, %2"
+ [(set_attr "predicable" "yes")
+ (set_attr "insn" "sdiv")]
+)
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "s_register_operand" "=r")
+ (udiv:SI (match_operand:SI 1 "s_register_operand" "r")
+ (match_operand:SI 2 "s_register_operand" "r")))]
+ "TARGET_IDIV"
+ "udiv%?\t%0, %1, %2"
+ [(set_attr "predicable" "yes")
+ (set_attr "insn" "udiv")]
+)
+
;; Unary arithmetic insns
=== modified file 'gcc/config/arm/thumb2.md'
--- old/gcc/config/arm/thumb2.md 2011-05-11 07:15:47 +0000
+++ new/gcc/config/arm/thumb2.md 2011-06-14 14:37:30 +0000
@@ -779,26 +779,6 @@
(set_attr "length" "2")]
)
-(define_insn "divsi3"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (div:SI (match_operand:SI 1 "s_register_operand" "r")
- (match_operand:SI 2 "s_register_operand" "r")))]
- "TARGET_THUMB2 && arm_arch_hwdiv"
- "sdiv%?\t%0, %1, %2"
- [(set_attr "predicable" "yes")
- (set_attr "insn" "sdiv")]
-)
-
-(define_insn "udivsi3"
- [(set (match_operand:SI 0 "s_register_operand" "=r")
- (udiv:SI (match_operand:SI 1 "s_register_operand" "r")
- (match_operand:SI 2 "s_register_operand" "r")))]
- "TARGET_THUMB2 && arm_arch_hwdiv"
- "udiv%?\t%0, %1, %2"
- [(set_attr "predicable" "yes")
- (set_attr "insn" "udiv")]
-)
-
(define_insn "*thumb2_subsi_short"
[(set (match_operand:SI 0 "low_register_operand" "=l")
(minus:SI (match_operand:SI 1 "low_register_operand" "l")
=== modified file 'gcc/doc/invoke.texi'
--- old/gcc/doc/invoke.texi 2011-05-11 07:15:47 +0000
+++ new/gcc/doc/invoke.texi 2011-06-14 14:37:30 +0000
@@ -10208,7 +10208,8 @@
@samp{arm1136j-s}, @samp{arm1136jf-s}, @samp{mpcore}, @samp{mpcorenovfp},
@samp{arm1156t2-s}, @samp{arm1156t2f-s}, @samp{arm1176jz-s}, @samp{arm1176jzf-s},
@samp{cortex-a5}, @samp{cortex-a8}, @samp{cortex-a9}, @samp{cortex-a15},
-@samp{cortex-r4}, @samp{cortex-r4f}, @samp{cortex-m4}, @samp{cortex-m3},
+@samp{cortex-r4}, @samp{cortex-r4f}, @samp{cortex-r5},
+@samp{cortex-m4}, @samp{cortex-m3},
@samp{cortex-m1},
@samp{cortex-m0},
@samp{xscale}, @samp{iwmmxt}, @samp{iwmmxt2}, @samp{ep9312}.
=== modified file 'gcc/dojump.c'
--- old/gcc/dojump.c 2010-05-19 19:09:57 +0000
+++ new/gcc/dojump.c 2011-06-14 14:53:07 +0000
@@ -36,6 +36,7 @@
#include "ggc.h"
#include "basic-block.h"
#include "output.h"
+#include "tm_p.h"
static bool prefer_and_bit_test (enum machine_mode, int);
static void do_jump_by_parts_greater (tree, tree, int, rtx, rtx, int);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
2011-06-28 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline.
gcc/
2011-06-24 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
PR target/49385
* config/arm/thumb2.md (*thumb2_movhi_insn): Make sure atleast
one of the operands is a register.
Index: gcc-4_6-branch/gcc/config/arm/thumb2.md
===================================================================
--- gcc-4_6-branch.orig/gcc/config/arm/thumb2.md 2011-09-16 20:22:40.000000000 -0700
+++ gcc-4_6-branch/gcc/config/arm/thumb2.md 2011-09-16 20:28:47.648690433 -0700
@@ -207,7 +207,9 @@
(define_insn "*thumb2_movhi_insn"
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r")
(match_operand:HI 1 "general_operand" "rI,n,r,m"))]
- "TARGET_THUMB2"
+ "TARGET_THUMB2
+ && (register_operand (operands[0], HImode)
+ || register_operand (operands[1], HImode))"
"@
mov%?\\t%0, %1\\t%@ movhi
movw%?\\t%0, %L1\\t%@ movhi
@@ -0,0 +1,25 @@
2011-06-30 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline.
LP 744754
2011-04-17 Chung-Lin Tang <cltang@codesourcery.com>
* config/arm/arm.c (neon_struct_mem_operand):
Support POST_INC/PRE_DEC memory operands.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-06-27 22:14:07 +0000
+++ new/gcc/config/arm/arm.c 2011-06-29 09:13:17 +0000
@@ -9357,6 +9357,11 @@
if (GET_CODE (ind) == REG)
return arm_address_register_rtx_p (ind, 0);
+ /* vldm/vstm allows POST_INC (ia) and PRE_DEC (db). */
+ if (GET_CODE (ind) == POST_INC
+ || GET_CODE (ind) == PRE_DEC)
+ return arm_address_register_rtx_p (XEXP (ind, 0), 0);
+
return FALSE;
}
@@ -0,0 +1,25 @@
2011-07-03 Ira Rosen <ira.rosen@linaro.org>
Backport from FSF:
2011-06-12 Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-vect-data-refs.c (vect_peeling_hash_get_most_frequent):
Take number of iterations to peel into account for equally frequent
misalignment values.
=== modified file 'gcc/tree-vect-data-refs.c'
--- old/gcc/tree-vect-data-refs.c 2011-06-02 12:12:00 +0000
+++ new/gcc/tree-vect-data-refs.c 2011-06-29 11:20:24 +0000
@@ -1256,7 +1256,9 @@
vect_peel_info elem = (vect_peel_info) *slot;
vect_peel_extended_info max = (vect_peel_extended_info) data;
- if (elem->count > max->peel_info.count)
+ if (elem->count > max->peel_info.count
+ || (elem->count == max->peel_info.count
+ && max->peel_info.npeel > elem->npeel))
{
max->peel_info.npeel = elem->npeel;
max->peel_info.count = elem->count;
@@ -0,0 +1,182 @@
2011-07-07 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
* builtins.c (get_object_alignment): Fix comment.
* fold-const.c (get_pointer_modulus_and_residue): Remove
allow_func_align. Use get_object_alignment.
(fold_binary_loc): Update caller.
2011-07-07 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-06-29 Richard Sandiford <richard.sandiford@linaro.org>
PR tree-optimization/49545
* builtins.c (get_object_alignment_1): Update function comment.
Do not use DECL_ALIGN for functions, but test
TARGET_PTRMEMFUNC_VBIT_LOCATION instead.
* fold-const.c (get_pointer_modulus_and_residue): Don't check
for functions here.
* tree-ssa-ccp.c (get_value_from_alignment): Likewise.
gcc/testsuite/
Backport from mainline:
2011-06-29 Richard Sandiford <richard.sandiford@linaro.org>
* gcc.dg/torture/pr49169.c: Restrict to ARM and MIPS targets.
2011-07-07 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-07-27 Richard Guenther <rguenther@suse.de>
PR tree-optimization/49169
* fold-const.c (get_pointer_modulus_and_residue): Don't rely on
the alignment of function decls.
gcc/testsuite/
Backport from mainline:
2011-07-27 Michael Hope <michael.hope@linaro.org>
Richard Sandiford <richard.sandiford@linaro.org>
PR tree-optimization/49169
* gcc.dg/torture/pr49169.c: New test.
=== modified file 'gcc/builtins.c'
--- old/gcc/builtins.c 2011-03-03 21:56:58 +0000
+++ new/gcc/builtins.c 2011-07-04 09:52:27 +0000
@@ -264,7 +264,14 @@
}
/* Return the alignment in bits of EXP, an object.
- Don't return more than MAX_ALIGN no matter what. */
+ Don't return more than MAX_ALIGN no matter what.
+
+ Note that the address (and thus the alignment) computed here is based
+ on the address to which a symbol resolves, whereas DECL_ALIGN is based
+ on the address at which an object is actually located. These two
+ addresses are not always the same. For example, on ARM targets,
+ the address &foo of a Thumb function foo() has the lowest bit set,
+ whereas foo() itself starts on an even address. */
unsigned int
get_object_alignment (tree exp, unsigned int max_align)
@@ -286,7 +293,21 @@
exp = DECL_INITIAL (exp);
if (DECL_P (exp)
&& TREE_CODE (exp) != LABEL_DECL)
- align = DECL_ALIGN (exp);
+ {
+ if (TREE_CODE (exp) == FUNCTION_DECL)
+ {
+ /* Function addresses can encode extra information besides their
+ alignment. However, if TARGET_PTRMEMFUNC_VBIT_LOCATION
+ allows the low bit to be used as a virtual bit, we know
+ that the address itself must be 2-byte aligned. */
+ if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn)
+ align = 2 * BITS_PER_UNIT;
+ else
+ align = BITS_PER_UNIT;
+ }
+ else
+ align = DECL_ALIGN (exp);
+ }
else if (CONSTANT_CLASS_P (exp))
{
align = TYPE_ALIGN (TREE_TYPE (exp));
=== modified file 'gcc/fold-const.c'
--- old/gcc/fold-const.c 2011-05-23 20:37:18 +0000
+++ new/gcc/fold-const.c 2011-07-04 09:52:27 +0000
@@ -9232,15 +9232,10 @@
0 <= N < M as is common. In general, the precise value of P is unknown.
M is chosen as large as possible such that constant N can be determined.
- Returns M and sets *RESIDUE to N.
-
- If ALLOW_FUNC_ALIGN is true, do take functions' DECL_ALIGN_UNIT into
- account. This is not always possible due to PR 35705.
- */
+ Returns M and sets *RESIDUE to N. */
static unsigned HOST_WIDE_INT
-get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue,
- bool allow_func_align)
+get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue)
{
enum tree_code code;
@@ -9270,9 +9265,8 @@
}
}
- if (DECL_P (expr)
- && (allow_func_align || TREE_CODE (expr) != FUNCTION_DECL))
- return DECL_ALIGN_UNIT (expr);
+ if (DECL_P (expr))
+ return get_object_alignment (expr, ~0U) / BITS_PER_UNIT;
}
else if (code == POINTER_PLUS_EXPR)
{
@@ -9282,8 +9276,7 @@
op0 = TREE_OPERAND (expr, 0);
STRIP_NOPS (op0);
- modulus = get_pointer_modulus_and_residue (op0, residue,
- allow_func_align);
+ modulus = get_pointer_modulus_and_residue (op0, residue);
op1 = TREE_OPERAND (expr, 1);
STRIP_NOPS (op1);
@@ -11163,8 +11156,7 @@
unsigned HOST_WIDE_INT modulus, residue;
unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg1);
- modulus = get_pointer_modulus_and_residue (arg0, &residue,
- integer_onep (arg1));
+ modulus = get_pointer_modulus_and_residue (arg0, &residue);
/* This works because modulus is a power of 2. If this weren't the
case, we'd have to replace it by its greatest power-of-2
=== added file 'gcc/testsuite/gcc.dg/torture/pr49169.c'
--- old/gcc/testsuite/gcc.dg/torture/pr49169.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/torture/pr49169.c 2011-06-29 09:46:06 +0000
@@ -0,0 +1,15 @@
+/* { dg-do compile { target { arm*-*-* || mips*-*-* } } } */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+int
+main (void)
+{
+ void *p = main;
+ if ((intptr_t) p & 1)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-assembler "abort" } } */
=== modified file 'gcc/tree-ssa-ccp.c'
--- old/gcc/tree-ssa-ccp.c 2011-05-05 15:42:22 +0000
+++ new/gcc/tree-ssa-ccp.c 2011-06-29 09:46:06 +0000
@@ -522,10 +522,6 @@
val = bit_value_binop (PLUS_EXPR, TREE_TYPE (expr),
TREE_OPERAND (base, 0), TREE_OPERAND (base, 1));
else if (base
- /* ??? While function decls have DECL_ALIGN their addresses
- may encode extra information in the lower bits on some
- targets (PR47239). Simply punt for function decls for now. */
- && TREE_CODE (base) != FUNCTION_DECL
&& ((align = get_object_alignment (base, BIGGEST_ALIGNMENT))
> BITS_PER_UNIT))
{
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,138 @@
2011-07-11 Revital Eres <revital.eres@linaro.org>
Backport from mainline -r175090.
gcc/
* ddg.c (add_intra_loop_mem_dep): New function.
(build_intra_loop_deps): Call it.
gcc/testsuite
* gcc.dg/sms-9.c: New file.
=== modified file 'gcc/ddg.c'
--- old/gcc/ddg.c 2011-05-13 16:03:40 +0000
+++ new/gcc/ddg.c 2011-07-04 11:00:06 +0000
@@ -390,6 +390,33 @@
&PATTERN (insn2));
}
+/* Given two nodes, analyze their RTL insns and add intra-loop mem deps
+ to ddg G. */
+static void
+add_intra_loop_mem_dep (ddg_ptr g, ddg_node_ptr from, ddg_node_ptr to)
+{
+
+ if ((from->cuid == to->cuid)
+ || !insns_may_alias_p (from->insn, to->insn))
+ /* Do not create edge if memory references have disjoint alias sets
+ or 'to' and 'from' are the same instruction. */
+ return;
+
+ if (mem_write_insn_p (from->insn))
+ {
+ if (mem_read_insn_p (to->insn))
+ create_ddg_dep_no_link (g, from, to,
+ DEBUG_INSN_P (to->insn)
+ ? ANTI_DEP : TRUE_DEP, MEM_DEP, 0);
+ else
+ create_ddg_dep_no_link (g, from, to,
+ DEBUG_INSN_P (to->insn)
+ ? ANTI_DEP : OUTPUT_DEP, MEM_DEP, 0);
+ }
+ else if (!mem_read_insn_p (to->insn))
+ create_ddg_dep_no_link (g, from, to, ANTI_DEP, MEM_DEP, 0);
+}
+
/* Given two nodes, analyze their RTL insns and add inter-loop mem deps
to ddg G. */
static void
@@ -477,10 +504,22 @@
if (DEBUG_INSN_P (j_node->insn))
continue;
if (mem_access_insn_p (j_node->insn))
- /* Don't bother calculating inter-loop dep if an intra-loop dep
- already exists. */
+ {
+ /* Don't bother calculating inter-loop dep if an intra-loop dep
+ already exists. */
if (! TEST_BIT (dest_node->successors, j))
add_inter_loop_mem_dep (g, dest_node, j_node);
+ /* If -fmodulo-sched-allow-regmoves
+ is set certain anti-dep edges are not created.
+ It might be that these anti-dep edges are on the
+ path from one memory instruction to another such that
+ removing these edges could cause a violation of the
+ memory dependencies. Thus we add intra edges between
+ every two memory instructions in this case. */
+ if (flag_modulo_sched_allow_regmoves
+ && !TEST_BIT (dest_node->predecessors, j))
+ add_intra_loop_mem_dep (g, j_node, dest_node);
+ }
}
}
}
=== added file 'gcc/testsuite/gcc.dg/sms-9.c'
--- old/gcc/testsuite/gcc.dg/sms-9.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/sms-9.c 2011-07-04 11:00:06 +0000
@@ -0,0 +1,60 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fmodulo-sched -fno-auto-inc-dec -O2 -fmodulo-sched-allow-regmoves" } */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+struct df_ref_info
+{
+ unsigned int *begin;
+ unsigned int *count;
+};
+
+extern void *memset (void *s, int c, __SIZE_TYPE__ n);
+
+
+__attribute__ ((noinline))
+ int
+ df_reorganize_refs_by_reg_by_insn (struct df_ref_info *ref_info,
+ int num, unsigned int start)
+{
+ unsigned int m = num;
+ unsigned int offset = 77;
+ unsigned int r;
+
+ for (r = start; r < m; r++)
+ {
+ ref_info->begin[r] = offset;
+ offset += ref_info->count[r];
+ ref_info->count[r] = 0;
+ }
+
+ return offset;
+}
+
+int
+main ()
+{
+ struct df_ref_info temp;
+ int num = 100;
+ unsigned int start = 5;
+ int i, offset;
+
+ temp.begin = malloc (100 * sizeof (unsigned int));
+ temp.count = malloc (100 * sizeof (unsigned int));
+
+ memset (temp.begin, 0, sizeof (unsigned int) * num);
+ memset (temp.count, 0, sizeof (unsigned int) * num);
+
+ for (i = 0; i < num; i++)
+ temp.count[i] = i + 1;
+
+ offset = df_reorganize_refs_by_reg_by_insn (&temp, num, start);
+
+ if (offset != 5112)
+ abort ();
+
+ free (temp.begin);
+ free (temp.count);
+ return 0;
+}
@@ -0,0 +1,211 @@
2011-07-11 Revital Eres <revital.eres@linaro.org>
Backport from mainline -r175091
gcc/
* modulo-sched.c (struct ps_insn): Remove row_rest_count
field.
(struct partial_schedule): Add rows_length field.
(verify_partial_schedule): Check rows_length.
(ps_insert_empty_row): Handle rows_length.
(create_partial_schedule): Likewise.
(free_partial_schedule): Likewise.
(reset_partial_schedule): Likewise.
(create_ps_insn): Remove rest_count argument.
(remove_node_from_ps): Update rows_length.
(add_node_to_ps): Update rows_length and call create_ps_insn without
passing row_rest_count.
(rotate_partial_schedule): Update rows_length.
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-05-13 16:03:40 +0000
+++ new/gcc/modulo-sched.c 2011-07-04 12:01:34 +0000
@@ -134,8 +134,6 @@
ps_insn_ptr next_in_row,
prev_in_row;
- /* The number of nodes in the same row that come after this node. */
- int row_rest_count;
};
/* Holds the partial schedule as an array of II rows. Each entry of the
@@ -149,6 +147,12 @@
/* rows[i] points to linked list of insns scheduled in row i (0<=i<ii). */
ps_insn_ptr *rows;
+ /* rows_length[i] holds the number of instructions in the row.
+ It is used only (as an optimization) to back off quickly from
+ trying to schedule a node in a full row; that is, to avoid running
+ through futile DFA state transitions. */
+ int *rows_length;
+
/* The earliest absolute cycle of an insn in the partial schedule. */
int min_cycle;
@@ -1907,6 +1911,7 @@
int ii = ps->ii;
int new_ii = ii + 1;
int row;
+ int *rows_length_new;
verify_partial_schedule (ps, sched_nodes);
@@ -1921,9 +1926,11 @@
rotate_partial_schedule (ps, PS_MIN_CYCLE (ps));
rows_new = (ps_insn_ptr *) xcalloc (new_ii, sizeof (ps_insn_ptr));
+ rows_length_new = (int *) xcalloc (new_ii, sizeof (int));
for (row = 0; row < split_row; row++)
{
rows_new[row] = ps->rows[row];
+ rows_length_new[row] = ps->rows_length[row];
ps->rows[row] = NULL;
for (crr_insn = rows_new[row];
crr_insn; crr_insn = crr_insn->next_in_row)
@@ -1944,6 +1951,7 @@
for (row = split_row; row < ii; row++)
{
rows_new[row + 1] = ps->rows[row];
+ rows_length_new[row + 1] = ps->rows_length[row];
ps->rows[row] = NULL;
for (crr_insn = rows_new[row + 1];
crr_insn; crr_insn = crr_insn->next_in_row)
@@ -1965,6 +1973,8 @@
+ (SMODULO (ps->max_cycle, ii) >= split_row ? 1 : 0);
free (ps->rows);
ps->rows = rows_new;
+ free (ps->rows_length);
+ ps->rows_length = rows_length_new;
ps->ii = new_ii;
gcc_assert (ps->min_cycle >= 0);
@@ -2040,16 +2050,23 @@
ps_insn_ptr crr_insn;
for (row = 0; row < ps->ii; row++)
- for (crr_insn = ps->rows[row]; crr_insn; crr_insn = crr_insn->next_in_row)
- {
- ddg_node_ptr u = crr_insn->node;
-
- gcc_assert (TEST_BIT (sched_nodes, u->cuid));
- /* ??? Test also that all nodes of sched_nodes are in ps, perhaps by
- popcount (sched_nodes) == number of insns in ps. */
- gcc_assert (SCHED_TIME (u) >= ps->min_cycle);
- gcc_assert (SCHED_TIME (u) <= ps->max_cycle);
- }
+ {
+ int length = 0;
+
+ for (crr_insn = ps->rows[row]; crr_insn; crr_insn = crr_insn->next_in_row)
+ {
+ ddg_node_ptr u = crr_insn->node;
+
+ length++;
+ gcc_assert (TEST_BIT (sched_nodes, u->cuid));
+ /* ??? Test also that all nodes of sched_nodes are in ps, perhaps by
+ popcount (sched_nodes) == number of insns in ps. */
+ gcc_assert (SCHED_TIME (u) >= ps->min_cycle);
+ gcc_assert (SCHED_TIME (u) <= ps->max_cycle);
+ }
+
+ gcc_assert (ps->rows_length[row] == length);
+ }
}
@@ -2455,6 +2472,7 @@
{
partial_schedule_ptr ps = XNEW (struct partial_schedule);
ps->rows = (ps_insn_ptr *) xcalloc (ii, sizeof (ps_insn_ptr));
+ ps->rows_length = (int *) xcalloc (ii, sizeof (int));
ps->ii = ii;
ps->history = history;
ps->min_cycle = INT_MAX;
@@ -2493,6 +2511,7 @@
return;
free_ps_insns (ps);
free (ps->rows);
+ free (ps->rows_length);
free (ps);
}
@@ -2510,6 +2529,8 @@
ps->rows = (ps_insn_ptr *) xrealloc (ps->rows, new_ii
* sizeof (ps_insn_ptr));
memset (ps->rows, 0, new_ii * sizeof (ps_insn_ptr));
+ ps->rows_length = (int *) xrealloc (ps->rows_length, new_ii * sizeof (int));
+ memset (ps->rows_length, 0, new_ii * sizeof (int));
ps->ii = new_ii;
ps->min_cycle = INT_MAX;
ps->max_cycle = INT_MIN;
@@ -2538,14 +2559,13 @@
/* Creates an object of PS_INSN and initializes it to the given parameters. */
static ps_insn_ptr
-create_ps_insn (ddg_node_ptr node, int rest_count, int cycle)
+create_ps_insn (ddg_node_ptr node, int cycle)
{
ps_insn_ptr ps_i = XNEW (struct ps_insn);
ps_i->node = node;
ps_i->next_in_row = NULL;
ps_i->prev_in_row = NULL;
- ps_i->row_rest_count = rest_count;
ps_i->cycle = cycle;
return ps_i;
@@ -2578,6 +2598,8 @@
if (ps_i->next_in_row)
ps_i->next_in_row->prev_in_row = ps_i->prev_in_row;
}
+
+ ps->rows_length[row] -= 1;
free (ps_i);
return true;
}
@@ -2734,17 +2756,12 @@
sbitmap must_precede, sbitmap must_follow)
{
ps_insn_ptr ps_i;
- int rest_count = 1;
int row = SMODULO (cycle, ps->ii);
- if (ps->rows[row]
- && ps->rows[row]->row_rest_count >= issue_rate)
+ if (ps->rows_length[row] >= issue_rate)
return NULL;
- if (ps->rows[row])
- rest_count += ps->rows[row]->row_rest_count;
-
- ps_i = create_ps_insn (node, rest_count, cycle);
+ ps_i = create_ps_insn (node, cycle);
/* Finds and inserts PS_I according to MUST_FOLLOW and
MUST_PRECEDE. */
@@ -2754,6 +2771,7 @@
return NULL;
}
+ ps->rows_length[row] += 1;
return ps_i;
}
@@ -2909,11 +2927,16 @@
for (i = 0; i < backward_rotates; i++)
{
ps_insn_ptr first_row = ps->rows[0];
+ int first_row_length = ps->rows_length[0];
for (row = 0; row < last_row; row++)
- ps->rows[row] = ps->rows[row+1];
+ {
+ ps->rows[row] = ps->rows[row + 1];
+ ps->rows_length[row] = ps->rows_length[row + 1];
+ }
ps->rows[last_row] = first_row;
+ ps->rows_length[last_row] = first_row_length;
}
ps->max_cycle -= start_cycle;
@@ -0,0 +1,350 @@
2011-07-11 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
gcc/
2011-06-22 Dmitry Plotnikov <dplotnikov@ispras.ru>
Dmitry Melnik <dm@ispras.ru>
* config/arm/arm.c (neon_immediate_valid_for_shift): New function.
(neon_output_shift_immediate): Ditto.
* config/arm/arm-protos.h (neon_immediate_valid_for_shift): New
prototype.
(neon_output_shift_immediate): Ditto.
* config/arm/neon.md (vashl<mode>3): Modified constraint.
(vashr<mode>3_imm): New insn pattern.
(vlshr<mode>3_imm): Ditto.
(vashr<mode>3): Modified constraint.
(vlshr<mode>3): Ditto.
* config/arm/predicates.md (imm_for_neon_lshift_operand): New
predicate.
(imm_for_neon_rshift_operand): Ditto.
(imm_lshift_or_reg_neon): Ditto.
(imm_rshift_or_reg_neon): Ditto.
* optabs.c (init_optabs): Init optab codes for vashl, vashr, vlshr.
=== modified file 'gcc/config/arm/arm-protos.h'
--- old/gcc/config/arm/arm-protos.h 2011-06-14 16:00:30 +0000
+++ new/gcc/config/arm/arm-protos.h 2011-07-04 14:03:49 +0000
@@ -64,8 +64,12 @@
extern int neon_immediate_valid_for_move (rtx, enum machine_mode, rtx *, int *);
extern int neon_immediate_valid_for_logic (rtx, enum machine_mode, int, rtx *,
int *);
+extern int neon_immediate_valid_for_shift (rtx, enum machine_mode, rtx *,
+ int *, bool);
extern char *neon_output_logic_immediate (const char *, rtx *,
enum machine_mode, int, int);
+extern char *neon_output_shift_immediate (const char *, char, rtx *,
+ enum machine_mode, int, bool);
extern void neon_pairwise_reduce (rtx, rtx, enum machine_mode,
rtx (*) (rtx, rtx, rtx));
extern rtx neon_make_constant (rtx);
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-06-29 09:13:17 +0000
+++ new/gcc/config/arm/arm.c 2011-07-04 14:03:49 +0000
@@ -8863,6 +8863,66 @@
return 1;
}
+/* Return TRUE if rtx OP is legal for use in a VSHR or VSHL instruction. If
+ the immediate is valid, write a constant suitable for using as an operand
+ to VSHR/VSHL to *MODCONST and the corresponding element width to
+ *ELEMENTWIDTH. ISLEFTSHIFT is for determine left or right shift,
+ because they have different limitations. */
+
+int
+neon_immediate_valid_for_shift (rtx op, enum machine_mode mode,
+ rtx *modconst, int *elementwidth,
+ bool isleftshift)
+{
+ unsigned int innersize = GET_MODE_SIZE (GET_MODE_INNER (mode));
+ unsigned int n_elts = CONST_VECTOR_NUNITS (op), i;
+ unsigned HOST_WIDE_INT last_elt = 0;
+ unsigned HOST_WIDE_INT maxshift;
+
+ /* Split vector constant out into a byte vector. */
+ for (i = 0; i < n_elts; i++)
+ {
+ rtx el = CONST_VECTOR_ELT (op, i);
+ unsigned HOST_WIDE_INT elpart;
+
+ if (GET_CODE (el) == CONST_INT)
+ elpart = INTVAL (el);
+ else if (GET_CODE (el) == CONST_DOUBLE)
+ return 0;
+ else
+ gcc_unreachable ();
+
+ if (i != 0 && elpart != last_elt)
+ return 0;
+
+ last_elt = elpart;
+ }
+
+ /* Shift less than element size. */
+ maxshift = innersize * 8;
+
+ if (isleftshift)
+ {
+ /* Left shift immediate value can be from 0 to <size>-1. */
+ if (last_elt >= maxshift)
+ return 0;
+ }
+ else
+ {
+ /* Right shift immediate value can be from 1 to <size>. */
+ if (last_elt == 0 || last_elt > maxshift)
+ return 0;
+ }
+
+ if (elementwidth)
+ *elementwidth = innersize * 8;
+
+ if (modconst)
+ *modconst = CONST_VECTOR_ELT (op, 0);
+
+ return 1;
+}
+
/* Return a string suitable for output of Neon immediate logic operation
MNEM. */
@@ -8885,6 +8945,28 @@
return templ;
}
+/* Return a string suitable for output of Neon immediate shift operation
+ (VSHR or VSHL) MNEM. */
+
+char *
+neon_output_shift_immediate (const char *mnem, char sign, rtx *op2,
+ enum machine_mode mode, int quad,
+ bool isleftshift)
+{
+ int width, is_valid;
+ static char templ[40];
+
+ is_valid = neon_immediate_valid_for_shift (*op2, mode, op2, &width, isleftshift);
+ gcc_assert (is_valid != 0);
+
+ if (quad)
+ sprintf (templ, "%s.%c%d\t%%q0, %%q1, %%2", mnem, sign, width);
+ else
+ sprintf (templ, "%s.%c%d\t%%P0, %%P1, %%2", mnem, sign, width);
+
+ return templ;
+}
+
/* Output a sequence of pairwise operations to implement a reduction.
NOTE: We do "too much work" here, because pairwise operations work on two
registers-worth of operands in one go. Unfortunately we can't exploit those
=== modified file 'gcc/config/arm/neon.md'
--- old/gcc/config/arm/neon.md 2011-07-01 09:19:21 +0000
+++ new/gcc/config/arm/neon.md 2011-07-04 14:03:49 +0000
@@ -956,15 +956,57 @@
; SImode elements.
(define_insn "vashl<mode>3"
- [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
- (ashift:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
- (match_operand:VDQIW 2 "s_register_operand" "w")))]
- "TARGET_NEON"
- "vshl.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2"
- [(set (attr "neon_type")
- (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
- (const_string "neon_vshl_ddd")
- (const_string "neon_shift_3")))]
+ [(set (match_operand:VDQIW 0 "s_register_operand" "=w,w")
+ (ashift:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w,w")
+ (match_operand:VDQIW 2 "imm_lshift_or_reg_neon" "w,Dn")))]
+ "TARGET_NEON"
+ {
+ switch (which_alternative)
+ {
+ case 0: return "vshl.<V_s_elem>\t%<V_reg>0, %<V_reg>1, %<V_reg>2";
+ case 1: return neon_output_shift_immediate ("vshl", 'i', &operands[2],
+ <MODE>mode,
+ VALID_NEON_QREG_MODE (<MODE>mode),
+ true);
+ default: gcc_unreachable ();
+ }
+ }
+ [(set (attr "neon_type")
+ (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+ (const_string "neon_vshl_ddd")
+ (const_string "neon_shift_3")))]
+)
+
+(define_insn "vashr<mode>3_imm"
+ [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
+ (ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
+ (match_operand:VDQIW 2 "imm_for_neon_rshift_operand" "Dn")))]
+ "TARGET_NEON"
+ {
+ return neon_output_shift_immediate ("vshr", 's', &operands[2],
+ <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode),
+ false);
+ }
+ [(set (attr "neon_type")
+ (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+ (const_string "neon_vshl_ddd")
+ (const_string "neon_shift_3")))]
+)
+
+(define_insn "vlshr<mode>3_imm"
+ [(set (match_operand:VDQIW 0 "s_register_operand" "=w")
+ (lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "w")
+ (match_operand:VDQIW 2 "imm_for_neon_rshift_operand" "Dn")))]
+ "TARGET_NEON"
+ {
+ return neon_output_shift_immediate ("vshr", 'u', &operands[2],
+ <MODE>mode, VALID_NEON_QREG_MODE (<MODE>mode),
+ false);
+ }
+ [(set (attr "neon_type")
+ (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+ (const_string "neon_vshl_ddd")
+ (const_string "neon_shift_3")))]
)
; Used for implementing logical shift-right, which is a left-shift by a negative
@@ -1004,28 +1046,34 @@
(define_expand "vashr<mode>3"
[(set (match_operand:VDQIW 0 "s_register_operand" "")
(ashiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
- (match_operand:VDQIW 2 "s_register_operand" "")))]
+ (match_operand:VDQIW 2 "imm_rshift_or_reg_neon" "")))]
"TARGET_NEON"
{
rtx neg = gen_reg_rtx (<MODE>mode);
-
- emit_insn (gen_neg<mode>2 (neg, operands[2]));
- emit_insn (gen_ashl<mode>3_signed (operands[0], operands[1], neg));
-
+ if (REG_P (operands[2]))
+ {
+ emit_insn (gen_neg<mode>2 (neg, operands[2]));
+ emit_insn (gen_ashl<mode>3_signed (operands[0], operands[1], neg));
+ }
+ else
+ emit_insn (gen_vashr<mode>3_imm (operands[0], operands[1], operands[2]));
DONE;
})
(define_expand "vlshr<mode>3"
[(set (match_operand:VDQIW 0 "s_register_operand" "")
(lshiftrt:VDQIW (match_operand:VDQIW 1 "s_register_operand" "")
- (match_operand:VDQIW 2 "s_register_operand" "")))]
+ (match_operand:VDQIW 2 "imm_rshift_or_reg_neon" "")))]
"TARGET_NEON"
{
rtx neg = gen_reg_rtx (<MODE>mode);
-
- emit_insn (gen_neg<mode>2 (neg, operands[2]));
- emit_insn (gen_ashl<mode>3_unsigned (operands[0], operands[1], neg));
-
+ if (REG_P (operands[2]))
+ {
+ emit_insn (gen_neg<mode>2 (neg, operands[2]));
+ emit_insn (gen_ashl<mode>3_unsigned (operands[0], operands[1], neg));
+ }
+ else
+ emit_insn (gen_vlshr<mode>3_imm (operands[0], operands[1], operands[2]));
DONE;
})
=== modified file 'gcc/config/arm/predicates.md'
--- old/gcc/config/arm/predicates.md 2011-06-22 15:50:23 +0000
+++ new/gcc/config/arm/predicates.md 2011-07-04 14:03:49 +0000
@@ -585,6 +585,26 @@
return neon_immediate_valid_for_move (op, mode, NULL, NULL);
})
+(define_predicate "imm_for_neon_lshift_operand"
+ (match_code "const_vector")
+{
+ return neon_immediate_valid_for_shift (op, mode, NULL, NULL, true);
+})
+
+(define_predicate "imm_for_neon_rshift_operand"
+ (match_code "const_vector")
+{
+ return neon_immediate_valid_for_shift (op, mode, NULL, NULL, false);
+})
+
+(define_predicate "imm_lshift_or_reg_neon"
+ (ior (match_operand 0 "s_register_operand")
+ (match_operand 0 "imm_for_neon_lshift_operand")))
+
+(define_predicate "imm_rshift_or_reg_neon"
+ (ior (match_operand 0 "s_register_operand")
+ (match_operand 0 "imm_for_neon_rshift_operand")))
+
(define_predicate "imm_for_neon_logic_operand"
(match_code "const_vector")
{
=== modified file 'gcc/optabs.c'
--- old/gcc/optabs.c 2011-03-04 10:27:10 +0000
+++ new/gcc/optabs.c 2011-07-04 14:03:49 +0000
@@ -6171,6 +6171,9 @@
init_optab (usashl_optab, US_ASHIFT);
init_optab (ashr_optab, ASHIFTRT);
init_optab (lshr_optab, LSHIFTRT);
+ init_optabv (vashl_optab, ASHIFT);
+ init_optabv (vashr_optab, ASHIFTRT);
+ init_optabv (vlshr_optab, LSHIFTRT);
init_optab (rotl_optab, ROTATE);
init_optab (rotr_optab, ROTATERT);
init_optab (smin_optab, SMIN);
=== added file 'gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c'
--- old/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/neon-vlshr-imm-1.c 2011-07-04 14:03:49 +0000
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
+/* { dg-final { scan-assembler "vshr\.u32.*#3" } } */
+
+/* Verify that VSHR immediate is used. */
+void f1(int n, unsigned int x[], unsigned int y[]) {
+ int i;
+ for (i = 0; i < n; ++i)
+ y[i] = x[i] >> 3;
+}
=== added file 'gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c'
--- old/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/neon-vshl-imm-1.c 2011-07-04 14:03:49 +0000
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
+/* { dg-final { scan-assembler "vshl\.i32.*#3" } } */
+
+/* Verify that VSHR immediate is used. */
+void f1(int n, int x[], int y[]) {
+ int i;
+ for (i = 0; i < n; ++i)
+ y[i] = x[i] << 3;
+}
=== added file 'gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c'
--- old/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/neon-vshr-imm-1.c 2011-07-04 14:03:49 +0000
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize" } */
+/* { dg-final { scan-assembler "vshr\.s32.*#3" } } */
+
+/* Verify that VSHR immediate is used. */
+void f1(int n, int x[], int y[]) {
+ int i;
+ for (i = 0; i < n; ++i)
+ y[i] = x[i] >> 3;
+}
@@ -0,0 +1,119 @@
2011-07-13 Richard Sandiford <richard.sandiford@linaro.org>
Backport from mainline:
gcc/
2011-07-07 Richard Sandiford <richard.sandiford@linaro.org>
* reload1.c (choose_reload_regs): Use mode sizes to check whether
an old reload register completely defines the required value.
gcc/testsuite/
2011-07-07 Richard Sandiford <richard.sandiford@linaro.org>
* gcc.target/arm/neon-modes-3.c: New test.
=== modified file 'gcc/reload1.c'
--- old/gcc/reload1.c 2011-07-01 09:19:21 +0000
+++ new/gcc/reload1.c 2011-07-11 10:06:50 +0000
@@ -6451,6 +6451,8 @@
if (regno >= 0
&& reg_last_reload_reg[regno] != 0
+ && (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno]))
+ >= GET_MODE_SIZE (mode) + byte)
#ifdef CANNOT_CHANGE_MODE_CLASS
/* Verify that the register it's in can be used in
mode MODE. */
@@ -6462,24 +6464,12 @@
{
enum reg_class rclass = rld[r].rclass, last_class;
rtx last_reg = reg_last_reload_reg[regno];
- enum machine_mode need_mode;
i = REGNO (last_reg);
i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode);
last_class = REGNO_REG_CLASS (i);
- if (byte == 0)
- need_mode = mode;
- else
- need_mode
- = smallest_mode_for_size
- (GET_MODE_BITSIZE (mode) + byte * BITS_PER_UNIT,
- GET_MODE_CLASS (mode) == MODE_PARTIAL_INT
- ? MODE_INT : GET_MODE_CLASS (mode));
-
- if ((GET_MODE_SIZE (GET_MODE (last_reg))
- >= GET_MODE_SIZE (need_mode))
- && reg_reloaded_contents[i] == regno
+ if (reg_reloaded_contents[i] == regno
&& TEST_HARD_REG_BIT (reg_reloaded_valid, i)
&& HARD_REGNO_MODE_OK (i, rld[r].mode)
&& (TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], i)
=== added file 'gcc/testsuite/gcc.target/arm/neon-modes-3.c'
--- old/gcc/testsuite/gcc.target/arm/neon-modes-3.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/neon-modes-3.c 2011-07-11 10:06:50 +0000
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O" } */
+/* { dg-add-options arm_neon } */
+
+#include <arm_neon.h>
+
+void f1 (volatile float32x4_t *dest, volatile float32x4x4_t *src, int n)
+{
+ float32x4x4_t a5, a6, a7, a8, a9;
+ int i;
+
+ a5 = *src;
+ a6 = *src;
+ a7 = *src;
+ a8 = *src;
+ a9 = *src;
+ while (n--)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ float32x4x4_t a0, a1, a2, a3, a4;
+
+ a0 = *src;
+ a1 = *src;
+ a2 = *src;
+ a3 = *src;
+ a4 = *src;
+ *src = a0;
+ *dest = a0.val[0];
+ *dest = a0.val[3];
+ *src = a1;
+ *dest = a1.val[0];
+ *dest = a1.val[3];
+ *src = a2;
+ *dest = a2.val[0];
+ *dest = a2.val[3];
+ *src = a3;
+ *dest = a3.val[0];
+ *dest = a3.val[3];
+ *src = a4;
+ *dest = a4.val[0];
+ *dest = a4.val[3];
+ }
+ *src = a5;
+ *dest = a5.val[0];
+ *dest = a5.val[3];
+ *src = a6;
+ *dest = a6.val[0];
+ *dest = a6.val[3];
+ *src = a7;
+ *dest = a7.val[0];
+ *dest = a7.val[3];
+ *src = a8;
+ *dest = a8.val[0];
+ *dest = a8.val[3];
+ *src = a9;
+ *dest = a9.val[0];
+ *dest = a9.val[3];
+ }
+}
@@ -0,0 +1,67 @@
2011-07-15 Michael Hope <michael.hope@linaro.org>
gcc/
Backport from mainline:
2011-04-05 Eric Botcazou <ebotcazou@adacore.com>
* ifcvt.c (cond_exec_process_insns): Disallow converting a block
that contains the prologue.
gcc/testsuite/
Backport from mainline:
2011-04-01 Bernd Schmidt <bernds@codesourcery.com>
* gcc.c-torture/compile/20110401-1.c: New test.
=== modified file 'gcc/ifcvt.c'
--- old/gcc/ifcvt.c 2010-12-14 00:23:40 +0000
+++ new/gcc/ifcvt.c 2011-07-11 04:02:28 +0000
@@ -1,5 +1,6 @@
/* If-conversion support.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010,
+ 2011
Free Software Foundation, Inc.
This file is part of GCC.
@@ -304,6 +305,10 @@
for (insn = start; ; insn = NEXT_INSN (insn))
{
+ /* dwarf2out can't cope with conditional prologues. */
+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_PROLOGUE_END)
+ return FALSE;
+
if (NOTE_P (insn) || DEBUG_INSN_P (insn))
goto insn_done;
=== added file 'gcc/testsuite/gcc.c-torture/compile/20110401-1.c'
--- old/gcc/testsuite/gcc.c-torture/compile/20110401-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.c-torture/compile/20110401-1.c 2011-07-11 04:02:28 +0000
@@ -0,0 +1,22 @@
+void asn1_length_der (unsigned long int len, unsigned char *ans, int *ans_len)
+{
+ int k;
+ unsigned char temp[4];
+ if (len < 128) {
+ if (ans != ((void *) 0))
+ ans[0] = (unsigned char) len;
+ *ans_len = 1;
+ } else {
+ k = 0;
+ while (len) {
+ temp[k++] = len & 0xFF;
+ len = len >> 8;
+ }
+ *ans_len = k + 1;
+ if (ans != ((void *) 0)) {
+ ans[0] = ((unsigned char) k & 0x7F) + 128;
+ while (k--)
+ ans[*ans_len - 1 - k] = temp[k];
+ }
+ }
+}
@@ -0,0 +1,46 @@
2011-07-15 Michael Hope <michael.hope@linaro.org>
gcc/
Backport from mainline:
2011-03-22 Eric Botcazou <ebotcazou@adacore.com>
* combine.c (simplify_set): Try harder to find the best CC mode when
simplifying a nested COMPARE on the RHS.
=== modified file 'gcc/combine.c'
--- old/gcc/combine.c 2011-05-27 14:31:18 +0000
+++ new/gcc/combine.c 2011-07-11 03:52:31 +0000
@@ -6287,10 +6287,18 @@
enum rtx_code new_code;
rtx op0, op1, tmp;
int other_changed = 0;
+ rtx inner_compare = NULL_RTX;
enum machine_mode compare_mode = GET_MODE (dest);
if (GET_CODE (src) == COMPARE)
- op0 = XEXP (src, 0), op1 = XEXP (src, 1);
+ {
+ op0 = XEXP (src, 0), op1 = XEXP (src, 1);
+ if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
+ {
+ inner_compare = op0;
+ op0 = XEXP (inner_compare, 0), op1 = XEXP (inner_compare, 1);
+ }
+ }
else
op0 = src, op1 = CONST0_RTX (GET_MODE (src));
@@ -6332,6 +6340,12 @@
need to use a different CC mode here. */
if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
compare_mode = GET_MODE (op0);
+ else if (inner_compare
+ && GET_MODE_CLASS (GET_MODE (inner_compare)) == MODE_CC
+ && new_code == old_code
+ && op0 == XEXP (inner_compare, 0)
+ && op1 == XEXP (inner_compare, 1))
+ compare_mode = GET_MODE (inner_compare);
else
compare_mode = SELECT_CC_MODE (new_code, op0, op1);
@@ -0,0 +1,192 @@
2011-07-15 Michael Hope <michael.hope@linaro.org>
gcc/
Backport from mainline:
2011-06-29 Nathan Sidwell <nathan@codesourcery.com>
* config/arm/unwind-arm.c (enum __cxa_type_match_result): New.
(cxa_type_match): Correct declaration.
(__gnu_unwind_pr_common): Reconstruct
additional indirection when __cxa_type_match returns
succeeded_with_ptr_to_base.
libstdc++-v3/
Backport from mainline:
2011-06-29 Nathan Sidwell <nathan@codesourcery.com>
* libsupc++/eh_arm.c (__cxa_type_match): Construct address of
thrown object here. Return succeded_with_ptr_to_base for all
pointer cases.
=== modified file 'gcc/config/arm/unwind-arm.c'
--- old/gcc/config/arm/unwind-arm.c 2011-03-22 10:59:10 +0000
+++ new/gcc/config/arm/unwind-arm.c 2011-07-11 03:35:44 +0000
@@ -32,13 +32,18 @@
typedef unsigned char bool;
typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
+enum __cxa_type_match_result
+ {
+ ctm_failed = 0,
+ ctm_succeeded = 1,
+ ctm_succeeded_with_ptr_to_base = 2
+ };
void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp);
-bool __attribute__((weak)) __cxa_type_match(_Unwind_Control_Block *ucbp,
- const type_info *rttip,
- bool is_reference,
- void **matched_object);
+enum __cxa_type_match_result __attribute__((weak)) __cxa_type_match
+ (_Unwind_Control_Block *ucbp, const type_info *rttip,
+ bool is_reference, void **matched_object);
_Unwind_Ptr __attribute__((weak))
__gnu_Unwind_Find_exidx (_Unwind_Ptr, int *);
@@ -1107,6 +1112,7 @@
_uw rtti;
bool is_reference = (data[0] & uint32_highbit) != 0;
void *matched;
+ enum __cxa_type_match_result match_type;
/* Check for no-throw areas. */
if (data[1] == (_uw) -2)
@@ -1118,17 +1124,31 @@
{
/* Match a catch specification. */
rtti = _Unwind_decode_target2 ((_uw) &data[1]);
- if (!__cxa_type_match (ucbp, (type_info *) rtti,
- is_reference,
- &matched))
- matched = (void *)0;
+ match_type = __cxa_type_match (ucbp,
+ (type_info *) rtti,
+ is_reference,
+ &matched);
}
+ else
+ match_type = ctm_succeeded;
- if (matched)
+ if (match_type)
{
ucbp->barrier_cache.sp =
_Unwind_GetGR (context, R_SP);
- ucbp->barrier_cache.bitpattern[0] = (_uw) matched;
+ // ctm_succeeded_with_ptr_to_base really
+ // means _c_t_m indirected the pointer
+ // object. We have to reconstruct the
+ // additional pointer layer by using a temporary.
+ if (match_type == ctm_succeeded_with_ptr_to_base)
+ {
+ ucbp->barrier_cache.bitpattern[2]
+ = (_uw) matched;
+ ucbp->barrier_cache.bitpattern[0]
+ = (_uw) &ucbp->barrier_cache.bitpattern[2];
+ }
+ else
+ ucbp->barrier_cache.bitpattern[0] = (_uw) matched;
ucbp->barrier_cache.bitpattern[1] = (_uw) data;
return _URC_HANDLER_FOUND;
}
=== modified file 'libstdc++-v3/libsupc++/eh_arm.cc'
--- old/libstdc++-v3/libsupc++/eh_arm.cc 2011-01-03 20:52:22 +0000
+++ new/libstdc++-v3/libsupc++/eh_arm.cc 2011-07-11 03:35:44 +0000
@@ -30,10 +30,11 @@
using namespace __cxxabiv1;
-// Given the thrown type THROW_TYPE, pointer to a variable containing a
-// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
-// compare against, return whether or not there is a match and if so,
-// update *THROWN_PTR_P.
+// Given the thrown type THROW_TYPE, exception object UE_HEADER and a
+// type CATCH_TYPE to compare against, return whether or not there is
+// a match and if so, update *THROWN_PTR_P to point to either the
+// type-matched object, or in the case of a pointer type, the object
+// pointed to by the pointer.
extern "C" __cxa_type_match_result
__cxa_type_match(_Unwind_Exception* ue_header,
@@ -41,51 +42,51 @@
bool is_reference __attribute__((__unused__)),
void** thrown_ptr_p)
{
- bool forced_unwind = __is_gxx_forced_unwind_class(ue_header->exception_class);
- bool foreign_exception = !forced_unwind && !__is_gxx_exception_class(ue_header->exception_class);
- bool dependent_exception =
- __is_dependent_exception(ue_header->exception_class);
+ bool forced_unwind
+ = __is_gxx_forced_unwind_class(ue_header->exception_class);
+ bool foreign_exception
+ = !forced_unwind && !__is_gxx_exception_class(ue_header->exception_class);
+ bool dependent_exception
+ = __is_dependent_exception(ue_header->exception_class);
__cxa_exception* xh = __get_exception_header_from_ue(ue_header);
__cxa_dependent_exception *dx = __get_dependent_exception_from_ue(ue_header);
const std::type_info* throw_type;
+ void *thrown_ptr = 0;
if (forced_unwind)
throw_type = &typeid(abi::__forced_unwind);
else if (foreign_exception)
throw_type = &typeid(abi::__foreign_exception);
- else if (dependent_exception)
- throw_type = __get_exception_header_from_obj
- (dx->primaryException)->exceptionType;
else
- throw_type = xh->exceptionType;
-
- void* thrown_ptr = *thrown_ptr_p;
+ {
+ if (dependent_exception)
+ xh = __get_exception_header_from_obj (dx->primaryException);
+ throw_type = xh->exceptionType;
+ // We used to require the caller set the target of thrown_ptr_p,
+ // but that's incorrect -- the EHABI makes no such requirement
+ // -- and not all callers will set it. Fortunately callers that
+ // do initialize will always pass us the value we calculate
+ // here, so there's no backwards compatibility problem.
+ thrown_ptr = __get_object_from_ue (ue_header);
+ }
+
+ __cxa_type_match_result result = ctm_succeeded;
// Pointer types need to adjust the actual pointer, not
// the pointer to pointer that is the exception object.
// This also has the effect of passing pointer types
// "by value" through the __cxa_begin_catch return value.
if (throw_type->__is_pointer_p())
- thrown_ptr = *(void**) thrown_ptr;
+ {
+ thrown_ptr = *(void**) thrown_ptr;
+ // We need to indicate the indirection to our caller.
+ result = ctm_succeeded_with_ptr_to_base;
+ }
if (catch_type->__do_catch(throw_type, &thrown_ptr, 1))
{
*thrown_ptr_p = thrown_ptr;
-
- if (typeid(*catch_type) == typeid (typeid(void*)))
- {
- const __pointer_type_info *catch_pointer_type =
- static_cast<const __pointer_type_info *> (catch_type);
- const __pointer_type_info *throw_pointer_type =
- static_cast<const __pointer_type_info *> (throw_type);
-
- if (typeid (*catch_pointer_type->__pointee) != typeid (void)
- && (*catch_pointer_type->__pointee !=
- *throw_pointer_type->__pointee))
- return ctm_succeeded_with_ptr_to_base;
- }
-
- return ctm_succeeded;
+ return result;
}
return ctm_failed;
File diff suppressed because one or more lines are too long
@@ -0,0 +1,741 @@
2011-07-21 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
PR middle-end/49736
* expr.c (all_zeros_p): Undo bogus part of last change.
2011-07-21 Richard Sandiford <richard.sandiford@linaro.org>
Backport from mainline:
gcc/cp/
2011-07-13 Richard Sandiford <richard.sandiford@linaro.org>
* typeck2.c (split_nonconstant_init_1): Pass the initializer directly,
rather than a pointer to it. Return true if the whole of the value
was initialized by the generated statements. Use
complete_ctor_at_level_p instead of count_type_elements.
gcc/
2011-07-13 Richard Sandiford <richard.sandiford@linaro.org>
* tree.h (categorize_ctor_elements): Remove comment. Fix long line.
(count_type_elements): Delete.
(complete_ctor_at_level_p): Declare.
* expr.c (flexible_array_member_p): New function, split out from...
(count_type_elements): ...here. Make static. Replace allow_flexarr
parameter with for_ctor_p. When for_ctor_p is true, return the
number of elements that should appear in the top-level constructor,
otherwise return an estimate of the number of scalars.
(categorize_ctor_elements): Replace p_must_clear with p_complete.
(categorize_ctor_elements_1): Likewise. Use complete_ctor_at_level_p.
(complete_ctor_at_level_p): New function, borrowing union logic
from old categorize_ctor_elements_1.
(mostly_zeros_p): Return true if the constructor is not complete.
(all_zeros_p): Update call to categorize_ctor_elements.
* gimplify.c (gimplify_init_constructor): Update call to
categorize_ctor_elements. Don't call count_type_elements.
Unconditionally prevent clearing for variable-sized types,
otherwise rely on categorize_ctor_elements to detect
incomplete initializers.
gcc/testsuite/
2011-07-13 Chung-Lin Tang <cltang@codesourcery.com>
* gcc.target/arm/pr48183.c: New test.
=== modified file 'gcc/cp/typeck2.c'
--- old/gcc/cp/typeck2.c 2011-05-20 21:29:14 +0000
+++ new/gcc/cp/typeck2.c 2011-07-13 13:17:31 +0000
@@ -473,18 +473,20 @@
/* The recursive part of split_nonconstant_init. DEST is an lvalue
- expression to which INIT should be assigned. INIT is a CONSTRUCTOR. */
+ expression to which INIT should be assigned. INIT is a CONSTRUCTOR.
+ Return true if the whole of the value was initialized by the
+ generated statements. */
-static void
-split_nonconstant_init_1 (tree dest, tree *initp)
+static bool
+split_nonconstant_init_1 (tree dest, tree init)
{
unsigned HOST_WIDE_INT idx;
- tree init = *initp;
tree field_index, value;
tree type = TREE_TYPE (dest);
tree inner_type = NULL;
bool array_type_p = false;
- HOST_WIDE_INT num_type_elements, num_initialized_elements;
+ bool complete_p = true;
+ HOST_WIDE_INT num_split_elts = 0;
switch (TREE_CODE (type))
{
@@ -496,7 +498,6 @@
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
- num_initialized_elements = 0;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx,
field_index, value)
{
@@ -519,13 +520,14 @@
sub = build3 (COMPONENT_REF, inner_type, dest, field_index,
NULL_TREE);
- split_nonconstant_init_1 (sub, &value);
+ if (!split_nonconstant_init_1 (sub, value))
+ complete_p = false;
+ num_split_elts++;
}
else if (!initializer_constant_valid_p (value, inner_type))
{
tree code;
tree sub;
- HOST_WIDE_INT inner_elements;
/* FIXME: Ordered removal is O(1) so the whole function is
worst-case quadratic. This could be fixed using an aside
@@ -549,21 +551,9 @@
code = build_stmt (input_location, EXPR_STMT, code);
add_stmt (code);
- inner_elements = count_type_elements (inner_type, true);
- if (inner_elements < 0)
- num_initialized_elements = -1;
- else if (num_initialized_elements >= 0)
- num_initialized_elements += inner_elements;
- continue;
+ num_split_elts++;
}
}
-
- num_type_elements = count_type_elements (type, true);
- /* If all elements of the initializer are non-constant and
- have been split out, we don't need the empty CONSTRUCTOR. */
- if (num_type_elements > 0
- && num_type_elements == num_initialized_elements)
- *initp = NULL;
break;
case VECTOR_TYPE:
@@ -575,6 +565,7 @@
code = build2 (MODIFY_EXPR, type, dest, cons);
code = build_stmt (input_location, EXPR_STMT, code);
add_stmt (code);
+ num_split_elts += CONSTRUCTOR_NELTS (init);
}
break;
@@ -584,6 +575,8 @@
/* The rest of the initializer is now a constant. */
TREE_CONSTANT (init) = 1;
+ return complete_p && complete_ctor_at_level_p (TREE_TYPE (init),
+ num_split_elts, inner_type);
}
/* A subroutine of store_init_value. Splits non-constant static
@@ -599,7 +592,8 @@
if (TREE_CODE (init) == CONSTRUCTOR)
{
code = push_stmt_list ();
- split_nonconstant_init_1 (dest, &init);
+ if (split_nonconstant_init_1 (dest, init))
+ init = NULL_TREE;
code = pop_stmt_list (code);
DECL_INITIAL (dest) = init;
TREE_READONLY (dest) = 0;
=== modified file 'gcc/expr.c'
--- old/gcc/expr.c 2011-06-02 12:12:00 +0000
+++ new/gcc/expr.c 2011-07-14 11:52:32 +0000
@@ -4866,16 +4866,136 @@
return NULL_RTX;
}
+/* Return true if field F of structure TYPE is a flexible array. */
+
+static bool
+flexible_array_member_p (const_tree f, const_tree type)
+{
+ const_tree tf;
+
+ tf = TREE_TYPE (f);
+ return (DECL_CHAIN (f) == NULL
+ && TREE_CODE (tf) == ARRAY_TYPE
+ && TYPE_DOMAIN (tf)
+ && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
+ && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf)))
+ && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf))
+ && int_size_in_bytes (type) >= 0);
+}
+
+/* If FOR_CTOR_P, return the number of top-level elements that a constructor
+ must have in order for it to completely initialize a value of type TYPE.
+ Return -1 if the number isn't known.
+
+ If !FOR_CTOR_P, return an estimate of the number of scalars in TYPE. */
+
+static HOST_WIDE_INT
+count_type_elements (const_tree type, bool for_ctor_p)
+{
+ switch (TREE_CODE (type))
+ {
+ case ARRAY_TYPE:
+ {
+ tree nelts;
+
+ nelts = array_type_nelts (type);
+ if (nelts && host_integerp (nelts, 1))
+ {
+ unsigned HOST_WIDE_INT n;
+
+ n = tree_low_cst (nelts, 1) + 1;
+ if (n == 0 || for_ctor_p)
+ return n;
+ else
+ return n * count_type_elements (TREE_TYPE (type), false);
+ }
+ return for_ctor_p ? -1 : 1;
+ }
+
+ case RECORD_TYPE:
+ {
+ unsigned HOST_WIDE_INT n;
+ tree f;
+
+ n = 0;
+ for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL)
+ {
+ if (!for_ctor_p)
+ n += count_type_elements (TREE_TYPE (f), false);
+ else if (!flexible_array_member_p (f, type))
+ /* Don't count flexible arrays, which are not supposed
+ to be initialized. */
+ n += 1;
+ }
+
+ return n;
+ }
+
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ {
+ tree f;
+ HOST_WIDE_INT n, m;
+
+ gcc_assert (!for_ctor_p);
+ /* Estimate the number of scalars in each field and pick the
+ maximum. Other estimates would do instead; the idea is simply
+ to make sure that the estimate is not sensitive to the ordering
+ of the fields. */
+ n = 1;
+ for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
+ if (TREE_CODE (f) == FIELD_DECL)
+ {
+ m = count_type_elements (TREE_TYPE (f), false);
+ /* If the field doesn't span the whole union, add an extra
+ scalar for the rest. */
+ if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (f)),
+ TYPE_SIZE (type)) != 1)
+ m++;
+ if (n < m)
+ n = m;
+ }
+ return n;
+ }
+
+ case COMPLEX_TYPE:
+ return 2;
+
+ case VECTOR_TYPE:
+ return TYPE_VECTOR_SUBPARTS (type);
+
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case FIXED_POINT_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case POINTER_TYPE:
+ case OFFSET_TYPE:
+ case REFERENCE_TYPE:
+ return 1;
+
+ case ERROR_MARK:
+ return 0;
+
+ case VOID_TYPE:
+ case METHOD_TYPE:
+ case FUNCTION_TYPE:
+ case LANG_TYPE:
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Helper for categorize_ctor_elements. Identical interface. */
static bool
categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
- HOST_WIDE_INT *p_elt_count,
- bool *p_must_clear)
+ HOST_WIDE_INT *p_init_elts, bool *p_complete)
{
unsigned HOST_WIDE_INT idx;
- HOST_WIDE_INT nz_elts, elt_count;
- tree value, purpose;
+ HOST_WIDE_INT nz_elts, init_elts, num_fields;
+ tree value, purpose, elt_type;
/* Whether CTOR is a valid constant initializer, in accordance with what
initializer_constant_valid_p does. If inferred from the constructor
@@ -4884,7 +5004,9 @@
bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor);
nz_elts = 0;
- elt_count = 0;
+ init_elts = 0;
+ num_fields = 0;
+ elt_type = NULL_TREE;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
{
@@ -4899,6 +5021,8 @@
mult = (tree_low_cst (hi_index, 1)
- tree_low_cst (lo_index, 1) + 1);
}
+ num_fields += mult;
+ elt_type = TREE_TYPE (value);
switch (TREE_CODE (value))
{
@@ -4906,11 +5030,11 @@
{
HOST_WIDE_INT nz = 0, ic = 0;
- bool const_elt_p
- = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear);
+ bool const_elt_p = categorize_ctor_elements_1 (value, &nz, &ic,
+ p_complete);
nz_elts += mult * nz;
- elt_count += mult * ic;
+ init_elts += mult * ic;
if (const_from_elts_p && const_p)
const_p = const_elt_p;
@@ -4922,12 +5046,12 @@
case FIXED_CST:
if (!initializer_zerop (value))
nz_elts += mult;
- elt_count += mult;
+ init_elts += mult;
break;
case STRING_CST:
nz_elts += mult * TREE_STRING_LENGTH (value);
- elt_count += mult * TREE_STRING_LENGTH (value);
+ init_elts += mult * TREE_STRING_LENGTH (value);
break;
case COMPLEX_CST:
@@ -4935,7 +5059,7 @@
nz_elts += mult;
if (!initializer_zerop (TREE_IMAGPART (value)))
nz_elts += mult;
- elt_count += mult;
+ init_elts += mult;
break;
case VECTOR_CST:
@@ -4945,65 +5069,31 @@
{
if (!initializer_zerop (TREE_VALUE (v)))
nz_elts += mult;
- elt_count += mult;
+ init_elts += mult;
}
}
break;
default:
{
- HOST_WIDE_INT tc = count_type_elements (TREE_TYPE (value), true);
- if (tc < 1)
- tc = 1;
+ HOST_WIDE_INT tc = count_type_elements (elt_type, false);
nz_elts += mult * tc;
- elt_count += mult * tc;
+ init_elts += mult * tc;
if (const_from_elts_p && const_p)
- const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
+ const_p = initializer_constant_valid_p (value, elt_type)
!= NULL_TREE;
}
break;
}
}
- if (!*p_must_clear
- && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
- || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE))
- {
- tree init_sub_type;
- bool clear_this = true;
-
- if (!VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)))
- {
- /* We don't expect more than one element of the union to be
- initialized. Not sure what we should do otherwise... */
- gcc_assert (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor))
- == 1);
-
- init_sub_type = TREE_TYPE (VEC_index (constructor_elt,
- CONSTRUCTOR_ELTS (ctor),
- 0)->value);
-
- /* ??? We could look at each element of the union, and find the
- largest element. Which would avoid comparing the size of the
- initialized element against any tail padding in the union.
- Doesn't seem worth the effort... */
- if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)),
- TYPE_SIZE (init_sub_type)) == 1)
- {
- /* And now we have to find out if the element itself is fully
- constructed. E.g. for union { struct { int a, b; } s; } u
- = { .s = { .a = 1 } }. */
- if (elt_count == count_type_elements (init_sub_type, false))
- clear_this = false;
- }
- }
-
- *p_must_clear = clear_this;
- }
+ if (*p_complete && !complete_ctor_at_level_p (TREE_TYPE (ctor),
+ num_fields, elt_type))
+ *p_complete = false;
*p_nz_elts += nz_elts;
- *p_elt_count += elt_count;
+ *p_init_elts += init_elts;
return const_p;
}
@@ -5013,111 +5103,50 @@
and place it in *P_NZ_ELTS;
* how many scalar fields in total are in CTOR,
and place it in *P_ELT_COUNT.
- * if a type is a union, and the initializer from the constructor
- is not the largest element in the union, then set *p_must_clear.
+ * whether the constructor is complete -- in the sense that every
+ meaningful byte is explicitly given a value --
+ and place it in *P_COMPLETE.
Return whether or not CTOR is a valid static constant initializer, the same
as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0". */
bool
categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
- HOST_WIDE_INT *p_elt_count,
- bool *p_must_clear)
+ HOST_WIDE_INT *p_init_elts, bool *p_complete)
{
*p_nz_elts = 0;
- *p_elt_count = 0;
- *p_must_clear = false;
+ *p_init_elts = 0;
+ *p_complete = true;
- return
- categorize_ctor_elements_1 (ctor, p_nz_elts, p_elt_count, p_must_clear);
+ return categorize_ctor_elements_1 (ctor, p_nz_elts, p_init_elts, p_complete);
}
-/* Count the number of scalars in TYPE. Return -1 on overflow or
- variable-sized. If ALLOW_FLEXARR is true, don't count flexible
- array member at the end of the structure. */
+/* TYPE is initialized by a constructor with NUM_ELTS elements, the last
+ of which had type LAST_TYPE. Each element was itself a complete
+ initializer, in the sense that every meaningful byte was explicitly
+ given a value. Return true if the same is true for the constructor
+ as a whole. */
-HOST_WIDE_INT
-count_type_elements (const_tree type, bool allow_flexarr)
+bool
+complete_ctor_at_level_p (const_tree type, HOST_WIDE_INT num_elts,
+ const_tree last_type)
{
- const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
- switch (TREE_CODE (type))
+ if (TREE_CODE (type) == UNION_TYPE
+ || TREE_CODE (type) == QUAL_UNION_TYPE)
{
- case ARRAY_TYPE:
- {
- tree telts = array_type_nelts (type);
- if (telts && host_integerp (telts, 1))
- {
- HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1;
- HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type), false);
- if (n == 0)
- return 0;
- else if (max / n > m)
- return n * m;
- }
- return -1;
- }
-
- case RECORD_TYPE:
- {
- HOST_WIDE_INT n = 0, t;
- tree f;
-
- for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
- if (TREE_CODE (f) == FIELD_DECL)
- {
- t = count_type_elements (TREE_TYPE (f), false);
- if (t < 0)
- {
- /* Check for structures with flexible array member. */
- tree tf = TREE_TYPE (f);
- if (allow_flexarr
- && DECL_CHAIN (f) == NULL
- && TREE_CODE (tf) == ARRAY_TYPE
- && TYPE_DOMAIN (tf)
- && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
- && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf)))
- && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf))
- && int_size_in_bytes (type) >= 0)
- break;
-
- return -1;
- }
- n += t;
- }
-
- return n;
- }
-
- case UNION_TYPE:
- case QUAL_UNION_TYPE:
- return -1;
-
- case COMPLEX_TYPE:
- return 2;
-
- case VECTOR_TYPE:
- return TYPE_VECTOR_SUBPARTS (type);
-
- case INTEGER_TYPE:
- case REAL_TYPE:
- case FIXED_POINT_TYPE:
- case ENUMERAL_TYPE:
- case BOOLEAN_TYPE:
- case POINTER_TYPE:
- case OFFSET_TYPE:
- case REFERENCE_TYPE:
- return 1;
-
- case ERROR_MARK:
- return 0;
-
- case VOID_TYPE:
- case METHOD_TYPE:
- case FUNCTION_TYPE:
- case LANG_TYPE:
- default:
- gcc_unreachable ();
+ if (num_elts == 0)
+ return false;
+
+ gcc_assert (num_elts == 1 && last_type);
+
+ /* ??? We could look at each element of the union, and find the
+ largest element. Which would avoid comparing the size of the
+ initialized element against any tail padding in the union.
+ Doesn't seem worth the effort... */
+ return simple_cst_equal (TYPE_SIZE (type), TYPE_SIZE (last_type)) == 1;
}
+
+ return count_type_elements (type, true) == num_elts;
}
/* Return 1 if EXP contains mostly (3/4) zeros. */
@@ -5126,18 +5155,12 @@
mostly_zeros_p (const_tree exp)
{
if (TREE_CODE (exp) == CONSTRUCTOR)
-
{
- HOST_WIDE_INT nz_elts, count, elts;
- bool must_clear;
-
- categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
- if (must_clear)
- return 1;
-
- elts = count_type_elements (TREE_TYPE (exp), false);
-
- return nz_elts < elts / 4;
+ HOST_WIDE_INT nz_elts, init_elts;
+ bool complete_p;
+
+ categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
+ return !complete_p || nz_elts < init_elts / 4;
}
return initializer_zerop (exp);
@@ -5149,12 +5172,11 @@
all_zeros_p (const_tree exp)
{
if (TREE_CODE (exp) == CONSTRUCTOR)
-
{
- HOST_WIDE_INT nz_elts, count;
- bool must_clear;
+ HOST_WIDE_INT nz_elts, init_elts;
+ bool complete_p;
- categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
+ categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
return nz_elts == 0;
}
=== modified file 'gcc/gimplify.c'
--- old/gcc/gimplify.c 2011-05-26 10:27:57 +0000
+++ new/gcc/gimplify.c 2011-07-13 13:17:31 +0000
@@ -3693,9 +3693,8 @@
case ARRAY_TYPE:
{
struct gimplify_init_ctor_preeval_data preeval_data;
- HOST_WIDE_INT num_type_elements, num_ctor_elements;
- HOST_WIDE_INT num_nonzero_elements;
- bool cleared, valid_const_initializer;
+ HOST_WIDE_INT num_ctor_elements, num_nonzero_elements;
+ bool cleared, complete_p, valid_const_initializer;
/* Aggregate types must lower constructors to initialization of
individual elements. The exception is that a CONSTRUCTOR node
@@ -3712,7 +3711,7 @@
can only do so if it known to be a valid constant initializer. */
valid_const_initializer
= categorize_ctor_elements (ctor, &num_nonzero_elements,
- &num_ctor_elements, &cleared);
+ &num_ctor_elements, &complete_p);
/* If a const aggregate variable is being initialized, then it
should never be a lose to promote the variable to be static. */
@@ -3750,26 +3749,29 @@
parts in, then generate code for the non-constant parts. */
/* TODO. There's code in cp/typeck.c to do this. */
- num_type_elements = count_type_elements (type, true);
+ if (int_size_in_bytes (TREE_TYPE (ctor)) < 0)
+ /* store_constructor will ignore the clearing of variable-sized
+ objects. Initializers for such objects must explicitly set
+ every field that needs to be set. */
+ cleared = false;
+ else if (!complete_p)
+ /* If the constructor isn't complete, clear the whole object
+ beforehand.
- /* If count_type_elements could not determine number of type elements
- for a constant-sized object, assume clearing is needed.
- Don't do this for variable-sized objects, as store_constructor
- will ignore the clearing of variable-sized objects. */
- if (num_type_elements < 0 && int_size_in_bytes (type) >= 0)
+ ??? This ought not to be needed. For any element not present
+ in the initializer, we should simply set them to zero. Except
+ we'd need to *find* the elements that are not present, and that
+ requires trickery to avoid quadratic compile-time behavior in
+ large cases or excessive memory use in small cases. */
cleared = true;
- /* If there are "lots" of zeros, then block clear the object first. */
- else if (num_type_elements - num_nonzero_elements
+ else if (num_ctor_elements - num_nonzero_elements
> CLEAR_RATIO (optimize_function_for_speed_p (cfun))
- && num_nonzero_elements < num_type_elements/4)
- cleared = true;
- /* ??? This bit ought not be needed. For any element not present
- in the initializer, we should simply set them to zero. Except
- we'd need to *find* the elements that are not present, and that
- requires trickery to avoid quadratic compile-time behavior in
- large cases or excessive memory use in small cases. */
- else if (num_ctor_elements < num_type_elements)
- cleared = true;
+ && num_nonzero_elements < num_ctor_elements / 4)
+ /* If there are "lots" of zeros, it's more efficient to clear
+ the memory and then set the nonzero elements. */
+ cleared = true;
+ else
+ cleared = false;
/* If there are "lots" of initialized elements, and all of them
are valid address constants, then the entire initializer can
=== added file 'gcc/testsuite/gcc.target/arm/pr48183.c'
--- old/gcc/testsuite/gcc.target/arm/pr48183.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/pr48183.c 2011-07-13 13:17:31 +0000
@@ -0,0 +1,25 @@
+/* testsuite/gcc.target/arm/pr48183.c */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O -g" } */
+/* { dg-add-options arm_neon } */
+
+#include <arm_neon.h>
+
+void move_16bit_to_32bit (int32_t *dst, const short *src, unsigned n)
+{
+ unsigned i;
+ int16x4x2_t input;
+ int32x4x2_t mid;
+ int32x4x2_t output;
+
+ for (i = 0; i < n/2; i += 8) {
+ input = vld2_s16(src + i);
+ mid.val[0] = vmovl_s16(input.val[0]);
+ mid.val[1] = vmovl_s16(input.val[1]);
+ output.val[0] = vshlq_n_s32(mid.val[0], 8);
+ output.val[1] = vshlq_n_s32(mid.val[1], 8);
+ vst2q_s32((int32_t *)dst + i, output);
+ }
+}
=== modified file 'gcc/tree.h'
--- old/gcc/tree.h 2011-07-01 09:19:21 +0000
+++ new/gcc/tree.h 2011-07-13 13:17:31 +0000
@@ -4627,21 +4627,10 @@
extern VEC(tree,gc) *ctor_to_vec (tree);
-/* Examine CTOR to discover:
- * how many scalar fields are set to nonzero values,
- and place it in *P_NZ_ELTS;
- * how many scalar fields in total are in CTOR,
- and place it in *P_ELT_COUNT.
- * if a type is a union, and the initializer from the constructor
- is not the largest element in the union, then set *p_must_clear.
-
- Return whether or not CTOR is a valid static constant initializer, the same
- as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0". */
-
-extern bool categorize_ctor_elements (const_tree, HOST_WIDE_INT *, HOST_WIDE_INT *,
- bool *);
-
-extern HOST_WIDE_INT count_type_elements (const_tree, bool);
+extern bool categorize_ctor_elements (const_tree, HOST_WIDE_INT *,
+ HOST_WIDE_INT *, bool *);
+
+extern bool complete_ctor_at_level_p (const_tree, HOST_WIDE_INT, const_tree);
/* integer_zerop (tree x) is nonzero if X is an integer constant of value 0. */
@@ -0,0 +1,27 @@
2011-07-21 Richard Sandiford <rdsandiford@googlemail.com>
gcc/
Backport from mainline:
2011-07-21 Richard Sandiford <richard.sandiford@linaro.org>
* regcprop.c (maybe_mode_change): Check HARD_REGNO_MODE_OK.
=== modified file 'gcc/regcprop.c'
--- old/gcc/regcprop.c 2010-12-17 22:51:25 +0000
+++ new/gcc/regcprop.c 2011-07-21 11:30:53 +0000
@@ -418,10 +418,9 @@
offset = ((WORDS_BIG_ENDIAN ? wordoffset : 0)
+ (BYTES_BIG_ENDIAN ? byteoffset : 0));
- return gen_rtx_raw_REG (new_mode,
- regno + subreg_regno_offset (regno, orig_mode,
- offset,
- new_mode));
+ regno += subreg_regno_offset (regno, orig_mode, offset, new_mode);
+ if (HARD_REGNO_MODE_OK (regno, new_mode))
+ return gen_rtx_raw_REG (new_mode, regno);
}
return NULL_RTX;
}
@@ -0,0 +1,62 @@
2011-07-31 Revital Eres <revital.eres@linaro.org>
gcc/
Backport from trunk -r176970:
* modulo-sched.c: Change comment.
(reset_sched_times): Fix print message.
(print_partial_schedule): Add print info.
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-07-04 12:01:34 +0000
+++ new/gcc/modulo-sched.c 2011-07-31 10:58:46 +0000
@@ -84,13 +84,14 @@
II cycles (i.e. use register copies to prevent a def from overwriting
itself before reaching the use).
- SMS works with countable loops whose loop count can be easily
- adjusted. This is because we peel a constant number of iterations
- into a prologue and epilogue for which we want to avoid emitting
- the control part, and a kernel which is to iterate that constant
- number of iterations less than the original loop. So the control
- part should be a set of insns clearly identified and having its
- own iv, not otherwise used in the loop (at-least for now), which
+ SMS works with countable loops (1) whose control part can be easily
+ decoupled from the rest of the loop and (2) whose loop count can
+ be easily adjusted. This is because we peel a constant number of
+ iterations into a prologue and epilogue for which we want to avoid
+ emitting the control part, and a kernel which is to iterate that
+ constant number of iterations less than the original loop. So the
+ control part should be a set of insns clearly identified and having
+ its own iv, not otherwise used in the loop (at-least for now), which
initializes a register before the loop to the number of iterations.
Currently SMS relies on the do-loop pattern to recognize such loops,
where (1) the control part comprises of all insns defining and/or
@@ -598,8 +599,8 @@
/* Print the scheduling times after the rotation. */
fprintf (dump_file, "crr_insn->node=%d (insn id %d), "
"crr_insn->cycle=%d, min_cycle=%d", crr_insn->node->cuid,
- INSN_UID (crr_insn->node->insn), SCHED_TIME (u),
- normalized_time);
+ INSN_UID (crr_insn->node->insn), normalized_time,
+ new_min_cycle);
if (JUMP_P (crr_insn->node->insn))
fprintf (dump_file, " (branch)");
fprintf (dump_file, "\n");
@@ -2550,8 +2551,13 @@
fprintf (dump, "\n[ROW %d ]: ", i);
while (ps_i)
{
- fprintf (dump, "%d, ",
- INSN_UID (ps_i->node->insn));
+ if (JUMP_P (ps_i->node->insn))
+ fprintf (dump, "%d (branch), ",
+ INSN_UID (ps_i->node->insn));
+ else
+ fprintf (dump, "%d, ",
+ INSN_UID (ps_i->node->insn));
+
ps_i = ps_i->next_in_row;
}
}
@@ -0,0 +1,458 @@
2011-08-09 Revital Eres <revital.eres@linaro.org>
gcc/
Backport from trunk -r177235.
* modulo-sched.c (calculate_stage_count,
calculate_must_precede_follow, get_sched_window,
try_scheduling_node_in_cycle, remove_node_from_ps):
Add declaration.
(update_node_sched_params, set_must_precede_follow, optimize_sc):
New functions.
(reset_sched_times): Call update_node_sched_params.
(sms_schedule): Call optimize_sc.
(get_sched_window): Change function arguments.
(sms_schedule_by_order): Update call to get_sched_window.
Call set_must_precede_follow.
(calculate_stage_count): Add function argument.
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-07-31 10:58:46 +0000
+++ new/gcc/modulo-sched.c 2011-08-09 04:51:48 +0000
@@ -203,7 +203,16 @@
rtx, rtx);
static void duplicate_insns_of_cycles (partial_schedule_ptr,
int, int, int, rtx);
-static int calculate_stage_count (partial_schedule_ptr ps);
+static int calculate_stage_count (partial_schedule_ptr, int);
+static void calculate_must_precede_follow (ddg_node_ptr, int, int,
+ int, int, sbitmap, sbitmap, sbitmap);
+static int get_sched_window (partial_schedule_ptr, ddg_node_ptr,
+ sbitmap, int, int *, int *, int *);
+static bool try_scheduling_node_in_cycle (partial_schedule_ptr, ddg_node_ptr,
+ int, int, sbitmap, int *, sbitmap,
+ sbitmap);
+static bool remove_node_from_ps (partial_schedule_ptr, ps_insn_ptr);
+
#define SCHED_ASAP(x) (((node_sched_params_ptr)(x)->aux.info)->asap)
#define SCHED_TIME(x) (((node_sched_params_ptr)(x)->aux.info)->time)
#define SCHED_FIRST_REG_MOVE(x) \
@@ -577,6 +586,36 @@
}
}
+/* Update the sched_params (time, row and stage) for node U using the II,
+ the CYCLE of U and MIN_CYCLE.
+ We're not simply taking the following
+ SCHED_STAGE (u) = CALC_STAGE_COUNT (SCHED_TIME (u), min_cycle, ii);
+ because the stages may not be aligned on cycle 0. */
+static void
+update_node_sched_params (ddg_node_ptr u, int ii, int cycle, int min_cycle)
+{
+ int sc_until_cycle_zero;
+ int stage;
+
+ SCHED_TIME (u) = cycle;
+ SCHED_ROW (u) = SMODULO (cycle, ii);
+
+ /* The calculation of stage count is done adding the number
+ of stages before cycle zero and after cycle zero. */
+ sc_until_cycle_zero = CALC_STAGE_COUNT (-1, min_cycle, ii);
+
+ if (SCHED_TIME (u) < 0)
+ {
+ stage = CALC_STAGE_COUNT (-1, SCHED_TIME (u), ii);
+ SCHED_STAGE (u) = sc_until_cycle_zero - stage;
+ }
+ else
+ {
+ stage = CALC_STAGE_COUNT (SCHED_TIME (u), 0, ii);
+ SCHED_STAGE (u) = sc_until_cycle_zero + stage - 1;
+ }
+}
+
/* Bump the SCHED_TIMEs of all nodes by AMOUNT. Set the values of
SCHED_ROW and SCHED_STAGE. */
static void
@@ -592,7 +631,6 @@
ddg_node_ptr u = crr_insn->node;
int normalized_time = SCHED_TIME (u) - amount;
int new_min_cycle = PS_MIN_CYCLE (ps) - amount;
- int sc_until_cycle_zero, stage;
if (dump_file)
{
@@ -608,23 +646,9 @@
gcc_assert (SCHED_TIME (u) >= ps->min_cycle);
gcc_assert (SCHED_TIME (u) <= ps->max_cycle);
- SCHED_TIME (u) = normalized_time;
- SCHED_ROW (u) = SMODULO (normalized_time, ii);
-
- /* The calculation of stage count is done adding the number
- of stages before cycle zero and after cycle zero. */
- sc_until_cycle_zero = CALC_STAGE_COUNT (-1, new_min_cycle, ii);
-
- if (SCHED_TIME (u) < 0)
- {
- stage = CALC_STAGE_COUNT (-1, SCHED_TIME (u), ii);
- SCHED_STAGE (u) = sc_until_cycle_zero - stage;
- }
- else
- {
- stage = CALC_STAGE_COUNT (SCHED_TIME (u), 0, ii);
- SCHED_STAGE (u) = sc_until_cycle_zero + stage - 1;
- }
+
+ crr_insn->cycle = normalized_time;
+ update_node_sched_params (u, ii, normalized_time, new_min_cycle);
}
}
@@ -661,6 +685,206 @@
PREV_INSN (last));
}
+/* Set bitmaps TMP_FOLLOW and TMP_PRECEDE to MUST_FOLLOW and MUST_PRECEDE
+ respectively only if cycle C falls on the border of the scheduling
+ window boundaries marked by START and END cycles. STEP is the
+ direction of the window. */
+static inline void
+set_must_precede_follow (sbitmap *tmp_follow, sbitmap must_follow,
+ sbitmap *tmp_precede, sbitmap must_precede, int c,
+ int start, int end, int step)
+{
+ *tmp_precede = NULL;
+ *tmp_follow = NULL;
+
+ if (c == start)
+ {
+ if (step == 1)
+ *tmp_precede = must_precede;
+ else /* step == -1. */
+ *tmp_follow = must_follow;
+ }
+ if (c == end - step)
+ {
+ if (step == 1)
+ *tmp_follow = must_follow;
+ else /* step == -1. */
+ *tmp_precede = must_precede;
+ }
+
+}
+
+/* Return True if the branch can be moved to row ii-1 while
+ normalizing the partial schedule PS to start from cycle zero and thus
+ optimize the SC. Otherwise return False. */
+static bool
+optimize_sc (partial_schedule_ptr ps, ddg_ptr g)
+{
+ int amount = PS_MIN_CYCLE (ps);
+ sbitmap sched_nodes = sbitmap_alloc (g->num_nodes);
+ int start, end, step;
+ int ii = ps->ii;
+ bool ok = false;
+ int stage_count, stage_count_curr;
+
+ /* Compare the SC after normalization and SC after bringing the branch
+ to row ii-1. If they are equal just bail out. */
+ stage_count = calculate_stage_count (ps, amount);
+ stage_count_curr =
+ calculate_stage_count (ps, SCHED_TIME (g->closing_branch) - (ii - 1));
+
+ if (stage_count == stage_count_curr)
+ {
+ if (dump_file)
+ fprintf (dump_file, "SMS SC already optimized.\n");
+
+ ok = false;
+ goto clear;
+ }
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "SMS Trying to optimize branch location\n");
+ fprintf (dump_file, "SMS partial schedule before trial:\n");
+ print_partial_schedule (ps, dump_file);
+ }
+
+ /* First, normalize the partial scheduling. */
+ reset_sched_times (ps, amount);
+ rotate_partial_schedule (ps, amount);
+ if (dump_file)
+ {
+ fprintf (dump_file,
+ "SMS partial schedule after normalization (ii, %d, SC %d):\n",
+ ii, stage_count);
+ print_partial_schedule (ps, dump_file);
+ }
+
+ if (SMODULO (SCHED_TIME (g->closing_branch), ii) == ii - 1)
+ {
+ ok = true;
+ goto clear;
+ }
+
+ sbitmap_ones (sched_nodes);
+
+ /* Calculate the new placement of the branch. It should be in row
+ ii-1 and fall into it's scheduling window. */
+ if (get_sched_window (ps, g->closing_branch, sched_nodes, ii, &start,
+ &step, &end) == 0)
+ {
+ bool success;
+ ps_insn_ptr next_ps_i;
+ int branch_cycle = SCHED_TIME (g->closing_branch);
+ int row = SMODULO (branch_cycle, ps->ii);
+ int num_splits = 0;
+ sbitmap must_precede, must_follow, tmp_precede, tmp_follow;
+ int c;
+
+ if (dump_file)
+ fprintf (dump_file, "\nTrying to schedule node %d "
+ "INSN = %d in (%d .. %d) step %d\n",
+ g->closing_branch->cuid,
+ (INSN_UID (g->closing_branch->insn)), start, end, step);
+
+ gcc_assert ((step > 0 && start < end) || (step < 0 && start > end));
+ if (step == 1)
+ {
+ c = start + ii - SMODULO (start, ii) - 1;
+ gcc_assert (c >= start);
+ if (c >= end)
+ {
+ ok = false;
+ if (dump_file)
+ fprintf (dump_file,
+ "SMS failed to schedule branch at cycle: %d\n", c);
+ goto clear;
+ }
+ }
+ else
+ {
+ c = start - SMODULO (start, ii) - 1;
+ gcc_assert (c <= start);
+
+ if (c <= end)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "SMS failed to schedule branch at cycle: %d\n", c);
+ ok = false;
+ goto clear;
+ }
+ }
+
+ must_precede = sbitmap_alloc (g->num_nodes);
+ must_follow = sbitmap_alloc (g->num_nodes);
+
+ /* Try to schedule the branch is it's new cycle. */
+ calculate_must_precede_follow (g->closing_branch, start, end,
+ step, ii, sched_nodes,
+ must_precede, must_follow);
+
+ set_must_precede_follow (&tmp_follow, must_follow, &tmp_precede,
+ must_precede, c, start, end, step);
+
+ /* Find the element in the partial schedule related to the closing
+ branch so we can remove it from it's current cycle. */
+ for (next_ps_i = ps->rows[row];
+ next_ps_i; next_ps_i = next_ps_i->next_in_row)
+ if (next_ps_i->node->cuid == g->closing_branch->cuid)
+ break;
+
+ gcc_assert (next_ps_i);
+ gcc_assert (remove_node_from_ps (ps, next_ps_i));
+ success =
+ try_scheduling_node_in_cycle (ps, g->closing_branch,
+ g->closing_branch->cuid, c,
+ sched_nodes, &num_splits,
+ tmp_precede, tmp_follow);
+ gcc_assert (num_splits == 0);
+ if (!success)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "SMS failed to schedule branch at cycle: %d, "
+ "bringing it back to cycle %d\n", c, branch_cycle);
+
+ /* The branch was failed to be placed in row ii - 1.
+ Put it back in it's original place in the partial
+ schedualing. */
+ set_must_precede_follow (&tmp_follow, must_follow, &tmp_precede,
+ must_precede, branch_cycle, start, end,
+ step);
+ success =
+ try_scheduling_node_in_cycle (ps, g->closing_branch,
+ g->closing_branch->cuid,
+ branch_cycle, sched_nodes,
+ &num_splits, tmp_precede,
+ tmp_follow);
+ gcc_assert (success && (num_splits == 0));
+ ok = false;
+ }
+ else
+ {
+ /* The branch is placed in row ii - 1. */
+ if (dump_file)
+ fprintf (dump_file,
+ "SMS success in moving branch to cycle %d\n", c);
+
+ update_node_sched_params (g->closing_branch, ii, c,
+ PS_MIN_CYCLE (ps));
+ ok = true;
+ }
+
+ free (must_precede);
+ free (must_follow);
+ }
+
+clear:
+ free (sched_nodes);
+ return ok;
+}
+
static void
duplicate_insns_of_cycles (partial_schedule_ptr ps, int from_stage,
int to_stage, int for_prolog, rtx count_reg)
@@ -1116,6 +1340,7 @@
int mii, rec_mii;
unsigned stage_count = 0;
HOST_WIDEST_INT loop_count = 0;
+ bool opt_sc_p = false;
if (! (g = g_arr[loop->num]))
continue;
@@ -1197,14 +1422,32 @@
set_node_sched_params (g);
ps = sms_schedule_by_order (g, mii, maxii, node_order);
-
- if (ps)
- {
- stage_count = calculate_stage_count (ps);
- gcc_assert(stage_count >= 1);
- PS_STAGE_COUNT(ps) = stage_count;
- }
-
+
+ if (ps)
+ {
+ /* Try to achieve optimized SC by normalizing the partial
+ schedule (having the cycles start from cycle zero).
+ The branch location must be placed in row ii-1 in the
+ final scheduling. If failed, shift all instructions to
+ position the branch in row ii-1. */
+ opt_sc_p = optimize_sc (ps, g);
+ if (opt_sc_p)
+ stage_count = calculate_stage_count (ps, 0);
+ else
+ {
+ /* Bring the branch to cycle ii-1. */
+ int amount = SCHED_TIME (g->closing_branch) - (ps->ii - 1);
+
+ if (dump_file)
+ fprintf (dump_file, "SMS schedule branch at cycle ii-1\n");
+
+ stage_count = calculate_stage_count (ps, amount);
+ }
+
+ gcc_assert (stage_count >= 1);
+ PS_STAGE_COUNT (ps) = stage_count;
+ }
+
/* The default value of PARAM_SMS_MIN_SC is 2 as stage count of
1 means that there is no interleaving between iterations thus
we let the scheduling passes do the job in this case. */
@@ -1225,12 +1468,16 @@
else
{
struct undo_replace_buff_elem *reg_move_replaces;
- int amount = SCHED_TIME (g->closing_branch) + 1;
+
+ if (!opt_sc_p)
+ {
+ /* Rotate the partial schedule to have the branch in row ii-1. */
+ int amount = SCHED_TIME (g->closing_branch) - (ps->ii - 1);
+
+ reset_sched_times (ps, amount);
+ rotate_partial_schedule (ps, amount);
+ }
- /* Set the stage boundaries. The closing_branch was scheduled
- and should appear in the last (ii-1) row. */
- reset_sched_times (ps, amount);
- rotate_partial_schedule (ps, amount);
set_columns_for_ps (ps);
canon_loop (loop);
@@ -1382,13 +1629,11 @@
scheduling window is empty and zero otherwise. */
static int
-get_sched_window (partial_schedule_ptr ps, int *nodes_order, int i,
+get_sched_window (partial_schedule_ptr ps, ddg_node_ptr u_node,
sbitmap sched_nodes, int ii, int *start_p, int *step_p, int *end_p)
{
int start, step, end;
ddg_edge_ptr e;
- int u = nodes_order [i];
- ddg_node_ptr u_node = &ps->g->nodes[u];
sbitmap psp = sbitmap_alloc (ps->g->num_nodes);
sbitmap pss = sbitmap_alloc (ps->g->num_nodes);
sbitmap u_node_preds = NODE_PREDECESSORS (u_node);
@@ -1800,7 +2045,7 @@
/* Try to get non-empty scheduling window. */
success = 0;
- if (get_sched_window (ps, nodes_order, i, sched_nodes, ii, &start,
+ if (get_sched_window (ps, u_node, sched_nodes, ii, &start,
&step, &end) == 0)
{
if (dump_file)
@@ -1817,24 +2062,11 @@
for (c = start; c != end; c += step)
{
- sbitmap tmp_precede = NULL;
- sbitmap tmp_follow = NULL;
-
- if (c == start)
- {
- if (step == 1)
- tmp_precede = must_precede;
- else /* step == -1. */
- tmp_follow = must_follow;
- }
- if (c == end - step)
- {
- if (step == 1)
- tmp_follow = must_follow;
- else /* step == -1. */
- tmp_precede = must_precede;
- }
-
+ sbitmap tmp_precede, tmp_follow;
+
+ set_must_precede_follow (&tmp_follow, must_follow,
+ &tmp_precede, must_precede,
+ c, start, end, step);
success =
try_scheduling_node_in_cycle (ps, u_node, u, c,
sched_nodes,
@@ -2899,12 +3131,10 @@
}
/* Calculate the stage count of the partial schedule PS. The calculation
- takes into account the rotation to bring the closing branch to row
- ii-1. */
+ takes into account the rotation amount passed in ROTATION_AMOUNT. */
int
-calculate_stage_count (partial_schedule_ptr ps)
+calculate_stage_count (partial_schedule_ptr ps, int rotation_amount)
{
- int rotation_amount = (SCHED_TIME (ps->g->closing_branch)) + 1;
int new_min_cycle = PS_MIN_CYCLE (ps) - rotation_amount;
int new_max_cycle = PS_MAX_CYCLE (ps) - rotation_amount;
int stage_count = CALC_STAGE_COUNT (-1, new_min_cycle, ps->ii);
@@ -0,0 +1,39 @@
2011-08-09 Revital Eres <revital.eres@linaro.org>
gcc/
Backport from trunk -r176972:
* ddg.c (create_ddg_dep_from_intra_loop_link): Remove
the creation of anti-dep edge from a branch.
(add_cross_iteration_register_deps):
Create anti-dep edge from a branch.
=== modified file 'gcc/ddg.c'
--- old/gcc/ddg.c 2011-07-04 11:00:06 +0000
+++ new/gcc/ddg.c 2011-07-31 11:29:10 +0000
@@ -197,11 +197,6 @@
}
}
- /* If a true dep edge enters the branch create an anti edge in the
- opposite direction to prevent the creation of reg-moves. */
- if ((DEP_TYPE (link) == REG_DEP_TRUE) && JUMP_P (dest_node->insn))
- create_ddg_dep_no_link (g, dest_node, src_node, ANTI_DEP, REG_DEP, 1);
-
latency = dep_cost (link);
e = create_ddg_edge (src_node, dest_node, t, dt, latency, distance);
add_edge_to_ddg (g, e);
@@ -306,8 +301,11 @@
gcc_assert (first_def_node);
+ /* Always create the edge if the use node is a branch in
+ order to prevent the creation of reg-moves. */
if (DF_REF_ID (last_def) != DF_REF_ID (first_def)
- || !flag_modulo_sched_allow_regmoves)
+ || !flag_modulo_sched_allow_regmoves
+ || JUMP_P (use_node->insn))
create_ddg_dep_no_link (g, use_node, first_def_node, ANTI_DEP,
REG_DEP, 1);
@@ -0,0 +1,94 @@
2011-08-11 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
gcc/
Backport from mainline:
2011-07-28 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
* config/arm/vfp.md ("*movdf_vfp"): Handle the VFP constraints
before the core constraints. Adjust attributes.
(*thumb2_movdf_vfp"): Likewise.
=== modified file 'gcc/config/arm/vfp.md'
--- old/gcc/config/arm/vfp.md 2011-01-20 22:03:29 +0000
+++ new/gcc/config/arm/vfp.md 2011-07-27 12:59:19 +0000
@@ -401,8 +401,8 @@
;; DFmode moves
(define_insn "*movdf_vfp"
- [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,r, m,w ,Uv,w,r")
- (match_operand:DF 1 "soft_df_operand" " ?r,w,Dy,mF,r,UvF,w, w,r"))]
+ [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,w ,Uv,r, m,w,r")
+ (match_operand:DF 1 "soft_df_operand" " ?r,w,Dy,UvF,w ,mF,r,w,r"))]
"TARGET_ARM && TARGET_HARD_FLOAT && TARGET_VFP
&& ( register_operand (operands[0], DFmode)
|| register_operand (operands[1], DFmode))"
@@ -418,9 +418,9 @@
gcc_assert (TARGET_VFP_DOUBLE);
return \"fconstd%?\\t%P0, #%G1\";
case 3: case 4:
+ return output_move_vfp (operands);
+ case 5: case 6:
return output_move_double (operands);
- case 5: case 6:
- return output_move_vfp (operands);
case 7:
if (TARGET_VFP_SINGLE)
return \"fcpys%?\\t%0, %1\;fcpys%?\\t%p0, %p1\";
@@ -435,7 +435,7 @@
"
[(set_attr "type"
"r_2_f,f_2_r,fconstd,f_loadd,f_stored,load2,store2,ffarithd,*")
- (set (attr "length") (cond [(eq_attr "alternative" "3,4,8") (const_int 8)
+ (set (attr "length") (cond [(eq_attr "alternative" "5,6,8") (const_int 8)
(eq_attr "alternative" "7")
(if_then_else
(eq (symbol_ref "TARGET_VFP_SINGLE")
@@ -449,8 +449,8 @@
)
(define_insn "*thumb2_movdf_vfp"
- [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,r, m,w ,Uv,w,r")
- (match_operand:DF 1 "soft_df_operand" " ?r,w,Dy,mF,r,UvF,w, w,r"))]
+ [(set (match_operand:DF 0 "nonimmediate_soft_df_operand" "=w,?r,w ,w ,Uv,r ,m,w,r")
+ (match_operand:DF 1 "soft_df_operand" " ?r,w,Dy,UvF,w, mF,r, w,r"))]
"TARGET_THUMB2 && TARGET_HARD_FLOAT && TARGET_VFP"
"*
{
@@ -463,10 +463,10 @@
case 2:
gcc_assert (TARGET_VFP_DOUBLE);
return \"fconstd%?\\t%P0, #%G1\";
- case 3: case 4: case 8:
+ case 3: case 4:
+ return output_move_vfp (operands);
+ case 5: case 6: case 8:
return output_move_double (operands);
- case 5: case 6:
- return output_move_vfp (operands);
case 7:
if (TARGET_VFP_SINGLE)
return \"fcpys%?\\t%0, %1\;fcpys%?\\t%p0, %p1\";
@@ -478,8 +478,8 @@
}
"
[(set_attr "type"
- "r_2_f,f_2_r,fconstd,load2,store2,f_loadd,f_stored,ffarithd,*")
- (set (attr "length") (cond [(eq_attr "alternative" "3,4,8") (const_int 8)
+ "r_2_f,f_2_r,fconstd,f_loadd,f_stored,load2,store2,ffarithd,*")
+ (set (attr "length") (cond [(eq_attr "alternative" "5,6,8") (const_int 8)
(eq_attr "alternative" "7")
(if_then_else
(eq (symbol_ref "TARGET_VFP_SINGLE")
@@ -487,8 +487,8 @@
(const_int 8)
(const_int 4))]
(const_int 4)))
- (set_attr "pool_range" "*,*,*,4096,*,1020,*,*,*")
- (set_attr "neg_pool_range" "*,*,*,0,*,1008,*,*,*")]
+ (set_attr "pool_range" "*,*,*,1020,*,4096,*,*,*")
+ (set_attr "neg_pool_range" "*,*,*,1008,*,0,*,*,*")]
)
@@ -0,0 +1,30 @@
2011-08-15 Michael Hope <michael.hope@linaro.org>
Backport from mainline r177357
gcc/testsuite/
2011-08-04 Ian Bolton <ian.bolton@arm.com>
* gcc.target/arm/vfp-1.c: no large negative offsets on Thumb2.
=== modified file 'gcc/testsuite/gcc.target/arm/vfp-1.c'
--- old/gcc/testsuite/gcc.target/arm/vfp-1.c 2011-01-01 08:52:03 +0000
+++ new/gcc/testsuite/gcc.target/arm/vfp-1.c 2011-08-09 23:22:51 +0000
@@ -127,13 +127,13 @@
void test_ldst (float f[], double d[]) {
/* { dg-final { scan-assembler "flds.+ \\\[r0, #1020\\\]" } } */
- /* { dg-final { scan-assembler "flds.+ \\\[r0, #-1020\\\]" } } */
+ /* { dg-final { scan-assembler "flds.+ \\\[r\[0-9\], #-1020\\\]" { target { arm32 && { ! arm_thumb2_ok } } } } } */
/* { dg-final { scan-assembler "add.+ r0, #1024" } } */
- /* { dg-final { scan-assembler "fsts.+ \\\[r0, #0\\\]\n" } } */
+ /* { dg-final { scan-assembler "fsts.+ \\\[r\[0-9\], #0\\\]\n" } } */
f[256] = f[255] + f[-255];
/* { dg-final { scan-assembler "fldd.+ \\\[r1, #1016\\\]" } } */
- /* { dg-final { scan-assembler "fldd.+ \\\[r1, #-1016\\\]" } } */
+ /* { dg-final { scan-assembler "fldd.+ \\\[r\[1-9\], #-1016\\\]" { target { arm32 && { ! arm_thumb2_ok } } } } } */
/* { dg-final { scan-assembler "fstd.+ \\\[r1, #256\\\]" } } */
d[32] = d[127] + d[-127];
}
@@ -0,0 +1,33 @@
2011-08-15 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
* config/rs6000/rs6000.c (paired_expand_vector_init): Don't create
CONST_VECTORs with symbolic elements.
(rs6000_expand_vector_init): Likewise.
=== modified file 'gcc/config/rs6000/rs6000.c'
--- old/gcc/config/rs6000/rs6000.c 2011-07-27 18:17:15 +0000
+++ new/gcc/config/rs6000/rs6000.c 2011-08-16 08:59:36 +0000
@@ -5134,7 +5134,9 @@
for (i = 0; i < n_elts; ++i)
{
x = XVECEXP (vals, 0, i);
- if (!CONSTANT_P (x))
+ if (!(CONST_INT_P (x)
+ || GET_CODE (x) == CONST_DOUBLE
+ || GET_CODE (x) == CONST_FIXED))
++n_var;
}
if (n_var == 0)
@@ -5286,7 +5288,9 @@
for (i = 0; i < n_elts; ++i)
{
x = XVECEXP (vals, 0, i);
- if (!CONSTANT_P (x))
+ if (!(CONST_INT_P (x)
+ || GET_CODE (x) == CONST_DOUBLE
+ || GET_CODE (x) == CONST_FIXED))
++n_var, one_var = i;
else if (x != CONST0_RTX (inner_mode))
all_const_zero = false;
@@ -0,0 +1,61 @@
2011-08-18 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-08-12 Richard Sandiford <rdsandiford@googlemail.com>
* config/arm/arm.c (get_label_padding): New function.
(create_fix_barrier, arm_reorg): Use it.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-07-04 14:03:49 +0000
+++ new/gcc/config/arm/arm.c 2011-08-12 08:08:31 +0000
@@ -11769,6 +11769,19 @@
return 0;
}
+/* Return the maximum amount of padding that will be inserted before
+ label LABEL. */
+
+static HOST_WIDE_INT
+get_label_padding (rtx label)
+{
+ HOST_WIDE_INT align, min_insn_size;
+
+ align = 1 << label_to_alignment (label);
+ min_insn_size = TARGET_THUMB ? 2 : 4;
+ return align > min_insn_size ? align - min_insn_size : 0;
+}
+
/* Move a minipool fix MP from its current location to before MAX_MP.
If MAX_MP is NULL, then MP doesn't need moving, but the addressing
constraints may need updating. */
@@ -12315,8 +12328,12 @@
within range. */
gcc_assert (GET_CODE (from) != BARRIER);
- /* Count the length of this insn. */
- count += get_attr_length (from);
+ /* Count the length of this insn. This must stay in sync with the
+ code that pushes minipool fixes. */
+ if (LABEL_P (from))
+ count += get_label_padding (from);
+ else
+ count += get_attr_length (from);
/* If there is a jump table, add its length. */
tmp = is_jump_table (from);
@@ -12736,6 +12753,11 @@
insn = table;
}
}
+ else if (LABEL_P (insn))
+ /* Add the worst-case padding due to alignment. We don't add
+ the _current_ padding because the minipool insertions
+ themselves might change it. */
+ address += get_label_padding (insn);
}
fix = minipool_fix_head;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,23 @@
2011-08-26 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-08-26 Richard Sandiford <richard.sandiford@linaro.org>
* df-problems.c (df_note_bb_compute): Pass uses rather than defs
to df_set_dead_notes_for_mw.
=== modified file 'gcc/df-problems.c'
--- old/gcc/df-problems.c 2011-07-07 19:10:01 +0000
+++ new/gcc/df-problems.c 2011-08-26 14:32:47 +0000
@@ -3375,7 +3375,7 @@
while (*mws_rec)
{
struct df_mw_hardreg *mws = *mws_rec;
- if ((DF_MWS_REG_DEF_P (mws))
+ if (DF_MWS_REG_USE_P (mws)
&& !df_ignore_stack_reg (mws->start_regno))
{
bool really_add_notes = debug_insn != 0;
@@ -0,0 +1,23 @@
2011-09-05 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
gcc/
2011-08-12 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
PR target/48328
* config/arm/arm.h (CASE_VECTOR_SHORTEN_MODE): Fix distance
for tbh instructions.
=== modified file 'gcc/config/arm/arm.h'
--- old/gcc/config/arm/arm.h 2011-08-24 17:35:16 +0000
+++ new/gcc/config/arm/arm.h 2011-09-05 14:32:11 +0000
@@ -1961,7 +1961,7 @@
: min >= -4096 && max < 4096 \
? (ADDR_DIFF_VEC_FLAGS (body).offset_unsigned = 0, HImode) \
: SImode) \
- : ((min < 0 || max >= 0x2000 || !TARGET_THUMB2) ? SImode \
+ : ((min < 0 || max >= 0x20000 || !TARGET_THUMB2) ? SImode \
: (max >= 0x200) ? HImode \
: QImode))
@@ -0,0 +1,75 @@
2011-09-05 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline.
2011-08-26 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
* config/arm/cortex-a9.md ("cortex_a9_mult_long"): New.
("cortex_a9_multiply_long"): New and use above. Handle all
long multiply cases.
("cortex_a9_multiply"): Handle smmul and smmulr.
("cortex_a9_mac"): Handle smmla.
=== modified file 'gcc/config/arm/cortex-a9.md'
--- old/gcc/config/arm/cortex-a9.md 2011-01-18 15:28:08 +0000
+++ new/gcc/config/arm/cortex-a9.md 2011-08-26 08:52:15 +0000
@@ -68,7 +68,8 @@
"cortex_a9_mac_m1*2, cortex_a9_mac_m2, cortex_a9_p0_wb")
(define_reservation "cortex_a9_mac"
"cortex_a9_multcycle1*2 ,cortex_a9_mac_m2, cortex_a9_p0_wb")
-
+(define_reservation "cortex_a9_mult_long"
+ "cortex_a9_mac_m1*3, cortex_a9_mac_m2, cortex_a9_p0_wb")
;; Issue at the same time along the load store pipeline and
;; the VFP / Neon pipeline is not possible.
@@ -139,29 +140,35 @@
(eq_attr "insn" "smlaxy"))
"cortex_a9_mac16")
-
(define_insn_reservation "cortex_a9_multiply" 4
(and (eq_attr "tune" "cortexa9")
- (eq_attr "insn" "mul"))
+ (eq_attr "insn" "mul,smmul,smmulr"))
"cortex_a9_mult")
(define_insn_reservation "cortex_a9_mac" 4
(and (eq_attr "tune" "cortexa9")
- (eq_attr "insn" "mla"))
+ (eq_attr "insn" "mla,smmla"))
"cortex_a9_mac")
+(define_insn_reservation "cortex_a9_multiply_long" 5
+ (and (eq_attr "tune" "cortexa9")
+ (eq_attr "insn" "smull,umull,smulls,umulls,smlal,smlals,umlal,umlals"))
+ "cortex_a9_mult_long")
+
;; An instruction with a result in E2 can be forwarded
;; to E2 or E1 or M1 or the load store unit in the next cycle.
(define_bypass 1 "cortex_a9_dp"
"cortex_a9_dp_shift, cortex_a9_multiply,
cortex_a9_load1_2, cortex_a9_dp, cortex_a9_store1_2,
- cortex_a9_mult16, cortex_a9_mac16, cortex_a9_mac, cortex_a9_store3_4, cortex_a9_load3_4")
+ cortex_a9_mult16, cortex_a9_mac16, cortex_a9_mac, cortex_a9_store3_4, cortex_a9_load3_4,
+ cortex_a9_multiply_long")
(define_bypass 2 "cortex_a9_dp_shift"
"cortex_a9_dp_shift, cortex_a9_multiply,
cortex_a9_load1_2, cortex_a9_dp, cortex_a9_store1_2,
- cortex_a9_mult16, cortex_a9_mac16, cortex_a9_mac, cortex_a9_store3_4, cortex_a9_load3_4")
+ cortex_a9_mult16, cortex_a9_mac16, cortex_a9_mac, cortex_a9_store3_4, cortex_a9_load3_4,
+ cortex_a9_multiply_long")
;; An instruction in the load store pipeline can provide
;; read access to a DP instruction in the P0 default pipeline
@@ -212,7 +219,7 @@
(define_bypass 1
"cortex_a9_fps"
- "cortex_a9_fadd, cortex_a9_fps, cortex_a9_fcmp, cortex_a9_dp, cortex_a9_dp_shift, cortex_a9_multiply")
+ "cortex_a9_fadd, cortex_a9_fps, cortex_a9_fcmp, cortex_a9_dp, cortex_a9_dp_shift, cortex_a9_multiply, cortex_a9_multiply_long")
;; Scheduling on the FP_ADD pipeline.
(define_reservation "ca9fp_add" "ca9_issue_vfp_neon + ca9fp_add1, ca9fp_add2, ca9fp_add3, ca9fp_add4")
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,948 @@
2011-09-12 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF mainline:
2011-08-30 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm.c (optimal_immediate_sequence_1): Make b1, b2,
b3 and b4 unsigned.
2011-08-30 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm.c (arm_gen_constant): Set can_negate correctly
when code is SET.
2011-08-26 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm.c (struct four_ints): New type.
(count_insns_for_constant): Delete function.
(find_best_start): Delete function.
(optimal_immediate_sequence): New function.
(optimal_immediate_sequence_1): New function.
(arm_gen_constant): Move constant splitting code to
optimal_immediate_sequence.
Rewrite constant negation/invertion code.
gcc/testsuite/
* gcc.target/arm/thumb2-replicated-constant1.c: New file.
* gcc.target/arm/thumb2-replicated-constant2.c: New file.
* gcc.target/arm/thumb2-replicated-constant3.c: New file.
* gcc.target/arm/thumb2-replicated-constant4.c: New file.
2011-08-26 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm-protos.h (const_ok_for_op): Add prototype.
* config/arm/arm.c (const_ok_for_op): Add support for addw/subw.
Remove prototype. Remove static function type.
* config/arm/arm.md (*arm_addsi3): Add addw/subw support.
Add arch attribute.
* config/arm/constraints.md (Pj, PJ): New constraints.
2011-04-20 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm.c (arm_gen_constant): Move mowv support ....
(const_ok_for_op): ... to here.
2011-04-20 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm.c (arm_gen_constant): Remove redundant can_invert.
=== modified file 'gcc/config/arm/arm-protos.h'
--- old/gcc/config/arm/arm-protos.h 2011-07-04 14:03:49 +0000
+++ new/gcc/config/arm/arm-protos.h 2011-08-25 13:26:58 +0000
@@ -46,6 +46,7 @@
extern bool arm_small_register_classes_for_mode_p (enum machine_mode);
extern int arm_hard_regno_mode_ok (unsigned int, enum machine_mode);
extern int const_ok_for_arm (HOST_WIDE_INT);
+extern int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
extern int arm_split_constant (RTX_CODE, enum machine_mode, rtx,
HOST_WIDE_INT, rtx, rtx, int);
extern RTX_CODE arm_canonicalize_comparison (RTX_CODE, rtx *, rtx *);
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-08-24 17:35:16 +0000
+++ new/gcc/config/arm/arm.c 2011-09-06 12:57:56 +0000
@@ -63,6 +63,11 @@
void (*arm_lang_output_object_attributes_hook)(void);
+struct four_ints
+{
+ int i[4];
+};
+
/* Forward function declarations. */
static bool arm_needs_doubleword_align (enum machine_mode, const_tree);
static int arm_compute_static_chain_stack_bytes (void);
@@ -81,7 +86,6 @@
static bool arm_legitimate_address_p (enum machine_mode, rtx, bool);
static int thumb_far_jump_used_p (void);
static bool thumb_force_lr_save (void);
-static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
static rtx emit_sfm (int, int);
static unsigned arm_size_return_regs (void);
static bool arm_assemble_integer (rtx, unsigned int, int);
@@ -129,7 +133,13 @@
static int arm_comp_type_attributes (const_tree, const_tree);
static void arm_set_default_type_attributes (tree);
static int arm_adjust_cost (rtx, rtx, rtx, int);
-static int count_insns_for_constant (HOST_WIDE_INT, int);
+static int optimal_immediate_sequence (enum rtx_code code,
+ unsigned HOST_WIDE_INT val,
+ struct four_ints *return_sequence);
+static int optimal_immediate_sequence_1 (enum rtx_code code,
+ unsigned HOST_WIDE_INT val,
+ struct four_ints *return_sequence,
+ int i);
static int arm_get_strip_length (int);
static bool arm_function_ok_for_sibcall (tree, tree);
static enum machine_mode arm_promote_function_mode (const_tree,
@@ -2525,7 +2535,7 @@
}
/* Return true if I is a valid constant for the operation CODE. */
-static int
+int
const_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
{
if (const_ok_for_arm (i))
@@ -2533,7 +2543,21 @@
switch (code)
{
+ case SET:
+ /* See if we can use movw. */
+ if (arm_arch_thumb2 && (i & 0xffff0000) == 0)
+ return 1;
+ else
+ return 0;
+
case PLUS:
+ /* See if we can use addw or subw. */
+ if (TARGET_THUMB2
+ && ((i & 0xfffff000) == 0
+ || ((-i) & 0xfffff000) == 0))
+ return 1;
+ /* else fall through. */
+
case COMPARE:
case EQ:
case NE:
@@ -2649,68 +2673,41 @@
1);
}
-/* Return the number of instructions required to synthesize the given
- constant, if we start emitting them from bit-position I. */
-static int
-count_insns_for_constant (HOST_WIDE_INT remainder, int i)
-{
- HOST_WIDE_INT temp1;
- int step_size = TARGET_ARM ? 2 : 1;
- int num_insns = 0;
-
- gcc_assert (TARGET_ARM || i == 0);
-
- do
- {
- int end;
-
- if (i <= 0)
- i += 32;
- if (remainder & (((1 << step_size) - 1) << (i - step_size)))
- {
- end = i - 8;
- if (end < 0)
- end += 32;
- temp1 = remainder & ((0x0ff << end)
- | ((i < end) ? (0xff >> (32 - end)) : 0));
- remainder &= ~temp1;
- num_insns++;
- i -= 8 - step_size;
- }
- i -= step_size;
- } while (remainder);
- return num_insns;
-}
-
-static int
-find_best_start (unsigned HOST_WIDE_INT remainder)
+/* Return a sequence of integers, in RETURN_SEQUENCE that fit into
+ ARM/THUMB2 immediates, and add up to VAL.
+ Thr function return value gives the number of insns required. */
+static int
+optimal_immediate_sequence (enum rtx_code code, unsigned HOST_WIDE_INT val,
+ struct four_ints *return_sequence)
{
int best_consecutive_zeros = 0;
int i;
int best_start = 0;
+ int insns1, insns2;
+ struct four_ints tmp_sequence;
/* If we aren't targetting ARM, the best place to start is always at
- the bottom. */
- if (! TARGET_ARM)
- return 0;
-
- for (i = 0; i < 32; i += 2)
+ the bottom, otherwise look more closely. */
+ if (TARGET_ARM)
{
- int consecutive_zeros = 0;
-
- if (!(remainder & (3 << i)))
+ for (i = 0; i < 32; i += 2)
{
- while ((i < 32) && !(remainder & (3 << i)))
- {
- consecutive_zeros += 2;
- i += 2;
- }
- if (consecutive_zeros > best_consecutive_zeros)
- {
- best_consecutive_zeros = consecutive_zeros;
- best_start = i - consecutive_zeros;
- }
- i -= 2;
+ int consecutive_zeros = 0;
+
+ if (!(val & (3 << i)))
+ {
+ while ((i < 32) && !(val & (3 << i)))
+ {
+ consecutive_zeros += 2;
+ i += 2;
+ }
+ if (consecutive_zeros > best_consecutive_zeros)
+ {
+ best_consecutive_zeros = consecutive_zeros;
+ best_start = i - consecutive_zeros;
+ }
+ i -= 2;
+ }
}
}
@@ -2737,13 +2734,161 @@
the constant starting from `best_start', and also starting from
zero (i.e. with bit 31 first to be output). If `best_start' doesn't
yield a shorter sequence, we may as well use zero. */
+ insns1 = optimal_immediate_sequence_1 (code, val, return_sequence, best_start);
if (best_start != 0
- && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
- && (count_insns_for_constant (remainder, 0) <=
- count_insns_for_constant (remainder, best_start)))
- best_start = 0;
-
- return best_start;
+ && ((((unsigned HOST_WIDE_INT) 1) << best_start) < val))
+ {
+ insns2 = optimal_immediate_sequence_1 (code, val, &tmp_sequence, 0);
+ if (insns2 <= insns1)
+ {
+ *return_sequence = tmp_sequence;
+ insns1 = insns2;
+ }
+ }
+
+ return insns1;
+}
+
+/* As for optimal_immediate_sequence, but starting at bit-position I. */
+static int
+optimal_immediate_sequence_1 (enum rtx_code code, unsigned HOST_WIDE_INT val,
+ struct four_ints *return_sequence, int i)
+{
+ int remainder = val & 0xffffffff;
+ int insns = 0;
+
+ /* Try and find a way of doing the job in either two or three
+ instructions.
+
+ In ARM mode we can use 8-bit constants, rotated to any 2-bit aligned
+ location. We start at position I. This may be the MSB, or
+ optimial_immediate_sequence may have positioned it at the largest block
+ of zeros that are aligned on a 2-bit boundary. We then fill up the temps,
+ wrapping around to the top of the word when we drop off the bottom.
+ In the worst case this code should produce no more than four insns.
+
+ In Thumb2 mode, we can use 32/16-bit replicated constants, and 8-bit
+ constants, shifted to any arbitrary location. We should always start
+ at the MSB. */
+ do
+ {
+ int end;
+ unsigned int b1, b2, b3, b4;
+ unsigned HOST_WIDE_INT result;
+ int loc;
+
+ gcc_assert (insns < 4);
+
+ if (i <= 0)
+ i += 32;
+
+ /* First, find the next normal 12/8-bit shifted/rotated immediate. */
+ if (remainder & ((TARGET_ARM ? (3 << (i - 2)) : (1 << (i - 1)))))
+ {
+ loc = i;
+ if (i <= 12 && TARGET_THUMB2 && code == PLUS)
+ /* We can use addw/subw for the last 12 bits. */
+ result = remainder;
+ else
+ {
+ /* Use an 8-bit shifted/rotated immediate. */
+ end = i - 8;
+ if (end < 0)
+ end += 32;
+ result = remainder & ((0x0ff << end)
+ | ((i < end) ? (0xff >> (32 - end))
+ : 0));
+ i -= 8;
+ }
+ }
+ else
+ {
+ /* Arm allows rotates by a multiple of two. Thumb-2 allows
+ arbitrary shifts. */
+ i -= TARGET_ARM ? 2 : 1;
+ continue;
+ }
+
+ /* Next, see if we can do a better job with a thumb2 replicated
+ constant.
+
+ We do it this way around to catch the cases like 0x01F001E0 where
+ two 8-bit immediates would work, but a replicated constant would
+ make it worse.
+
+ TODO: 16-bit constants that don't clear all the bits, but still win.
+ TODO: Arithmetic splitting for set/add/sub, rather than bitwise. */
+ if (TARGET_THUMB2)
+ {
+ b1 = (remainder & 0xff000000) >> 24;
+ b2 = (remainder & 0x00ff0000) >> 16;
+ b3 = (remainder & 0x0000ff00) >> 8;
+ b4 = remainder & 0xff;
+
+ if (loc > 24)
+ {
+ /* The 8-bit immediate already found clears b1 (and maybe b2),
+ but must leave b3 and b4 alone. */
+
+ /* First try to find a 32-bit replicated constant that clears
+ almost everything. We can assume that we can't do it in one,
+ or else we wouldn't be here. */
+ unsigned int tmp = b1 & b2 & b3 & b4;
+ unsigned int tmp2 = tmp + (tmp << 8) + (tmp << 16)
+ + (tmp << 24);
+ unsigned int matching_bytes = (tmp == b1) + (tmp == b2)
+ + (tmp == b3) + (tmp == b4);
+ if (tmp
+ && (matching_bytes >= 3
+ || (matching_bytes == 2
+ && const_ok_for_op (remainder & ~tmp2, code))))
+ {
+ /* At least 3 of the bytes match, and the fourth has at
+ least as many bits set, or two of the bytes match
+ and it will only require one more insn to finish. */
+ result = tmp2;
+ i = tmp != b1 ? 32
+ : tmp != b2 ? 24
+ : tmp != b3 ? 16
+ : 8;
+ }
+
+ /* Second, try to find a 16-bit replicated constant that can
+ leave three of the bytes clear. If b2 or b4 is already
+ zero, then we can. If the 8-bit from above would not
+ clear b2 anyway, then we still win. */
+ else if (b1 == b3 && (!b2 || !b4
+ || (remainder & 0x00ff0000 & ~result)))
+ {
+ result = remainder & 0xff00ff00;
+ i = 24;
+ }
+ }
+ else if (loc > 16)
+ {
+ /* The 8-bit immediate already found clears b2 (and maybe b3)
+ and we don't get here unless b1 is alredy clear, but it will
+ leave b4 unchanged. */
+
+ /* If we can clear b2 and b4 at once, then we win, since the
+ 8-bits couldn't possibly reach that far. */
+ if (b2 == b4)
+ {
+ result = remainder & 0x00ff00ff;
+ i = 16;
+ }
+ }
+ }
+
+ return_sequence->i[insns++] = result;
+ remainder &= ~result;
+
+ if (code == SET || code == MINUS)
+ code = PLUS;
+ }
+ while (remainder);
+
+ return insns;
}
/* Emit an instruction with the indicated PATTERN. If COND is
@@ -2760,7 +2905,6 @@
/* As above, but extra parameter GENERATE which, if clear, suppresses
RTL generation. */
-/* ??? This needs more work for thumb2. */
static int
arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
@@ -2772,15 +2916,15 @@
int final_invert = 0;
int can_negate_initial = 0;
int i;
- int num_bits_set = 0;
int set_sign_bit_copies = 0;
int clear_sign_bit_copies = 0;
int clear_zero_bit_copies = 0;
int set_zero_bit_copies = 0;
- int insns = 0;
+ int insns = 0, neg_insns, inv_insns;
unsigned HOST_WIDE_INT temp1, temp2;
unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
- int step_size = TARGET_ARM ? 2 : 1;
+ struct four_ints *immediates;
+ struct four_ints pos_immediates, neg_immediates, inv_immediates;
/* Find out which operations are safe for a given CODE. Also do a quick
check for degenerate cases; these can occur when DImode operations
@@ -2789,7 +2933,6 @@
{
case SET:
can_invert = 1;
- can_negate = 1;
break;
case PLUS:
@@ -2817,9 +2960,6 @@
gen_rtx_SET (VOIDmode, target, source));
return 1;
}
-
- if (TARGET_THUMB2)
- can_invert = 1;
break;
case AND:
@@ -2861,6 +3001,7 @@
gen_rtx_NOT (mode, source)));
return 1;
}
+ final_invert = 1;
break;
case MINUS:
@@ -2883,7 +3024,6 @@
source)));
return 1;
}
- can_negate = 1;
break;
@@ -2892,9 +3032,7 @@
}
/* If we can do it in one insn get out quickly. */
- if (const_ok_for_arm (val)
- || (can_negate_initial && const_ok_for_arm (-val))
- || (can_invert && const_ok_for_arm (~val)))
+ if (const_ok_for_op (val, code))
{
if (generate)
emit_constant_insn (cond,
@@ -2947,15 +3085,6 @@
switch (code)
{
case SET:
- /* See if we can use movw. */
- if (arm_arch_thumb2 && (remainder & 0xffff0000) == 0)
- {
- if (generate)
- emit_constant_insn (cond, gen_rtx_SET (VOIDmode, target,
- GEN_INT (val)));
- return 1;
- }
-
/* See if we can do this by sign_extending a constant that is known
to be negative. This is a good, way of doing it, since the shift
may well merge into a subsequent insn. */
@@ -3306,121 +3435,97 @@
break;
}
- for (i = 0; i < 32; i++)
- if (remainder & (1 << i))
- num_bits_set++;
-
- if ((code == AND)
- || (code != IOR && can_invert && num_bits_set > 16))
- remainder ^= 0xffffffff;
- else if (code == PLUS && num_bits_set > 16)
- remainder = (-remainder) & 0xffffffff;
-
- /* For XOR, if more than half the bits are set and there's a sequence
- of more than 8 consecutive ones in the pattern then we can XOR by the
- inverted constant and then invert the final result; this may save an
- instruction and might also lead to the final mvn being merged with
- some other operation. */
- else if (code == XOR && num_bits_set > 16
- && (count_insns_for_constant (remainder ^ 0xffffffff,
- find_best_start
- (remainder ^ 0xffffffff))
- < count_insns_for_constant (remainder,
- find_best_start (remainder))))
- {
- remainder ^= 0xffffffff;
- final_invert = 1;
+ /* Calculate what the instruction sequences would be if we generated it
+ normally, negated, or inverted. */
+ if (code == AND)
+ /* AND cannot be split into multiple insns, so invert and use BIC. */
+ insns = 99;
+ else
+ insns = optimal_immediate_sequence (code, remainder, &pos_immediates);
+
+ if (can_negate)
+ neg_insns = optimal_immediate_sequence (code, (-remainder) & 0xffffffff,
+ &neg_immediates);
+ else
+ neg_insns = 99;
+
+ if (can_invert || final_invert)
+ inv_insns = optimal_immediate_sequence (code, remainder ^ 0xffffffff,
+ &inv_immediates);
+ else
+ inv_insns = 99;
+
+ immediates = &pos_immediates;
+
+ /* Is the negated immediate sequence more efficient? */
+ if (neg_insns < insns && neg_insns <= inv_insns)
+ {
+ insns = neg_insns;
+ immediates = &neg_immediates;
+ }
+ else
+ can_negate = 0;
+
+ /* Is the inverted immediate sequence more efficient?
+ We must allow for an extra NOT instruction for XOR operations, although
+ there is some chance that the final 'mvn' will get optimized later. */
+ if ((inv_insns + 1) < insns || (!final_invert && inv_insns < insns))
+ {
+ insns = inv_insns;
+ immediates = &inv_immediates;
}
else
{
can_invert = 0;
- can_negate = 0;
+ final_invert = 0;
}
- /* Now try and find a way of doing the job in either two or three
- instructions.
- We start by looking for the largest block of zeros that are aligned on
- a 2-bit boundary, we then fill up the temps, wrapping around to the
- top of the word when we drop off the bottom.
- In the worst case this code should produce no more than four insns.
- Thumb-2 constants are shifted, not rotated, so the MSB is always the
- best place to start. */
-
- /* ??? Use thumb2 replicated constants when the high and low halfwords are
- the same. */
- {
- /* Now start emitting the insns. */
- i = find_best_start (remainder);
- do
- {
- int end;
-
- if (i <= 0)
- i += 32;
- if (remainder & (3 << (i - 2)))
- {
- end = i - 8;
- if (end < 0)
- end += 32;
- temp1 = remainder & ((0x0ff << end)
- | ((i < end) ? (0xff >> (32 - end)) : 0));
- remainder &= ~temp1;
-
- if (generate)
- {
- rtx new_src, temp1_rtx;
-
- if (code == SET || code == MINUS)
- {
- new_src = (subtargets ? gen_reg_rtx (mode) : target);
- if (can_invert && code != MINUS)
- temp1 = ~temp1;
- }
- else
- {
- if ((final_invert || remainder) && subtargets)
- new_src = gen_reg_rtx (mode);
- else
- new_src = target;
- if (can_invert)
- temp1 = ~temp1;
- else if (can_negate)
- temp1 = -temp1;
- }
-
- temp1 = trunc_int_for_mode (temp1, mode);
- temp1_rtx = GEN_INT (temp1);
-
- if (code == SET)
- ;
- else if (code == MINUS)
- temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
- else
- temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
-
- emit_constant_insn (cond,
- gen_rtx_SET (VOIDmode, new_src,
- temp1_rtx));
- source = new_src;
- }
-
- if (code == SET)
- {
- can_invert = 0;
- code = PLUS;
- }
- else if (code == MINUS)
+ /* Now output the chosen sequence as instructions. */
+ if (generate)
+ {
+ for (i = 0; i < insns; i++)
+ {
+ rtx new_src, temp1_rtx;
+
+ temp1 = immediates->i[i];
+
+ if (code == SET || code == MINUS)
+ new_src = (subtargets ? gen_reg_rtx (mode) : target);
+ else if ((final_invert || i < (insns - 1)) && subtargets)
+ new_src = gen_reg_rtx (mode);
+ else
+ new_src = target;
+
+ if (can_invert)
+ temp1 = ~temp1;
+ else if (can_negate)
+ temp1 = -temp1;
+
+ temp1 = trunc_int_for_mode (temp1, mode);
+ temp1_rtx = GEN_INT (temp1);
+
+ if (code == SET)
+ ;
+ else if (code == MINUS)
+ temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
+ else
+ temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
+
+ emit_constant_insn (cond,
+ gen_rtx_SET (VOIDmode, new_src,
+ temp1_rtx));
+ source = new_src;
+
+ if (code == SET)
+ {
+ can_negate = can_invert;
+ can_invert = 0;
code = PLUS;
-
- insns++;
- i -= 8 - step_size;
- }
- /* Arm allows rotates by a multiple of two. Thumb-2 allows arbitrary
- shifts. */
- i -= step_size;
- }
- while (remainder);
- }
+ }
+ else if (code == MINUS)
+ code = PLUS;
+ }
+ }
if (final_invert)
{
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2011-08-25 11:42:09 +0000
+++ new/gcc/config/arm/arm.md 2011-08-25 13:26:58 +0000
@@ -701,21 +701,24 @@
;; (plus (reg rN) (reg sp)) into (reg rN). In this case reload will
;; put the duplicated register first, and not try the commutative version.
(define_insn_and_split "*arm_addsi3"
- [(set (match_operand:SI 0 "s_register_operand" "=r, k,r,r, k,r")
- (plus:SI (match_operand:SI 1 "s_register_operand" "%rk,k,r,rk,k,rk")
- (match_operand:SI 2 "reg_or_int_operand" "rI,rI,k,L, L,?n")))]
+ [(set (match_operand:SI 0 "s_register_operand" "=r, k,r,r, k, r, k,r, k, r")
+ (plus:SI (match_operand:SI 1 "s_register_operand" "%rk,k,r,rk,k, rk,k,rk,k, rk")
+ (match_operand:SI 2 "reg_or_int_operand" "rI,rI,k,Pj,Pj,L, L,PJ,PJ,?n")))]
"TARGET_32BIT"
"@
add%?\\t%0, %1, %2
add%?\\t%0, %1, %2
add%?\\t%0, %2, %1
- sub%?\\t%0, %1, #%n2
- sub%?\\t%0, %1, #%n2
+ addw%?\\t%0, %1, %2
+ addw%?\\t%0, %1, %2
+ sub%?\\t%0, %1, #%n2
+ sub%?\\t%0, %1, #%n2
+ subw%?\\t%0, %1, #%n2
+ subw%?\\t%0, %1, #%n2
#"
"TARGET_32BIT
&& GET_CODE (operands[2]) == CONST_INT
- && !(const_ok_for_arm (INTVAL (operands[2]))
- || const_ok_for_arm (-INTVAL (operands[2])))
+ && !const_ok_for_op (INTVAL (operands[2]), PLUS)
&& (reload_completed || !arm_eliminable_register (operands[1]))"
[(clobber (const_int 0))]
"
@@ -724,8 +727,9 @@
operands[1], 0);
DONE;
"
- [(set_attr "length" "4,4,4,4,4,16")
- (set_attr "predicable" "yes")]
+ [(set_attr "length" "4,4,4,4,4,4,4,4,4,16")
+ (set_attr "predicable" "yes")
+ (set_attr "arch" "*,*,*,t2,t2,*,*,t2,t2,*")]
)
(define_insn_and_split "*thumb1_addsi3"
=== modified file 'gcc/config/arm/constraints.md'
--- old/gcc/config/arm/constraints.md 2011-01-03 20:52:22 +0000
+++ new/gcc/config/arm/constraints.md 2011-08-25 13:26:58 +0000
@@ -31,7 +31,7 @@
;; The following multi-letter normal constraints have been used:
;; in ARM/Thumb-2 state: Da, Db, Dc, Dn, Dl, DL, Dv, Dy, Di, Dz
;; in Thumb-1 state: Pa, Pb, Pc, Pd
-;; in Thumb-2 state: Ps, Pt, Pu, Pv, Pw, Px
+;; in Thumb-2 state: Pj, PJ, Ps, Pt, Pu, Pv, Pw, Px
;; The following memory constraints have been used:
;; in ARM/Thumb-2 state: Q, Ut, Uv, Uy, Un, Um, Us
@@ -74,6 +74,18 @@
(and (match_code "const_int")
(match_test "(ival & 0xffff0000) == 0")))))
+(define_constraint "Pj"
+ "@internal A 12-bit constant suitable for an ADDW or SUBW instruction. (Thumb-2)"
+ (and (match_code "const_int")
+ (and (match_test "TARGET_THUMB2")
+ (match_test "(ival & 0xfffff000) == 0"))))
+
+(define_constraint "PJ"
+ "@internal A constant that satisfies the Pj constrant if negated."
+ (and (match_code "const_int")
+ (and (match_test "TARGET_THUMB2")
+ (match_test "((-ival) & 0xfffff000) == 0"))))
+
(define_register_constraint "k" "STACK_REG"
"@internal The stack register.")
=== added file 'gcc/testsuite/gcc.target/arm/thumb2-replicated-constant1.c'
--- old/gcc/testsuite/gcc.target/arm/thumb2-replicated-constant1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/thumb2-replicated-constant1.c 2011-08-25 13:31:00 +0000
@@ -0,0 +1,27 @@
+/* Ensure simple replicated constant immediates work. */
+/* { dg-options "-mthumb -O2" } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+
+int
+foo1 (int a)
+{
+ return a + 0xfefefefe;
+}
+
+/* { dg-final { scan-assembler "add.*#-16843010" } } */
+
+int
+foo2 (int a)
+{
+ return a - 0xab00ab00;
+}
+
+/* { dg-final { scan-assembler "sub.*#-1426019584" } } */
+
+int
+foo3 (int a)
+{
+ return a & 0x00cd00cd;
+}
+
+/* { dg-final { scan-assembler "and.*#13435085" } } */
=== added file 'gcc/testsuite/gcc.target/arm/thumb2-replicated-constant2.c'
--- old/gcc/testsuite/gcc.target/arm/thumb2-replicated-constant2.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/thumb2-replicated-constant2.c 2011-08-25 13:31:00 +0000
@@ -0,0 +1,75 @@
+/* Ensure split constants can use replicated patterns. */
+/* { dg-options "-mthumb -O2" } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+
+int
+foo1 (int a)
+{
+ return a + 0xfe00fe01;
+}
+
+/* { dg-final { scan-assembler "add.*#-33489408" } } */
+/* { dg-final { scan-assembler "add.*#1" } } */
+
+int
+foo2 (int a)
+{
+ return a + 0xdd01dd00;
+}
+
+/* { dg-final { scan-assembler "add.*#-587145984" } } */
+/* { dg-final { scan-assembler "add.*#65536" } } */
+
+int
+foo3 (int a)
+{
+ return a + 0x00443344;
+}
+
+/* { dg-final { scan-assembler "add.*#4456516" } } */
+/* { dg-final { scan-assembler "add.*#13056" } } */
+
+int
+foo4 (int a)
+{
+ return a + 0x77330033;
+}
+
+/* { dg-final { scan-assembler "add.*#1996488704" } } */
+/* { dg-final { scan-assembler "add.*#3342387" } } */
+
+int
+foo5 (int a)
+{
+ return a + 0x11221122;
+}
+
+/* { dg-final { scan-assembler "add.*#285217024" } } */
+/* { dg-final { scan-assembler "add.*#2228258" } } */
+
+int
+foo6 (int a)
+{
+ return a + 0x66666677;
+}
+
+/* { dg-final { scan-assembler "add.*#1717986918" } } */
+/* { dg-final { scan-assembler "add.*#17" } } */
+
+int
+foo7 (int a)
+{
+ return a + 0x99888888;
+}
+
+/* { dg-final { scan-assembler "add.*#-2004318072" } } */
+/* { dg-final { scan-assembler "add.*#285212672" } } */
+
+int
+foo8 (int a)
+{
+ return a + 0xdddddfff;
+}
+
+/* { dg-final { scan-assembler "add.*#-572662307" } } */
+/* { dg-final { scan-assembler "addw.*#546" } } */
=== added file 'gcc/testsuite/gcc.target/arm/thumb2-replicated-constant3.c'
--- old/gcc/testsuite/gcc.target/arm/thumb2-replicated-constant3.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/thumb2-replicated-constant3.c 2011-08-25 13:31:00 +0000
@@ -0,0 +1,28 @@
+/* Ensure negated/inverted replicated constant immediates work. */
+/* { dg-options "-mthumb -O2" } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+
+int
+foo1 (int a)
+{
+ return a | 0xffffff00;
+}
+
+/* { dg-final { scan-assembler "orn.*#255" } } */
+
+int
+foo2 (int a)
+{
+ return a & 0xffeeffee;
+}
+
+/* { dg-final { scan-assembler "bic.*#1114129" } } */
+
+int
+foo3 (int a)
+{
+ return a & 0xaaaaaa00;
+}
+
+/* { dg-final { scan-assembler "and.*#-1431655766" } } */
+/* { dg-final { scan-assembler "bic.*#170" } } */
=== added file 'gcc/testsuite/gcc.target/arm/thumb2-replicated-constant4.c'
--- old/gcc/testsuite/gcc.target/arm/thumb2-replicated-constant4.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/thumb2-replicated-constant4.c 2011-08-25 13:31:00 +0000
@@ -0,0 +1,22 @@
+/* Ensure replicated constants don't make things worse. */
+/* { dg-options "-mthumb -O2" } */
+/* { dg-require-effective-target arm_thumb2_ok } */
+
+int
+foo1 (int a)
+{
+ /* It might be tempting to use 0x01000100, but it wouldn't help. */
+ return a + 0x01f001e0;
+}
+
+/* { dg-final { scan-assembler "add.*#32505856" } } */
+/* { dg-final { scan-assembler "add.*#480" } } */
+
+int
+foo2 (int a)
+{
+ return a + 0x0f100e10;
+}
+
+/* { dg-final { scan-assembler "add.*#252706816" } } */
+/* { dg-final { scan-assembler "add.*#3600" } } */
@@ -0,0 +1,201 @@
2011-09-12 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
PR target/49030
* config/arm/arm-protos.h (maybe_get_arm_condition_code): Declare.
* config/arm/arm.c (maybe_get_arm_condition_code): New function,
reusing the old code from get_arm_condition_code. Return ARM_NV
for invalid comparison codes.
(get_arm_condition_code): Redefine in terms of
maybe_get_arm_condition_code.
* config/arm/predicates.md (arm_comparison_operator): Use
maybe_get_arm_condition_code.
gcc/testsuite/
PR target/49030
* gcc.dg/torture/pr49030.c: New test.
=== modified file 'gcc/config/arm/arm-protos.h'
--- old/gcc/config/arm/arm-protos.h 2011-08-25 13:26:58 +0000
+++ new/gcc/config/arm/arm-protos.h 2011-09-12 11:03:11 +0000
@@ -179,6 +179,7 @@
#endif
extern int thumb_shiftable_const (unsigned HOST_WIDE_INT);
#ifdef RTX_CODE
+extern enum arm_cond_code maybe_get_arm_condition_code (rtx);
extern void thumb1_final_prescan_insn (rtx);
extern void thumb2_final_prescan_insn (rtx);
extern const char *thumb_load_double_from_address (rtx *);
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-09-06 12:57:56 +0000
+++ new/gcc/config/arm/arm.c 2011-09-12 11:03:11 +0000
@@ -17494,10 +17494,10 @@
decremented/zeroed by arm_asm_output_opcode as the insns are output. */
/* Returns the index of the ARM condition code string in
- `arm_condition_codes'. COMPARISON should be an rtx like
- `(eq (...) (...))'. */
-static enum arm_cond_code
-get_arm_condition_code (rtx comparison)
+ `arm_condition_codes', or ARM_NV if the comparison is invalid.
+ COMPARISON should be an rtx like `(eq (...) (...))'. */
+enum arm_cond_code
+maybe_get_arm_condition_code (rtx comparison)
{
enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
enum arm_cond_code code;
@@ -17521,11 +17521,11 @@
case CC_DLTUmode: code = ARM_CC;
dominance:
- gcc_assert (comp_code == EQ || comp_code == NE);
-
if (comp_code == EQ)
return ARM_INVERSE_CONDITION_CODE (code);
- return code;
+ if (comp_code == NE)
+ return code;
+ return ARM_NV;
case CC_NOOVmode:
switch (comp_code)
@@ -17534,7 +17534,7 @@
case EQ: return ARM_EQ;
case GE: return ARM_PL;
case LT: return ARM_MI;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_Zmode:
@@ -17542,7 +17542,7 @@
{
case NE: return ARM_NE;
case EQ: return ARM_EQ;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_Nmode:
@@ -17550,7 +17550,7 @@
{
case NE: return ARM_MI;
case EQ: return ARM_PL;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CCFPEmode:
@@ -17575,7 +17575,7 @@
/* UNEQ and LTGT do not have a representation. */
case UNEQ: /* Fall through. */
case LTGT: /* Fall through. */
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_SWPmode:
@@ -17591,7 +17591,7 @@
case GTU: return ARM_CC;
case LEU: return ARM_CS;
case LTU: return ARM_HI;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_Cmode:
@@ -17599,7 +17599,7 @@
{
case LTU: return ARM_CS;
case GEU: return ARM_CC;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_CZmode:
@@ -17611,7 +17611,7 @@
case GTU: return ARM_HI;
case LEU: return ARM_LS;
case LTU: return ARM_CC;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_NCVmode:
@@ -17621,7 +17621,7 @@
case LT: return ARM_LT;
case GEU: return ARM_CS;
case LTU: return ARM_CC;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CCmode:
@@ -17637,13 +17637,22 @@
case GTU: return ARM_HI;
case LEU: return ARM_LS;
case LTU: return ARM_CC;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
default: gcc_unreachable ();
}
}
+/* Like maybe_get_arm_condition_code, but never return ARM_NV. */
+static enum arm_cond_code
+get_arm_condition_code (rtx comparison)
+{
+ enum arm_cond_code code = maybe_get_arm_condition_code (comparison);
+ gcc_assert (code != ARM_NV);
+ return code;
+}
+
/* Tell arm_asm_output_opcode to output IT blocks for conditionally executed
instructions. */
void
=== modified file 'gcc/config/arm/predicates.md'
--- old/gcc/config/arm/predicates.md 2011-08-13 08:40:36 +0000
+++ new/gcc/config/arm/predicates.md 2011-09-05 09:40:19 +0000
@@ -242,10 +242,9 @@
;; True for integer comparisons and, if FP is active, for comparisons
;; other than LTGT or UNEQ.
(define_special_predicate "arm_comparison_operator"
- (ior (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu")
- (and (match_test "TARGET_32BIT && TARGET_HARD_FLOAT
- && (TARGET_FPA || TARGET_VFP)")
- (match_code "unordered,ordered,unlt,unle,unge,ungt"))))
+ (and (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,
+ unordered,ordered,unlt,unle,unge,ungt")
+ (match_test "maybe_get_arm_condition_code (op) != ARM_NV")))
(define_special_predicate "lt_ge_comparison_operator"
(match_code "lt,ge"))
=== added file 'gcc/testsuite/gcc.dg/torture/pr49030.c'
--- old/gcc/testsuite/gcc.dg/torture/pr49030.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/torture/pr49030.c 2011-09-05 09:40:19 +0000
@@ -0,0 +1,19 @@
+void
+sample_move_d32u24_sS (char *dst, float *src, unsigned long nsamples,
+ unsigned long dst_skip)
+{
+ long long y;
+ while (nsamples--)
+ {
+ y = (long long) (*src * 8388608.0f) << 8;
+ if (y > 2147483647) {
+ *(int *) dst = 2147483647;
+ } else if (y < -2147483647 - 1) {
+ *(int *) dst = -2147483647 - 1;
+ } else {
+ *(int *) dst = (int) y;
+ }
+ dst += dst_skip;
+ src++;
+ }
+}
@@ -0,0 +1,38 @@
2011-09-01 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/predicates.md (shift_amount_operand): Ensure shift
amount is positive.
gcc/testsuite/
* gcc.dg/pr50193-1.c: New file.
=== modified file 'gcc/config/arm/predicates.md'
--- old/gcc/config/arm/predicates.md 2011-09-05 09:40:19 +0000
+++ new/gcc/config/arm/predicates.md 2011-09-12 11:24:34 +0000
@@ -132,7 +132,8 @@
(define_predicate "shift_amount_operand"
(ior (and (match_test "TARGET_ARM")
(match_operand 0 "s_register_operand"))
- (match_operand 0 "const_int_operand")))
+ (and (match_operand 0 "const_int_operand")
+ (match_test "INTVAL (op) > 0"))))
(define_predicate "arm_add_operand"
(ior (match_operand 0 "arm_rhs_operand")
=== added file 'gcc/testsuite/gcc.dg/pr50193-1.c'
--- old/gcc/testsuite/gcc.dg/pr50193-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/pr50193-1.c 2011-09-01 12:22:14 +0000
@@ -0,0 +1,10 @@
+/* PR 50193: ARM: ICE on a | (b << negative-constant) */
+/* Ensure that the compiler doesn't ICE. */
+
+/* { dg-options "-O2" } */
+
+int
+foo(int a, int b)
+{
+ return a | (b << -3); /* { dg-warning "left shift count is negative" } */
+}
@@ -0,0 +1,47 @@
2011-09-12 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF mainline:
2011-09-08 Andrew Stubbs <ams@codesourcery.com>
PR tree-optimization/50318
gcc/
* tree-ssa-math-opts.c (convert_plusminus_to_widen): Correct
typo in use of mult_rhs1 and mult_rhs2.
gcc/testsuite/
* gcc.target/arm/pr50318-1.c: New file.
=== added file 'gcc/testsuite/gcc.target/arm/pr50318-1.c'
--- old/gcc/testsuite/gcc.target/arm/pr50318-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/pr50318-1.c 2011-09-08 20:11:43 +0000
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target arm_dsp } */
+
+long long test (unsigned int sec, unsigned long long nsecs)
+{
+ return (long long)(long)sec * 1000000000L + (long long)(unsigned
+ long)nsecs;
+}
+
+/* { dg-final { scan-assembler "umlal" } } */
=== modified file 'gcc/tree-ssa-math-opts.c'
--- old/gcc/tree-ssa-math-opts.c 2011-08-09 10:26:48 +0000
+++ new/gcc/tree-ssa-math-opts.c 2011-09-08 20:11:43 +0000
@@ -1699,9 +1699,9 @@
/* Handle constants. */
if (TREE_CODE (mult_rhs1) == INTEGER_CST)
- rhs1 = fold_convert (type1, mult_rhs1);
+ mult_rhs1 = fold_convert (type1, mult_rhs1);
if (TREE_CODE (mult_rhs2) == INTEGER_CST)
- rhs2 = fold_convert (type2, mult_rhs2);
+ mult_rhs2 = fold_convert (type2, mult_rhs2);
gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, mult_rhs1, mult_rhs2,
add_rhs);
@@ -0,0 +1,92 @@
2011-09-12 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
gcc/testsuite/
* gcc.target/arm/pr50099.c: Fix testcase from previous commit.
2011-09-12 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
LP:838994
gcc/
Backport from mainline.
2011-09-06 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
PR target/50099
* config/arm/iterators.md (qhs_zextenddi_cstr): New.
(qhs_zextenddi_op): New.
* config/arm/arm.md ("zero_extend<mode>di2"): Use them.
* config/arm/predicates.md ("arm_extendqisi_mem_op"):
Distinguish between ARM and Thumb2 states.
gcc/testsuite/
* gcc.target/arm/pr50099.c: New test.
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2011-08-25 13:26:58 +0000
+++ new/gcc/config/arm/arm.md 2011-09-12 12:32:29 +0000
@@ -4136,8 +4136,8 @@
(define_insn "zero_extend<mode>di2"
[(set (match_operand:DI 0 "s_register_operand" "=r")
- (zero_extend:DI (match_operand:QHSI 1 "<qhs_extenddi_op>"
- "<qhs_extenddi_cstr>")))]
+ (zero_extend:DI (match_operand:QHSI 1 "<qhs_zextenddi_op>"
+ "<qhs_zextenddi_cstr>")))]
"TARGET_32BIT <qhs_zextenddi_cond>"
"#"
[(set_attr "length" "8")
=== modified file 'gcc/config/arm/iterators.md'
--- old/gcc/config/arm/iterators.md 2011-05-03 15:14:56 +0000
+++ new/gcc/config/arm/iterators.md 2011-09-06 14:29:24 +0000
@@ -379,10 +379,14 @@
(define_mode_attr qhs_zextenddi_cond [(SI "") (HI "&& arm_arch6") (QI "")])
(define_mode_attr qhs_sextenddi_cond [(SI "") (HI "&& arm_arch6")
(QI "&& arm_arch6")])
+(define_mode_attr qhs_zextenddi_op [(SI "s_register_operand")
+ (HI "nonimmediate_operand")
+ (QI "nonimmediate_operand")])
(define_mode_attr qhs_extenddi_op [(SI "s_register_operand")
(HI "nonimmediate_operand")
- (QI "nonimmediate_operand")])
-(define_mode_attr qhs_extenddi_cstr [(SI "r") (HI "rm") (QI "rm")])
+ (QI "arm_reg_or_extendqisi_mem_op")])
+(define_mode_attr qhs_extenddi_cstr [(SI "r") (HI "rm") (QI "rUq")])
+(define_mode_attr qhs_zextenddi_cstr [(SI "r") (HI "rm") (QI "rm")])
;;----------------------------------------------------------------------------
;; Code attributes
=== modified file 'gcc/config/arm/predicates.md'
--- old/gcc/config/arm/predicates.md 2011-09-12 11:24:34 +0000
+++ new/gcc/config/arm/predicates.md 2011-09-12 12:32:29 +0000
@@ -289,8 +289,11 @@
(define_special_predicate "arm_extendqisi_mem_op"
(and (match_operand 0 "memory_operand")
- (match_test "arm_legitimate_address_outer_p (mode, XEXP (op, 0),
- SIGN_EXTEND, 0)")))
+ (match_test "TARGET_ARM ? arm_legitimate_address_outer_p (mode,
+ XEXP (op, 0),
+ SIGN_EXTEND,
+ 0)
+ : memory_address_p (QImode, XEXP (op, 0))")))
(define_special_predicate "arm_reg_or_extendqisi_mem_op"
(ior (match_operand 0 "arm_extendqisi_mem_op")
=== added file 'gcc/testsuite/gcc.target/arm/pr50099.c'
--- old/gcc/testsuite/gcc.target/arm/pr50099.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/pr50099.c 2011-09-09 16:42:45 +0000
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+long long foo (signed char * arg)
+{
+ long long temp_1;
+
+ temp_1 = arg[256];
+ return temp_1;
+}
@@ -0,0 +1,767 @@
2011-08-26 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from FSF mainline:
2011-04-06 Wei Guozhi <carrot@google.com>
PR target/47855
gcc/
* config/arm/arm.md (arm_cmpsi_insn): Compute attr "length".
(arm_cond_branch): Likewise.
(arm_cond_branch_reversed): Likewise.
(arm_jump): Likewise.
(push_multi): Likewise.
* config/arm/constraints.md (Py): New constraint.
2011-04-08 Wei Guozhi <carrot@google.com>
PR target/47855
* config/arm/arm-protos.h (arm_attr_length_push_multi): New prototype.
* config/arm/arm.c (arm_attr_length_push_multi): New function.
* config/arm/arm.md (*push_multi): Change the length computation to
call a C function.
2011-08-26 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from FSF mainline:
2011-08-18 Jiangning Liu <jiangning.liu@arm.com>
gcc/
* config/arm/arm.md (*ior_scc_scc): Enable for Thumb2 as well.
(*ior_scc_scc_cmp): Likewise
(*and_scc_scc): Likewise.
(*and_scc_scc_cmp): Likewise.
(*and_scc_scc_nodom): Likewise.
(*cmp_ite0, *cmp_ite1, *cmp_and, *cmp_ior): Handle Thumb2.
gcc/testsuite
* gcc.target/arm/thumb2-cond-cmp-1.c: New. Make sure conditional
compare can be generated.
* gcc.target/arm/thumb2-cond-cmp-2.c: Likewise.
* gcc.target/arm/thumb2-cond-cmp-3.c: Likewise.
* gcc.target/arm/thumb2-cond-cmp-4.c: Likewise.
=== modified file 'gcc/config/arm/arm-protos.h'
--- old/gcc/config/arm/arm-protos.h 2011-09-12 11:03:11 +0000
+++ new/gcc/config/arm/arm-protos.h 2011-09-12 14:14:00 +0000
@@ -156,6 +156,7 @@
extern const char *arm_output_memory_barrier (rtx *);
extern const char *arm_output_sync_insn (rtx, rtx *);
extern unsigned int arm_sync_loop_insns (rtx , rtx *);
+extern int arm_attr_length_push_multi(rtx, rtx);
#if defined TREE_CODE
extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-09-12 11:03:11 +0000
+++ new/gcc/config/arm/arm.c 2011-09-12 14:14:00 +0000
@@ -24391,4 +24391,30 @@
return NO_REGS;
}
+/* Compute the atrribute "length" of insn "*push_multi".
+ So this function MUST be kept in sync with that insn pattern. */
+int
+arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
+{
+ int i, regno, hi_reg;
+ int num_saves = XVECLEN (parallel_op, 0);
+
+ /* ARM mode. */
+ if (TARGET_ARM)
+ return 4;
+
+ /* Thumb2 mode. */
+ regno = REGNO (first_op);
+ hi_reg = (REGNO_REG_CLASS (regno) == HI_REGS) && (regno != LR_REGNUM);
+ for (i = 1; i < num_saves && !hi_reg; i++)
+ {
+ regno = REGNO (XEXP (XVECEXP (parallel_op, 0, i), 0));
+ hi_reg |= (REGNO_REG_CLASS (regno) == HI_REGS) && (regno != LR_REGNUM);
+ }
+
+ if (!hi_reg)
+ return 2;
+ return 4;
+}
+
#include "gt-arm.h"
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2011-09-12 12:32:29 +0000
+++ new/gcc/config/arm/arm.md 2011-09-12 14:14:00 +0000
@@ -48,6 +48,15 @@
(DOM_CC_X_OR_Y 2)
]
)
+;; conditional compare combination
+(define_constants
+ [(CMP_CMP 0)
+ (CMN_CMP 1)
+ (CMP_CMN 2)
+ (CMN_CMN 3)
+ (NUM_OF_COND_CMP 4)
+ ]
+)
;; UNSPEC Usage:
;; Note: sin and cos are no-longer used.
@@ -7198,13 +7207,17 @@
(define_insn "*arm_cmpsi_insn"
[(set (reg:CC CC_REGNUM)
- (compare:CC (match_operand:SI 0 "s_register_operand" "r,r")
- (match_operand:SI 1 "arm_add_operand" "rI,L")))]
+ (compare:CC (match_operand:SI 0 "s_register_operand" "l,r,r,r")
+ (match_operand:SI 1 "arm_add_operand" "Py,r,rI,L")))]
"TARGET_32BIT"
"@
cmp%?\\t%0, %1
+ cmp%?\\t%0, %1
+ cmp%?\\t%0, %1
cmn%?\\t%0, #%n1"
- [(set_attr "conds" "set")]
+ [(set_attr "conds" "set")
+ (set_attr "arch" "t2,t2,any,any")
+ (set_attr "length" "2,2,4,4")]
)
(define_insn "*cmpsi_shiftsi"
@@ -7375,7 +7388,14 @@
return \"b%d1\\t%l0\";
"
[(set_attr "conds" "use")
- (set_attr "type" "branch")]
+ (set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else
+ (and (ne (symbol_ref "TARGET_THUMB2") (const_int 0))
+ (and (ge (minus (match_dup 0) (pc)) (const_int -250))
+ (le (minus (match_dup 0) (pc)) (const_int 256))))
+ (const_int 2)
+ (const_int 4)))]
)
(define_insn "*arm_cond_branch_reversed"
@@ -7394,7 +7414,14 @@
return \"b%D1\\t%l0\";
"
[(set_attr "conds" "use")
- (set_attr "type" "branch")]
+ (set_attr "type" "branch")
+ (set (attr "length")
+ (if_then_else
+ (and (ne (symbol_ref "TARGET_THUMB2") (const_int 0))
+ (and (ge (minus (match_dup 0) (pc)) (const_int -250))
+ (le (minus (match_dup 0) (pc)) (const_int 256))))
+ (const_int 2)
+ (const_int 4)))]
)
@@ -7846,7 +7873,14 @@
return \"b%?\\t%l0\";
}
"
- [(set_attr "predicable" "yes")]
+ [(set_attr "predicable" "yes")
+ (set (attr "length")
+ (if_then_else
+ (and (ne (symbol_ref "TARGET_THUMB2") (const_int 0))
+ (and (ge (minus (match_dup 0) (pc)) (const_int -2044))
+ (le (minus (match_dup 0) (pc)) (const_int 2048))))
+ (const_int 2)
+ (const_int 4)))]
)
(define_insn "*thumb_jump"
@@ -8931,40 +8965,85 @@
(set_attr "length" "8,12")]
)
-;; ??? Is it worth using these conditional patterns in Thumb-2 mode?
(define_insn "*cmp_ite0"
[(set (match_operand 6 "dominant_cc_register" "")
(compare
(if_then_else:SI
(match_operator 4 "arm_comparison_operator"
- [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
- (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
+ [(match_operand:SI 0 "s_register_operand"
+ "l,l,l,r,r,r,r,r,r")
+ (match_operand:SI 1 "arm_add_operand"
+ "lPy,lPy,lPy,rI,L,rI,L,rI,L")])
(match_operator:SI 5 "arm_comparison_operator"
- [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
- (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")])
+ [(match_operand:SI 2 "s_register_operand"
+ "l,r,r,l,l,r,r,r,r")
+ (match_operand:SI 3 "arm_add_operand"
+ "lPy,rI,L,lPy,lPy,rI,rI,L,L")])
(const_int 0))
(const_int 0)))]
- "TARGET_ARM"
+ "TARGET_32BIT"
"*
{
- static const char * const opcodes[4][2] =
- {
- {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",
- \"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"},
- {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\",
- \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"},
- {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\",
- \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"},
- {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\",
- \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"}
- };
+ static const char * const cmp1[NUM_OF_COND_CMP][2] =
+ {
+ {\"cmp%d5\\t%0, %1\",
+ \"cmp%d4\\t%2, %3\"},
+ {\"cmn%d5\\t%0, #%n1\",
+ \"cmp%d4\\t%2, %3\"},
+ {\"cmp%d5\\t%0, %1\",
+ \"cmn%d4\\t%2, #%n3\"},
+ {\"cmn%d5\\t%0, #%n1\",
+ \"cmn%d4\\t%2, #%n3\"}
+ };
+ static const char * const cmp2[NUM_OF_COND_CMP][2] =
+ {
+ {\"cmp\\t%2, %3\",
+ \"cmp\\t%0, %1\"},
+ {\"cmp\\t%2, %3\",
+ \"cmn\\t%0, #%n1\"},
+ {\"cmn\\t%2, #%n3\",
+ \"cmp\\t%0, %1\"},
+ {\"cmn\\t%2, #%n3\",
+ \"cmn\\t%0, #%n1\"}
+ };
+ static const char * const ite[2] =
+ {
+ \"it\\t%d5\",
+ \"it\\t%d4\"
+ };
+ static const int cmp_idx[9] = {CMP_CMP, CMP_CMP, CMP_CMN,
+ CMP_CMP, CMN_CMP, CMP_CMP,
+ CMN_CMP, CMP_CMN, CMN_CMN};
int swap =
comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
- return opcodes[which_alternative][swap];
+ output_asm_insn (cmp2[cmp_idx[which_alternative]][swap], operands);
+ if (TARGET_THUMB2) {
+ output_asm_insn (ite[swap], operands);
+ }
+ output_asm_insn (cmp1[cmp_idx[which_alternative]][swap], operands);
+ return \"\";
}"
[(set_attr "conds" "set")
- (set_attr "length" "8")]
+ (set_attr "arch" "t2,t2,t2,t2,t2,any,any,any,any")
+ (set_attr_alternative "length"
+ [(const_int 6)
+ (const_int 8)
+ (const_int 8)
+ (const_int 8)
+ (const_int 8)
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))])]
)
(define_insn "*cmp_ite1"
@@ -8972,35 +9051,81 @@
(compare
(if_then_else:SI
(match_operator 4 "arm_comparison_operator"
- [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
- (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
+ [(match_operand:SI 0 "s_register_operand"
+ "l,l,l,r,r,r,r,r,r")
+ (match_operand:SI 1 "arm_add_operand"
+ "lPy,lPy,lPy,rI,L,rI,L,rI,L")])
(match_operator:SI 5 "arm_comparison_operator"
- [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
- (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")])
+ [(match_operand:SI 2 "s_register_operand"
+ "l,r,r,l,l,r,r,r,r")
+ (match_operand:SI 3 "arm_add_operand"
+ "lPy,rI,L,lPy,lPy,rI,rI,L,L")])
(const_int 1))
(const_int 0)))]
- "TARGET_ARM"
+ "TARGET_32BIT"
"*
{
- static const char * const opcodes[4][2] =
- {
- {\"cmp\\t%0, %1\;cmp%d4\\t%2, %3\",
- \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"},
- {\"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\",
- \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"},
- {\"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\",
- \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"},
- {\"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\",
- \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"}
- };
+ static const char * const cmp1[NUM_OF_COND_CMP][2] =
+ {
+ {\"cmp\\t%0, %1\",
+ \"cmp\\t%2, %3\"},
+ {\"cmn\\t%0, #%n1\",
+ \"cmp\\t%2, %3\"},
+ {\"cmp\\t%0, %1\",
+ \"cmn\\t%2, #%n3\"},
+ {\"cmn\\t%0, #%n1\",
+ \"cmn\\t%2, #%n3\"}
+ };
+ static const char * const cmp2[NUM_OF_COND_CMP][2] =
+ {
+ {\"cmp%d4\\t%2, %3\",
+ \"cmp%D5\\t%0, %1\"},
+ {\"cmp%d4\\t%2, %3\",
+ \"cmn%D5\\t%0, #%n1\"},
+ {\"cmn%d4\\t%2, #%n3\",
+ \"cmp%D5\\t%0, %1\"},
+ {\"cmn%d4\\t%2, #%n3\",
+ \"cmn%D5\\t%0, #%n1\"}
+ };
+ static const char * const ite[2] =
+ {
+ \"it\\t%d4\",
+ \"it\\t%D5\"
+ };
+ static const int cmp_idx[9] = {CMP_CMP, CMP_CMP, CMP_CMN,
+ CMP_CMP, CMN_CMP, CMP_CMP,
+ CMN_CMP, CMP_CMN, CMN_CMN};
int swap =
comparison_dominates_p (GET_CODE (operands[5]),
reverse_condition (GET_CODE (operands[4])));
- return opcodes[which_alternative][swap];
+ output_asm_insn (cmp1[cmp_idx[which_alternative]][swap], operands);
+ if (TARGET_THUMB2) {
+ output_asm_insn (ite[swap], operands);
+ }
+ output_asm_insn (cmp2[cmp_idx[which_alternative]][swap], operands);
+ return \"\";
}"
[(set_attr "conds" "set")
- (set_attr "length" "8")]
+ (set_attr "arch" "t2,t2,t2,t2,t2,any,any,any,any")
+ (set_attr_alternative "length"
+ [(const_int 6)
+ (const_int 8)
+ (const_int 8)
+ (const_int 8)
+ (const_int 8)
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))])]
)
(define_insn "*cmp_and"
@@ -9008,34 +9133,80 @@
(compare
(and:SI
(match_operator 4 "arm_comparison_operator"
- [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
- (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
+ [(match_operand:SI 0 "s_register_operand"
+ "l,l,l,r,r,r,r,r,r")
+ (match_operand:SI 1 "arm_add_operand"
+ "lPy,lPy,lPy,rI,L,rI,L,rI,L")])
(match_operator:SI 5 "arm_comparison_operator"
- [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
- (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]))
+ [(match_operand:SI 2 "s_register_operand"
+ "l,r,r,l,l,r,r,r,r")
+ (match_operand:SI 3 "arm_add_operand"
+ "lPy,rI,L,lPy,lPy,rI,rI,L,L")]))
(const_int 0)))]
- "TARGET_ARM"
+ "TARGET_32BIT"
"*
{
- static const char *const opcodes[4][2] =
- {
- {\"cmp\\t%2, %3\;cmp%d5\\t%0, %1\",
- \"cmp\\t%0, %1\;cmp%d4\\t%2, %3\"},
- {\"cmp\\t%2, %3\;cmn%d5\\t%0, #%n1\",
- \"cmn\\t%0, #%n1\;cmp%d4\\t%2, %3\"},
- {\"cmn\\t%2, #%n3\;cmp%d5\\t%0, %1\",
- \"cmp\\t%0, %1\;cmn%d4\\t%2, #%n3\"},
- {\"cmn\\t%2, #%n3\;cmn%d5\\t%0, #%n1\",
- \"cmn\\t%0, #%n1\;cmn%d4\\t%2, #%n3\"}
- };
+ static const char *const cmp1[NUM_OF_COND_CMP][2] =
+ {
+ {\"cmp%d5\\t%0, %1\",
+ \"cmp%d4\\t%2, %3\"},
+ {\"cmn%d5\\t%0, #%n1\",
+ \"cmp%d4\\t%2, %3\"},
+ {\"cmp%d5\\t%0, %1\",
+ \"cmn%d4\\t%2, #%n3\"},
+ {\"cmn%d5\\t%0, #%n1\",
+ \"cmn%d4\\t%2, #%n3\"}
+ };
+ static const char *const cmp2[NUM_OF_COND_CMP][2] =
+ {
+ {\"cmp\\t%2, %3\",
+ \"cmp\\t%0, %1\"},
+ {\"cmp\\t%2, %3\",
+ \"cmn\\t%0, #%n1\"},
+ {\"cmn\\t%2, #%n3\",
+ \"cmp\\t%0, %1\"},
+ {\"cmn\\t%2, #%n3\",
+ \"cmn\\t%0, #%n1\"}
+ };
+ static const char *const ite[2] =
+ {
+ \"it\\t%d5\",
+ \"it\\t%d4\"
+ };
+ static const int cmp_idx[9] = {CMP_CMP, CMP_CMP, CMP_CMN,
+ CMP_CMP, CMN_CMP, CMP_CMP,
+ CMN_CMP, CMP_CMN, CMN_CMN};
int swap =
comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
- return opcodes[which_alternative][swap];
+ output_asm_insn (cmp2[cmp_idx[which_alternative]][swap], operands);
+ if (TARGET_THUMB2) {
+ output_asm_insn (ite[swap], operands);
+ }
+ output_asm_insn (cmp1[cmp_idx[which_alternative]][swap], operands);
+ return \"\";
}"
[(set_attr "conds" "set")
(set_attr "predicable" "no")
- (set_attr "length" "8")]
+ (set_attr "arch" "t2,t2,t2,t2,t2,any,any,any,any")
+ (set_attr_alternative "length"
+ [(const_int 6)
+ (const_int 8)
+ (const_int 8)
+ (const_int 8)
+ (const_int 8)
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))])]
)
(define_insn "*cmp_ior"
@@ -9043,34 +9214,80 @@
(compare
(ior:SI
(match_operator 4 "arm_comparison_operator"
- [(match_operand:SI 0 "s_register_operand" "r,r,r,r")
- (match_operand:SI 1 "arm_add_operand" "rI,L,rI,L")])
+ [(match_operand:SI 0 "s_register_operand"
+ "l,l,l,r,r,r,r,r,r")
+ (match_operand:SI 1 "arm_add_operand"
+ "lPy,lPy,lPy,rI,L,rI,L,rI,L")])
(match_operator:SI 5 "arm_comparison_operator"
- [(match_operand:SI 2 "s_register_operand" "r,r,r,r")
- (match_operand:SI 3 "arm_add_operand" "rI,rI,L,L")]))
+ [(match_operand:SI 2 "s_register_operand"
+ "l,r,r,l,l,r,r,r,r")
+ (match_operand:SI 3 "arm_add_operand"
+ "lPy,rI,L,lPy,lPy,rI,rI,L,L")]))
(const_int 0)))]
- "TARGET_ARM"
+ "TARGET_32BIT"
"*
-{
- static const char *const opcodes[4][2] =
{
- {\"cmp\\t%0, %1\;cmp%D4\\t%2, %3\",
- \"cmp\\t%2, %3\;cmp%D5\\t%0, %1\"},
- {\"cmn\\t%0, #%n1\;cmp%D4\\t%2, %3\",
- \"cmp\\t%2, %3\;cmn%D5\\t%0, #%n1\"},
- {\"cmp\\t%0, %1\;cmn%D4\\t%2, #%n3\",
- \"cmn\\t%2, #%n3\;cmp%D5\\t%0, %1\"},
- {\"cmn\\t%0, #%n1\;cmn%D4\\t%2, #%n3\",
- \"cmn\\t%2, #%n3\;cmn%D5\\t%0, #%n1\"}
- };
- int swap =
- comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
+ static const char *const cmp1[NUM_OF_COND_CMP][2] =
+ {
+ {\"cmp\\t%0, %1\",
+ \"cmp\\t%2, %3\"},
+ {\"cmn\\t%0, #%n1\",
+ \"cmp\\t%2, %3\"},
+ {\"cmp\\t%0, %1\",
+ \"cmn\\t%2, #%n3\"},
+ {\"cmn\\t%0, #%n1\",
+ \"cmn\\t%2, #%n3\"}
+ };
+ static const char *const cmp2[NUM_OF_COND_CMP][2] =
+ {
+ {\"cmp%D4\\t%2, %3\",
+ \"cmp%D5\\t%0, %1\"},
+ {\"cmp%D4\\t%2, %3\",
+ \"cmn%D5\\t%0, #%n1\"},
+ {\"cmn%D4\\t%2, #%n3\",
+ \"cmp%D5\\t%0, %1\"},
+ {\"cmn%D4\\t%2, #%n3\",
+ \"cmn%D5\\t%0, #%n1\"}
+ };
+ static const char *const ite[2] =
+ {
+ \"it\\t%D4\",
+ \"it\\t%D5\"
+ };
+ static const int cmp_idx[9] = {CMP_CMP, CMP_CMP, CMP_CMN,
+ CMP_CMP, CMN_CMP, CMP_CMP,
+ CMN_CMP, CMP_CMN, CMN_CMN};
+ int swap =
+ comparison_dominates_p (GET_CODE (operands[5]), GET_CODE (operands[4]));
- return opcodes[which_alternative][swap];
-}
-"
+ output_asm_insn (cmp1[cmp_idx[which_alternative]][swap], operands);
+ if (TARGET_THUMB2) {
+ output_asm_insn (ite[swap], operands);
+ }
+ output_asm_insn (cmp2[cmp_idx[which_alternative]][swap], operands);
+ return \"\";
+ }
+ "
[(set_attr "conds" "set")
- (set_attr "length" "8")]
+ (set_attr "arch" "t2,t2,t2,t2,t2,any,any,any,any")
+ (set_attr_alternative "length"
+ [(const_int 6)
+ (const_int 8)
+ (const_int 8)
+ (const_int 8)
+ (const_int 8)
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))
+ (if_then_else (eq_attr "is_thumb" "no")
+ (const_int 8)
+ (const_int 10))])]
)
(define_insn_and_split "*ior_scc_scc"
@@ -9082,11 +9299,11 @@
[(match_operand:SI 4 "s_register_operand" "r")
(match_operand:SI 5 "arm_add_operand" "rIL")])))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM
+ "TARGET_32BIT
&& (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_OR_Y)
!= CCmode)"
"#"
- "TARGET_ARM && reload_completed"
+ "TARGET_32BIT && reload_completed"
[(set (match_dup 7)
(compare
(ior:SI
@@ -9115,9 +9332,9 @@
(set (match_operand:SI 7 "s_register_operand" "=r")
(ior:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])
(match_op_dup 6 [(match_dup 4) (match_dup 5)])))]
- "TARGET_ARM"
+ "TARGET_32BIT"
"#"
- "TARGET_ARM && reload_completed"
+ "TARGET_32BIT && reload_completed"
[(set (match_dup 0)
(compare
(ior:SI
@@ -9138,11 +9355,11 @@
[(match_operand:SI 4 "s_register_operand" "r")
(match_operand:SI 5 "arm_add_operand" "rIL")])))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM
+ "TARGET_32BIT
&& (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
!= CCmode)"
"#"
- "TARGET_ARM && reload_completed
+ "TARGET_32BIT && reload_completed
&& (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
!= CCmode)"
[(set (match_dup 7)
@@ -9173,9 +9390,9 @@
(set (match_operand:SI 7 "s_register_operand" "=r")
(and:SI (match_op_dup 3 [(match_dup 1) (match_dup 2)])
(match_op_dup 6 [(match_dup 4) (match_dup 5)])))]
- "TARGET_ARM"
+ "TARGET_32BIT"
"#"
- "TARGET_ARM && reload_completed"
+ "TARGET_32BIT && reload_completed"
[(set (match_dup 0)
(compare
(and:SI
@@ -9200,11 +9417,11 @@
[(match_operand:SI 4 "s_register_operand" "r,r,r")
(match_operand:SI 5 "arm_add_operand" "rIL,rIL,rIL")])))
(clobber (reg:CC CC_REGNUM))]
- "TARGET_ARM
+ "TARGET_32BIT
&& (arm_select_dominance_cc_mode (operands[3], operands[6], DOM_CC_X_AND_Y)
== CCmode)"
"#"
- "TARGET_ARM && reload_completed"
+ "TARGET_32BIT && reload_completed"
[(parallel [(set (match_dup 0)
(match_op_dup 3 [(match_dup 1) (match_dup 2)]))
(clobber (reg:CC CC_REGNUM))])
@@ -10314,6 +10531,8 @@
;; Push multiple registers to the stack. Registers are in parallel (use ...)
;; expressions. For simplicity, the first register is also in the unspec
;; part.
+;; To avoid the usage of GNU extension, the length attribute is computed
+;; in a C function arm_attr_length_push_multi.
(define_insn "*push_multi"
[(match_parallel 2 "multi_register_push"
[(set (match_operand:BLK 0 "memory_operand" "=m")
@@ -10353,7 +10572,9 @@
return \"\";
}"
- [(set_attr "type" "store4")]
+ [(set_attr "type" "store4")
+ (set (attr "length")
+ (symbol_ref "arm_attr_length_push_multi (operands[2], operands[1])"))]
)
(define_insn "stack_tie"
=== modified file 'gcc/config/arm/constraints.md'
--- old/gcc/config/arm/constraints.md 2011-08-25 13:26:58 +0000
+++ new/gcc/config/arm/constraints.md 2011-09-12 14:14:00 +0000
@@ -31,7 +31,7 @@
;; The following multi-letter normal constraints have been used:
;; in ARM/Thumb-2 state: Da, Db, Dc, Dn, Dl, DL, Dv, Dy, Di, Dz
;; in Thumb-1 state: Pa, Pb, Pc, Pd
-;; in Thumb-2 state: Pj, PJ, Ps, Pt, Pu, Pv, Pw, Px
+;; in Thumb-2 state: Pj, PJ, Ps, Pt, Pu, Pv, Pw, Px, Py
;; The following memory constraints have been used:
;; in ARM/Thumb-2 state: Q, Ut, Uv, Uy, Un, Um, Us
@@ -201,6 +201,11 @@
(and (match_code "const_int")
(match_test "TARGET_THUMB2 && ival >= -7 && ival <= -1")))
+(define_constraint "Py"
+ "@internal In Thumb-2 state a constant in the range 0 to 255"
+ (and (match_code "const_int")
+ (match_test "TARGET_THUMB2 && ival >= 0 && ival <= 255")))
+
(define_constraint "G"
"In ARM/Thumb-2 state a valid FPA immediate constant."
(and (match_code "const_double")
=== added file 'gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-1.c'
--- old/gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-1.c 2011-09-12 14:14:00 +0000
@@ -0,0 +1,13 @@
+/* Use conditional compare */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { arm_thumb1_ok } } */
+/* { dg-final { scan-assembler "cmpne" } } */
+
+int f(int i, int j)
+{
+ if ( (i == '+') || (j == '-') ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
=== added file 'gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-2.c'
--- old/gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-2.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-2.c 2011-09-12 14:14:00 +0000
@@ -0,0 +1,13 @@
+/* Use conditional compare */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { arm_thumb1_ok } } */
+/* { dg-final { scan-assembler "cmpeq" } } */
+
+int f(int i, int j)
+{
+ if ( (i == '+') && (j == '-') ) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
=== added file 'gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-3.c'
--- old/gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-3.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-3.c 2011-09-12 14:14:00 +0000
@@ -0,0 +1,12 @@
+/* Use conditional compare */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { arm_thumb1_ok } } */
+/* { dg-final { scan-assembler "cmpgt" } } */
+
+int f(int i, int j)
+{
+ if ( (i >= '+') ? (j > '-') : 0)
+ return 1;
+ else
+ return 0;
+}
=== added file 'gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-4.c'
--- old/gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-4.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/thumb2-cond-cmp-4.c 2011-09-12 14:14:00 +0000
@@ -0,0 +1,12 @@
+/* Use conditional compare */
+/* { dg-options "-O2" } */
+/* { dg-skip-if "" { arm_thumb1_ok } } */
+/* { dg-final { scan-assembler "cmpgt" } } */
+
+int f(int i, int j)
+{
+ if ( (i >= '+') ? (j <= '-') : 1)
+ return 1;
+ else
+ return 0;
+}
@@ -0,0 +1,203 @@
2011-09-15 Richard Sandiford <richard.sandiford@linaro.org>
Revert:
gcc/
PR target/49030
* config/arm/arm-protos.h (maybe_get_arm_condition_code): Declare.
* config/arm/arm.c (maybe_get_arm_condition_code): New function,
reusing the old code from get_arm_condition_code. Return ARM_NV
for invalid comparison codes.
(get_arm_condition_code): Redefine in terms of
maybe_get_arm_condition_code.
* config/arm/predicates.md (arm_comparison_operator): Use
maybe_get_arm_condition_code.
gcc/testsuite/
PR target/49030
* gcc.dg/torture/pr49030.c: New test.
=== modified file 'gcc/config/arm/arm-protos.h'
--- old/gcc/config/arm/arm-protos.h 2011-09-12 14:14:00 +0000
+++ new/gcc/config/arm/arm-protos.h 2011-09-15 09:45:31 +0000
@@ -180,7 +180,6 @@
#endif
extern int thumb_shiftable_const (unsigned HOST_WIDE_INT);
#ifdef RTX_CODE
-extern enum arm_cond_code maybe_get_arm_condition_code (rtx);
extern void thumb1_final_prescan_insn (rtx);
extern void thumb2_final_prescan_insn (rtx);
extern const char *thumb_load_double_from_address (rtx *);
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-09-12 14:14:00 +0000
+++ new/gcc/config/arm/arm.c 2011-09-15 09:45:31 +0000
@@ -17494,10 +17494,10 @@
decremented/zeroed by arm_asm_output_opcode as the insns are output. */
/* Returns the index of the ARM condition code string in
- `arm_condition_codes', or ARM_NV if the comparison is invalid.
- COMPARISON should be an rtx like `(eq (...) (...))'. */
-enum arm_cond_code
-maybe_get_arm_condition_code (rtx comparison)
+ `arm_condition_codes'. COMPARISON should be an rtx like
+ `(eq (...) (...))'. */
+static enum arm_cond_code
+get_arm_condition_code (rtx comparison)
{
enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
enum arm_cond_code code;
@@ -17521,11 +17521,11 @@
case CC_DLTUmode: code = ARM_CC;
dominance:
+ gcc_assert (comp_code == EQ || comp_code == NE);
+
if (comp_code == EQ)
return ARM_INVERSE_CONDITION_CODE (code);
- if (comp_code == NE)
- return code;
- return ARM_NV;
+ return code;
case CC_NOOVmode:
switch (comp_code)
@@ -17534,7 +17534,7 @@
case EQ: return ARM_EQ;
case GE: return ARM_PL;
case LT: return ARM_MI;
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
case CC_Zmode:
@@ -17542,7 +17542,7 @@
{
case NE: return ARM_NE;
case EQ: return ARM_EQ;
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
case CC_Nmode:
@@ -17550,7 +17550,7 @@
{
case NE: return ARM_MI;
case EQ: return ARM_PL;
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
case CCFPEmode:
@@ -17575,7 +17575,7 @@
/* UNEQ and LTGT do not have a representation. */
case UNEQ: /* Fall through. */
case LTGT: /* Fall through. */
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
case CC_SWPmode:
@@ -17591,7 +17591,7 @@
case GTU: return ARM_CC;
case LEU: return ARM_CS;
case LTU: return ARM_HI;
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
case CC_Cmode:
@@ -17599,7 +17599,7 @@
{
case LTU: return ARM_CS;
case GEU: return ARM_CC;
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
case CC_CZmode:
@@ -17611,7 +17611,7 @@
case GTU: return ARM_HI;
case LEU: return ARM_LS;
case LTU: return ARM_CC;
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
case CC_NCVmode:
@@ -17621,7 +17621,7 @@
case LT: return ARM_LT;
case GEU: return ARM_CS;
case LTU: return ARM_CC;
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
case CCmode:
@@ -17637,22 +17637,13 @@
case GTU: return ARM_HI;
case LEU: return ARM_LS;
case LTU: return ARM_CC;
- default: return ARM_NV;
+ default: gcc_unreachable ();
}
default: gcc_unreachable ();
}
}
-/* Like maybe_get_arm_condition_code, but never return ARM_NV. */
-static enum arm_cond_code
-get_arm_condition_code (rtx comparison)
-{
- enum arm_cond_code code = maybe_get_arm_condition_code (comparison);
- gcc_assert (code != ARM_NV);
- return code;
-}
-
/* Tell arm_asm_output_opcode to output IT blocks for conditionally executed
instructions. */
void
=== modified file 'gcc/config/arm/predicates.md'
--- old/gcc/config/arm/predicates.md 2011-09-12 12:32:29 +0000
+++ new/gcc/config/arm/predicates.md 2011-09-15 09:45:31 +0000
@@ -243,9 +243,10 @@
;; True for integer comparisons and, if FP is active, for comparisons
;; other than LTGT or UNEQ.
(define_special_predicate "arm_comparison_operator"
- (and (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,
- unordered,ordered,unlt,unle,unge,ungt")
- (match_test "maybe_get_arm_condition_code (op) != ARM_NV")))
+ (ior (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu")
+ (and (match_test "TARGET_32BIT && TARGET_HARD_FLOAT
+ && (TARGET_FPA || TARGET_VFP)")
+ (match_code "unordered,ordered,unlt,unle,unge,ungt"))))
(define_special_predicate "lt_ge_comparison_operator"
(match_code "lt,ge"))
=== removed file 'gcc/testsuite/gcc.dg/torture/pr49030.c'
--- old/gcc/testsuite/gcc.dg/torture/pr49030.c 2011-09-05 09:40:19 +0000
+++ new/gcc/testsuite/gcc.dg/torture/pr49030.c 1970-01-01 00:00:00 +0000
@@ -1,19 +0,0 @@
-void
-sample_move_d32u24_sS (char *dst, float *src, unsigned long nsamples,
- unsigned long dst_skip)
-{
- long long y;
- while (nsamples--)
- {
- y = (long long) (*src * 8388608.0f) << 8;
- if (y > 2147483647) {
- *(int *) dst = 2147483647;
- } else if (y < -2147483647 - 1) {
- *(int *) dst = -2147483647 - 1;
- } else {
- *(int *) dst = (int) y;
- }
- dst += dst_skip;
- src++;
- }
-}
@@ -0,0 +1,80 @@
2011-09-22 Revital Eres <revital.eres@linaro.org>
gcc/
Backport from trunk -r178804:
modulo-sched.c (remove_node_from_ps): Return void
instead of bool.
(optimize_sc): Adjust call to remove_node_from_ps.
(sms_schedule): Add print info.
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-08-09 04:51:48 +0000
+++ new/gcc/modulo-sched.c 2011-09-14 11:06:06 +0000
@@ -211,7 +211,7 @@
static bool try_scheduling_node_in_cycle (partial_schedule_ptr, ddg_node_ptr,
int, int, sbitmap, int *, sbitmap,
sbitmap);
-static bool remove_node_from_ps (partial_schedule_ptr, ps_insn_ptr);
+static void remove_node_from_ps (partial_schedule_ptr, ps_insn_ptr);
#define SCHED_ASAP(x) (((node_sched_params_ptr)(x)->aux.info)->asap)
#define SCHED_TIME(x) (((node_sched_params_ptr)(x)->aux.info)->time)
@@ -834,8 +834,7 @@
if (next_ps_i->node->cuid == g->closing_branch->cuid)
break;
- gcc_assert (next_ps_i);
- gcc_assert (remove_node_from_ps (ps, next_ps_i));
+ remove_node_from_ps (ps, next_ps_i);
success =
try_scheduling_node_in_cycle (ps, g->closing_branch,
g->closing_branch->cuid, c,
@@ -1485,8 +1484,8 @@
if (dump_file)
{
fprintf (dump_file,
- "SMS succeeded %d %d (with ii, sc)\n", ps->ii,
- stage_count);
+ "%s:%d SMS succeeded %d %d (with ii, sc)\n",
+ insn_file (tail), insn_line (tail), ps->ii, stage_count);
print_partial_schedule (ps, dump_file);
}
@@ -2810,22 +2809,18 @@
}
-/* Removes the given PS_INSN from the partial schedule. Returns false if the
- node is not found in the partial schedule, else returns true. */
-static bool
+/* Removes the given PS_INSN from the partial schedule. */
+static void
remove_node_from_ps (partial_schedule_ptr ps, ps_insn_ptr ps_i)
{
int row;
- if (!ps || !ps_i)
- return false;
-
+ gcc_assert (ps && ps_i);
+
row = SMODULO (ps_i->cycle, ps->ii);
if (! ps_i->prev_in_row)
{
- if (ps_i != ps->rows[row])
- return false;
-
+ gcc_assert (ps_i == ps->rows[row]);
ps->rows[row] = ps_i->next_in_row;
if (ps->rows[row])
ps->rows[row]->prev_in_row = NULL;
@@ -2839,7 +2834,7 @@
ps->rows_length[row] -= 1;
free (ps_i);
- return true;
+ return;
}
/* Unlike what literature describes for modulo scheduling (which focuses
@@ -0,0 +1,528 @@
2011-09-25 Ira Rosen <ira.rosen@linaro.org>
gcc/testsuite/
* lib/target-supports.exp (check_effective_target_vect_multiple_sizes):
Replace check_effective_target_arm_neon with
check_effective_target_arm_neon_ok.
Backport from mainline:
2011-09-06 Ira Rosen <ira.rosen@linaro.org>
gcc/
* config/arm/arm.c (arm_preferred_simd_mode): Check
TARGET_NEON_VECTORIZE_DOUBLE instead of
TARGET_NEON_VECTORIZE_QUAD.
(arm_autovectorize_vector_sizes): Likewise.
* config/arm/arm.opt (mvectorize-with-neon-quad): Make inverse
mask of mvectorize-with-neon-double. Add RejectNegative.
(mvectorize-with-neon-double): New.
gcc/testsuite/
* lib/target-supports.exp (check_effective_target_vect_multiple_sizes):
New procedure.
(add_options_for_quad_vectors): Replace with ...
(add_options_for_double_vectors): ... this.
* gfortran.dg/vect/pr19049.f90: Expect more printings on targets that
support multiple vector sizes since the vectorizer attempts to
vectorize with both vector sizes.
* gcc.dg/vect/no-vfa-vect-79.c,
gcc.dg/vect/no-vfa-vect-102a.c, gcc.dg/vect/vect-outer-1a.c,
gcc.dg/vect/vect-outer-1b.c, gcc.dg/vect/vect-outer-2b.c,
gcc.dg/vect/vect-outer-3a.c, gcc.dg/vect/no-vfa-vect-37.c,
gcc.dg/vect/vect-outer-3b.c, gcc.dg/vect/no-vfa-vect-101.c,
gcc.dg/vect/no-vfa-vect-102.c, gcc.dg/vect/vect-reduc-dot-s8b.c,
gcc.dg/vect/vect-outer-1.c, gcc.dg/vect/vect-104.c: Likewise.
* gcc.dg/vect/vect-42.c: Run with 64 bit vectors if applicable.
* gcc.dg/vect/vect-multitypes-6.c, gcc.dg/vect/vect-52.c,
gcc.dg/vect/vect-54.c, gcc.dg/vect/vect-46.c, gcc.dg/vect/vect-48.c,
gcc.dg/vect/vect-96.c, gcc.dg/vect/vect-multitypes-3.c,
gcc.dg/vect/vect-40.c: Likewise.
* gcc.dg/vect/vect-outer-5.c: Remove quad-vectors option as
redundant.
* gcc.dg/vect/vect-109.c, gcc.dg/vect/vect-peel-1.c,
gcc.dg/vect/vect-peel-2.c, gcc.dg/vect/slp-25.c,
gcc.dg/vect/vect-multitypes-1.c, gcc.dg/vect/slp-3.c,
gcc.dg/vect/no-vfa-pr29145.c, gcc.dg/vect/vect-multitypes-4.c:
Likewise.
* gcc.dg/vect/vect-peel-4.c: Make ia global.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-09-15 09:45:31 +0000
+++ new/gcc/config/arm/arm.c 2011-09-19 07:44:24 +0000
@@ -22974,7 +22974,7 @@
return false;
}
-/* Use the option -mvectorize-with-neon-quad to override the use of doubleword
+/* Use the option -mvectorize-with-neon-double to override the use of quardword
registers when autovectorizing for Neon, at least until multiple vector
widths are supported properly by the middle-end. */
@@ -22985,15 +22985,15 @@
switch (mode)
{
case SFmode:
- return TARGET_NEON_VECTORIZE_QUAD ? V4SFmode : V2SFmode;
+ return TARGET_NEON_VECTORIZE_DOUBLE ? V2SFmode : V4SFmode;
case SImode:
- return TARGET_NEON_VECTORIZE_QUAD ? V4SImode : V2SImode;
+ return TARGET_NEON_VECTORIZE_DOUBLE ? V2SImode : V4SImode;
case HImode:
- return TARGET_NEON_VECTORIZE_QUAD ? V8HImode : V4HImode;
+ return TARGET_NEON_VECTORIZE_DOUBLE ? V4HImode : V8HImode;
case QImode:
- return TARGET_NEON_VECTORIZE_QUAD ? V16QImode : V8QImode;
+ return TARGET_NEON_VECTORIZE_DOUBLE ? V8QImode : V16QImode;
case DImode:
- if (TARGET_NEON_VECTORIZE_QUAD)
+ if (!TARGET_NEON_VECTORIZE_DOUBLE)
return V2DImode;
break;
@@ -24226,7 +24226,7 @@
static unsigned int
arm_autovectorize_vector_sizes (void)
{
- return TARGET_NEON_VECTORIZE_QUAD ? 16 | 8 : 0;
+ return TARGET_NEON_VECTORIZE_DOUBLE ? 0 : (16 | 8);
}
static bool
=== modified file 'gcc/config/arm/arm.opt'
--- old/gcc/config/arm/arm.opt 2009-06-18 11:24:10 +0000
+++ new/gcc/config/arm/arm.opt 2011-09-19 07:44:24 +0000
@@ -158,9 +158,13 @@
Assume big endian bytes, little endian words
mvectorize-with-neon-quad
-Target Report Mask(NEON_VECTORIZE_QUAD)
+Target Report RejectNegative InverseMask(NEON_VECTORIZE_DOUBLE)
Use Neon quad-word (rather than double-word) registers for vectorization
+mvectorize-with-neon-double
+Target Report RejectNegative Mask(NEON_VECTORIZE_DOUBLE)
+Use Neon double-word (rather than quad-word) registers for vectorization
+
mword-relocations
Target Report Var(target_word_relocations) Init(TARGET_DEFAULT_WORD_RELOCATIONS)
Only generate absolute relocations on word sized values.
=== modified file 'gcc/testsuite/gcc.dg/vect/no-vfa-pr29145.c'
--- old/gcc/testsuite/gcc.dg/vect/no-vfa-pr29145.c 2011-04-28 11:46:58 +0000
+++ new/gcc/testsuite/gcc.dg/vect/no-vfa-pr29145.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/no-vfa-vect-101.c'
--- old/gcc/testsuite/gcc.dg/vect/no-vfa-vect-101.c 2007-09-04 12:05:19 +0000
+++ new/gcc/testsuite/gcc.dg/vect/no-vfa-vect-101.c 2011-09-19 07:44:24 +0000
@@ -45,6 +45,7 @@
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
-/* { dg-final { scan-tree-dump-times "can't determine dependence" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "can't determine dependence" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "can't determine dependence" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/no-vfa-vect-102.c'
--- old/gcc/testsuite/gcc.dg/vect/no-vfa-vect-102.c 2007-09-12 07:48:44 +0000
+++ new/gcc/testsuite/gcc.dg/vect/no-vfa-vect-102.c 2011-09-19 07:44:24 +0000
@@ -53,6 +53,7 @@
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
-/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/no-vfa-vect-102a.c'
--- old/gcc/testsuite/gcc.dg/vect/no-vfa-vect-102a.c 2007-09-12 07:48:44 +0000
+++ new/gcc/testsuite/gcc.dg/vect/no-vfa-vect-102a.c 2011-09-19 07:44:24 +0000
@@ -53,6 +53,7 @@
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
-/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/no-vfa-vect-37.c'
--- old/gcc/testsuite/gcc.dg/vect/no-vfa-vect-37.c 2009-05-08 12:39:01 +0000
+++ new/gcc/testsuite/gcc.dg/vect/no-vfa-vect-37.c 2011-09-19 07:44:24 +0000
@@ -58,5 +58,6 @@
If/when the aliasing problems are resolved, unalignment may
prevent vectorization on some targets. */
/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "can't determine dependence between" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "can't determine dependence" 2 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "can't determine dependence" 4 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/no-vfa-vect-79.c'
--- old/gcc/testsuite/gcc.dg/vect/no-vfa-vect-79.c 2009-05-08 12:39:01 +0000
+++ new/gcc/testsuite/gcc.dg/vect/no-vfa-vect-79.c 2011-09-19 07:44:24 +0000
@@ -46,5 +46,6 @@
If/when the aliasing problems are resolved, unalignment may
prevent vectorization on some targets. */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "can't determine dependence between" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "can't determine dependence" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "can't determine dependence" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/slp-25.c'
--- old/gcc/testsuite/gcc.dg/vect/slp-25.c 2010-10-04 14:59:30 +0000
+++ new/gcc/testsuite/gcc.dg/vect/slp-25.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/slp-3.c'
--- old/gcc/testsuite/gcc.dg/vect/slp-3.c 2011-04-28 11:46:58 +0000
+++ new/gcc/testsuite/gcc.dg/vect/slp-3.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-104.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-104.c 2007-09-12 07:48:44 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-104.c 2011-09-19 07:44:24 +0000
@@ -64,6 +64,7 @@
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
-/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-109.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-109.c 2010-10-04 14:59:30 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-109.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-40.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-40.c 2009-05-25 14:18:21 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-40.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_float } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-42.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-42.c 2010-10-04 14:59:30 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-42.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_float } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-46.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-46.c 2009-05-25 14:18:21 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-46.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_float } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-48.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-48.c 2009-11-04 10:22:22 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-48.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_float } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-52.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-52.c 2009-11-04 10:22:22 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-52.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_float } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-54.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-54.c 2009-10-27 11:46:07 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-54.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_float } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-96.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-96.c 2010-10-04 14:59:30 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-96.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c 2010-10-04 14:59:30 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-multitypes-3.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-multitypes-3.c 2009-11-04 10:22:22 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-multitypes-3.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-multitypes-4.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-multitypes-4.c 2010-10-04 14:59:30 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-multitypes-4.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-multitypes-6.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-multitypes-6.c 2009-11-10 18:01:22 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-multitypes-6.c 2011-09-19 07:44:24 +0000
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-add-options double_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-outer-1.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-outer-1.c 2009-05-08 12:39:01 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-outer-1.c 2011-09-19 07:44:24 +0000
@@ -22,5 +22,6 @@
}
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-outer-1a.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-outer-1a.c 2009-06-16 06:21:12 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-outer-1a.c 2011-09-19 07:44:24 +0000
@@ -20,5 +20,6 @@
}
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-outer-1b.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-outer-1b.c 2007-08-19 11:02:48 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-outer-1b.c 2011-09-19 07:44:24 +0000
@@ -22,5 +22,6 @@
}
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-outer-2b.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-outer-2b.c 2009-05-08 12:39:01 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-outer-2b.c 2011-09-19 07:44:24 +0000
@@ -37,5 +37,6 @@
return 0;
}
-/* { dg-final { scan-tree-dump-times "strided access in outer loop." 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-outer-3a.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-outer-3a.c 2009-05-08 12:39:01 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-outer-3a.c 2011-09-19 07:44:24 +0000
@@ -49,5 +49,6 @@
}
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail vect_no_align } } } */
-/* { dg-final { scan-tree-dump-times "step doesn't divide the vector-size" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "step doesn't divide the vector-size" 2 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "step doesn't divide the vector-size" 3 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-outer-3b.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-outer-3b.c 2009-05-08 12:39:01 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-outer-3b.c 2011-09-19 07:44:24 +0000
@@ -49,5 +49,6 @@
}
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 2 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "strided access in outer loop" 4 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-outer-5.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-outer-5.c 2011-04-28 11:46:58 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-outer-5.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_float } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include <signal.h>
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-peel-1.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-peel-1.c 2011-01-10 12:41:40 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-peel-1.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-peel-2.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-peel-2.c 2011-01-10 12:41:40 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-peel-2.c 2011-09-19 07:44:24 +0000
@@ -1,5 +1,4 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-add-options quad_vectors } */
#include <stdarg.h>
#include "tree-vect.h"
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-peel-4.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-peel-4.c 2011-01-10 12:41:40 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-peel-4.c 2011-09-19 07:44:24 +0000
@@ -6,12 +6,12 @@
#define N 128
int ib[N+7];
+int ia[N+1];
__attribute__ ((noinline))
int main1 ()
{
int i;
- int ia[N+1];
/* Don't peel keeping one load and the store aligned. */
for (i = 0; i <= N; i++)
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8b.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8b.c 2010-05-27 12:23:45 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-reduc-dot-s8b.c 2011-09-19 07:44:24 +0000
@@ -58,7 +58,8 @@
}
/* { dg-final { scan-tree-dump-times "vect_recog_dot_prod_pattern: detected" 1 "vect" { xfail *-*-* } } } */
-/* { dg-final { scan-tree-dump-times "vect_recog_widen_mult_pattern: detected" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_widen_mult_pattern: detected" 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_widen_mult_pattern: detected" 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */
=== modified file 'gcc/testsuite/gfortran.dg/vect/pr19049.f90'
--- old/gcc/testsuite/gfortran.dg/vect/pr19049.f90 2005-07-25 11:05:07 +0000
+++ new/gcc/testsuite/gfortran.dg/vect/pr19049.f90 2011-09-19 07:44:24 +0000
@@ -19,6 +19,7 @@
end
! { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } }
-! { dg-final { scan-tree-dump-times "complicated access pattern" 1 "vect" } }
+! { dg-final { scan-tree-dump-times "complicated access pattern" 1 "vect" { xfail vect_multiple_sizes } } }
+! { dg-final { scan-tree-dump-times "complicated access pattern" 2 "vect" { target vect_multiple_sizes } } }
! { dg-final { cleanup-tree-dump "vect" } }
=== modified file 'gcc/testsuite/lib/target-supports.exp'
--- old/gcc/testsuite/lib/target-supports.exp 2011-08-13 08:32:32 +0000
+++ new/gcc/testsuite/lib/target-supports.exp 2011-09-20 07:54:28 +0000
@@ -3265,6 +3265,24 @@
}]
}
+# Return 1 if the target supports multiple vector sizes
+
+proc check_effective_target_vect_multiple_sizes { } {
+ global et_vect_multiple_sizes
+
+ if [info exists et_vect_multiple_sizes_saved] {
+ verbose "check_effective_target_vect_multiple_sizes: using cached result" 2
+ } else {
+ set et_vect_multiple_sizes_saved 0
+ if { ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok]) } {
+ set et_vect_multiple_sizes_saved 1
+ }
+ }
+
+ verbose "check_effective_target_vect_multiple_sizes: returning $et_vect_multiple_sizes_saved" 2
+ return $et_vect_multiple_sizes_saved
+}
+
# Return 1 if the target supports section-anchors
proc check_effective_target_section_anchors { } {
@@ -3648,11 +3666,11 @@
return $flags
}
-# Add to FLAGS the flags needed to enable 128-bit vectors.
+# Add to FLAGS the flags needed to enable 64-bit vectors.
-proc add_options_for_quad_vectors { flags } {
+proc add_options_for_double_vectors { flags } {
if [is-effective-target arm_neon_ok] {
- return "$flags -mvectorize-with-neon-quad"
+ return "$flags -mvectorize-with-neon-double"
}
return $flags
@@ -0,0 +1,387 @@
2011-09-28 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-09-28 Richard Sandiford <richard.sandiford@linaro.org>
* config/arm/neon.md (neon_move_lo_quad_<mode>): Delete.
(neon_move_hi_quad_<mode>): Likewise.
(move_hi_quad_<mode>, move_lo_quad_<mode>): Use subreg moves.
2011-09-28 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-09-27 Richard Sandiford <richard.sandiford@linaro.org>
* config/arm/neon.md (neon_vget_highv16qi, neon_vget_highv8hi)
(neon_vget_highv4si, neon_vget_highv4sf, neon_vget_highv2di)
(neon_vget_lowv16qi, neon_vget_lowv8hi, neon_vget_lowv4si)
(neon_vget_lowv4sf, neon_vget_lowv2di): Turn into define_expands
that produce subreg moves. Define using VQX iterators.
2011-09-28 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-09-14 Richard Sandiford <richard.sandiford@linaro.org>
* simplify-rtx.c (simplify_subreg): Check that the inner mode is
a scalar integer before applying integer-only optimisations to
inner arithmetic.
=== modified file 'gcc/config/arm/neon.md'
--- old/gcc/config/arm/neon.md 2011-07-04 14:03:49 +0000
+++ new/gcc/config/arm/neon.md 2011-09-28 15:14:59 +0000
@@ -1235,66 +1235,14 @@
(const_string "neon_int_1") (const_string "neon_int_5")))]
)
-; FIXME: We wouldn't need the following insns if we could write subregs of
-; vector registers. Make an attempt at removing unnecessary moves, though
-; we're really at the mercy of the register allocator.
-
-(define_insn "neon_move_lo_quad_<mode>"
- [(set (match_operand:ANY128 0 "s_register_operand" "+w")
- (vec_concat:ANY128
- (match_operand:<V_HALF> 1 "s_register_operand" "w")
- (vec_select:<V_HALF>
- (match_dup 0)
- (match_operand:ANY128 2 "vect_par_constant_high" ""))))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src)
- return "vmov\t%e0, %P1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_move_hi_quad_<mode>"
- [(set (match_operand:ANY128 0 "s_register_operand" "+w")
- (vec_concat:ANY128
- (vec_select:<V_HALF>
- (match_dup 0)
- (match_operand:ANY128 2 "vect_par_constant_low" ""))
- (match_operand:<V_HALF> 1 "s_register_operand" "w")))]
-
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src)
- return "vmov\t%f0, %P1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
(define_expand "move_hi_quad_<mode>"
[(match_operand:ANY128 0 "s_register_operand" "")
(match_operand:<V_HALF> 1 "s_register_operand" "")]
"TARGET_NEON"
{
- rtvec v = rtvec_alloc (<V_mode_nunits>/2);
- rtx t1;
- int i;
-
- for (i=0; i < (<V_mode_nunits>/2); i++)
- RTVEC_ELT (v, i) = GEN_INT (i);
-
- t1 = gen_rtx_PARALLEL (<MODE>mode, v);
- emit_insn (gen_neon_move_hi_quad_<mode> (operands[0], operands[1], t1));
-
+ emit_move_insn (simplify_gen_subreg (<V_HALF>mode, operands[0], <MODE>mode,
+ GET_MODE_SIZE (<V_HALF>mode)),
+ operands[1]);
DONE;
})
@@ -1303,16 +1251,9 @@
(match_operand:<V_HALF> 1 "s_register_operand" "")]
"TARGET_NEON"
{
- rtvec v = rtvec_alloc (<V_mode_nunits>/2);
- rtx t1;
- int i;
-
- for (i=0; i < (<V_mode_nunits>/2); i++)
- RTVEC_ELT (v, i) = GEN_INT ((<V_mode_nunits>/2) + i);
-
- t1 = gen_rtx_PARALLEL (<MODE>mode, v);
- emit_insn (gen_neon_move_lo_quad_<mode> (operands[0], operands[1], t1));
-
+ emit_move_insn (simplify_gen_subreg (<V_HALF>mode, operands[0],
+ <MODE>mode, 0),
+ operands[1]);
DONE;
})
@@ -2950,183 +2891,27 @@
(set_attr "neon_type" "neon_bp_simple")]
)
-(define_insn "neon_vget_highv16qi"
- [(set (match_operand:V8QI 0 "s_register_operand" "=w")
- (vec_select:V8QI (match_operand:V16QI 1 "s_register_operand" "w")
- (parallel [(const_int 8) (const_int 9)
- (const_int 10) (const_int 11)
- (const_int 12) (const_int 13)
- (const_int 14) (const_int 15)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src + 2)
- return "vmov\t%P0, %f1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_highv8hi"
- [(set (match_operand:V4HI 0 "s_register_operand" "=w")
- (vec_select:V4HI (match_operand:V8HI 1 "s_register_operand" "w")
- (parallel [(const_int 4) (const_int 5)
- (const_int 6) (const_int 7)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src + 2)
- return "vmov\t%P0, %f1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_highv4si"
- [(set (match_operand:V2SI 0 "s_register_operand" "=w")
- (vec_select:V2SI (match_operand:V4SI 1 "s_register_operand" "w")
- (parallel [(const_int 2) (const_int 3)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src + 2)
- return "vmov\t%P0, %f1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_highv4sf"
- [(set (match_operand:V2SF 0 "s_register_operand" "=w")
- (vec_select:V2SF (match_operand:V4SF 1 "s_register_operand" "w")
- (parallel [(const_int 2) (const_int 3)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src + 2)
- return "vmov\t%P0, %f1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_highv2di"
- [(set (match_operand:DI 0 "s_register_operand" "=w")
- (vec_select:DI (match_operand:V2DI 1 "s_register_operand" "w")
- (parallel [(const_int 1)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src + 2)
- return "vmov\t%P0, %f1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_lowv16qi"
- [(set (match_operand:V8QI 0 "s_register_operand" "=w")
- (vec_select:V8QI (match_operand:V16QI 1 "s_register_operand" "w")
- (parallel [(const_int 0) (const_int 1)
- (const_int 2) (const_int 3)
- (const_int 4) (const_int 5)
- (const_int 6) (const_int 7)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src)
- return "vmov\t%P0, %e1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_lowv8hi"
- [(set (match_operand:V4HI 0 "s_register_operand" "=w")
- (vec_select:V4HI (match_operand:V8HI 1 "s_register_operand" "w")
- (parallel [(const_int 0) (const_int 1)
- (const_int 2) (const_int 3)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src)
- return "vmov\t%P0, %e1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_lowv4si"
- [(set (match_operand:V2SI 0 "s_register_operand" "=w")
- (vec_select:V2SI (match_operand:V4SI 1 "s_register_operand" "w")
- (parallel [(const_int 0) (const_int 1)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src)
- return "vmov\t%P0, %e1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_lowv4sf"
- [(set (match_operand:V2SF 0 "s_register_operand" "=w")
- (vec_select:V2SF (match_operand:V4SF 1 "s_register_operand" "w")
- (parallel [(const_int 0) (const_int 1)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src)
- return "vmov\t%P0, %e1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
-
-(define_insn "neon_vget_lowv2di"
- [(set (match_operand:DI 0 "s_register_operand" "=w")
- (vec_select:DI (match_operand:V2DI 1 "s_register_operand" "w")
- (parallel [(const_int 0)])))]
- "TARGET_NEON"
-{
- int dest = REGNO (operands[0]);
- int src = REGNO (operands[1]);
-
- if (dest != src)
- return "vmov\t%P0, %e1";
- else
- return "";
-}
- [(set_attr "neon_type" "neon_bp_simple")]
-)
+(define_expand "neon_vget_high<mode>"
+ [(match_operand:<V_HALF> 0 "s_register_operand")
+ (match_operand:VQX 1 "s_register_operand")]
+ "TARGET_NEON"
+{
+ emit_move_insn (operands[0],
+ simplify_gen_subreg (<V_HALF>mode, operands[1], <MODE>mode,
+ GET_MODE_SIZE (<V_HALF>mode)));
+ DONE;
+})
+
+(define_expand "neon_vget_low<mode>"
+ [(match_operand:<V_HALF> 0 "s_register_operand")
+ (match_operand:VQX 1 "s_register_operand")]
+ "TARGET_NEON"
+{
+ emit_move_insn (operands[0],
+ simplify_gen_subreg (<V_HALF>mode, operands[1],
+ <MODE>mode, 0));
+ DONE;
+})
(define_insn "neon_vcvt<mode>"
[(set (match_operand:<V_CVTTO> 0 "s_register_operand" "=w")
=== modified file 'gcc/simplify-rtx.c'
--- old/gcc/simplify-rtx.c 2011-08-13 08:32:32 +0000
+++ new/gcc/simplify-rtx.c 2011-09-28 15:11:59 +0000
@@ -5567,6 +5567,7 @@
/* Optimize SUBREG truncations of zero and sign extended values. */
if ((GET_CODE (op) == ZERO_EXTEND
|| GET_CODE (op) == SIGN_EXTEND)
+ && SCALAR_INT_MODE_P (innermode)
&& GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode))
{
unsigned int bitpos = subreg_lsb_1 (outermode, innermode, byte);
@@ -5605,6 +5606,7 @@
if ((GET_CODE (op) == LSHIFTRT
|| GET_CODE (op) == ASHIFTRT)
&& SCALAR_INT_MODE_P (outermode)
+ && SCALAR_INT_MODE_P (innermode)
/* Ensure that OUTERMODE is at least twice as wide as the INNERMODE
to avoid the possibility that an outer LSHIFTRT shifts by more
than the sign extension's sign_bit_copies and introduces zeros
@@ -5624,6 +5626,7 @@
if ((GET_CODE (op) == LSHIFTRT
|| GET_CODE (op) == ASHIFTRT)
&& SCALAR_INT_MODE_P (outermode)
+ && SCALAR_INT_MODE_P (innermode)
&& GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
&& CONST_INT_P (XEXP (op, 1))
&& GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
@@ -5638,6 +5641,7 @@
the outer subreg is effectively a truncation to the original mode. */
if (GET_CODE (op) == ASHIFT
&& SCALAR_INT_MODE_P (outermode)
+ && SCALAR_INT_MODE_P (innermode)
&& GET_MODE_BITSIZE (outermode) < GET_MODE_BITSIZE (innermode)
&& CONST_INT_P (XEXP (op, 1))
&& (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND
@@ -5651,7 +5655,7 @@
/* Recognize a word extraction from a multi-word subreg. */
if ((GET_CODE (op) == LSHIFTRT
|| GET_CODE (op) == ASHIFTRT)
- && SCALAR_INT_MODE_P (outermode)
+ && SCALAR_INT_MODE_P (innermode)
&& GET_MODE_BITSIZE (outermode) >= BITS_PER_WORD
&& GET_MODE_BITSIZE (innermode) >= (2 * GET_MODE_BITSIZE (outermode))
&& CONST_INT_P (XEXP (op, 1))
@@ -5673,6 +5677,7 @@
if ((GET_CODE (op) == LSHIFTRT
|| GET_CODE (op) == ASHIFTRT)
+ && SCALAR_INT_MODE_P (innermode)
&& MEM_P (XEXP (op, 0))
&& CONST_INT_P (XEXP (op, 1))
&& GET_MODE_SIZE (outermode) < GET_MODE_SIZE (GET_MODE (op))
@@ -0,0 +1,290 @@
2011-10-01 Revital Eres <revital.eres@linaro.org>
gcc/
Backport from mainline -r179380 and -r179381
* ddg.c (autoinc_var_is_used_p): New function.
(create_ddg_dep_from_intra_loop_link,
add_cross_iteration_register_deps): Call it.
* ddg.h (autoinc_var_is_used_p): Declare.
* modulo-sched.c (sms_schedule): Handle instructions with REG_INC.
(generate_reg_moves): Call autoinc_var_is_used_p. Skip
instructions that do not set a register and verify no regmoves
are created for !single_set instructions.
gcc/testsuite/
* gcc.dg/sms-10.c: New file
=== modified file 'gcc/ddg.c'
--- old/gcc/ddg.c 2011-07-31 11:29:10 +0000
+++ new/gcc/ddg.c 2011-10-02 06:56:53 +0000
@@ -145,6 +145,27 @@
return rtx_mem_access_p (PATTERN (insn));
}
+/* Return true if DEF_INSN contains address being auto-inc or auto-dec
+ which is used in USE_INSN. Otherwise return false. The result is
+ being used to decide whether to remove the edge between def_insn and
+ use_insn when -fmodulo-sched-allow-regmoves is set. This function
+ doesn't need to consider the specific address register; no reg_moves
+ will be allowed for any life range defined by def_insn and used
+ by use_insn, if use_insn uses an address register auto-inc'ed by
+ def_insn. */
+bool
+autoinc_var_is_used_p (rtx def_insn, rtx use_insn)
+{
+ rtx note;
+
+ for (note = REG_NOTES (def_insn); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_INC
+ && reg_referenced_p (XEXP (note, 0), PATTERN (use_insn)))
+ return true;
+
+ return false;
+}
+
/* Computes the dependence parameters (latency, distance etc.), creates
a ddg_edge and adds it to the given DDG. */
static void
@@ -173,10 +194,15 @@
compensate for that by generating reg-moves based on the life-range
analysis. The anti-deps that will be deleted are the ones which
have true-deps edges in the opposite direction (in other words
- the kernel has only one def of the relevant register). TODO:
- support the removal of all anti-deps edges, i.e. including those
+ the kernel has only one def of the relevant register).
+ If the address that is being auto-inc or auto-dec in DEST_NODE
+ is used in SRC_NODE then do not remove the edge to make sure
+ reg-moves will not be created for this address.
+ TODO: support the removal of all anti-deps edges, i.e. including those
whose register has multiple defs in the loop. */
- if (flag_modulo_sched_allow_regmoves && (t == ANTI_DEP && dt == REG_DEP))
+ if (flag_modulo_sched_allow_regmoves
+ && (t == ANTI_DEP && dt == REG_DEP)
+ && !autoinc_var_is_used_p (dest_node->insn, src_node->insn))
{
rtx set;
@@ -302,10 +328,14 @@
gcc_assert (first_def_node);
/* Always create the edge if the use node is a branch in
- order to prevent the creation of reg-moves. */
+ order to prevent the creation of reg-moves.
+ If the address that is being auto-inc or auto-dec in LAST_DEF
+ is used in USE_INSN then do not remove the edge to make sure
+ reg-moves will not be created for that address. */
if (DF_REF_ID (last_def) != DF_REF_ID (first_def)
|| !flag_modulo_sched_allow_regmoves
- || JUMP_P (use_node->insn))
+ || JUMP_P (use_node->insn)
+ || autoinc_var_is_used_p (DF_REF_INSN (last_def), use_insn))
create_ddg_dep_no_link (g, use_node, first_def_node, ANTI_DEP,
REG_DEP, 1);
=== modified file 'gcc/ddg.h'
--- old/gcc/ddg.h 2009-11-25 10:55:54 +0000
+++ new/gcc/ddg.h 2011-10-02 06:56:53 +0000
@@ -186,4 +186,6 @@
int find_nodes_on_paths (sbitmap result, ddg_ptr, sbitmap from, sbitmap to);
int longest_simple_path (ddg_ptr, int from, int to, sbitmap via);
+bool autoinc_var_is_used_p (rtx, rtx);
+
#endif /* GCC_DDG_H */
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-09-14 11:06:06 +0000
+++ new/gcc/modulo-sched.c 2011-10-02 06:56:53 +0000
@@ -477,7 +477,12 @@
sbitmap *uses_of_defs;
rtx last_reg_move;
rtx prev_reg, old_reg;
-
+ rtx set = single_set (u->insn);
+
+ /* Skip instructions that do not set a register. */
+ if ((set && !REG_P (SET_DEST (set))))
+ continue;
+
/* Compute the number of reg_moves needed for u, by looking at life
ranges started at u (excluding self-loops). */
for (e = u->out; e; e = e->next_out)
@@ -494,6 +499,20 @@
&& SCHED_COLUMN (e->dest) < SCHED_COLUMN (e->src))
nreg_moves4e--;
+ if (nreg_moves4e >= 1)
+ {
+ /* !single_set instructions are not supported yet and
+ thus we do not except to encounter them in the loop
+ except from the doloop part. For the latter case
+ we assume no regmoves are generated as the doloop
+ instructions are tied to the branch with an edge. */
+ gcc_assert (set);
+ /* If the instruction contains auto-inc register then
+ validate that the regmov is being generated for the
+ target regsiter rather then the inc'ed register. */
+ gcc_assert (!autoinc_var_is_used_p (u->insn, e->dest->insn));
+ }
+
nreg_moves = MAX (nreg_moves, nreg_moves4e);
}
@@ -1266,12 +1285,10 @@
continue;
}
- /* Don't handle BBs with calls or barriers or auto-increment insns
- (to avoid creating invalid reg-moves for the auto-increment insns),
+ /* Don't handle BBs with calls or barriers
or !single_set with the exception of instructions that include
count_reg---these instructions are part of the control part
that do-loop recognizes.
- ??? Should handle auto-increment insns.
??? Should handle insns defining subregs. */
for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
{
@@ -1282,7 +1299,6 @@
|| (NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
&& !single_set (insn) && GET_CODE (PATTERN (insn)) != USE
&& !reg_mentioned_p (count_reg, insn))
- || (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
|| (INSN_P (insn) && (set = single_set (insn))
&& GET_CODE (SET_DEST (set)) == SUBREG))
break;
@@ -1296,8 +1312,6 @@
fprintf (dump_file, "SMS loop-with-call\n");
else if (BARRIER_P (insn))
fprintf (dump_file, "SMS loop-with-barrier\n");
- else if (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
- fprintf (dump_file, "SMS reg inc\n");
else if ((NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
&& !single_set (insn) && GET_CODE (PATTERN (insn)) != USE))
fprintf (dump_file, "SMS loop-with-not-single-set\n");
=== added file 'gcc/testsuite/gcc.dg/sms-10.c'
--- old/gcc/testsuite/gcc.dg/sms-10.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/sms-10.c 2011-10-02 06:56:53 +0000
@@ -0,0 +1,118 @@
+ /* { dg-do run } */
+ /* { dg-options "-O2 -fmodulo-sched -fmodulo-sched-allow-regmoves -fdump-rtl-sms" } */
+
+
+typedef __SIZE_TYPE__ size_t;
+extern void *malloc (size_t);
+extern void free (void *);
+extern void abort (void);
+
+struct regstat_n_sets_and_refs_t
+{
+ int sets;
+ int refs;
+};
+
+struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
+
+struct df_reg_info
+{
+ unsigned int n_refs;
+};
+
+struct df_d
+{
+ struct df_reg_info **def_regs;
+ struct df_reg_info **use_regs;
+};
+struct df_d *df;
+
+static inline int
+REG_N_SETS (int regno)
+{
+ return regstat_n_sets_and_refs[regno].sets;
+}
+
+__attribute__ ((noinline))
+ int max_reg_num (void)
+{
+ return 100;
+}
+
+__attribute__ ((noinline))
+ void regstat_init_n_sets_and_refs (void)
+{
+ unsigned int i;
+ unsigned int max_regno = max_reg_num ();
+
+ for (i = 0; i < max_regno; i++)
+ {
+ (regstat_n_sets_and_refs[i].sets = (df->def_regs[(i)]->n_refs));
+ (regstat_n_sets_and_refs[i].refs =
+ (df->use_regs[(i)]->n_refs) + REG_N_SETS (i));
+ }
+}
+
+int a_sets[100] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+ 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
+};
+
+int a_refs[100] =
+ { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38,
+ 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76,
+ 78, 80, 82,
+ 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116,
+ 118, 120,
+ 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150,
+ 152, 154, 156,
+ 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186,
+ 188, 190, 192,
+ 194, 196, 198
+};
+
+int
+main ()
+{
+ struct df_reg_info *b[100], *c[100];
+ struct df_d df1;
+ size_t s = sizeof (struct df_reg_info);
+ struct regstat_n_sets_and_refs_t a[100];
+
+ df = &df1;
+ regstat_n_sets_and_refs = a;
+ int i;
+
+ for (i = 0; i < 100; i++)
+ {
+ b[i] = (struct df_reg_info *) malloc (s);
+ b[i]->n_refs = i;
+ c[i] = (struct df_reg_info *) malloc (s);
+ c[i]->n_refs = i;
+ }
+
+ df1.def_regs = b;
+ df1.use_regs = c;
+ regstat_init_n_sets_and_refs ();
+
+ for (i = 0; i < 100; i++)
+ if ((a[i].sets != a_sets[i]) || (a[i].refs != a_refs[i]))
+ abort ();
+
+ for (i = 0; i < 100; i++)
+ {
+ free (b[i]);
+ free (c[i]);
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-rtl-dump-times "SMS succeeded" 1 "sms" { target powerpc*-*-* } } } */
+/* { dg-final { cleanup-rtl-dump "sms" } } */
@@ -0,0 +1,105 @@
2011-10-03 Michael Hope <michael.hope@linaro.org>
Backport from mainline:
2011-09-13 Sevak Sargsyan <sevak.sargsyan@ispras.ru>
gcc/
* config/arm/neon.md (neon_vabd<mode>_2, neon_vabd<mode>_3): New
define_insn patterns for combine.
gcc/testsuite/
* gcc.target/arm/neon-combine-sub-abs-into-vabd.c: New test.
=== modified file 'gcc/config/arm/neon.md'
--- old/gcc/config/arm/neon.md 2011-09-28 15:14:59 +0000
+++ new/gcc/config/arm/neon.md 2011-10-03 01:32:17 +0000
@@ -5428,3 +5428,32 @@
emit_insn (gen_neon_vec_pack_trunc_<V_double> (operands[0], tempreg));
DONE;
})
+
+(define_insn "neon_vabd<mode>_2"
+ [(set (match_operand:VDQ 0 "s_register_operand" "=w")
+ (abs:VDQ (minus:VDQ (match_operand:VDQ 1 "s_register_operand" "w")
+ (match_operand:VDQ 2 "s_register_operand" "w"))))]
+ "TARGET_NEON && (!<Is_float_mode> || flag_unsafe_math_optimizations)"
+ "vabd.<V_s_elem> %<V_reg>0, %<V_reg>1, %<V_reg>2"
+ [(set (attr "neon_type")
+ (if_then_else (ne (symbol_ref "<Is_float_mode>") (const_int 0))
+ (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+ (const_string "neon_fp_vadd_ddd_vabs_dd")
+ (const_string "neon_fp_vadd_qqq_vabs_qq"))
+ (const_string "neon_int_5")))]
+)
+
+(define_insn "neon_vabd<mode>_3"
+ [(set (match_operand:VDQ 0 "s_register_operand" "=w")
+ (abs:VDQ (unspec:VDQ [(match_operand:VDQ 1 "s_register_operand" "w")
+ (match_operand:VDQ 2 "s_register_operand" "w")]
+ UNSPEC_VSUB)))]
+ "TARGET_NEON && (!<Is_float_mode> || flag_unsafe_math_optimizations)"
+ "vabd.<V_if_elem> %<V_reg>0, %<V_reg>1, %<V_reg>2"
+ [(set (attr "neon_type")
+ (if_then_else (ne (symbol_ref "<Is_float_mode>") (const_int 0))
+ (if_then_else (ne (symbol_ref "<Is_d_reg>") (const_int 0))
+ (const_string "neon_fp_vadd_ddd_vabs_dd")
+ (const_string "neon_fp_vadd_qqq_vabs_qq"))
+ (const_string "neon_int_5")))]
+)
=== added file 'gcc/testsuite/gcc.target/arm/neon-combine-sub-abs-into-vabd.c'
--- old/gcc/testsuite/gcc.target/arm/neon-combine-sub-abs-into-vabd.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/neon-combine-sub-abs-into-vabd.c 2011-10-03 01:32:17 +0000
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 -funsafe-math-optimizations" } */
+/* { dg-add-options arm_neon } */
+
+#include <arm_neon.h>
+float32x2_t f_sub_abs_to_vabd_32()
+{
+ float32x2_t val1 = vdup_n_f32 (10);
+ float32x2_t val2 = vdup_n_f32 (30);
+ float32x2_t sres = vsub_f32(val1, val2);
+ float32x2_t res = vabs_f32 (sres);
+
+ return res;
+}
+/* { dg-final { scan-assembler "vabd\.f32" } }*/
+
+#include <arm_neon.h>
+int8x8_t sub_abs_to_vabd_8()
+{
+ int8x8_t val1 = vdup_n_s8 (10);
+ int8x8_t val2 = vdup_n_s8 (30);
+ int8x8_t sres = vsub_s8(val1, val2);
+ int8x8_t res = vabs_s8 (sres);
+
+ return res;
+}
+/* { dg-final { scan-assembler "vabd\.s8" } }*/
+
+int16x4_t sub_abs_to_vabd_16()
+{
+ int16x4_t val1 = vdup_n_s16 (10);
+ int16x4_t val2 = vdup_n_s16 (30);
+ int16x4_t sres = vsub_s16(val1, val2);
+ int16x4_t res = vabs_s16 (sres);
+
+ return res;
+}
+/* { dg-final { scan-assembler "vabd\.s16" } }*/
+
+int32x2_t sub_abs_to_vabd_32()
+{
+ int32x2_t val1 = vdup_n_s32 (10);
+ int32x2_t val2 = vdup_n_s32 (30);
+ int32x2_t sres = vsub_s32(val1, val2);
+ int32x2_t res = vabs_s32 (sres);
+
+ return res;
+}
+/* { dg-final { scan-assembler "vabd\.s32" } }*/
@@ -0,0 +1,436 @@
2011-10-03 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-09-22 Richard Sandiford <richard.sandiford@linaro.org>
* config/arm/predicates.md (expandable_comparison_operator): New
predicate, extracted from...
(arm_comparison_operator): ...here.
* config/arm/arm.md (cbranchsi4, cbranchsf4, cbranchdf4, cbranchdi4)
(cstoresi4, cstoresf4, cstoredf4, cstoredi4, movsicc, movsfcc)
(movdfcc): Use expandable_comparison_operator.
gcc/testsuite/
Backport from mainline:
2011-09-22 Richard Sandiford <richard.sandiford@linaro.org>
* gcc.target/arm/cmp-1.c: New test.
* gcc.target/arm/cmp-2.c: Likewise.
2011-10-03 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
Backport from mainline:
2011-09-07 Richard Sandiford <richard.sandiford@linaro.org>
PR target/49030
* config/arm/arm-protos.h (maybe_get_arm_condition_code): Declare.
* config/arm/arm.c (maybe_get_arm_condition_code): New function,
reusing the old code from get_arm_condition_code. Return ARM_NV
for invalid comparison codes.
(get_arm_condition_code): Redefine in terms of
maybe_get_arm_condition_code.
* config/arm/predicates.md (arm_comparison_operator): Use
maybe_get_arm_condition_code.
gcc/testsuite/
Backport from mainline:
2011-09-07 Richard Sandiford <richard.sandiford@linaro.org>
PR target/49030
* gcc.dg/torture/pr49030.c: New test.
=== modified file 'gcc/config/arm/arm-protos.h'
--- old/gcc/config/arm/arm-protos.h 2011-09-15 09:45:31 +0000
+++ new/gcc/config/arm/arm-protos.h 2011-10-03 09:46:40 +0000
@@ -180,6 +180,7 @@
#endif
extern int thumb_shiftable_const (unsigned HOST_WIDE_INT);
#ifdef RTX_CODE
+extern enum arm_cond_code maybe_get_arm_condition_code (rtx);
extern void thumb1_final_prescan_insn (rtx);
extern void thumb2_final_prescan_insn (rtx);
extern const char *thumb_load_double_from_address (rtx *);
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-09-19 07:44:24 +0000
+++ new/gcc/config/arm/arm.c 2011-10-03 09:46:40 +0000
@@ -17494,10 +17494,10 @@
decremented/zeroed by arm_asm_output_opcode as the insns are output. */
/* Returns the index of the ARM condition code string in
- `arm_condition_codes'. COMPARISON should be an rtx like
- `(eq (...) (...))'. */
-static enum arm_cond_code
-get_arm_condition_code (rtx comparison)
+ `arm_condition_codes', or ARM_NV if the comparison is invalid.
+ COMPARISON should be an rtx like `(eq (...) (...))'. */
+enum arm_cond_code
+maybe_get_arm_condition_code (rtx comparison)
{
enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
enum arm_cond_code code;
@@ -17521,11 +17521,11 @@
case CC_DLTUmode: code = ARM_CC;
dominance:
- gcc_assert (comp_code == EQ || comp_code == NE);
-
if (comp_code == EQ)
return ARM_INVERSE_CONDITION_CODE (code);
- return code;
+ if (comp_code == NE)
+ return code;
+ return ARM_NV;
case CC_NOOVmode:
switch (comp_code)
@@ -17534,7 +17534,7 @@
case EQ: return ARM_EQ;
case GE: return ARM_PL;
case LT: return ARM_MI;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_Zmode:
@@ -17542,7 +17542,7 @@
{
case NE: return ARM_NE;
case EQ: return ARM_EQ;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_Nmode:
@@ -17550,7 +17550,7 @@
{
case NE: return ARM_MI;
case EQ: return ARM_PL;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CCFPEmode:
@@ -17575,7 +17575,7 @@
/* UNEQ and LTGT do not have a representation. */
case UNEQ: /* Fall through. */
case LTGT: /* Fall through. */
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_SWPmode:
@@ -17591,7 +17591,7 @@
case GTU: return ARM_CC;
case LEU: return ARM_CS;
case LTU: return ARM_HI;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_Cmode:
@@ -17599,7 +17599,7 @@
{
case LTU: return ARM_CS;
case GEU: return ARM_CC;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_CZmode:
@@ -17611,7 +17611,7 @@
case GTU: return ARM_HI;
case LEU: return ARM_LS;
case LTU: return ARM_CC;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CC_NCVmode:
@@ -17621,7 +17621,7 @@
case LT: return ARM_LT;
case GEU: return ARM_CS;
case LTU: return ARM_CC;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
case CCmode:
@@ -17637,13 +17637,22 @@
case GTU: return ARM_HI;
case LEU: return ARM_LS;
case LTU: return ARM_CC;
- default: gcc_unreachable ();
+ default: return ARM_NV;
}
default: gcc_unreachable ();
}
}
+/* Like maybe_get_arm_condition_code, but never return ARM_NV. */
+static enum arm_cond_code
+get_arm_condition_code (rtx comparison)
+{
+ enum arm_cond_code code = maybe_get_arm_condition_code (comparison);
+ gcc_assert (code != ARM_NV);
+ return code;
+}
+
/* Tell arm_asm_output_opcode to output IT blocks for conditionally executed
instructions. */
void
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2011-09-12 14:14:00 +0000
+++ new/gcc/config/arm/arm.md 2011-10-03 09:47:33 +0000
@@ -6543,7 +6543,7 @@
(define_expand "cbranchsi4"
[(set (pc) (if_then_else
- (match_operator 0 "arm_comparison_operator"
+ (match_operator 0 "expandable_comparison_operator"
[(match_operand:SI 1 "s_register_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")])
(label_ref (match_operand 3 "" ""))
@@ -6594,7 +6594,7 @@
(define_expand "cbranchsf4"
[(set (pc) (if_then_else
- (match_operator 0 "arm_comparison_operator"
+ (match_operator 0 "expandable_comparison_operator"
[(match_operand:SF 1 "s_register_operand" "")
(match_operand:SF 2 "arm_float_compare_operand" "")])
(label_ref (match_operand 3 "" ""))
@@ -6606,7 +6606,7 @@
(define_expand "cbranchdf4"
[(set (pc) (if_then_else
- (match_operator 0 "arm_comparison_operator"
+ (match_operator 0 "expandable_comparison_operator"
[(match_operand:DF 1 "s_register_operand" "")
(match_operand:DF 2 "arm_float_compare_operand" "")])
(label_ref (match_operand 3 "" ""))
@@ -6618,7 +6618,7 @@
(define_expand "cbranchdi4"
[(set (pc) (if_then_else
- (match_operator 0 "arm_comparison_operator"
+ (match_operator 0 "expandable_comparison_operator"
[(match_operand:DI 1 "cmpdi_operand" "")
(match_operand:DI 2 "cmpdi_operand" "")])
(label_ref (match_operand 3 "" ""))
@@ -7473,7 +7473,7 @@
(define_expand "cstoresi4"
[(set (match_operand:SI 0 "s_register_operand" "")
- (match_operator:SI 1 "arm_comparison_operator"
+ (match_operator:SI 1 "expandable_comparison_operator"
[(match_operand:SI 2 "s_register_operand" "")
(match_operand:SI 3 "reg_or_int_operand" "")]))]
"TARGET_32BIT || TARGET_THUMB1"
@@ -7609,7 +7609,7 @@
(define_expand "cstoresf4"
[(set (match_operand:SI 0 "s_register_operand" "")
- (match_operator:SI 1 "arm_comparison_operator"
+ (match_operator:SI 1 "expandable_comparison_operator"
[(match_operand:SF 2 "s_register_operand" "")
(match_operand:SF 3 "arm_float_compare_operand" "")]))]
"TARGET_32BIT && TARGET_HARD_FLOAT"
@@ -7619,7 +7619,7 @@
(define_expand "cstoredf4"
[(set (match_operand:SI 0 "s_register_operand" "")
- (match_operator:SI 1 "arm_comparison_operator"
+ (match_operator:SI 1 "expandable_comparison_operator"
[(match_operand:DF 2 "s_register_operand" "")
(match_operand:DF 3 "arm_float_compare_operand" "")]))]
"TARGET_32BIT && TARGET_HARD_FLOAT && !TARGET_VFP_SINGLE"
@@ -7629,7 +7629,7 @@
(define_expand "cstoredi4"
[(set (match_operand:SI 0 "s_register_operand" "")
- (match_operator:SI 1 "arm_comparison_operator"
+ (match_operator:SI 1 "expandable_comparison_operator"
[(match_operand:DI 2 "cmpdi_operand" "")
(match_operand:DI 3 "cmpdi_operand" "")]))]
"TARGET_32BIT"
@@ -7749,7 +7749,7 @@
(define_expand "movsicc"
[(set (match_operand:SI 0 "s_register_operand" "")
- (if_then_else:SI (match_operand 1 "arm_comparison_operator" "")
+ (if_then_else:SI (match_operand 1 "expandable_comparison_operator" "")
(match_operand:SI 2 "arm_not_operand" "")
(match_operand:SI 3 "arm_not_operand" "")))]
"TARGET_32BIT"
@@ -7769,7 +7769,7 @@
(define_expand "movsfcc"
[(set (match_operand:SF 0 "s_register_operand" "")
- (if_then_else:SF (match_operand 1 "arm_comparison_operator" "")
+ (if_then_else:SF (match_operand 1 "expandable_comparison_operator" "")
(match_operand:SF 2 "s_register_operand" "")
(match_operand:SF 3 "nonmemory_operand" "")))]
"TARGET_32BIT && TARGET_HARD_FLOAT"
@@ -7795,7 +7795,7 @@
(define_expand "movdfcc"
[(set (match_operand:DF 0 "s_register_operand" "")
- (if_then_else:DF (match_operand 1 "arm_comparison_operator" "")
+ (if_then_else:DF (match_operand 1 "expandable_comparison_operator" "")
(match_operand:DF 2 "s_register_operand" "")
(match_operand:DF 3 "arm_float_add_operand" "")))]
"TARGET_32BIT && TARGET_HARD_FLOAT && (TARGET_FPA || TARGET_VFP_DOUBLE)"
=== modified file 'gcc/config/arm/predicates.md'
--- old/gcc/config/arm/predicates.md 2011-09-15 09:45:31 +0000
+++ new/gcc/config/arm/predicates.md 2011-10-03 09:47:33 +0000
@@ -242,11 +242,15 @@
;; True for integer comparisons and, if FP is active, for comparisons
;; other than LTGT or UNEQ.
+(define_special_predicate "expandable_comparison_operator"
+ (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,
+ unordered,ordered,unlt,unle,unge,ungt"))
+
+;; Likewise, but only accept comparisons that are directly supported
+;; by ARM condition codes.
(define_special_predicate "arm_comparison_operator"
- (ior (match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu")
- (and (match_test "TARGET_32BIT && TARGET_HARD_FLOAT
- && (TARGET_FPA || TARGET_VFP)")
- (match_code "unordered,ordered,unlt,unle,unge,ungt"))))
+ (and (match_operand 0 "expandable_comparison_operator")
+ (match_test "maybe_get_arm_condition_code (op) != ARM_NV")))
(define_special_predicate "lt_ge_comparison_operator"
(match_code "lt,ge"))
=== added file 'gcc/testsuite/gcc.dg/torture/pr49030.c'
--- old/gcc/testsuite/gcc.dg/torture/pr49030.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/torture/pr49030.c 2011-10-03 09:46:40 +0000
@@ -0,0 +1,19 @@
+void
+sample_move_d32u24_sS (char *dst, float *src, unsigned long nsamples,
+ unsigned long dst_skip)
+{
+ long long y;
+ while (nsamples--)
+ {
+ y = (long long) (*src * 8388608.0f) << 8;
+ if (y > 2147483647) {
+ *(int *) dst = 2147483647;
+ } else if (y < -2147483647 - 1) {
+ *(int *) dst = -2147483647 - 1;
+ } else {
+ *(int *) dst = (int) y;
+ }
+ dst += dst_skip;
+ src++;
+ }
+}
=== added file 'gcc/testsuite/gcc.target/arm/cmp-1.c'
--- old/gcc/testsuite/gcc.target/arm/cmp-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/cmp-1.c 2011-10-03 09:47:33 +0000
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+/* { dg-final { scan-assembler-not "\tbl\t" } } */
+/* { dg-final { scan-assembler-not "__aeabi" } } */
+int x, y;
+
+#define TEST_EXPR(NAME, ARGS, EXPR) \
+ int NAME##1 ARGS { return (EXPR); } \
+ int NAME##2 ARGS { return !(EXPR); } \
+ int NAME##3 ARGS { return (EXPR) ? x : y; } \
+ void NAME##4 ARGS { if (EXPR) x++; } \
+ void NAME##5 ARGS { if (!(EXPR)) x++; }
+
+#define TEST(NAME, TYPE, OPERATOR) \
+ TEST_EXPR (NAME##_rr, (TYPE a1, TYPE a2), a1 OPERATOR a2) \
+ TEST_EXPR (NAME##_rm, (TYPE a1, TYPE *a2), a1 OPERATOR *a2) \
+ TEST_EXPR (NAME##_mr, (TYPE *a1, TYPE a2), *a1 OPERATOR a2) \
+ TEST_EXPR (NAME##_mm, (TYPE *a1, TYPE *a2), *a1 OPERATOR *a2) \
+ TEST_EXPR (NAME##_rc, (TYPE a1), a1 OPERATOR 100) \
+ TEST_EXPR (NAME##_cr, (TYPE a1), 100 OPERATOR a1)
+
+#define TEST_OP(NAME, OPERATOR) \
+ TEST (sc_##NAME, signed char, OPERATOR) \
+ TEST (uc_##NAME, unsigned char, OPERATOR) \
+ TEST (ss_##NAME, short, OPERATOR) \
+ TEST (us_##NAME, unsigned short, OPERATOR) \
+ TEST (si_##NAME, int, OPERATOR) \
+ TEST (ui_##NAME, unsigned int, OPERATOR) \
+ TEST (sll_##NAME, long long, OPERATOR) \
+ TEST (ull_##NAME, unsigned long long, OPERATOR)
+
+TEST_OP (eq, ==)
+TEST_OP (ne, !=)
+TEST_OP (lt, <)
+TEST_OP (gt, >)
+TEST_OP (le, <=)
+TEST_OP (ge, >=)
=== added file 'gcc/testsuite/gcc.target/arm/cmp-2.c'
--- old/gcc/testsuite/gcc.target/arm/cmp-2.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/cmp-2.c 2011-10-03 09:47:33 +0000
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_vfp_ok } */
+/* { dg-skip-if "need fp instructions" { *-*-* } { "-mfloat-abi=soft" } { "" } } */
+/* { dg-options "-O -mfpu=vfp -mfloat-abi=softfp" } */
+/* { dg-final { scan-assembler-not "\tbl\t" } } */
+/* { dg-final { scan-assembler-not "__aeabi" } } */
+int x, y;
+
+#define EQ(X, Y) ((X) == (Y))
+#define NE(X, Y) ((X) != (Y))
+#define LT(X, Y) ((X) < (Y))
+#define GT(X, Y) ((X) > (Y))
+#define LE(X, Y) ((X) <= (Y))
+#define GE(X, Y) ((X) >= (Y))
+
+#define TEST_EXPR(NAME, ARGS, EXPR) \
+ int NAME##1 ARGS { return (EXPR); } \
+ int NAME##2 ARGS { return !(EXPR); } \
+ int NAME##3 ARGS { return (EXPR) ? x : y; } \
+ void NAME##4 ARGS { if (EXPR) x++; } \
+ void NAME##5 ARGS { if (!(EXPR)) x++; }
+
+#define TEST(NAME, TYPE, OPERATOR) \
+ TEST_EXPR (NAME##_rr, (TYPE a1, TYPE a2), OPERATOR (a1, a2)) \
+ TEST_EXPR (NAME##_rm, (TYPE a1, TYPE *a2), OPERATOR (a1, *a2)) \
+ TEST_EXPR (NAME##_mr, (TYPE *a1, TYPE a2), OPERATOR (*a1, a2)) \
+ TEST_EXPR (NAME##_mm, (TYPE *a1, TYPE *a2), OPERATOR (*a1, *a2)) \
+ TEST_EXPR (NAME##_rc, (TYPE a1), OPERATOR (a1, 100)) \
+ TEST_EXPR (NAME##_cr, (TYPE a1), OPERATOR (100, a1))
+
+#define TEST_OP(NAME, OPERATOR) \
+ TEST (f_##NAME, float, OPERATOR) \
+ TEST (d_##NAME, double, OPERATOR) \
+ TEST (ld_##NAME, long double, OPERATOR)
+
+TEST_OP (eq, EQ)
+TEST_OP (ne, NE)
+TEST_OP (lt, LT)
+TEST_OP (gt, GT)
+TEST_OP (le, LE)
+TEST_OP (ge, GE)
+TEST_OP (blt, __builtin_isless)
+TEST_OP (bgt, __builtin_isgreater)
+TEST_OP (ble, __builtin_islessequal)
+TEST_OP (bge, __builtin_isgreaterequal)
+/* This one should be expanded into separate ordered and equality
+ comparisons. */
+TEST_OP (blg, __builtin_islessgreater)
+TEST_OP (bun, __builtin_isunordered)
@@ -0,0 +1,378 @@
2011-10-06 Ira Rosen <ira.rosen@linaro.org>
Backport from mainline:
2011-09-25 Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-data-ref.c (dr_analyze_innermost): Add new argument.
Allow not simple iv if analyzing basic block.
(create_data_ref): Update call to dr_analyze_innermost.
(stmt_with_adjacent_zero_store_dr_p, ref_base_address): Likewise.
* tree-loop-distribution.c (generate_memset_zero): Likewise.
* tree-predcom.c (find_looparound_phi): Likewise.
* tree-data-ref.h (dr_analyze_innermost): Add new argument.
gcc/testsuite/
* gcc.dg/vect/bb-slp-24.c: New.
2011-09-15 Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-vect-data-refs.c (vect_analyze_data_ref_dependence): Allow
read-after-read dependencies in basic block SLP.
gcc/testsuite/
* gcc.dg/vect/bb-slp-25.c: New.
2011-04-21 Richard Sandiford <richard.sandiford@linaro.org>
gcc/
* tree-vect-data-refs.c (vect_drs_dependent_in_basic_block): Use
operand_equal_p to compare DR_BASE_ADDRESSes.
(vect_check_interleaving): Likewise.
gcc/testsuite/
* gcc.dg/vect/vect-119.c: New test.
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-24.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-24.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-24.c 2011-10-02 08:43:10 +0000
@@ -0,0 +1,59 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define A 3
+#define N 256
+
+short src[N], dst[N];
+
+void foo (short * __restrict__ dst, short * __restrict__ src, int h,
+ int stride, int dummy)
+{
+ int i;
+ h /= 8;
+ for (i = 0; i < h; i++)
+ {
+ dst[0] += A*src[0];
+ dst[1] += A*src[1];
+ dst[2] += A*src[2];
+ dst[3] += A*src[3];
+ dst[4] += A*src[4];
+ dst[5] += A*src[5];
+ dst[6] += A*src[6];
+ dst[7] += A*src[7];
+ dst += stride;
+ src += stride;
+ if (dummy == 32)
+ abort ();
+ }
+}
+
+
+int main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ dst[i] = 0;
+ src[i] = i;
+ }
+
+ foo (dst, src, N, 8, 0);
+
+ for (i = 0; i < N; i++)
+ {
+ if (dst[i] != A * i)
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target vect_element_align } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-25.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-25.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-25.c 2011-10-02 08:43:10 +0000
@@ -0,0 +1,59 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define A 3
+#define B 4
+#define N 256
+
+short src[N], dst[N];
+
+void foo (short * __restrict__ dst, short * __restrict__ src, int h, int stride, int dummy)
+{
+ int i;
+ h /= 16;
+ for (i = 0; i < h; i++)
+ {
+ dst[0] += A*src[0] + src[stride];
+ dst[1] += A*src[1] + src[1+stride];
+ dst[2] += A*src[2] + src[2+stride];
+ dst[3] += A*src[3] + src[3+stride];
+ dst[4] += A*src[4] + src[4+stride];
+ dst[5] += A*src[5] + src[5+stride];
+ dst[6] += A*src[6] + src[6+stride];
+ dst[7] += A*src[7] + src[7+stride];
+ dst += 8;
+ src += 8;
+ if (dummy == 32)
+ abort ();
+ }
+}
+
+
+int main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ dst[i] = 0;
+ src[i] = i;
+ }
+
+ foo (dst, src, N, 8, 0);
+
+ for (i = 0; i < N/2; i++)
+ {
+ if (dst[i] != A * i + i + 8)
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target vect_element_align } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== added file 'gcc/testsuite/gcc.dg/vect/vect-119.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-119.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-119.c 2011-10-02 08:43:10 +0000
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+
+#define OUTER 32
+#define INNER 40
+
+static unsigned int
+bar (const unsigned int x[INNER][2], unsigned int sum)
+{
+ int i;
+
+ for (i = 0; i < INNER; i++)
+ sum += x[i][0] * x[i][0] + x[i][1] * x[i][1];
+ return sum;
+}
+
+unsigned int foo (const unsigned int x[OUTER][INNER][2])
+{
+ int i;
+ unsigned int sum;
+
+ sum = 0.0f;
+ for (i = 0; i < OUTER; i++)
+ sum = bar (x[i], sum);
+ return sum;
+}
+
+/* { dg-final { scan-tree-dump-times "Detected interleaving of size 2" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/tree-data-ref.c'
--- old/gcc/tree-data-ref.c 2011-05-26 14:27:33 +0000
+++ new/gcc/tree-data-ref.c 2011-10-02 08:43:10 +0000
@@ -721,11 +721,11 @@
}
/* Analyzes the behavior of the memory reference DR in the innermost loop or
- basic block that contains it. Returns true if analysis succeed or false
+ basic block that contains it. Returns true if analysis succeed or false
otherwise. */
bool
-dr_analyze_innermost (struct data_reference *dr)
+dr_analyze_innermost (struct data_reference *dr, struct loop *nest)
{
gimple stmt = DR_STMT (dr);
struct loop *loop = loop_containing_stmt (stmt);
@@ -768,14 +768,25 @@
}
else
base = build_fold_addr_expr (base);
+
if (in_loop)
{
if (!simple_iv (loop, loop_containing_stmt (stmt), base, &base_iv,
false))
{
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "failed: evolution of base is not affine.\n");
- return false;
+ if (nest)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "failed: evolution of base is not"
+ " affine.\n");
+ return false;
+ }
+ else
+ {
+ base_iv.base = base;
+ base_iv.step = ssize_int (0);
+ base_iv.no_overflow = true;
+ }
}
}
else
@@ -800,10 +811,18 @@
else if (!simple_iv (loop, loop_containing_stmt (stmt),
poffset, &offset_iv, false))
{
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "failed: evolution of offset is not"
- " affine.\n");
- return false;
+ if (nest)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "failed: evolution of offset is not"
+ " affine.\n");
+ return false;
+ }
+ else
+ {
+ offset_iv.base = poffset;
+ offset_iv.step = ssize_int (0);
+ }
}
}
@@ -967,7 +986,7 @@
DR_REF (dr) = memref;
DR_IS_READ (dr) = is_read;
- dr_analyze_innermost (dr);
+ dr_analyze_innermost (dr, nest);
dr_analyze_indices (dr, nest, loop);
dr_analyze_alias (dr);
@@ -5185,7 +5204,7 @@
DR_STMT (dr) = stmt;
DR_REF (dr) = op0;
- res = dr_analyze_innermost (dr)
+ res = dr_analyze_innermost (dr, loop_containing_stmt (stmt))
&& stride_of_unit_type_p (DR_STEP (dr), TREE_TYPE (op0));
free_data_ref (dr);
@@ -5225,7 +5244,7 @@
DR_STMT (dr) = stmt;
DR_REF (dr) = *ref->pos;
- dr_analyze_innermost (dr);
+ dr_analyze_innermost (dr, loop_containing_stmt (stmt));
base_address = DR_BASE_ADDRESS (dr);
if (!base_address)
=== modified file 'gcc/tree-data-ref.h'
--- old/gcc/tree-data-ref.h 2011-03-27 09:38:18 +0000
+++ new/gcc/tree-data-ref.h 2011-10-02 08:43:10 +0000
@@ -386,7 +386,7 @@
DEF_VEC_ALLOC_O (data_ref_loc, heap);
bool get_references_in_stmt (gimple, VEC (data_ref_loc, heap) **);
-bool dr_analyze_innermost (struct data_reference *);
+bool dr_analyze_innermost (struct data_reference *, struct loop *);
extern bool compute_data_dependences_for_loop (struct loop *, bool,
VEC (loop_p, heap) **,
VEC (data_reference_p, heap) **,
=== modified file 'gcc/tree-loop-distribution.c'
--- old/gcc/tree-loop-distribution.c 2011-05-11 13:07:54 +0000
+++ new/gcc/tree-loop-distribution.c 2011-10-02 08:43:10 +0000
@@ -267,7 +267,7 @@
DR_STMT (dr) = stmt;
DR_REF (dr) = op0;
- res = dr_analyze_innermost (dr);
+ res = dr_analyze_innermost (dr, loop_containing_stmt (stmt));
gcc_assert (res && stride_of_unit_type_p (DR_STEP (dr), TREE_TYPE (op0)));
nb_bytes = build_size_arg_loc (loc, nb_iter, op0, &stmt_list);
=== modified file 'gcc/tree-predcom.c'
--- old/gcc/tree-predcom.c 2011-02-11 14:19:44 +0000
+++ new/gcc/tree-predcom.c 2011-10-02 08:43:10 +0000
@@ -1114,7 +1114,7 @@
memset (&init_dr, 0, sizeof (struct data_reference));
DR_REF (&init_dr) = init_ref;
DR_STMT (&init_dr) = phi;
- if (!dr_analyze_innermost (&init_dr))
+ if (!dr_analyze_innermost (&init_dr, loop))
return NULL;
if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref))
=== modified file 'gcc/tree-vect-data-refs.c'
--- old/gcc/tree-vect-data-refs.c 2011-07-04 11:13:51 +0000
+++ new/gcc/tree-vect-data-refs.c 2011-10-02 08:43:10 +0000
@@ -353,11 +353,7 @@
/* Check that the data-refs have same bases and offsets. If not, we can't
determine if they are dependent. */
- if ((DR_BASE_ADDRESS (dra) != DR_BASE_ADDRESS (drb)
- && (TREE_CODE (DR_BASE_ADDRESS (dra)) != ADDR_EXPR
- || TREE_CODE (DR_BASE_ADDRESS (drb)) != ADDR_EXPR
- || TREE_OPERAND (DR_BASE_ADDRESS (dra), 0)
- != TREE_OPERAND (DR_BASE_ADDRESS (drb),0)))
+ if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0)
|| !dr_equal_offsets_p (dra, drb))
return true;
@@ -403,11 +399,7 @@
/* Check that the data-refs have same first location (except init) and they
are both either store or load (not load and store). */
- if ((DR_BASE_ADDRESS (dra) != DR_BASE_ADDRESS (drb)
- && (TREE_CODE (DR_BASE_ADDRESS (dra)) != ADDR_EXPR
- || TREE_CODE (DR_BASE_ADDRESS (drb)) != ADDR_EXPR
- || TREE_OPERAND (DR_BASE_ADDRESS (dra), 0)
- != TREE_OPERAND (DR_BASE_ADDRESS (drb),0)))
+ if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0)
|| !dr_equal_offsets_p (dra, drb)
|| !tree_int_cst_compare (DR_INIT (dra), DR_INIT (drb))
|| DR_IS_READ (dra) != DR_IS_READ (drb))
@@ -615,6 +607,11 @@
if (vect_check_interleaving (dra, drb))
return false;
+ /* Read-read is OK (we need this check here, after checking for
+ interleaving). */
+ if (DR_IS_READ (dra) && DR_IS_READ (drb))
+ return false;
+
if (vect_print_dump_info (REPORT_DR_DETAILS))
{
fprintf (vect_dump, "can't determine dependence between ");
@@ -0,0 +1,240 @@
2011-10-06 Ira Rosen <ira.rosen@linaro.org>
gcc/testsuite/
* gcc.dg/vect/bb-slp-26.c: Simplify to make the basic block
vectorizable.
Backport from mainline:
2011-09-25 Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-vect-slp.c (vect_slp_analyze_bb_1): Split out core part
of vect_analyze_bb here.
(vect_analyze_bb): Loop over vector sizes calling vect_analyze_bb_1.
gcc/testsuite/
* lib/target-supports.exp (check_effective_target_vect64): New.
* gcc.dg/vect/bb-slp-11.c: Expect the error message twice in case
of multiple vector sizes.
* gcc.dg/vect/bb-slp-26.c: New.
=== modified file 'gcc/testsuite/gcc.dg/vect/bb-slp-11.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-11.c 2010-11-22 12:16:52 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-11.c 2011-10-02 10:40:34 +0000
@@ -49,6 +49,7 @@
}
/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 0 "slp" } } */
-/* { dg-final { scan-tree-dump-times "SLP with multiple types" 1 "slp" } } */
+/* { dg-final { scan-tree-dump-times "SLP with multiple types" 1 "slp" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "SLP with multiple types" 2 "slp" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "slp" } } */
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-26.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-26.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-26.c 2011-10-02 10:40:34 +0000
@@ -0,0 +1,60 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define A 3
+#define B 4
+#define N 256
+
+char src[N], dst[N];
+
+void foo (char * __restrict__ dst, char * __restrict__ src, int h,
+ int stride, int dummy)
+{
+ int i;
+ h /= 16;
+ for (i = 0; i < h; i++)
+ {
+ dst[0] += A*src[0];
+ dst[1] += A*src[1];
+ dst[2] += A*src[2];
+ dst[3] += A*src[3];
+ dst[4] += A*src[4];
+ dst[5] += A*src[5];
+ dst[6] += A*src[6];
+ dst[7] += A*src[7];
+ dst += 8;
+ src += 8;
+ if (dummy == 32)
+ abort ();
+ }
+}
+
+
+int main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ dst[i] = 0;
+ src[i] = i/8;
+ }
+
+ foo (dst, src, N, 8, 0);
+
+ for (i = 0; i < N/2; i++)
+ {
+ if (dst[i] != A * src[i])
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target vect64 } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== modified file 'gcc/testsuite/lib/target-supports.exp'
--- old/gcc/testsuite/lib/target-supports.exp 2011-09-20 07:54:28 +0000
+++ new/gcc/testsuite/lib/target-supports.exp 2011-10-02 10:40:34 +0000
@@ -3283,6 +3283,24 @@
return $et_vect_multiple_sizes_saved
}
+# Return 1 if the target supports vectors of 64 bits.
+
+proc check_effective_target_vect64 { } {
+ global et_vect64
+
+ if [info exists et_vect64_saved] {
+ verbose "check_effective_target_vect64: using cached result" 2
+ } else {
+ set et_vect64_saved 0
+ if { ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok]) } {
+ set et_vect64_saved 1
+ }
+ }
+
+ verbose "check_effective_target_vect64: returning $et_vect64_saved" 2
+ return $et_vect64_saved
+}
+
# Return 1 if the target supports section-anchors
proc check_effective_target_section_anchors { } {
=== modified file 'gcc/tree-vect-slp.c'
--- old/gcc/tree-vect-slp.c 2011-07-06 12:04:10 +0000
+++ new/gcc/tree-vect-slp.c 2011-10-02 10:40:34 +0000
@@ -1664,42 +1664,18 @@
/* Check if the basic block can be vectorized. */
-bb_vec_info
-vect_slp_analyze_bb (basic_block bb)
+static bb_vec_info
+vect_slp_analyze_bb_1 (basic_block bb)
{
bb_vec_info bb_vinfo;
VEC (ddr_p, heap) *ddrs;
VEC (slp_instance, heap) *slp_instances;
slp_instance instance;
- int i, insns = 0;
- gimple_stmt_iterator gsi;
+ int i;
int min_vf = 2;
int max_vf = MAX_VECTORIZATION_FACTOR;
bool data_dependence_in_bb = false;
- current_vector_size = 0;
-
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "===vect_slp_analyze_bb===\n");
-
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple stmt = gsi_stmt (gsi);
- if (!is_gimple_debug (stmt)
- && !gimple_nop_p (stmt)
- && gimple_code (stmt) != GIMPLE_LABEL)
- insns++;
- }
-
- if (insns > PARAM_VALUE (PARAM_SLP_MAX_INSNS_IN_BB))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOCATIONS))
- fprintf (vect_dump, "not vectorized: too many instructions in basic "
- "block.\n");
-
- return NULL;
- }
-
bb_vinfo = new_bb_vec_info (bb);
if (!bb_vinfo)
return NULL;
@@ -1819,6 +1795,61 @@
}
+bb_vec_info
+vect_slp_analyze_bb (basic_block bb)
+{
+ bb_vec_info bb_vinfo;
+ int insns = 0;
+ gimple_stmt_iterator gsi;
+ unsigned int vector_sizes;
+
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "===vect_slp_analyze_bb===\n");
+
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ if (!is_gimple_debug (stmt)
+ && !gimple_nop_p (stmt)
+ && gimple_code (stmt) != GIMPLE_LABEL)
+ insns++;
+ }
+
+ if (insns > PARAM_VALUE (PARAM_SLP_MAX_INSNS_IN_BB))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOCATIONS))
+ fprintf (vect_dump, "not vectorized: too many instructions in basic "
+ "block.\n");
+
+ return NULL;
+ }
+
+ /* Autodetect first vector size we try. */
+ current_vector_size = 0;
+ vector_sizes = targetm.vectorize.autovectorize_vector_sizes ();
+
+ while (1)
+ {
+ bb_vinfo = vect_slp_analyze_bb_1 (bb);
+ if (bb_vinfo)
+ return bb_vinfo;
+
+ destroy_bb_vec_info (bb_vinfo);
+
+ vector_sizes &= ~current_vector_size;
+ if (vector_sizes == 0
+ || current_vector_size == 0)
+ return NULL;
+
+ /* Try the next biggest vector size. */
+ current_vector_size = 1 << floor_log2 (vector_sizes);
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "***** Re-trying analysis with "
+ "vector size %d\n", current_vector_size);
+ }
+}
+
+
/* SLP costs are calculated according to SLP instance unrolling factor (i.e.,
the number of created vector stmts depends on the unrolling factor).
However, the actual number of vector stmts for every SLP node depends on
@@ -0,0 +1,124 @@
2011-10-13 Andrew Stubbs <ams@codesourcery.com>
Backport from mainline:
2011-10-07 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/predicates.md (shift_amount_operand): Remove constant
range check.
(shift_operator): Check range of constants for all shift operators.
gcc/testsuite/
* gcc.dg/pr50193-1.c: New file.
* gcc.target/arm/shiftable.c: New file.
=== modified file 'gcc/config/arm/predicates.md'
--- old/gcc/config/arm/predicates.md 2011-10-03 09:47:33 +0000
+++ new/gcc/config/arm/predicates.md 2011-10-10 11:43:28 +0000
@@ -129,11 +129,12 @@
(ior (match_operand 0 "arm_rhs_operand")
(match_operand 0 "memory_operand")))
+;; This doesn't have to do much because the constant is already checked
+;; in the shift_operator predicate.
(define_predicate "shift_amount_operand"
(ior (and (match_test "TARGET_ARM")
(match_operand 0 "s_register_operand"))
- (and (match_operand 0 "const_int_operand")
- (match_test "INTVAL (op) > 0"))))
+ (match_operand 0 "const_int_operand")))
(define_predicate "arm_add_operand"
(ior (match_operand 0 "arm_rhs_operand")
@@ -219,13 +220,20 @@
(match_test "mode == GET_MODE (op)")))
;; True for shift operators.
+;; Notes:
+;; * mult is only permitted with a constant shift amount
+;; * patterns that permit register shift amounts only in ARM mode use
+;; shift_amount_operand, patterns that always allow registers do not,
+;; so we don't have to worry about that sort of thing here.
(define_special_predicate "shift_operator"
(and (ior (ior (and (match_code "mult")
(match_test "power_of_two_operand (XEXP (op, 1), mode)"))
(and (match_code "rotate")
(match_test "GET_CODE (XEXP (op, 1)) == CONST_INT
&& ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op, 1))) < 32")))
- (match_code "ashift,ashiftrt,lshiftrt,rotatert"))
+ (and (match_code "ashift,ashiftrt,lshiftrt,rotatert")
+ (match_test "GET_CODE (XEXP (op, 1)) != CONST_INT
+ || ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op, 1))) < 32")))
(match_test "mode == GET_MODE (op)")))
;; True for MULT, to identify which variant of shift_operator is in use.
=== added file 'gcc/testsuite/gcc.target/arm/shiftable.c'
--- old/gcc/testsuite/gcc.target/arm/shiftable.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/shiftable.c 2011-10-10 11:43:28 +0000
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target arm32 } */
+
+/* ARM has shift-and-alu insns. Depending on the ALU op GCC represents some
+ of these as a left shift, others as a multiply. Check that we match the
+ right one. */
+
+int
+plus (int a, int b)
+{
+ return (a * 64) + b;
+}
+
+/* { dg-final { scan-assembler "add.*\[al]sl #6" } } */
+
+int
+minus (int a, int b)
+{
+ return a - (b * 64);
+}
+
+/* { dg-final { scan-assembler "sub.*\[al]sl #6" } } */
+
+int
+ior (int a, int b)
+{
+ return (a * 64) | b;
+}
+
+/* { dg-final { scan-assembler "orr.*\[al]sl #6" } } */
+
+int
+xor (int a, int b)
+{
+ return (a * 64) ^ b;
+}
+
+/* { dg-final { scan-assembler "eor.*\[al]sl #6" } } */
+
+int
+and (int a, int b)
+{
+ return (a * 64) & b;
+}
+
+/* { dg-final { scan-assembler "and.*\[al]sl #6" } } */
+
+int
+rsb (int a, int b)
+{
+ return (a * 64) - b;
+}
+
+/* { dg-final { scan-assembler "rsb.*\[al]sl #6" } } */
+
+int
+mvn (int a, int b)
+{
+ return ~(a * 64);
+}
+
+/* { dg-final { scan-assembler "mvn.*\[al]sl #6" } } */
@@ -0,0 +1,362 @@
2011-10-16 Ira Rosen <ira.rosen@linaro.org>
Backport from mainline:
2011-09-27 Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-vect-stmts.c (vectorizable_type_demotion): Handle basic block
vectorization.
(vectorizable_type_promotion): Likewise.
(vect_analyze_stmt): Call vectorizable_type_demotion and
vectorizable_type_promotion for basic blocks.
(supportable_widening_operation): Don't assume loop vectorization.
* tree-vect-slp.c (vect_build_slp_tree): Allow multiple types for
basic blocks. Update vectorization factor for basic block
vectorization.
(vect_analyze_slp_instance): Allow multiple types for basic block
vectorization. Recheck unrolling factor after construction of SLP
instance.
gcc/testsuite/
* gcc.dg/vect/bb-slp-11.c: Expect to get vectorized with 64-bit
vectors.
* gcc.dg/vect/bb-slp-27.c: New.
* gcc.dg/vect/bb-slp-28.c: New.
2011-10-04 Ira Rosen <ira.rosen@linaro.org>
gcc/testsuite/
* lib/target-supports.exp (check_effective_target_vect_multiple_sizes):
Make et_vect_multiple_sizes_saved global.
(check_effective_target_vect64): Make et_vect64_saved global.
=== modified file 'gcc/testsuite/gcc.dg/vect/bb-slp-11.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-11.c 2011-10-02 10:40:34 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-11.c 2011-10-06 11:08:08 +0000
@@ -48,8 +48,6 @@
return 0;
}
-/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 0 "slp" } } */
-/* { dg-final { scan-tree-dump-times "SLP with multiple types" 1 "slp" { xfail vect_multiple_sizes } } } */
-/* { dg-final { scan-tree-dump-times "SLP with multiple types" 2 "slp" { target vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target vect64 } } } */
/* { dg-final { cleanup-tree-dump "slp" } } */
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-27.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-27.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-27.c 2011-10-06 11:08:08 +0000
@@ -0,0 +1,49 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define A 3
+#define N 16
+
+short src[N], dst[N];
+
+void foo (int a)
+{
+ dst[0] += a*src[0];
+ dst[1] += a*src[1];
+ dst[2] += a*src[2];
+ dst[3] += a*src[3];
+ dst[4] += a*src[4];
+ dst[5] += a*src[5];
+ dst[6] += a*src[6];
+ dst[7] += a*src[7];
+}
+
+
+int main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ dst[i] = 0;
+ src[i] = i;
+ }
+
+ foo (A);
+
+ for (i = 0; i < 8; i++)
+ {
+ if (dst[i] != A * i)
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target { vect_int_mult && { vect_unpack && vect_pack_trunc } } } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-28.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-28.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-28.c 2011-10-06 11:08:08 +0000
@@ -0,0 +1,71 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define A 300
+#define N 16
+
+char src[N];
+short dst[N];
+short src1[N], dst1[N];
+
+void foo (int a)
+{
+ dst[0] = (short) (a * (int) src[0]);
+ dst[1] = (short) (a * (int) src[1]);
+ dst[2] = (short) (a * (int) src[2]);
+ dst[3] = (short) (a * (int) src[3]);
+ dst[4] = (short) (a * (int) src[4]);
+ dst[5] = (short) (a * (int) src[5]);
+ dst[6] = (short) (a * (int) src[6]);
+ dst[7] = (short) (a * (int) src[7]);
+ dst[8] = (short) (a * (int) src[8]);
+ dst[9] = (short) (a * (int) src[9]);
+ dst[10] = (short) (a * (int) src[10]);
+ dst[11] = (short) (a * (int) src[11]);
+ dst[12] = (short) (a * (int) src[12]);
+ dst[13] = (short) (a * (int) src[13]);
+ dst[14] = (short) (a * (int) src[14]);
+ dst[15] = (short) (a * (int) src[15]);
+
+ dst1[0] += src1[0];
+ dst1[1] += src1[1];
+ dst1[2] += src1[2];
+ dst1[3] += src1[3];
+ dst1[4] += src1[4];
+ dst1[5] += src1[5];
+ dst1[6] += src1[6];
+ dst1[7] += src1[7];
+}
+
+
+int main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ dst[i] = 2;
+ dst1[i] = 0;
+ src[i] = i;
+ src1[i] = i+2;
+ }
+
+ foo (A);
+
+ for (i = 0; i < N; i++)
+ {
+ if (dst[i] != A * i
+ || (i < N/2 && dst1[i] != i + 2))
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target { vect_int_mult && { vect_pack_trunc && vect_unpack } } } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== modified file 'gcc/testsuite/lib/target-supports.exp'
--- old/gcc/testsuite/lib/target-supports.exp 2011-10-02 10:40:34 +0000
+++ new/gcc/testsuite/lib/target-supports.exp 2011-10-06 11:08:08 +0000
@@ -3268,7 +3268,7 @@
# Return 1 if the target supports multiple vector sizes
proc check_effective_target_vect_multiple_sizes { } {
- global et_vect_multiple_sizes
+ global et_vect_multiple_sizes_saved
if [info exists et_vect_multiple_sizes_saved] {
verbose "check_effective_target_vect_multiple_sizes: using cached result" 2
@@ -3286,7 +3286,7 @@
# Return 1 if the target supports vectors of 64 bits.
proc check_effective_target_vect64 { } {
- global et_vect64
+ global et_vect64_saved
if [info exists et_vect64_saved] {
verbose "check_effective_target_vect64: using cached result" 2
=== modified file 'gcc/tree-vect-slp.c'
--- old/gcc/tree-vect-slp.c 2011-10-02 10:40:34 +0000
+++ new/gcc/tree-vect-slp.c 2011-10-06 11:08:08 +0000
@@ -386,20 +386,15 @@
return false;
}
- ncopies = vectorization_factor / TYPE_VECTOR_SUBPARTS (vectype);
- if (ncopies != 1)
- {
- if (vect_print_dump_info (REPORT_SLP))
- fprintf (vect_dump, "SLP with multiple types ");
-
- /* FORNOW: multiple types are unsupported in BB SLP. */
- if (bb_vinfo)
- return false;
- }
-
/* In case of multiple types we need to detect the smallest type. */
if (*max_nunits < TYPE_VECTOR_SUBPARTS (vectype))
- *max_nunits = TYPE_VECTOR_SUBPARTS (vectype);
+ {
+ *max_nunits = TYPE_VECTOR_SUBPARTS (vectype);
+ if (bb_vinfo)
+ vectorization_factor = *max_nunits;
+ }
+
+ ncopies = vectorization_factor / TYPE_VECTOR_SUBPARTS (vectype);
if (is_gimple_call (stmt))
rhs_code = CALL_EXPR;
@@ -1183,7 +1178,6 @@
if (loop_vinfo)
vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
else
- /* No multitypes in BB SLP. */
vectorization_factor = nunits;
/* Calculate the unrolling factor. */
@@ -1246,16 +1240,23 @@
&max_nunits, &load_permutation, &loads,
vectorization_factor))
{
+ /* Calculate the unrolling factor based on the smallest type. */
+ if (max_nunits > nunits)
+ unrolling_factor = least_common_multiple (max_nunits, group_size)
+ / group_size;
+
+ if (unrolling_factor != 1 && !loop_vinfo)
+ {
+ if (vect_print_dump_info (REPORT_SLP))
+ fprintf (vect_dump, "Build SLP failed: unrolling required in basic"
+ " block SLP");
+ return false;
+ }
+
/* Create a new SLP instance. */
new_instance = XNEW (struct _slp_instance);
SLP_INSTANCE_TREE (new_instance) = node;
SLP_INSTANCE_GROUP_SIZE (new_instance) = group_size;
- /* Calculate the unrolling factor based on the smallest type in the
- loop. */
- if (max_nunits > nunits)
- unrolling_factor = least_common_multiple (max_nunits, group_size)
- / group_size;
-
SLP_INSTANCE_UNROLLING_FACTOR (new_instance) = unrolling_factor;
SLP_INSTANCE_OUTSIDE_OF_LOOP_COST (new_instance) = outside_cost;
SLP_INSTANCE_INSIDE_OF_LOOP_COST (new_instance) = inside_cost;
=== modified file 'gcc/tree-vect-stmts.c'
--- old/gcc/tree-vect-stmts.c 2011-10-04 08:57:25 +0000
+++ new/gcc/tree-vect-stmts.c 2011-10-16 12:16:07 +0000
@@ -3081,11 +3081,9 @@
VEC (tree, heap) *vec_oprnds0 = NULL;
VEC (tree, heap) *vec_dsts = NULL, *interm_types = NULL, *tmp_vec_dsts = NULL;
tree last_oprnd, intermediate_type;
-
- /* FORNOW: not supported by basic block SLP vectorization. */
- gcc_assert (loop_vinfo);
-
- if (!STMT_VINFO_RELEVANT_P (stmt_info))
+ bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info);
+
+ if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
@@ -3113,7 +3111,7 @@
&& SCALAR_FLOAT_TYPE_P (TREE_TYPE (op0))
&& CONVERT_EXPR_CODE_P (code))))
return false;
- if (!vect_is_simple_use_1 (op0, loop_vinfo, NULL,
+ if (!vect_is_simple_use_1 (op0, loop_vinfo, bb_vinfo,
&def_stmt, &def, &dt[0], &vectype_in))
{
if (vect_print_dump_info (REPORT_DETAILS))
@@ -3360,11 +3358,9 @@
int multi_step_cvt = 0;
VEC (tree, heap) *vec_oprnds0 = NULL, *vec_oprnds1 = NULL;
VEC (tree, heap) *vec_dsts = NULL, *interm_types = NULL, *tmp_vec_dsts = NULL;
-
- /* FORNOW: not supported by basic block SLP vectorization. */
- gcc_assert (loop_vinfo);
-
- if (!STMT_VINFO_RELEVANT_P (stmt_info))
+ bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info);
+
+ if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def)
@@ -3393,7 +3389,7 @@
&& SCALAR_FLOAT_TYPE_P (TREE_TYPE (op0))
&& CONVERT_EXPR_CODE_P (code))))
return false;
- if (!vect_is_simple_use_1 (op0, loop_vinfo, NULL,
+ if (!vect_is_simple_use_1 (op0, loop_vinfo, bb_vinfo,
&def_stmt, &def, &dt[0], &vectype_in))
{
if (vect_print_dump_info (REPORT_DETAILS))
@@ -5153,7 +5149,9 @@
else
{
if (bb_vinfo)
- ok = (vectorizable_shift (stmt, NULL, NULL, node)
+ ok = (vectorizable_type_promotion (stmt, NULL, NULL, node)
+ || vectorizable_type_demotion (stmt, NULL, NULL, node)
+ || vectorizable_shift (stmt, NULL, NULL, node)
|| vectorizable_operation (stmt, NULL, NULL, node)
|| vectorizable_assignment (stmt, NULL, NULL, node)
|| vectorizable_load (stmt, NULL, NULL, node, NULL)
@@ -5780,7 +5778,7 @@
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_info);
- struct loop *vect_loop = LOOP_VINFO_LOOP (loop_info);
+ struct loop *vect_loop = NULL;
bool ordered_p;
enum machine_mode vec_mode;
enum insn_code icode1, icode2;
@@ -5789,6 +5787,9 @@
tree wide_vectype = vectype_out;
enum tree_code c1, c2;
+ if (loop_info)
+ vect_loop = LOOP_VINFO_LOOP (loop_info);
+
/* The result of a vectorized widening operation usually requires two vectors
(because the widened results do not fit int one vector). The generated
vector results would normally be expected to be generated in the same
@@ -5809,7 +5810,8 @@
iterations in parallel). We therefore don't allow to change the order
of the computation in the inner-loop during outer-loop vectorization. */
- if (STMT_VINFO_RELEVANT (stmt_info) == vect_used_by_reduction
+ if (vect_loop
+ && STMT_VINFO_RELEVANT (stmt_info) == vect_used_by_reduction
&& !nested_in_vect_loop_p (vect_loop, stmt))
ordered_p = false;
else
@@ -0,0 +1,622 @@
2011-10-17 Michael Hope <michael.hope@linaro.org>
Backport from mainline r178852:
2011-09-14 Julian Brown <julian@codesourcery.com>
gcc/
* config/arm/arm.c (arm_override_options): Add unaligned_access
support.
(arm_file_start): Emit attribute for unaligned access as appropriate.
* config/arm/arm.md (UNSPEC_UNALIGNED_LOAD)
(UNSPEC_UNALIGNED_STORE): Add constants for unspecs.
(insv, extzv): Add unaligned-access support.
(extv): Change to expander. Likewise.
(extzv_t1, extv_regsi): Add helpers.
(unaligned_loadsi, unaligned_loadhis, unaligned_loadhiu)
(unaligned_storesi, unaligned_storehi): New.
(*extv_reg): New (previous extv implementation).
* config/arm/arm.opt (munaligned_access): Add option.
* config/arm/constraints.md (Uw): New constraint.
* expmed.c (store_bit_field_1): Adjust bitfield numbering according
to size of access, not size of unit, when BITS_BIG_ENDIAN !=
BYTES_BIG_ENDIAN. Don't use bitfield accesses for
volatile accesses when -fstrict-volatile-bitfields is in effect.
(extract_bit_field_1): Likewise.
Backport from mainline r172697:
2011-04-19 Wei Guozhi <carrot@google.com>
PR target/47855
gcc/
* config/arm/arm-protos.h (thumb1_legitimate_address_p): New prototype.
* config/arm/arm.c (thumb1_legitimate_address_p): Remove the static
linkage.
* config/arm/constraints.md (Uu): New constraint.
* config/arm/arm.md (*arm_movqi_insn): Compute attr "length".
=== modified file 'gcc/config/arm/arm-protos.h'
Index: gcc-4_6-branch/gcc/config/arm/arm-protos.h
===================================================================
--- gcc-4_6-branch.orig/gcc/config/arm/arm-protos.h 2012-03-05 16:07:15.000000000 -0800
+++ gcc-4_6-branch/gcc/config/arm/arm-protos.h 2012-03-05 16:07:50.392936694 -0800
@@ -59,6 +59,7 @@
int);
extern rtx thumb_legitimize_reload_address (rtx *, enum machine_mode, int, int,
int);
+extern int thumb1_legitimate_address_p (enum machine_mode, rtx, int);
extern int arm_const_double_rtx (rtx);
extern int neg_const_double_rtx_ok_for_fpa (rtx);
extern int vfp3_const_double_rtx (rtx);
Index: gcc-4_6-branch/gcc/config/arm/arm.c
===================================================================
--- gcc-4_6-branch.orig/gcc/config/arm/arm.c 2012-03-05 16:07:15.000000000 -0800
+++ gcc-4_6-branch/gcc/config/arm/arm.c 2012-03-05 16:07:50.400936694 -0800
@@ -2065,6 +2065,28 @@
fix_cm3_ldrd = 0;
}
+ /* Enable -munaligned-access by default for
+ - all ARMv6 architecture-based processors
+ - ARMv7-A, ARMv7-R, and ARMv7-M architecture-based processors.
+
+ Disable -munaligned-access by default for
+ - all pre-ARMv6 architecture-based processors
+ - ARMv6-M architecture-based processors. */
+
+ if (unaligned_access == 2)
+ {
+ if (arm_arch6 && (arm_arch_notm || arm_arch7))
+ unaligned_access = 1;
+ else
+ unaligned_access = 0;
+ }
+ else if (unaligned_access == 1
+ && !(arm_arch6 && (arm_arch_notm || arm_arch7)))
+ {
+ warning (0, "target CPU does not support unaligned accesses");
+ unaligned_access = 0;
+ }
+
if (TARGET_THUMB1 && flag_schedule_insns)
{
/* Don't warn since it's on by default in -O2. */
@@ -6123,7 +6145,7 @@
addresses based on the frame pointer or arg pointer until the
reload pass starts. This is so that eliminating such addresses
into stack based ones won't produce impossible code. */
-static int
+int
thumb1_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
{
/* ??? Not clear if this is right. Experiment. */
@@ -22251,6 +22273,10 @@
val = 6;
asm_fprintf (asm_out_file, "\t.eabi_attribute 30, %d\n", val);
+ /* Tag_CPU_unaligned_access. */
+ asm_fprintf (asm_out_file, "\t.eabi_attribute 34, %d\n",
+ unaligned_access);
+
/* Tag_ABI_FP_16bit_format. */
if (arm_fp16_format)
asm_fprintf (asm_out_file, "\t.eabi_attribute 38, %d\n",
Index: gcc-4_6-branch/gcc/config/arm/arm.md
===================================================================
--- gcc-4_6-branch.orig/gcc/config/arm/arm.md 2012-03-05 16:07:15.000000000 -0800
+++ gcc-4_6-branch/gcc/config/arm/arm.md 2012-03-05 16:09:26.284941314 -0800
@@ -114,6 +114,10 @@
; another symbolic address.
(UNSPEC_MEMORY_BARRIER 28) ; Represent a memory barrier.
(UNSPEC_PIC_UNIFIED 29) ; Create a common pic addressing form.
+ (UNSPEC_UNALIGNED_LOAD 30) ; Used to represent ldr/ldrh instructions that access
+ ; unaligned locations, on architectures which support
+ ; that.
+ (UNSPEC_UNALIGNED_STORE 31) ; Same for str/strh.
]
)
@@ -2461,10 +2465,10 @@
;;; this insv pattern, so this pattern needs to be reevalutated.
(define_expand "insv"
- [(set (zero_extract:SI (match_operand:SI 0 "s_register_operand" "")
- (match_operand:SI 1 "general_operand" "")
- (match_operand:SI 2 "general_operand" ""))
- (match_operand:SI 3 "reg_or_int_operand" ""))]
+ [(set (zero_extract (match_operand 0 "nonimmediate_operand" "")
+ (match_operand 1 "general_operand" "")
+ (match_operand 2 "general_operand" ""))
+ (match_operand 3 "reg_or_int_operand" ""))]
"TARGET_ARM || arm_arch_thumb2"
"
{
@@ -2475,35 +2479,70 @@
if (arm_arch_thumb2)
{
- bool use_bfi = TRUE;
-
- if (GET_CODE (operands[3]) == CONST_INT)
+ if (unaligned_access && MEM_P (operands[0])
+ && s_register_operand (operands[3], GET_MODE (operands[3]))
+ && (width == 16 || width == 32) && (start_bit % BITS_PER_UNIT) == 0)
{
- HOST_WIDE_INT val = INTVAL (operands[3]) & mask;
+ rtx base_addr;
+
+ if (BYTES_BIG_ENDIAN)
+ start_bit = GET_MODE_BITSIZE (GET_MODE (operands[3])) - width
+ - start_bit;
- if (val == 0)
+ if (width == 32)
{
- emit_insn (gen_insv_zero (operands[0], operands[1],
- operands[2]));
- DONE;
+ base_addr = adjust_address (operands[0], SImode,
+ start_bit / BITS_PER_UNIT);
+ emit_insn (gen_unaligned_storesi (base_addr, operands[3]));
}
+ else
+ {
+ rtx tmp = gen_reg_rtx (HImode);
- /* See if the set can be done with a single orr instruction. */
- if (val == mask && const_ok_for_arm (val << start_bit))
- use_bfi = FALSE;
+ base_addr = adjust_address (operands[0], HImode,
+ start_bit / BITS_PER_UNIT);
+ emit_move_insn (tmp, gen_lowpart (HImode, operands[3]));
+ emit_insn (gen_unaligned_storehi (base_addr, tmp));
+ }
+ DONE;
}
-
- if (use_bfi)
+ else if (s_register_operand (operands[0], GET_MODE (operands[0])))
{
- if (GET_CODE (operands[3]) != REG)
- operands[3] = force_reg (SImode, operands[3]);
+ bool use_bfi = TRUE;
- emit_insn (gen_insv_t2 (operands[0], operands[1], operands[2],
- operands[3]));
- DONE;
+ if (GET_CODE (operands[3]) == CONST_INT)
+ {
+ HOST_WIDE_INT val = INTVAL (operands[3]) & mask;
+
+ if (val == 0)
+ {
+ emit_insn (gen_insv_zero (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+
+ /* See if the set can be done with a single orr instruction. */
+ if (val == mask && const_ok_for_arm (val << start_bit))
+ use_bfi = FALSE;
+ }
+
+ if (use_bfi)
+ {
+ if (GET_CODE (operands[3]) != REG)
+ operands[3] = force_reg (SImode, operands[3]);
+
+ emit_insn (gen_insv_t2 (operands[0], operands[1], operands[2],
+ operands[3]));
+ DONE;
+ }
}
+ else
+ FAIL;
}
+ if (!s_register_operand (operands[0], GET_MODE (operands[0])))
+ FAIL;
+
target = copy_rtx (operands[0]);
/* Avoid using a subreg as a subtarget, and avoid writing a paradoxical
subreg as the final target. */
@@ -3695,12 +3734,10 @@
;; to reduce register pressure later on.
(define_expand "extzv"
- [(set (match_dup 4)
- (ashift:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "const_int_operand" "")))
- (set (match_operand:SI 0 "register_operand" "")
- (lshiftrt:SI (match_dup 4)
- (match_operand:SI 3 "const_int_operand" "")))]
+ [(set (match_operand 0 "s_register_operand" "")
+ (zero_extract (match_operand 1 "nonimmediate_operand" "")
+ (match_operand 2 "const_int_operand" "")
+ (match_operand 3 "const_int_operand" "")))]
"TARGET_THUMB1 || arm_arch_thumb2"
"
{
@@ -3709,10 +3746,57 @@
if (arm_arch_thumb2)
{
- emit_insn (gen_extzv_t2 (operands[0], operands[1], operands[2],
- operands[3]));
- DONE;
+ HOST_WIDE_INT width = INTVAL (operands[2]);
+ HOST_WIDE_INT bitpos = INTVAL (operands[3]);
+
+ if (unaligned_access && MEM_P (operands[1])
+ && (width == 16 || width == 32) && (bitpos % BITS_PER_UNIT) == 0)
+ {
+ rtx base_addr;
+
+ if (BYTES_BIG_ENDIAN)
+ bitpos = GET_MODE_BITSIZE (GET_MODE (operands[0])) - width
+ - bitpos;
+
+ if (width == 32)
+ {
+ base_addr = adjust_address (operands[1], SImode,
+ bitpos / BITS_PER_UNIT);
+ emit_insn (gen_unaligned_loadsi (operands[0], base_addr));
+ }
+ else
+ {
+ rtx dest = operands[0];
+ rtx tmp = gen_reg_rtx (SImode);
+
+ /* We may get a paradoxical subreg here. Strip it off. */
+ if (GET_CODE (dest) == SUBREG
+ && GET_MODE (dest) == SImode
+ && GET_MODE (SUBREG_REG (dest)) == HImode)
+ dest = SUBREG_REG (dest);
+
+ if (GET_MODE_BITSIZE (GET_MODE (dest)) != width)
+ FAIL;
+
+ base_addr = adjust_address (operands[1], HImode,
+ bitpos / BITS_PER_UNIT);
+ emit_insn (gen_unaligned_loadhiu (tmp, base_addr));
+ emit_move_insn (gen_lowpart (SImode, dest), tmp);
+ }
+ DONE;
+ }
+ else if (s_register_operand (operands[1], GET_MODE (operands[1])))
+ {
+ emit_insn (gen_extzv_t2 (operands[0], operands[1], operands[2],
+ operands[3]));
+ DONE;
+ }
+ else
+ FAIL;
}
+
+ if (!s_register_operand (operands[1], GET_MODE (operands[1])))
+ FAIL;
operands[3] = GEN_INT (rshift);
@@ -3722,12 +3806,154 @@
DONE;
}
- operands[2] = GEN_INT (lshift);
- operands[4] = gen_reg_rtx (SImode);
+ emit_insn (gen_extzv_t1 (operands[0], operands[1], GEN_INT (lshift),
+ operands[3], gen_reg_rtx (SImode)));
+ DONE;
}"
)
-(define_insn "extv"
+;; Helper for extzv, for the Thumb-1 register-shifts case.
+
+(define_expand "extzv_t1"
+ [(set (match_operand:SI 4 "s_register_operand" "")
+ (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")))
+ (set (match_operand:SI 0 "s_register_operand" "")
+ (lshiftrt:SI (match_dup 4)
+ (match_operand:SI 3 "const_int_operand" "")))]
+ "TARGET_THUMB1"
+ "")
+
+(define_expand "extv"
+ [(set (match_operand 0 "s_register_operand" "")
+ (sign_extract (match_operand 1 "nonimmediate_operand" "")
+ (match_operand 2 "const_int_operand" "")
+ (match_operand 3 "const_int_operand" "")))]
+ "arm_arch_thumb2"
+{
+ HOST_WIDE_INT width = INTVAL (operands[2]);
+ HOST_WIDE_INT bitpos = INTVAL (operands[3]);
+
+ if (unaligned_access && MEM_P (operands[1]) && (width == 16 || width == 32)
+ && (bitpos % BITS_PER_UNIT) == 0)
+ {
+ rtx base_addr;
+
+ if (BYTES_BIG_ENDIAN)
+ bitpos = GET_MODE_BITSIZE (GET_MODE (operands[0])) - width - bitpos;
+
+ if (width == 32)
+ {
+ base_addr = adjust_address (operands[1], SImode,
+ bitpos / BITS_PER_UNIT);
+ emit_insn (gen_unaligned_loadsi (operands[0], base_addr));
+ }
+ else
+ {
+ rtx dest = operands[0];
+ rtx tmp = gen_reg_rtx (SImode);
+
+ /* We may get a paradoxical subreg here. Strip it off. */
+ if (GET_CODE (dest) == SUBREG
+ && GET_MODE (dest) == SImode
+ && GET_MODE (SUBREG_REG (dest)) == HImode)
+ dest = SUBREG_REG (dest);
+
+ if (GET_MODE_BITSIZE (GET_MODE (dest)) != width)
+ FAIL;
+
+ base_addr = adjust_address (operands[1], HImode,
+ bitpos / BITS_PER_UNIT);
+ emit_insn (gen_unaligned_loadhis (tmp, base_addr));
+ emit_move_insn (gen_lowpart (SImode, dest), tmp);
+ }
+
+ DONE;
+ }
+ else if (!s_register_operand (operands[1], GET_MODE (operands[1])))
+ FAIL;
+ else if (GET_MODE (operands[0]) == SImode
+ && GET_MODE (operands[1]) == SImode)
+ {
+ emit_insn (gen_extv_regsi (operands[0], operands[1], operands[2],
+ operands[3]));
+ DONE;
+ }
+
+ FAIL;
+})
+
+; Helper to expand register forms of extv with the proper modes.
+
+(define_expand "extv_regsi"
+ [(set (match_operand:SI 0 "s_register_operand" "")
+ (sign_extract:SI (match_operand:SI 1 "s_register_operand" "")
+ (match_operand 2 "const_int_operand" "")
+ (match_operand 3 "const_int_operand" "")))]
+ ""
+{
+})
+
+; ARMv6+ unaligned load/store instructions (used for packed structure accesses).
+
+(define_insn "unaligned_loadsi"
+ [(set (match_operand:SI 0 "s_register_operand" "=l,r")
+ (unspec:SI [(match_operand:SI 1 "memory_operand" "Uw,m")]
+ UNSPEC_UNALIGNED_LOAD))]
+ "unaligned_access && TARGET_32BIT"
+ "ldr%?\t%0, %1\t@ unaligned"
+ [(set_attr "arch" "t2,any")
+ (set_attr "length" "2,4")
+ (set_attr "predicable" "yes")
+ (set_attr "type" "load1")])
+
+(define_insn "unaligned_loadhis"
+ [(set (match_operand:SI 0 "s_register_operand" "=l,r")
+ (sign_extend:SI
+ (unspec:HI [(match_operand:HI 1 "memory_operand" "Uw,m")]
+ UNSPEC_UNALIGNED_LOAD)))]
+ "unaligned_access && TARGET_32BIT"
+ "ldr%(sh%)\t%0, %1\t@ unaligned"
+ [(set_attr "arch" "t2,any")
+ (set_attr "length" "2,4")
+ (set_attr "predicable" "yes")
+ (set_attr "type" "load_byte")])
+
+(define_insn "unaligned_loadhiu"
+ [(set (match_operand:SI 0 "s_register_operand" "=l,r")
+ (zero_extend:SI
+ (unspec:HI [(match_operand:HI 1 "memory_operand" "Uw,m")]
+ UNSPEC_UNALIGNED_LOAD)))]
+ "unaligned_access && TARGET_32BIT"
+ "ldr%(h%)\t%0, %1\t@ unaligned"
+ [(set_attr "arch" "t2,any")
+ (set_attr "length" "2,4")
+ (set_attr "predicable" "yes")
+ (set_attr "type" "load_byte")])
+
+(define_insn "unaligned_storesi"
+ [(set (match_operand:SI 0 "memory_operand" "=Uw,m")
+ (unspec:SI [(match_operand:SI 1 "s_register_operand" "l,r")]
+ UNSPEC_UNALIGNED_STORE))]
+ "unaligned_access && TARGET_32BIT"
+ "str%?\t%1, %0\t@ unaligned"
+ [(set_attr "arch" "t2,any")
+ (set_attr "length" "2,4")
+ (set_attr "predicable" "yes")
+ (set_attr "type" "store1")])
+
+(define_insn "unaligned_storehi"
+ [(set (match_operand:HI 0 "memory_operand" "=Uw,m")
+ (unspec:HI [(match_operand:HI 1 "s_register_operand" "l,r")]
+ UNSPEC_UNALIGNED_STORE))]
+ "unaligned_access && TARGET_32BIT"
+ "str%(h%)\t%1, %0\t@ unaligned"
+ [(set_attr "arch" "t2,any")
+ (set_attr "length" "2,4")
+ (set_attr "predicable" "yes")
+ (set_attr "type" "store1")])
+
+(define_insn "*extv_reg"
[(set (match_operand:SI 0 "s_register_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "s_register_operand" "r")
(match_operand:SI 2 "const_int_operand" "M")
@@ -6069,8 +6295,8 @@
(define_insn "*arm_movqi_insn"
- [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,m")
- (match_operand:QI 1 "general_operand" "rI,K,m,r"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,l,Uu,r,m")
+ (match_operand:QI 1 "general_operand" "rI,K,Uu,l,m,r"))]
"TARGET_32BIT
&& ( register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode))"
@@ -6078,10 +6304,14 @@
mov%?\\t%0, %1
mvn%?\\t%0, #%B1
ldr%(b%)\\t%0, %1
+ str%(b%)\\t%1, %0
+ ldr%(b%)\\t%0, %1
str%(b%)\\t%1, %0"
- [(set_attr "type" "*,*,load1,store1")
- (set_attr "insn" "mov,mvn,*,*")
- (set_attr "predicable" "yes")]
+ [(set_attr "type" "*,*,load1,store1,load1,store1")
+ (set_attr "insn" "mov,mvn,*,*,*,*")
+ (set_attr "predicable" "yes")
+ (set_attr "arch" "any,any,t2,t2,any,any")
+ (set_attr "length" "4,4,2,2,4,4")]
)
(define_insn "*thumb1_movqi_insn"
Index: gcc-4_6-branch/gcc/config/arm/arm.opt
===================================================================
--- gcc-4_6-branch.orig/gcc/config/arm/arm.opt 2012-03-05 16:07:14.000000000 -0800
+++ gcc-4_6-branch/gcc/config/arm/arm.opt 2012-03-05 16:07:50.404936697 -0800
@@ -173,3 +173,7 @@
Target Report Var(fix_cm3_ldrd) Init(2)
Avoid overlapping destination and address registers on LDRD instructions
that may trigger Cortex-M3 errata.
+
+munaligned-access
+Target Report Var(unaligned_access) Init(2)
+Enable unaligned word and halfword accesses to packed data.
Index: gcc-4_6-branch/gcc/config/arm/constraints.md
===================================================================
--- gcc-4_6-branch.orig/gcc/config/arm/constraints.md 2012-03-05 16:07:14.000000000 -0800
+++ gcc-4_6-branch/gcc/config/arm/constraints.md 2012-03-05 16:07:50.404936697 -0800
@@ -36,6 +36,7 @@
;; The following memory constraints have been used:
;; in ARM/Thumb-2 state: Q, Ut, Uv, Uy, Un, Um, Us
;; in ARM state: Uq
+;; in Thumb state: Uu, Uw
(define_register_constraint "f" "TARGET_ARM ? FPA_REGS : NO_REGS"
@@ -344,6 +345,27 @@
(and (match_code "mem")
(match_test "REG_P (XEXP (op, 0))")))
+(define_memory_constraint "Uu"
+ "@internal
+ In Thumb state an address that is valid in 16bit encoding."
+ (and (match_code "mem")
+ (match_test "TARGET_THUMB
+ && thumb1_legitimate_address_p (GET_MODE (op), XEXP (op, 0),
+ 0)")))
+
+; The 16-bit post-increment LDR/STR accepted by thumb1_legitimate_address_p
+; are actually LDM/STM instructions, so cannot be used to access unaligned
+; data.
+(define_memory_constraint "Uw"
+ "@internal
+ In Thumb state an address that is valid in 16bit encoding, and that can be
+ used for unaligned accesses."
+ (and (match_code "mem")
+ (match_test "TARGET_THUMB
+ && thumb1_legitimate_address_p (GET_MODE (op), XEXP (op, 0),
+ 0)
+ && GET_CODE (XEXP (op, 0)) != POST_INC")))
+
;; We used to have constraint letters for S and R in ARM state, but
;; all uses of these now appear to have been removed.
Index: gcc-4_6-branch/gcc/expmed.c
===================================================================
--- gcc-4_6-branch.orig/gcc/expmed.c 2012-01-04 15:37:51.000000000 -0800
+++ gcc-4_6-branch/gcc/expmed.c 2012-03-05 16:07:50.404936697 -0800
@@ -657,6 +657,10 @@
&& GET_MODE (value) != BLKmode
&& bitsize > 0
&& GET_MODE_BITSIZE (op_mode) >= bitsize
+ /* Do not use insv for volatile bitfields when
+ -fstrict-volatile-bitfields is in effect. */
+ && !(MEM_P (op0) && MEM_VOLATILE_P (op0)
+ && flag_strict_volatile_bitfields > 0)
&& ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
&& (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))
&& insn_data[CODE_FOR_insv].operand[1].predicate (GEN_INT (bitsize),
@@ -700,19 +704,21 @@
copy_back = true;
}
- /* On big-endian machines, we count bits from the most significant.
- If the bit field insn does not, we must invert. */
-
- if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
- xbitpos = unit - bitsize - xbitpos;
-
/* We have been counting XBITPOS within UNIT.
Count instead within the size of the register. */
- if (BITS_BIG_ENDIAN && !MEM_P (xop0))
+ if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
xbitpos += GET_MODE_BITSIZE (op_mode) - unit;
unit = GET_MODE_BITSIZE (op_mode);
+ /* If BITS_BIG_ENDIAN is zero on a BYTES_BIG_ENDIAN machine, we count
+ "backwards" from the size of the unit we are inserting into.
+ Otherwise, we count bits from the most significant on a
+ BYTES/BITS_BIG_ENDIAN machine. */
+
+ if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
+ xbitpos = unit - bitsize - xbitpos;
+
/* Convert VALUE to op_mode (which insv insn wants) in VALUE1. */
value1 = value;
if (GET_MODE (value) != op_mode)
@@ -1528,6 +1534,10 @@
if (ext_mode != MAX_MACHINE_MODE
&& bitsize > 0
&& GET_MODE_BITSIZE (ext_mode) >= bitsize
+ /* Do not use extv/extzv for volatile bitfields when
+ -fstrict-volatile-bitfields is in effect. */
+ && !(MEM_P (op0) && MEM_VOLATILE_P (op0)
+ && flag_strict_volatile_bitfields > 0)
/* If op0 is a register, we need it in EXT_MODE to make it
acceptable to the format of ext(z)v. */
&& !(GET_CODE (op0) == SUBREG && GET_MODE (op0) != ext_mode)
@@ -1552,17 +1562,20 @@
/* Get ref to first byte containing part of the field. */
xop0 = adjust_address (xop0, byte_mode, xoffset);
- /* On big-endian machines, we count bits from the most significant.
- If the bit field insn does not, we must invert. */
- if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
- xbitpos = unit - bitsize - xbitpos;
-
/* Now convert from counting within UNIT to counting in EXT_MODE. */
- if (BITS_BIG_ENDIAN && !MEM_P (xop0))
+ if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
xbitpos += GET_MODE_BITSIZE (ext_mode) - unit;
unit = GET_MODE_BITSIZE (ext_mode);
+ /* If BITS_BIG_ENDIAN is zero on a BYTES_BIG_ENDIAN machine, we count
+ "backwards" from the size of the unit we are extracting from.
+ Otherwise, we count bits from the most significant on a
+ BYTES/BITS_BIG_ENDIAN machine. */
+
+ if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
+ xbitpos = unit - bitsize - xbitpos;
+
if (xtarget == 0)
xtarget = xspec_target = gen_reg_rtx (tmode);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,147 @@
2011-10-19 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF:
2011-09-09 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm-cores.def (generic-armv7-a): New architecture.
* config/arm/arm-tables.opt: Regenerate.
* config/arm/arm-tune.md: Regenerate.
* config/arm/arm.c (arm_file_start): Output .arch directive when
user passes -mcpu=generic-*.
(arm_issue_rate): Add genericv7a support.
* config/arm/arm.h (EXTRA_SPECS): Add asm_cpu_spec.
(ASM_CPU_SPEC): New define.
* config/arm/elf.h (ASM_SPEC): Use %(asm_cpu_spec).
* config/arm/semi.h (ASM_SPEC): Likewise.
* doc/invoke.texi (ARM Options): Document -mcpu=generic-*
and -mtune=generic-*.
=== modified file 'gcc/config/arm/arm-cores.def'
--- old/gcc/config/arm/arm-cores.def 2011-06-14 16:00:30 +0000
+++ new/gcc/config/arm/arm-cores.def 2011-10-19 16:46:51 +0000
@@ -124,6 +124,7 @@
ARM_CORE("mpcore", mpcore, 6K, FL_LDSCHED | FL_VFPV2, 9e)
ARM_CORE("arm1156t2-s", arm1156t2s, 6T2, FL_LDSCHED, v6t2)
ARM_CORE("arm1156t2f-s", arm1156t2fs, 6T2, FL_LDSCHED | FL_VFPV2, v6t2)
+ARM_CORE("generic-armv7-a", genericv7a, 7A, FL_LDSCHED, cortex)
ARM_CORE("cortex-a5", cortexa5, 7A, FL_LDSCHED, cortex_a5)
ARM_CORE("cortex-a8", cortexa8, 7A, FL_LDSCHED, cortex)
ARM_CORE("cortex-a9", cortexa9, 7A, FL_LDSCHED, cortex_a9)
@@ -135,3 +136,4 @@
ARM_CORE("cortex-m3", cortexm3, 7M, FL_LDSCHED, cortex)
ARM_CORE("cortex-m1", cortexm1, 6M, FL_LDSCHED, cortex)
ARM_CORE("cortex-m0", cortexm0, 6M, FL_LDSCHED, cortex)
+
=== modified file 'gcc/config/arm/arm-tune.md'
--- old/gcc/config/arm/arm-tune.md 2011-06-14 14:37:30 +0000
+++ new/gcc/config/arm/arm-tune.md 2011-10-19 16:46:51 +0000
@@ -1,5 +1,5 @@
;; -*- buffer-read-only: t -*-
;; Generated automatically by gentune.sh from arm-cores.def
(define_attr "tune"
- "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,fa526,fa626,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,cortexa5,cortexa8,cortexa9,cortexa15,cortexr4,cortexr4f,cortexr5,cortexm4,cortexm3,cortexm1,cortexm0"
+ "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,fa526,fa626,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,genericv7a,cortexa5,cortexa8,cortexa9,cortexa15,cortexr4,cortexr4f,cortexr5,cortexm4,cortexm3,cortexm1,cortexm0"
(const (symbol_ref "((enum attr_tune) arm_tune)")))
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-10-11 02:31:01 +0000
+++ new/gcc/config/arm/arm.c 2011-10-19 16:46:51 +0000
@@ -22185,6 +22185,8 @@
const char *fpu_name;
if (arm_selected_arch)
asm_fprintf (asm_out_file, "\t.arch %s\n", arm_selected_arch->name);
+ else if (strncmp (arm_selected_cpu->name, "generic", 7) == 0)
+ asm_fprintf (asm_out_file, "\t.arch %s\n", arm_selected_cpu->name + 8);
else
asm_fprintf (asm_out_file, "\t.cpu %s\n", arm_selected_cpu->name);
@@ -23717,6 +23719,7 @@
case cortexr4:
case cortexr4f:
case cortexr5:
+ case genericv7a:
case cortexa5:
case cortexa8:
case cortexa9:
=== modified file 'gcc/config/arm/arm.h'
--- old/gcc/config/arm/arm.h 2011-09-05 14:32:11 +0000
+++ new/gcc/config/arm/arm.h 2011-10-19 16:46:51 +0000
@@ -198,6 +198,7 @@
Do not define this macro if it does not need to do anything. */
#define EXTRA_SPECS \
{ "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \
+ { "asm_cpu_spec", ASM_CPU_SPEC }, \
SUBTARGET_EXTRA_SPECS
#ifndef SUBTARGET_EXTRA_SPECS
@@ -2278,4 +2279,8 @@
instruction. */
#define MAX_LDM_STM_OPS 4
+#define ASM_CPU_SPEC \
+ " %{mcpu=generic-*:-march=%*;" \
+ " :%{mcpu=*:-mcpu=%*} %{march=*:-march=%*}}"
+
#endif /* ! GCC_ARM_H */
=== modified file 'gcc/config/arm/elf.h'
--- old/gcc/config/arm/elf.h 2009-06-21 19:48:15 +0000
+++ new/gcc/config/arm/elf.h 2011-10-19 16:46:51 +0000
@@ -56,8 +56,7 @@
#define ASM_SPEC "\
%{mbig-endian:-EB} \
%{mlittle-endian:-EL} \
-%{mcpu=*:-mcpu=%*} \
-%{march=*:-march=%*} \
+%(asm_cpu_spec) \
%{mapcs-*:-mapcs-%*} \
%(subtarget_asm_float_spec) \
%{mthumb-interwork:-mthumb-interwork} \
=== modified file 'gcc/config/arm/semi.h'
--- old/gcc/config/arm/semi.h 2007-08-02 09:49:31 +0000
+++ new/gcc/config/arm/semi.h 2011-10-19 16:46:51 +0000
@@ -65,8 +65,7 @@
#define ASM_SPEC "\
%{fpic|fpie: -k} %{fPIC|fPIE: -k} \
%{mbig-endian:-EB} \
-%{mcpu=*:-mcpu=%*} \
-%{march=*:-march=%*} \
+%(arm_cpu_spec) \
%{mapcs-float:-mfloat} \
%{msoft-float:-mfloat-abi=soft} %{mhard-float:-mfloat-abi=hard} \
%{mfloat-abi=*} %{mfpu=*} \
=== modified file 'gcc/doc/invoke.texi'
--- old/gcc/doc/invoke.texi 2011-08-13 08:32:32 +0000
+++ new/gcc/doc/invoke.texi 2011-10-19 16:46:51 +0000
@@ -10215,6 +10215,10 @@
@samp{cortex-m0},
@samp{xscale}, @samp{iwmmxt}, @samp{iwmmxt2}, @samp{ep9312}.
+@option{-mcpu=generic-@var{arch}} is also permissible, and is
+equivalent to @option{-march=@var{arch} -mtune=generic-@var{arch}}.
+See @option{-mtune} for more information.
+
@item -mtune=@var{name}
@opindex mtune
This option is very similar to the @option{-mcpu=} option, except that
@@ -10226,6 +10230,13 @@
For some ARM implementations better performance can be obtained by using
this option.
+@option{-mtune=generic-@var{arch}} specifies that GCC should tune the
+performance for a blend of processors within architecture @var{arch}.
+The aim is to generate code that run well on the current most popular
+processors, balancing between optimizations that benefit some CPUs in the
+range, and avoiding performance pitfalls of other CPUs. The effects of
+this option may change in future GCC versions as CPU models come and go.
+
@item -march=@var{name}
@opindex march
This specifies the name of the target ARM architecture. GCC uses this
@@ -0,0 +1,304 @@
2011-10-19 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF:
2011-10-18 Andrew Stubbs <ams@codesourcery.com>
* config/arm/driver-arm.c (host_detect_local_cpu): Close the file
before exiting.
2011-10-18 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config.host (arm*-*-linux*): Add driver-arm.o and x-arm.
* config/arm/arm.opt: Add 'native' processor_type and
arm_arch enum values.
* config/arm/arm.h (host_detect_local_cpu): New prototype.
(EXTRA_SPEC_FUNCTIONS): New define.
(MCPU_MTUNE_NATIVE_SPECS): New define.
(DRIVER_SELF_SPECS): New define.
* config/arm/driver-arm.c: New file.
* config/arm/x-arm: New file.
* doc/invoke.texi (ARM Options): Document -mcpu=native,
-mtune=native and -march=native.
=== modified file 'gcc/config.host'
--- old/gcc/config.host 2011-02-15 09:49:14 +0000
+++ new/gcc/config.host 2011-10-19 17:01:50 +0000
@@ -100,6 +100,14 @@
esac
case ${host} in
+ arm*-*-linux*)
+ case ${target} in
+ arm*-*-*)
+ host_extra_gcc_objs="driver-arm.o"
+ host_xmake_file="${host_xmake_file} arm/x-arm"
+ ;;
+ esac
+ ;;
alpha*-*-linux*)
case ${target} in
alpha*-*-linux*)
=== modified file 'gcc/config/arm/arm.h'
--- old/gcc/config/arm/arm.h 2011-10-19 16:46:51 +0000
+++ new/gcc/config/arm/arm.h 2011-10-19 17:01:50 +0000
@@ -2283,4 +2283,21 @@
" %{mcpu=generic-*:-march=%*;" \
" :%{mcpu=*:-mcpu=%*} %{march=*:-march=%*}}"
+/* -mcpu=native handling only makes sense with compiler running on
+ an ARM chip. */
+#if defined(__arm__)
+extern const char *host_detect_local_cpu (int argc, const char **argv);
+# define EXTRA_SPEC_FUNCTIONS \
+ { "local_cpu_detect", host_detect_local_cpu },
+
+# define MCPU_MTUNE_NATIVE_SPECS \
+ " %{march=native:%<march=native %:local_cpu_detect(arch)}" \
+ " %{mcpu=native:%<mcpu=native %:local_cpu_detect(cpu)}" \
+ " %{mtune=native:%<mtune=native %:local_cpu_detect(tune)}"
+#else
+# define MCPU_MTUNE_NATIVE_SPECS ""
+#endif
+
+#define DRIVER_SELF_SPECS MCPU_MTUNE_NATIVE_SPECS
+
#endif /* ! GCC_ARM_H */
=== modified file 'gcc/config/arm/arm.opt'
--- old/gcc/config/arm/arm.opt 2011-10-11 02:31:01 +0000
+++ new/gcc/config/arm/arm.opt 2011-10-19 17:01:50 +0000
@@ -48,6 +48,11 @@
Target RejectNegative Joined
Specify the name of the target architecture
+; Other arm_arch values are loaded from arm-tables.opt
+; but that is a generated file and this is an odd-one-out.
+EnumValue
+Enum(arm_arch) String(native) Value(-1) DriverOnly
+
marm
Target RejectNegative InverseMask(THUMB) Undocumented
@@ -153,6 +158,11 @@
Target RejectNegative Joined
Tune code for the given processor
+; Other processor_type values are loaded from arm-tables.opt
+; but that is a generated file and this is an odd-one-out.
+EnumValue
+Enum(processor_type) String(native) Value(-1) DriverOnly
+
mwords-little-endian
Target Report RejectNegative Mask(LITTLE_WORDS)
Assume big endian bytes, little endian words
=== added file 'gcc/config/arm/driver-arm.c'
--- old/gcc/config/arm/driver-arm.c 1970-01-01 00:00:00 +0000
+++ new/gcc/config/arm/driver-arm.c 2011-10-19 17:07:55 +0000
@@ -0,0 +1,149 @@
+/* Subroutines for the gcc driver.
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "configargs.h"
+
+struct vendor_cpu {
+ const char *part_no;
+ const char *arch_name;
+ const char *cpu_name;
+};
+
+static struct vendor_cpu arm_cpu_table[] = {
+ {"0x926", "armv5te", "arm926ej-s"},
+ {"0xa26", "armv5te", "arm1026ej-s"},
+ {"0xb02", "armv6k", "mpcore"},
+ {"0xb36", "armv6j", "arm1136j-s"},
+ {"0xb56", "armv6t2", "arm1156t2-s"},
+ {"0xb76", "armv6zk", "arm1176jz-s"},
+ {"0xc05", "armv7-a", "cortex-a5"},
+ {"0xc08", "armv7-a", "cortex-a8"},
+ {"0xc09", "armv7-a", "cortex-a9"},
+ {"0xc0f", "armv7-a", "cortex-a15"},
+ {"0xc14", "armv7-r", "cortex-r4"},
+ {"0xc15", "armv7-r", "cortex-r5"},
+ {"0xc20", "armv6-m", "cortex-m0"},
+ {"0xc21", "armv6-m", "cortex-m1"},
+ {"0xc23", "armv7-m", "cortex-m3"},
+ {"0xc24", "armv7e-m", "cortex-m4"},
+ {NULL, NULL, NULL}
+};
+
+struct {
+ const char *vendor_no;
+ const struct vendor_cpu *vendor_parts;
+} vendors[] = {
+ {"0x41", arm_cpu_table},
+ {NULL, NULL}
+};
+
+/* This will be called by the spec parser in gcc.c when it sees
+ a %:local_cpu_detect(args) construct. Currently it will be called
+ with either "arch", "cpu" or "tune" as argument depending on if
+ -march=native, -mcpu=native or -mtune=native is to be substituted.
+
+ It returns a string containing new command line parameters to be
+ put at the place of the above two options, depending on what CPU
+ this is executed. E.g. "-march=armv7-a" on a Cortex-A8 for
+ -march=native. If the routine can't detect a known processor,
+ the -march or -mtune option is discarded.
+
+ ARGC and ARGV are set depending on the actual arguments given
+ in the spec. */
+const char *
+host_detect_local_cpu (int argc, const char **argv)
+{
+ const char *val = NULL;
+ char buf[128];
+ FILE *f = NULL;
+ bool arch;
+ const struct vendor_cpu *cpu_table = NULL;
+
+ if (argc < 1)
+ goto not_found;
+
+ arch = strcmp (argv[0], "arch") == 0;
+ if (!arch && strcmp (argv[0], "cpu") != 0 && strcmp (argv[0], "tune"))
+ goto not_found;
+
+ f = fopen ("/proc/cpuinfo", "r");
+ if (f == NULL)
+ goto not_found;
+
+ while (fgets (buf, sizeof (buf), f) != NULL)
+ {
+ /* Ensure that CPU implementer is ARM (0x41). */
+ if (strncmp (buf, "CPU implementer", sizeof ("CPU implementer") - 1) == 0)
+ {
+ int i;
+ for (i = 0; vendors[i].vendor_no != NULL; i++)
+ if (strstr (buf, vendors[i].vendor_no) != NULL)
+ {
+ cpu_table = vendors[i].vendor_parts;
+ break;
+ }
+ }
+
+ /* Detect arch/cpu. */
+ if (strncmp (buf, "CPU part", sizeof ("CPU part") - 1) == 0)
+ {
+ int i;
+
+ if (cpu_table == NULL)
+ goto not_found;
+
+ for (i = 0; cpu_table[i].part_no != NULL; i++)
+ if (strstr (buf, cpu_table[i].part_no) != NULL)
+ {
+ val = arch ? cpu_table[i].arch_name : cpu_table[i].cpu_name;
+ break;
+ }
+ break;
+ }
+ }
+
+ fclose (f);
+
+ if (val == NULL)
+ goto not_found;
+
+ return concat ("-m", argv[0], "=", val, NULL);
+
+not_found:
+ {
+ unsigned int i;
+ unsigned int opt;
+ const char *search[] = {NULL, "arch"};
+
+ if (f)
+ fclose (f);
+
+ search[0] = argv[0];
+ for (opt = 0; opt < ARRAY_SIZE (search); opt++)
+ for (i = 0; i < ARRAY_SIZE (configure_default_options); i++)
+ if (strcmp (configure_default_options[i].name, search[opt]) == 0)
+ return concat ("-m", search[opt], "=",
+ configure_default_options[i].value, NULL);
+ return NULL;
+ }
+}
=== added file 'gcc/config/arm/x-arm'
--- old/gcc/config/arm/x-arm 1970-01-01 00:00:00 +0000
+++ new/gcc/config/arm/x-arm 2011-10-19 17:01:50 +0000
@@ -0,0 +1,3 @@
+driver-arm.o: $(srcdir)/config/arm/driver-arm.c \
+ $(CONFIG_H) $(SYSTEM_H)
+ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
=== modified file 'gcc/doc/invoke.texi'
--- old/gcc/doc/invoke.texi 2011-10-19 16:46:51 +0000
+++ new/gcc/doc/invoke.texi 2011-10-19 17:01:50 +0000
@@ -10215,10 +10215,16 @@
@samp{cortex-m0},
@samp{xscale}, @samp{iwmmxt}, @samp{iwmmxt2}, @samp{ep9312}.
+
@option{-mcpu=generic-@var{arch}} is also permissible, and is
equivalent to @option{-march=@var{arch} -mtune=generic-@var{arch}}.
See @option{-mtune} for more information.
+@option{-mcpu=native} causes the compiler to auto-detect the CPU
+of the build computer. At present, this feature is only supported on
+Linux, and not all architectures are recognised. If the auto-detect is
+unsuccessful the option has no effect.
+
@item -mtune=@var{name}
@opindex mtune
This option is very similar to the @option{-mcpu=} option, except that
@@ -10237,6 +10243,11 @@
range, and avoiding performance pitfalls of other CPUs. The effects of
this option may change in future GCC versions as CPU models come and go.
+@option{-mtune=native} causes the compiler to auto-detect the CPU
+of the build computer. At present, this feature is only supported on
+Linux, and not all architectures are recognised. If the auto-detect is
+unsuccessful the option has no effect.
+
@item -march=@var{name}
@opindex march
This specifies the name of the target ARM architecture. GCC uses this
@@ -10250,6 +10261,11 @@
@samp{armv7}, @samp{armv7-a}, @samp{armv7-r}, @samp{armv7-m},
@samp{iwmmxt}, @samp{iwmmxt2}, @samp{ep9312}.
+@option{-march=native} causes the compiler to auto-detect the architecture
+of the build computer. At present, this feature is only supported on
+Linux, and not all architectures are recognised. If the auto-detect is
+unsuccessful the option has no effect.
+
@item -mfpu=@var{name}
@itemx -mfpe=@var{number}
@itemx -mfp=@var{number}
@@ -0,0 +1,123 @@
2011-10-19 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF:
2011-10-18 Andrew Stubbs <ams@codesourcery.com>
PR tree-optimization/50717
gcc/
* tree-ssa-math-opts.c (is_widening_mult_p): Remove the 'type'
parameter. Calculate 'type' from stmt.
(convert_mult_to_widen): Update call the is_widening_mult_p.
(convert_plusminus_to_widen): Likewise.
gcc/testsuite/
* gcc.dg/pr50717-1.c: New file.
* gcc.target/arm/wmul-12.c: Correct types.
* gcc.target/arm/wmul-8.c: Correct types.
=== added file 'gcc/testsuite/gcc.dg/pr50717-1.c'
--- old/gcc/testsuite/gcc.dg/pr50717-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/pr50717-1.c 2011-10-19 14:42:50 +0000
@@ -0,0 +1,26 @@
+/* PR tree-optimization/50717 */
+/* Ensure that widening multiply-and-accumulate is not used where integer
+ type promotion or users' casts should prevent it. */
+
+/* { dg-options "-O2 -fdump-tree-widening_mul" } */
+
+long long
+f (unsigned int a, char b, long long c)
+{
+ return (a * b) + c;
+}
+
+int
+g (short a, short b, int c)
+{
+ return (short)(a * b) + c;
+}
+
+int
+h (char a, char b, int c)
+{
+ return (char)(a * b) + c;
+}
+
+/* { dg-final { scan-tree-dump-times "WIDEN_MULT_PLUS_EXPR" 0 "widening_mul" } } */
+/* { dg-final { cleanup-tree-dump "widening_mul" } } */
=== modified file 'gcc/testsuite/gcc.target/arm/wmul-12.c'
--- old/gcc/testsuite/gcc.target/arm/wmul-12.c 2011-07-22 15:46:42 +0000
+++ new/gcc/testsuite/gcc.target/arm/wmul-12.c 2011-10-19 14:42:50 +0000
@@ -4,8 +4,8 @@
long long
foo (int *b, int *c)
{
- int tmp = *b * *c;
- return 10 + (long long)tmp;
+ long long tmp = (long long)*b * *c;
+ return 10 + tmp;
}
/* { dg-final { scan-assembler "smlal" } } */
=== modified file 'gcc/testsuite/gcc.target/arm/wmul-8.c'
--- old/gcc/testsuite/gcc.target/arm/wmul-8.c 2011-07-15 14:16:54 +0000
+++ new/gcc/testsuite/gcc.target/arm/wmul-8.c 2011-10-19 14:42:50 +0000
@@ -4,7 +4,7 @@
long long
foo (long long a, int *b, int *c)
{
- return a + *b * *c;
+ return a + (long long)*b * *c;
}
/* { dg-final { scan-assembler "smlal" } } */
=== modified file 'gcc/tree-ssa-math-opts.c'
--- old/gcc/tree-ssa-math-opts.c 2011-09-08 20:11:43 +0000
+++ new/gcc/tree-ssa-math-opts.c 2011-10-19 14:42:50 +0000
@@ -1351,10 +1351,12 @@
and *TYPE2_OUT would give the operands of the multiplication. */
static bool
-is_widening_mult_p (tree type, gimple stmt,
+is_widening_mult_p (gimple stmt,
tree *type1_out, tree *rhs1_out,
tree *type2_out, tree *rhs2_out)
{
+ tree type = TREE_TYPE (gimple_assign_lhs (stmt));
+
if (TREE_CODE (type) != INTEGER_TYPE
&& TREE_CODE (type) != FIXED_POINT_TYPE)
return false;
@@ -1416,7 +1418,7 @@
if (TREE_CODE (type) != INTEGER_TYPE)
return false;
- if (!is_widening_mult_p (type, stmt, &type1, &rhs1, &type2, &rhs2))
+ if (!is_widening_mult_p (stmt, &type1, &rhs1, &type2, &rhs2))
return false;
to_mode = TYPE_MODE (type);
@@ -1592,7 +1594,7 @@
if (code == PLUS_EXPR
&& (rhs1_code == MULT_EXPR || rhs1_code == WIDEN_MULT_EXPR))
{
- if (!is_widening_mult_p (type, rhs1_stmt, &type1, &mult_rhs1,
+ if (!is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,
&type2, &mult_rhs2))
return false;
add_rhs = rhs2;
@@ -1600,7 +1602,7 @@
}
else if (rhs2_code == MULT_EXPR || rhs2_code == WIDEN_MULT_EXPR)
{
- if (!is_widening_mult_p (type, rhs2_stmt, &type1, &mult_rhs1,
+ if (!is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1,
&type2, &mult_rhs2))
return false;
add_rhs = rhs1;
@@ -0,0 +1,24 @@
2011-10-21 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF mainline:
2011-10-21 Andrew Stubbs <ams@codesourcery.com>
PR target/50809
gcc/
* config/arm/driver-arm.c (vendors): Make static.
=== modified file 'gcc/config/arm/driver-arm.c'
--- old/gcc/config/arm/driver-arm.c 2011-10-19 17:07:55 +0000
+++ new/gcc/config/arm/driver-arm.c 2011-10-21 19:27:47 +0000
@@ -49,7 +49,7 @@
{NULL, NULL, NULL}
};
-struct {
+static struct {
const char *vendor_no;
const struct vendor_cpu *vendor_parts;
} vendors[] = {
@@ -0,0 +1,453 @@
2011-10-27 Ira Rosen <ira.rosen@linaro.org>
Backport from mainline:
2011-10-16 Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-vect-stmts.c (vectorizable_load): For SLP without permutation
treat the first load of the node as the first element in its
interleaving chain.
* tree-vect-slp.c (vect_get_and_check_slp_defs): Swap the operands if
necessary and possible.
(vect_build_slp_tree): Add new argument. Allow load groups of any size
in basic blocks. Keep all the loads for further permutation check.
Use the new argument to determine if there is a permutation. Update
the recursive calls.
(vect_supported_load_permutation_p): Allow subchains of interleaving
chains in basic block vectorization.
(vect_analyze_slp_instance): Update the call to vect_build_slp_tree.
Check load permutation based on the new parameter.
(vect_schedule_slp_instance): Don't start from the first element in
interleaving chain unless the loads are permuted.
gcc/testsuite/
* gcc.dg/vect/bb-slp-29.c: New test.
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-29.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-29.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-29.c 2011-10-23 11:29:25 +0000
@@ -0,0 +1,59 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define A 3
+#define B 4
+#define N 256
+
+short src[N], dst[N];
+
+void foo (short * __restrict__ dst, short * __restrict__ src, int h, int stride, int dummy)
+{
+ int i;
+ h /= 16;
+ for (i = 0; i < h; i++)
+ {
+ dst[0] = A*src[0] + B*src[1];
+ dst[1] = A*src[1] + B*src[2];
+ dst[2] = A*src[2] + B*src[3];
+ dst[3] = A*src[3] + B*src[4];
+ dst[4] = A*src[4] + B*src[5];
+ dst[5] = A*src[5] + B*src[6];
+ dst[6] = A*src[6] + B*src[7];
+ dst[7] = A*src[7] + B*src[8];
+ dst += stride;
+ src += stride;
+ if (dummy == 32)
+ abort ();
+ }
+}
+
+
+int main (void)
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ dst[i] = 0;
+ src[i] = i;
+ }
+
+ foo (dst, src, N, 8, 0);
+
+ for (i = 0; i < N/2; i++)
+ {
+ if (dst[i] != A * src[i] + B * src[i+1])
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target { vect_int_mult && vect_element_align } } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== modified file 'gcc/tree-vect-slp.c'
--- old/gcc/tree-vect-slp.c 2011-10-06 11:08:08 +0000
+++ new/gcc/tree-vect-slp.c 2011-10-23 11:29:25 +0000
@@ -115,13 +115,15 @@
{
tree oprnd;
unsigned int i, number_of_oprnds;
- tree def;
+ tree def[2];
gimple def_stmt;
enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
stmt_vec_info stmt_info =
vinfo_for_stmt (VEC_index (gimple, SLP_TREE_SCALAR_STMTS (slp_node), 0));
enum gimple_rhs_class rhs_class;
struct loop *loop = NULL;
+ enum tree_code rhs_code;
+ bool different_types = false;
if (loop_vinfo)
loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -133,7 +135,7 @@
{
oprnd = gimple_op (stmt, i + 1);
- if (!vect_is_simple_use (oprnd, loop_vinfo, bb_vinfo, &def_stmt, &def,
+ if (!vect_is_simple_use (oprnd, loop_vinfo, bb_vinfo, &def_stmt, &def[i],
&dt[i])
|| (!def_stmt && dt[i] != vect_constant_def))
{
@@ -188,11 +190,11 @@
switch (gimple_code (def_stmt))
{
case GIMPLE_PHI:
- def = gimple_phi_result (def_stmt);
+ def[i] = gimple_phi_result (def_stmt);
break;
case GIMPLE_ASSIGN:
- def = gimple_assign_lhs (def_stmt);
+ def[i] = gimple_assign_lhs (def_stmt);
break;
default:
@@ -206,8 +208,8 @@
{
/* op0 of the first stmt of the group - store its info. */
*first_stmt_dt0 = dt[i];
- if (def)
- *first_stmt_def0_type = TREE_TYPE (def);
+ if (def[i])
+ *first_stmt_def0_type = TREE_TYPE (def[i]);
else
*first_stmt_const_oprnd = oprnd;
@@ -227,8 +229,8 @@
{
/* op1 of the first stmt of the group - store its info. */
*first_stmt_dt1 = dt[i];
- if (def)
- *first_stmt_def1_type = TREE_TYPE (def);
+ if (def[i])
+ *first_stmt_def1_type = TREE_TYPE (def[i]);
else
{
/* We assume that the stmt contains only one constant
@@ -249,22 +251,53 @@
the def-stmt/s of the first stmt. */
if ((i == 0
&& (*first_stmt_dt0 != dt[i]
- || (*first_stmt_def0_type && def
+ || (*first_stmt_def0_type && def[0]
&& !types_compatible_p (*first_stmt_def0_type,
- TREE_TYPE (def)))))
+ TREE_TYPE (def[0])))))
|| (i == 1
&& (*first_stmt_dt1 != dt[i]
- || (*first_stmt_def1_type && def
+ || (*first_stmt_def1_type && def[1]
&& !types_compatible_p (*first_stmt_def1_type,
- TREE_TYPE (def)))))
- || (!def
+ TREE_TYPE (def[1])))))
+ || (!def[i]
&& !types_compatible_p (TREE_TYPE (*first_stmt_const_oprnd),
- TREE_TYPE (oprnd))))
+ TREE_TYPE (oprnd)))
+ || different_types)
{
- if (vect_print_dump_info (REPORT_SLP))
- fprintf (vect_dump, "Build SLP failed: different types ");
+ if (i != number_of_oprnds - 1)
+ different_types = true;
+ else
+ {
+ if (is_gimple_assign (stmt)
+ && (rhs_code = gimple_assign_rhs_code (stmt))
+ && TREE_CODE_CLASS (rhs_code) == tcc_binary
+ && commutative_tree_code (rhs_code)
+ && *first_stmt_dt0 == dt[1]
+ && *first_stmt_dt1 == dt[0]
+ && def[0] && def[1]
+ && !(*first_stmt_def0_type
+ && !types_compatible_p (*first_stmt_def0_type,
+ TREE_TYPE (def[1])))
+ && !(*first_stmt_def1_type
+ && !types_compatible_p (*first_stmt_def1_type,
+ TREE_TYPE (def[0]))))
+ {
+ if (vect_print_dump_info (REPORT_SLP))
+ {
+ fprintf (vect_dump, "Swapping operands of ");
+ print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM);
+ }
+ swap_tree_operands (stmt, gimple_assign_rhs1_ptr (stmt),
+ gimple_assign_rhs2_ptr (stmt));
+ }
+ else
+ {
+ if (vect_print_dump_info (REPORT_SLP))
+ fprintf (vect_dump, "Build SLP failed: different types ");
- return false;
+ return false;
+ }
+ }
}
}
}
@@ -278,10 +311,10 @@
case vect_internal_def:
case vect_reduction_def:
- if (i == 0)
+ if ((i == 0 && !different_types) || (i == 1 && different_types))
VEC_safe_push (gimple, heap, *def_stmts0, def_stmt);
else
- VEC_safe_push (gimple, heap, *def_stmts1, def_stmt);
+ VEC_safe_push (gimple, heap, *def_stmts1, def_stmt);
break;
default:
@@ -289,7 +322,7 @@
if (vect_print_dump_info (REPORT_SLP))
{
fprintf (vect_dump, "Build SLP failed: illegal type of def ");
- print_generic_expr (vect_dump, def, TDF_SLIM);
+ print_generic_expr (vect_dump, def[i], TDF_SLIM);
}
return false;
@@ -312,7 +345,7 @@
int ncopies_for_cost, unsigned int *max_nunits,
VEC (int, heap) **load_permutation,
VEC (slp_tree, heap) **loads,
- unsigned int vectorization_factor)
+ unsigned int vectorization_factor, bool *loads_permuted)
{
VEC (gimple, heap) *def_stmts0 = VEC_alloc (gimple, heap, group_size);
VEC (gimple, heap) *def_stmts1 = VEC_alloc (gimple, heap, group_size);
@@ -523,7 +556,9 @@
/* Check that the size of interleaved loads group is not
greater than the SLP group size. */
- if (DR_GROUP_SIZE (vinfo_for_stmt (stmt)) > ncopies * group_size)
+ if (loop_vinfo
+ && DR_GROUP_SIZE (vinfo_for_stmt (stmt))
+ > ncopies * group_size)
{
if (vect_print_dump_info (REPORT_SLP))
{
@@ -644,19 +679,22 @@
/* Strided loads were reached - stop the recursion. */
if (stop_recursion)
{
+ VEC_safe_push (slp_tree, heap, *loads, *node);
if (permutation)
{
- VEC_safe_push (slp_tree, heap, *loads, *node);
+
+ *loads_permuted = true;
*inside_cost
+= targetm.vectorize.builtin_vectorization_cost (vec_perm, NULL, 0)
* group_size;
}
else
- {
- /* We don't check here complex numbers chains, so we keep them in
- LOADS for further check in vect_supported_load_permutation_p. */
+ {
+ /* We don't check here complex numbers chains, so we set
+ LOADS_PERMUTED for further check in
+ vect_supported_load_permutation_p. */
if (rhs_code == REALPART_EXPR || rhs_code == IMAGPART_EXPR)
- VEC_safe_push (slp_tree, heap, *loads, *node);
+ *loads_permuted = true;
}
return true;
@@ -675,7 +713,7 @@
if (!vect_build_slp_tree (loop_vinfo, bb_vinfo, &left_node, group_size,
inside_cost, outside_cost, ncopies_for_cost,
max_nunits, load_permutation, loads,
- vectorization_factor))
+ vectorization_factor, loads_permuted))
return false;
SLP_TREE_LEFT (*node) = left_node;
@@ -693,7 +731,7 @@
if (!vect_build_slp_tree (loop_vinfo, bb_vinfo, &right_node, group_size,
inside_cost, outside_cost, ncopies_for_cost,
max_nunits, load_permutation, loads,
- vectorization_factor))
+ vectorization_factor, loads_permuted))
return false;
SLP_TREE_RIGHT (*node) = right_node;
@@ -879,8 +917,10 @@
bool supported, bad_permutation = false;
sbitmap load_index;
slp_tree node, other_complex_node;
- gimple stmt, first = NULL, other_node_first;
+ gimple stmt, first = NULL, other_node_first, load, next_load, first_load;
unsigned complex_numbers = 0;
+ struct data_reference *dr;
+ bb_vec_info bb_vinfo;
/* FORNOW: permutations are only supported in SLP. */
if (!slp_instn)
@@ -1040,6 +1080,76 @@
}
}
+ /* In basic block vectorization we allow any subchain of an interleaving
+ chain.
+ FORNOW: not supported in loop SLP because of realignment compications. */
+ bb_vinfo = STMT_VINFO_BB_VINFO (vinfo_for_stmt (stmt));
+ bad_permutation = false;
+ /* Check that for every node in the instance teh loads form a subchain. */
+ if (bb_vinfo)
+ {
+ FOR_EACH_VEC_ELT (slp_tree, SLP_INSTANCE_LOADS (slp_instn), i, node)
+ {
+ next_load = NULL;
+ first_load = NULL;
+ FOR_EACH_VEC_ELT (gimple, SLP_TREE_SCALAR_STMTS (node), j, load)
+ {
+ if (!first_load)
+ first_load = DR_GROUP_FIRST_DR (vinfo_for_stmt (load));
+ else if (first_load
+ != DR_GROUP_FIRST_DR (vinfo_for_stmt (load)))
+ {
+ bad_permutation = true;
+ break;
+ }
+
+ if (j != 0 && next_load != load)
+ {
+ bad_permutation = true;
+ break;
+ }
+
+ next_load = DR_GROUP_NEXT_DR (vinfo_for_stmt (load));
+ }
+
+ if (bad_permutation)
+ break;
+ }
+
+ /* Check that the alignment of the first load in every subchain, i.e.,
+ the first statement in every load node, is supported. */
+ if (!bad_permutation)
+ {
+ FOR_EACH_VEC_ELT (slp_tree, SLP_INSTANCE_LOADS (slp_instn), i, node)
+ {
+ first_load = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (node), 0);
+ if (first_load
+ != DR_GROUP_FIRST_DR (vinfo_for_stmt (first_load)))
+ {
+ dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_load));
+ if (vect_supportable_dr_alignment (dr, false)
+ == dr_unaligned_unsupported)
+ {
+ if (vect_print_dump_info (REPORT_SLP))
+ {
+ fprintf (vect_dump, "unsupported unaligned load ");
+ print_gimple_stmt (vect_dump, first_load, 0,
+ TDF_SLIM);
+ }
+ bad_permutation = true;
+ break;
+ }
+ }
+ }
+
+ if (!bad_permutation)
+ {
+ VEC_free (int, heap, SLP_INSTANCE_LOAD_PERMUTATION (slp_instn));
+ return true;
+ }
+ }
+ }
+
/* FORNOW: the only supported permutation is 0..01..1.. of length equal to
GROUP_SIZE and where each sequence of same drs is of GROUP_SIZE length as
well (unless it's reduction). */
@@ -1149,6 +1259,7 @@
VEC (int, heap) *load_permutation;
VEC (slp_tree, heap) *loads;
struct data_reference *dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (stmt));
+ bool loads_permuted = false;
if (dr)
{
@@ -1238,7 +1349,7 @@
if (vect_build_slp_tree (loop_vinfo, bb_vinfo, &node, group_size,
&inside_cost, &outside_cost, ncopies_for_cost,
&max_nunits, &load_permutation, &loads,
- vectorization_factor))
+ vectorization_factor, &loads_permuted))
{
/* Calculate the unrolling factor based on the smallest type. */
if (max_nunits > nunits)
@@ -1263,7 +1374,8 @@
SLP_INSTANCE_LOADS (new_instance) = loads;
SLP_INSTANCE_FIRST_LOAD_STMT (new_instance) = NULL;
SLP_INSTANCE_LOAD_PERMUTATION (new_instance) = load_permutation;
- if (VEC_length (slp_tree, loads))
+
+ if (loads_permuted)
{
if (!vect_supported_load_permutation_p (new_instance, group_size,
load_permutation))
@@ -2542,10 +2654,11 @@
/* Loads should be inserted before the first load. */
if (SLP_INSTANCE_FIRST_LOAD_STMT (instance)
&& STMT_VINFO_STRIDED_ACCESS (stmt_info)
- && !REFERENCE_CLASS_P (gimple_get_lhs (stmt)))
+ && !REFERENCE_CLASS_P (gimple_get_lhs (stmt))
+ && SLP_INSTANCE_LOAD_PERMUTATION (instance))
si = gsi_for_stmt (SLP_INSTANCE_FIRST_LOAD_STMT (instance));
else if (is_pattern_stmt_p (stmt_info))
- si = gsi_for_stmt (STMT_VINFO_RELATED_STMT (stmt_info));
+ si = gsi_for_stmt (STMT_VINFO_RELATED_STMT (stmt_info));
else
si = gsi_for_stmt (stmt);
=== modified file 'gcc/tree-vect-stmts.c'
--- old/gcc/tree-vect-stmts.c 2011-10-16 12:16:07 +0000
+++ new/gcc/tree-vect-stmts.c 2011-10-23 11:29:25 +0000
@@ -4285,6 +4285,11 @@
if (strided_load)
{
first_stmt = DR_GROUP_FIRST_DR (stmt_info);
+ if (slp
+ && !SLP_INSTANCE_LOAD_PERMUTATION (slp_node_instance)
+ && first_stmt != VEC_index (gimple, SLP_TREE_SCALAR_STMTS (slp_node), 0))
+ first_stmt = VEC_index (gimple, SLP_TREE_SCALAR_STMTS (slp_node), 0);
+
/* Check if the chain of loads is already vectorized. */
if (STMT_VINFO_VEC_STMT (vinfo_for_stmt (first_stmt)))
{
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,61 @@
2011-11-04 Revital Eres <revital.eres@linaro.org>
Backport from mainline -r180673:
gcc/
* modulo-sched.c (generate_prolog_epilog): Mark prolog
and epilog as BB_DISABLE_SCHEDULE.
(mark_loop_unsched): New function.
(sms_schedule): Call it.
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-10-10 14:35:32 +0000
+++ new/gcc/modulo-sched.c 2011-10-30 05:31:00 +0000
@@ -1173,6 +1173,8 @@
/* Put the prolog on the entry edge. */
e = loop_preheader_edge (loop);
split_edge_and_insert (e, get_insns ());
+ if (!flag_resched_modulo_sched)
+ e->dest->flags |= BB_DISABLE_SCHEDULE;
end_sequence ();
@@ -1186,9 +1188,24 @@
gcc_assert (single_exit (loop));
e = single_exit (loop);
split_edge_and_insert (e, get_insns ());
+ if (!flag_resched_modulo_sched)
+ e->dest->flags |= BB_DISABLE_SCHEDULE;
+
end_sequence ();
}
+/* Mark LOOP as software pipelined so the later
+ scheduling passes don't touch it. */
+static void
+mark_loop_unsched (struct loop *loop)
+{
+ unsigned i;
+ basic_block *bbs = get_loop_body (loop);
+
+ for (i = 0; i < loop->num_nodes; i++)
+ bbs[i]->flags |= BB_DISABLE_SCHEDULE;
+}
+
/* Return true if all the BBs of the loop are empty except the
loop header. */
static bool
@@ -1714,9 +1731,10 @@
permute_partial_schedule (ps, g->closing_branch->first_note);
/* Mark this loop as software pipelined so the later
- scheduling passes doesn't touch it. */
+ scheduling passes don't touch it. */
if (! flag_resched_modulo_sched)
- g->bb->flags |= BB_DISABLE_SCHEDULE;
+ mark_loop_unsched (loop);
+
/* The life-info is not valid any more. */
df_set_bb_dirty (g->bb);
@@ -0,0 +1,23 @@
2011-11-02 Andrew Stubbs <ams@codesourcery.com>
Backport from FSF mainline:
2011-11-01 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/bpabi.h (BE8_LINK_SPEC): Recognize generic-armv7 tuning.
=== modified file 'gcc/config/arm/bpabi.h'
--- old/gcc/config/arm/bpabi.h 2010-12-20 17:48:51 +0000
+++ new/gcc/config/arm/bpabi.h 2011-11-02 21:02:53 +0000
@@ -56,7 +56,8 @@
"|march=armv4|mcpu=fa526|mcpu=fa626:--fix-v4bx}"
#define BE8_LINK_SPEC " %{mbig-endian:%{march=armv7-a|mcpu=cortex-a5"\
- "|mcpu=cortex-a8|mcpu=cortex-a9|mcpu=cortex-a15:%{!r:--be8}}}"
+ "|mcpu=cortex-a8|mcpu=cortex-a9|mcpu=cortex-a15|mcpu=generic-armv7-a"\
+ ":%{!r:--be8}}}"
/* Tell the assembler to build BPABI binaries. */
#undef SUBTARGET_EXTRA_ASM_SPEC
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,515 @@
2011-11-21 Michael Hope <michael.hope@linaro.org>
Backport from mainline r180131:
2011-10-18 Julian Brown <julian@codesourcery.com>
gcc/
* config/arm/arm.c (arm_block_move_unaligned_straight)
(arm_adjust_block_mem, arm_block_move_unaligned_loop)
(arm_movmemqi_unaligned): New.
(arm_gen_movmemqi): Support unaligned block copies.
gcc/testsuite/
* lib/target-supports.exp (check_effective_target_arm_unaligned): New.
* gcc.target/arm/unaligned-memcpy-1.c: New.
* gcc.target/arm/unaligned-memcpy-2.c: New.
* gcc.target/arm/unaligned-memcpy-3.c: New.
* gcc.target/arm/unaligned-memcpy-4.c: New.
2011-09-15 James Greenhalgh <james.greenhalgh@arm.com>
gcc/
* config/arm/arm.h (TARGET_CPU_CPP_BUILTINS): New builtin macro.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-10-26 11:38:30 +0000
+++ new/gcc/config/arm/arm.c 2011-11-21 01:45:54 +0000
@@ -10803,6 +10803,335 @@
return true;
}
+/* Copy a block of memory using plain ldr/str/ldrh/strh instructions, to permit
+ unaligned copies on processors which support unaligned semantics for those
+ instructions. INTERLEAVE_FACTOR can be used to attempt to hide load latency
+ (using more registers) by doing e.g. load/load/store/store for a factor of 2.
+ An interleave factor of 1 (the minimum) will perform no interleaving.
+ Load/store multiple are used for aligned addresses where possible. */
+
+static void
+arm_block_move_unaligned_straight (rtx dstbase, rtx srcbase,
+ HOST_WIDE_INT length,
+ unsigned int interleave_factor)
+{
+ rtx *regs = XALLOCAVEC (rtx, interleave_factor);
+ int *regnos = XALLOCAVEC (int, interleave_factor);
+ HOST_WIDE_INT block_size_bytes = interleave_factor * UNITS_PER_WORD;
+ HOST_WIDE_INT i, j;
+ HOST_WIDE_INT remaining = length, words;
+ rtx halfword_tmp = NULL, byte_tmp = NULL;
+ rtx dst, src;
+ bool src_aligned = MEM_ALIGN (srcbase) >= BITS_PER_WORD;
+ bool dst_aligned = MEM_ALIGN (dstbase) >= BITS_PER_WORD;
+ HOST_WIDE_INT srcoffset, dstoffset;
+ HOST_WIDE_INT src_autoinc, dst_autoinc;
+ rtx mem, addr;
+
+ gcc_assert (1 <= interleave_factor && interleave_factor <= 4);
+
+ /* Use hard registers if we have aligned source or destination so we can use
+ load/store multiple with contiguous registers. */
+ if (dst_aligned || src_aligned)
+ for (i = 0; i < interleave_factor; i++)
+ regs[i] = gen_rtx_REG (SImode, i);
+ else
+ for (i = 0; i < interleave_factor; i++)
+ regs[i] = gen_reg_rtx (SImode);
+
+ dst = copy_addr_to_reg (XEXP (dstbase, 0));
+ src = copy_addr_to_reg (XEXP (srcbase, 0));
+
+ srcoffset = dstoffset = 0;
+
+ /* Calls to arm_gen_load_multiple and arm_gen_store_multiple update SRC/DST.
+ For copying the last bytes we want to subtract this offset again. */
+ src_autoinc = dst_autoinc = 0;
+
+ for (i = 0; i < interleave_factor; i++)
+ regnos[i] = i;
+
+ /* Copy BLOCK_SIZE_BYTES chunks. */
+
+ for (i = 0; i + block_size_bytes <= length; i += block_size_bytes)
+ {
+ /* Load words. */
+ if (src_aligned && interleave_factor > 1)
+ {
+ emit_insn (arm_gen_load_multiple (regnos, interleave_factor, src,
+ TRUE, srcbase, &srcoffset));
+ src_autoinc += UNITS_PER_WORD * interleave_factor;
+ }
+ else
+ {
+ for (j = 0; j < interleave_factor; j++)
+ {
+ addr = plus_constant (src, srcoffset + j * UNITS_PER_WORD
+ - src_autoinc);
+ mem = adjust_automodify_address (srcbase, SImode, addr,
+ srcoffset + j * UNITS_PER_WORD);
+ emit_insn (gen_unaligned_loadsi (regs[j], mem));
+ }
+ srcoffset += block_size_bytes;
+ }
+
+ /* Store words. */
+ if (dst_aligned && interleave_factor > 1)
+ {
+ emit_insn (arm_gen_store_multiple (regnos, interleave_factor, dst,
+ TRUE, dstbase, &dstoffset));
+ dst_autoinc += UNITS_PER_WORD * interleave_factor;
+ }
+ else
+ {
+ for (j = 0; j < interleave_factor; j++)
+ {
+ addr = plus_constant (dst, dstoffset + j * UNITS_PER_WORD
+ - dst_autoinc);
+ mem = adjust_automodify_address (dstbase, SImode, addr,
+ dstoffset + j * UNITS_PER_WORD);
+ emit_insn (gen_unaligned_storesi (mem, regs[j]));
+ }
+ dstoffset += block_size_bytes;
+ }
+
+ remaining -= block_size_bytes;
+ }
+
+ /* Copy any whole words left (note these aren't interleaved with any
+ subsequent halfword/byte load/stores in the interests of simplicity). */
+
+ words = remaining / UNITS_PER_WORD;
+
+ gcc_assert (words < interleave_factor);
+
+ if (src_aligned && words > 1)
+ {
+ emit_insn (arm_gen_load_multiple (regnos, words, src, TRUE, srcbase,
+ &srcoffset));
+ src_autoinc += UNITS_PER_WORD * words;
+ }
+ else
+ {
+ for (j = 0; j < words; j++)
+ {
+ addr = plus_constant (src,
+ srcoffset + j * UNITS_PER_WORD - src_autoinc);
+ mem = adjust_automodify_address (srcbase, SImode, addr,
+ srcoffset + j * UNITS_PER_WORD);
+ emit_insn (gen_unaligned_loadsi (regs[j], mem));
+ }
+ srcoffset += words * UNITS_PER_WORD;
+ }
+
+ if (dst_aligned && words > 1)
+ {
+ emit_insn (arm_gen_store_multiple (regnos, words, dst, TRUE, dstbase,
+ &dstoffset));
+ dst_autoinc += words * UNITS_PER_WORD;
+ }
+ else
+ {
+ for (j = 0; j < words; j++)
+ {
+ addr = plus_constant (dst,
+ dstoffset + j * UNITS_PER_WORD - dst_autoinc);
+ mem = adjust_automodify_address (dstbase, SImode, addr,
+ dstoffset + j * UNITS_PER_WORD);
+ emit_insn (gen_unaligned_storesi (mem, regs[j]));
+ }
+ dstoffset += words * UNITS_PER_WORD;
+ }
+
+ remaining -= words * UNITS_PER_WORD;
+
+ gcc_assert (remaining < 4);
+
+ /* Copy a halfword if necessary. */
+
+ if (remaining >= 2)
+ {
+ halfword_tmp = gen_reg_rtx (SImode);
+
+ addr = plus_constant (src, srcoffset - src_autoinc);
+ mem = adjust_automodify_address (srcbase, HImode, addr, srcoffset);
+ emit_insn (gen_unaligned_loadhiu (halfword_tmp, mem));
+
+ /* Either write out immediately, or delay until we've loaded the last
+ byte, depending on interleave factor. */
+ if (interleave_factor == 1)
+ {
+ addr = plus_constant (dst, dstoffset - dst_autoinc);
+ mem = adjust_automodify_address (dstbase, HImode, addr, dstoffset);
+ emit_insn (gen_unaligned_storehi (mem,
+ gen_lowpart (HImode, halfword_tmp)));
+ halfword_tmp = NULL;
+ dstoffset += 2;
+ }
+
+ remaining -= 2;
+ srcoffset += 2;
+ }
+
+ gcc_assert (remaining < 2);
+
+ /* Copy last byte. */
+
+ if ((remaining & 1) != 0)
+ {
+ byte_tmp = gen_reg_rtx (SImode);
+
+ addr = plus_constant (src, srcoffset - src_autoinc);
+ mem = adjust_automodify_address (srcbase, QImode, addr, srcoffset);
+ emit_move_insn (gen_lowpart (QImode, byte_tmp), mem);
+
+ if (interleave_factor == 1)
+ {
+ addr = plus_constant (dst, dstoffset - dst_autoinc);
+ mem = adjust_automodify_address (dstbase, QImode, addr, dstoffset);
+ emit_move_insn (mem, gen_lowpart (QImode, byte_tmp));
+ byte_tmp = NULL;
+ dstoffset++;
+ }
+
+ remaining--;
+ srcoffset++;
+ }
+
+ /* Store last halfword if we haven't done so already. */
+
+ if (halfword_tmp)
+ {
+ addr = plus_constant (dst, dstoffset - dst_autoinc);
+ mem = adjust_automodify_address (dstbase, HImode, addr, dstoffset);
+ emit_insn (gen_unaligned_storehi (mem,
+ gen_lowpart (HImode, halfword_tmp)));
+ dstoffset += 2;
+ }
+
+ /* Likewise for last byte. */
+
+ if (byte_tmp)
+ {
+ addr = plus_constant (dst, dstoffset - dst_autoinc);
+ mem = adjust_automodify_address (dstbase, QImode, addr, dstoffset);
+ emit_move_insn (mem, gen_lowpart (QImode, byte_tmp));
+ dstoffset++;
+ }
+
+ gcc_assert (remaining == 0 && srcoffset == dstoffset);
+}
+
+/* From mips_adjust_block_mem:
+
+ Helper function for doing a loop-based block operation on memory
+ reference MEM. Each iteration of the loop will operate on LENGTH
+ bytes of MEM.
+
+ Create a new base register for use within the loop and point it to
+ the start of MEM. Create a new memory reference that uses this
+ register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
+
+static void
+arm_adjust_block_mem (rtx mem, HOST_WIDE_INT length, rtx *loop_reg,
+ rtx *loop_mem)
+{
+ *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
+
+ /* Although the new mem does not refer to a known location,
+ it does keep up to LENGTH bytes of alignment. */
+ *loop_mem = change_address (mem, BLKmode, *loop_reg);
+ set_mem_align (*loop_mem, MIN (MEM_ALIGN (mem), length * BITS_PER_UNIT));
+}
+
+/* From mips_block_move_loop:
+
+ Move LENGTH bytes from SRC to DEST using a loop that moves BYTES_PER_ITER
+ bytes at a time. LENGTH must be at least BYTES_PER_ITER. Assume that
+ the memory regions do not overlap. */
+
+static void
+arm_block_move_unaligned_loop (rtx dest, rtx src, HOST_WIDE_INT length,
+ unsigned int interleave_factor,
+ HOST_WIDE_INT bytes_per_iter)
+{
+ rtx label, src_reg, dest_reg, final_src, test;
+ HOST_WIDE_INT leftover;
+
+ leftover = length % bytes_per_iter;
+ length -= leftover;
+
+ /* Create registers and memory references for use within the loop. */
+ arm_adjust_block_mem (src, bytes_per_iter, &src_reg, &src);
+ arm_adjust_block_mem (dest, bytes_per_iter, &dest_reg, &dest);
+
+ /* Calculate the value that SRC_REG should have after the last iteration of
+ the loop. */
+ final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
+ 0, 0, OPTAB_WIDEN);
+
+ /* Emit the start of the loop. */
+ label = gen_label_rtx ();
+ emit_label (label);
+
+ /* Emit the loop body. */
+ arm_block_move_unaligned_straight (dest, src, bytes_per_iter,
+ interleave_factor);
+
+ /* Move on to the next block. */
+ emit_move_insn (src_reg, plus_constant (src_reg, bytes_per_iter));
+ emit_move_insn (dest_reg, plus_constant (dest_reg, bytes_per_iter));
+
+ /* Emit the loop condition. */
+ test = gen_rtx_NE (VOIDmode, src_reg, final_src);
+ emit_jump_insn (gen_cbranchsi4 (test, src_reg, final_src, label));
+
+ /* Mop up any left-over bytes. */
+ if (leftover)
+ arm_block_move_unaligned_straight (dest, src, leftover, interleave_factor);
+}
+
+/* Emit a block move when either the source or destination is unaligned (not
+ aligned to a four-byte boundary). This may need further tuning depending on
+ core type, optimize_size setting, etc. */
+
+static int
+arm_movmemqi_unaligned (rtx *operands)
+{
+ HOST_WIDE_INT length = INTVAL (operands[2]);
+
+ if (optimize_size)
+ {
+ bool src_aligned = MEM_ALIGN (operands[1]) >= BITS_PER_WORD;
+ bool dst_aligned = MEM_ALIGN (operands[0]) >= BITS_PER_WORD;
+ /* Inlined memcpy using ldr/str/ldrh/strh can be quite big: try to limit
+ size of code if optimizing for size. We'll use ldm/stm if src_aligned
+ or dst_aligned though: allow more interleaving in those cases since the
+ resulting code can be smaller. */
+ unsigned int interleave_factor = (src_aligned || dst_aligned) ? 2 : 1;
+ HOST_WIDE_INT bytes_per_iter = (src_aligned || dst_aligned) ? 8 : 4;
+
+ if (length > 12)
+ arm_block_move_unaligned_loop (operands[0], operands[1], length,
+ interleave_factor, bytes_per_iter);
+ else
+ arm_block_move_unaligned_straight (operands[0], operands[1], length,
+ interleave_factor);
+ }
+ else
+ {
+ /* Note that the loop created by arm_block_move_unaligned_loop may be
+ subject to loop unrolling, which makes tuning this condition a little
+ redundant. */
+ if (length > 32)
+ arm_block_move_unaligned_loop (operands[0], operands[1], length, 4, 16);
+ else
+ arm_block_move_unaligned_straight (operands[0], operands[1], length, 4);
+ }
+
+ return 1;
+}
+
int
arm_gen_movmemqi (rtx *operands)
{
@@ -10815,8 +11144,13 @@
if (GET_CODE (operands[2]) != CONST_INT
|| GET_CODE (operands[3]) != CONST_INT
- || INTVAL (operands[2]) > 64
- || INTVAL (operands[3]) & 3)
+ || INTVAL (operands[2]) > 64)
+ return 0;
+
+ if (unaligned_access && (INTVAL (operands[3]) & 3) != 0)
+ return arm_movmemqi_unaligned (operands);
+
+ if (INTVAL (operands[3]) & 3)
return 0;
dstbase = operands[0];
=== modified file 'gcc/config/arm/arm.h'
--- old/gcc/config/arm/arm.h 2011-10-19 17:01:50 +0000
+++ new/gcc/config/arm/arm.h 2011-11-21 01:45:54 +0000
@@ -47,6 +47,8 @@
{ \
if (TARGET_DSP_MULTIPLY) \
builtin_define ("__ARM_FEATURE_DSP"); \
+ if (unaligned_access) \
+ builtin_define ("__ARM_FEATURE_UNALIGNED"); \
/* Define __arm__ even when in thumb mode, for \
consistency with armcc. */ \
builtin_define ("__arm__"); \
=== added file 'gcc/testsuite/gcc.target/arm/unaligned-memcpy-1.c'
--- old/gcc/testsuite/gcc.target/arm/unaligned-memcpy-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/unaligned-memcpy-1.c 2011-10-19 22:56:19 +0000
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_unaligned } */
+/* { dg-options "-O2" } */
+
+#include <string.h>
+
+void unknown_alignment (char *dest, char *src)
+{
+ memcpy (dest, src, 15);
+}
+
+/* We should see three unaligned word loads and store pairs, one unaligned
+ ldrh/strh pair, and an ldrb/strb pair. Sanity check that. */
+
+/* { dg-final { scan-assembler-times "@ unaligned" 8 } } */
+/* { dg-final { scan-assembler-times "ldrh" 1 } } */
+/* { dg-final { scan-assembler-times "strh" 1 } } */
+/* { dg-final { scan-assembler-times "ldrb" 1 } } */
+/* { dg-final { scan-assembler-times "strb" 1 } } */
=== added file 'gcc/testsuite/gcc.target/arm/unaligned-memcpy-2.c'
--- old/gcc/testsuite/gcc.target/arm/unaligned-memcpy-2.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/unaligned-memcpy-2.c 2011-10-19 22:56:19 +0000
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_unaligned } */
+/* { dg-options "-O2" } */
+
+#include <string.h>
+
+char dest[16];
+
+void aligned_dest (char *src)
+{
+ memcpy (dest, src, 15);
+}
+
+/* Expect a multi-word store for the main part of the copy, but subword
+ loads/stores for the remainder. */
+
+/* { dg-final { scan-assembler-times "stmia" 1 } } */
+/* { dg-final { scan-assembler-times "ldrh" 1 } } */
+/* { dg-final { scan-assembler-times "strh" 1 } } */
+/* { dg-final { scan-assembler-times "ldrb" 1 } } */
+/* { dg-final { scan-assembler-times "strb" 1 } } */
=== added file 'gcc/testsuite/gcc.target/arm/unaligned-memcpy-3.c'
--- old/gcc/testsuite/gcc.target/arm/unaligned-memcpy-3.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/unaligned-memcpy-3.c 2011-10-19 22:56:19 +0000
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_unaligned } */
+/* { dg-options "-O2" } */
+
+#include <string.h>
+
+char src[16];
+
+void aligned_src (char *dest)
+{
+ memcpy (dest, src, 15);
+}
+
+/* Expect a multi-word load for the main part of the copy, but subword
+ loads/stores for the remainder. */
+
+/* { dg-final { scan-assembler-times "ldmia" 1 } } */
+/* { dg-final { scan-assembler-times "ldrh" 1 } } */
+/* { dg-final { scan-assembler-times "strh" 1 } } */
+/* { dg-final { scan-assembler-times "ldrb" 1 } } */
+/* { dg-final { scan-assembler-times "strb" 1 } } */
=== added file 'gcc/testsuite/gcc.target/arm/unaligned-memcpy-4.c'
--- old/gcc/testsuite/gcc.target/arm/unaligned-memcpy-4.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/unaligned-memcpy-4.c 2011-10-19 22:56:19 +0000
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_unaligned } */
+/* { dg-options "-O2" } */
+
+#include <string.h>
+
+char src[16];
+char dest[16];
+
+void aligned_both (void)
+{
+ memcpy (dest, src, 15);
+}
+
+/* We know both src and dest to be aligned: expect multiword loads/stores. */
+
+/* { dg-final { scan-assembler-times "ldmia" 1 } } */
+/* { dg-final { scan-assembler-times "stmia" 1 } } */
=== modified file 'gcc/testsuite/lib/target-supports.exp'
--- old/gcc/testsuite/lib/target-supports.exp 2011-10-23 13:33:07 +0000
+++ new/gcc/testsuite/lib/target-supports.exp 2011-11-21 01:45:54 +0000
@@ -1894,6 +1894,18 @@
}]
}
+# Return 1 if this is an ARM target that supports unaligned word/halfword
+# load/store instructions.
+
+proc check_effective_target_arm_unaligned { } {
+ return [check_no_compiler_messages arm_unaligned assembly {
+ #ifndef __ARM_FEATURE_UNALIGNED
+ #error no unaligned support
+ #endif
+ int i;
+ }]
+}
+
# Add the options needed for NEON. We need either -mfloat-abi=softfp
# or -mfloat-abi=hard, but if one is already specified by the
# multilib, use it. Similarly, if a -mfpu option already enables
@@ -0,0 +1,375 @@
2011-11-22 Ira Rosen <ira.rosen@linaro.org>
Backport from mainline:
2011-10-06 Jakub Jelinek <jakub@redhat.com>
gcc/
PR tree-optimization/50596
* tree-vectorizer.h (vect_is_simple_cond): New prototype.
(NUM_PATTERNS): Change to 6.
* tree-vect-patterns.c (vect_recog_mixed_size_cond_pattern): New
function.
(vect_vect_recog_func_ptrs): Add vect_recog_mixed_size_cond_pattern.
(vect_mark_pattern_stmts): Don't create stmt_vinfo for def_stmt
if it already has one, and don't set STMT_VINFO_VECTYPE in it
if it is already set.
* tree-vect-stmts.c (vect_mark_stmts_to_be_vectorized): Handle
COND_EXPR in pattern stmts.
(vect_is_simple_cond): No longer static.
gcc/testsuite:
PR tree-optimization/50596
* gcc.dg/vect/vect-cond-8.c: New test.
2011-10-07 Jakub Jelinek <jakub@redhat.com>
gcc/
PR tree-optimization/50650
* tree-vect-patterns.c (vect_recog_mixed_size_cond_pattern): Don't
call vect_is_simple_cond here, instead fail if cond_expr isn't
COMPARISON_CLASS_P or if get_vectype_for_scalar_type returns NULL
for cond_expr's first operand.
* tree-vect-stmts.c (vect_is_simple_cond): Static again.
* tree-vectorizer.h (vect_is_simple_cond): Remove prototype.
gcc/
* tree-vect-patterns.c (vect_recog_mixed_size_cond_pattern): Reduce
it to integral types only.
gcc/testsuite/
* gcc.dg/vect/pr30858.c: Expect the error message twice for targets
with multiple vector sizes.
* gcc.dg/vect/vect-cond-8.c: Rename to...
* gcc.dg/vect/vect-cond-8a.c: ... this and change the type from float
to int.
* lib/target-supports.exp (check_effective_target_vect_condition):
Return true for NEON.
=== modified file 'gcc/testsuite/gcc.dg/vect/pr30858.c'
Index: gcc-4_6-branch/gcc/testsuite/gcc.dg/vect/pr30858.c
===================================================================
--- gcc-4_6-branch.orig/gcc/testsuite/gcc.dg/vect/pr30858.c 2012-01-04 15:33:52.000000000 -0800
+++ gcc-4_6-branch/gcc/testsuite/gcc.dg/vect/pr30858.c 2012-03-05 16:23:47.748983031 -0800
@@ -11,5 +11,6 @@
}
/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" } } */
-/* { dg-final { scan-tree-dump-times "Unknown def-use cycle pattern." 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "Unknown def-use cycle pattern." 1 "vect" { xfail vect_multiple_sizes } } } */
+/* { dg-final { scan-tree-dump-times "Unknown def-use cycle pattern." 2 "vect" { target vect_multiple_sizes } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
Index: gcc-4_6-branch/gcc/testsuite/gcc.dg/vect/vect-cond-8a.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gcc-4_6-branch/gcc/testsuite/gcc.dg/vect/vect-cond-8a.c 2012-03-05 16:23:47.748983031 -0800
@@ -0,0 +1,75 @@
+/* { dg-require-effective-target vect_condition } */
+
+#include "tree-vect.h"
+
+#define N 1024
+int a[N], b[N], c[N];
+char d[N], e[N], f[N];
+unsigned char k[N];
+
+__attribute__((noinline, noclone)) void
+f1 (void)
+{
+ int i;
+ for (i = 0; i < N; ++i)
+ k[i] = a[i] < b[i] ? 17 : 0;
+}
+
+__attribute__((noinline, noclone)) void
+f2 (void)
+{
+ int i;
+ for (i = 0; i < N; ++i)
+ k[i] = a[i] < b[i] ? 0 : 24;
+}
+
+__attribute__((noinline, noclone)) void
+f3 (void)
+{
+ int i;
+ for (i = 0; i < N; ++i)
+ k[i] = a[i] < b[i] ? 51 : 12;
+}
+
+int
+main ()
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ switch (i % 9)
+ {
+ case 0: asm (""); a[i] = - i - 1; b[i] = i + 1; break;
+ case 1: a[i] = 0; b[i] = 0; break;
+ case 2: a[i] = i + 1; b[i] = - i - 1; break;
+ case 3: a[i] = i; b[i] = i + 7; break;
+ case 4: a[i] = i; b[i] = i; break;
+ case 5: a[i] = i + 16; b[i] = i + 3; break;
+ case 6: a[i] = - i - 5; b[i] = - i; break;
+ case 7: a[i] = - i; b[i] = - i; break;
+ case 8: a[i] = - i; b[i] = - i - 7; break;
+ }
+ d[i] = i;
+ e[i] = 2 * i;
+ }
+ f1 ();
+ for (i = 0; i < N; i++)
+ if (k[i] != ((i % 3) == 0 ? 17 : 0))
+ abort ();
+ f2 ();
+ for (i = 0; i < N; i++)
+ if (k[i] != ((i % 3) == 0 ? 0 : 24))
+ abort ();
+ f3 ();
+ for (i = 0; i < N; i++)
+ if (k[i] != ((i % 3) == 0 ? 51 : 12))
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "note: vectorized 1 loops" 3 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
Index: gcc-4_6-branch/gcc/tree-vect-patterns.c
===================================================================
--- gcc-4_6-branch.orig/gcc/tree-vect-patterns.c 2012-03-05 16:23:10.000000000 -0800
+++ gcc-4_6-branch/gcc/tree-vect-patterns.c 2012-03-05 16:23:47.748983031 -0800
@@ -50,13 +50,16 @@
tree *);
static gimple vect_recog_widen_shift_pattern (VEC (gimple, heap) **,
tree *, tree *);
+static gimple vect_recog_mixed_size_cond_pattern (VEC (gimple, heap) **,
+ tree *, tree *);
static vect_recog_func_ptr vect_vect_recog_func_ptrs[NUM_PATTERNS] = {
vect_recog_widen_mult_pattern,
vect_recog_widen_sum_pattern,
vect_recog_dot_prod_pattern,
vect_recog_pow_pattern,
vect_recog_over_widening_pattern,
- vect_recog_widen_shift_pattern};
+ vect_recog_widen_shift_pattern,
+ vect_recog_mixed_size_cond_pattern};
/* Function widened_name_p
@@ -1441,6 +1444,118 @@
return pattern_stmt;
}
+/* Function vect_recog_mixed_size_cond_pattern
+
+ Try to find the following pattern:
+
+ type x_t, y_t;
+ TYPE a_T, b_T, c_T;
+ loop:
+ S1 a_T = x_t CMP y_t ? b_T : c_T;
+
+ where type 'TYPE' is an integral type which has different size
+ from 'type'. b_T and c_T are constants and if 'TYPE' is wider
+ than 'type', the constants need to fit into an integer type
+ with the same width as 'type'.
+
+ Input:
+
+ * LAST_STMT: A stmt from which the pattern search begins.
+
+ Output:
+
+ * TYPE_IN: The type of the input arguments to the pattern.
+
+ * TYPE_OUT: The type of the output of this pattern.
+
+ * Return value: A new stmt that will be used to replace the pattern.
+ Additionally a def_stmt is added.
+
+ a_it = x_t CMP y_t ? b_it : c_it;
+ a_T = (TYPE) a_it; */
+
+static gimple
+vect_recog_mixed_size_cond_pattern (VEC (gimple, heap) **stmts, tree *type_in,
+ tree *type_out)
+{
+ gimple last_stmt = VEC_index (gimple, *stmts, 0);
+ tree cond_expr, then_clause, else_clause;
+ stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt), def_stmt_info;
+ tree type, vectype, comp_vectype, comp_type, op, tmp;
+ enum machine_mode cmpmode;
+ gimple pattern_stmt, def_stmt;
+ loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+
+ if (!is_gimple_assign (last_stmt)
+ || gimple_assign_rhs_code (last_stmt) != COND_EXPR
+ || STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_internal_def)
+ return NULL;
+
+ op = gimple_assign_rhs1 (last_stmt);
+ cond_expr = TREE_OPERAND (op, 0);
+ then_clause = TREE_OPERAND (op, 1);
+ else_clause = TREE_OPERAND (op, 2);
+
+ if (TREE_CODE (then_clause) != INTEGER_CST
+ || TREE_CODE (else_clause) != INTEGER_CST)
+ return NULL;
+
+ if (!COMPARISON_CLASS_P (cond_expr))
+ return NULL;
+
+ type = gimple_expr_type (last_stmt);
+ comp_type = TREE_TYPE (TREE_OPERAND (cond_expr, 0));
+ if (!INTEGRAL_TYPE_P (comp_type)
+ || !INTEGRAL_TYPE_P (type))
+ return NULL;
+
+ comp_vectype = get_vectype_for_scalar_type (comp_type);
+ if (comp_vectype == NULL_TREE)
+ return NULL;
+
+ cmpmode = GET_MODE_INNER (TYPE_MODE (comp_vectype));
+
+ if (GET_MODE_BITSIZE (TYPE_MODE (type)) == GET_MODE_BITSIZE (cmpmode))
+ return NULL;
+
+ vectype = get_vectype_for_scalar_type (type);
+ if (vectype == NULL_TREE)
+ return NULL;
+
+ if (types_compatible_p (vectype, comp_vectype))
+ return NULL;
+
+ if (!expand_vec_cond_expr_p (comp_vectype, TYPE_MODE (comp_vectype)))
+ return NULL;
+
+ if (GET_MODE_BITSIZE (TYPE_MODE (type)) > GET_MODE_BITSIZE (cmpmode))
+ {
+ if (!int_fits_type_p (then_clause, comp_type)
+ || !int_fits_type_p (else_clause, comp_type))
+ return NULL;
+ }
+
+ tmp = build3 (COND_EXPR, comp_type, unshare_expr (cond_expr),
+ fold_convert (comp_type, then_clause),
+ fold_convert (comp_type, else_clause));
+ def_stmt = gimple_build_assign (vect_recog_temp_ssa_var (comp_type, NULL), tmp);
+
+ pattern_stmt
+ = gimple_build_assign_with_ops (NOP_EXPR,
+ vect_recog_temp_ssa_var (type, NULL),
+ gimple_assign_lhs (def_stmt), NULL_TREE);
+
+ STMT_VINFO_PATTERN_DEF_STMT (stmt_vinfo) = def_stmt;
+ def_stmt_info = new_stmt_vec_info (def_stmt, loop_vinfo, NULL);
+ set_vinfo_for_stmt (def_stmt, def_stmt_info);
+ STMT_VINFO_VECTYPE (def_stmt_info) = comp_vectype;
+ *type_in = vectype;
+ *type_out = vectype;
+
+ return pattern_stmt;
+}
+
+
/* Mark statements that are involved in a pattern. */
static inline void
@@ -1468,14 +1583,18 @@
if (STMT_VINFO_PATTERN_DEF_STMT (pattern_stmt_info))
{
def_stmt = STMT_VINFO_PATTERN_DEF_STMT (pattern_stmt_info);
- set_vinfo_for_stmt (def_stmt,
- new_stmt_vec_info (def_stmt, loop_vinfo, NULL));
- gimple_set_bb (def_stmt, gimple_bb (orig_stmt));
def_stmt_info = vinfo_for_stmt (def_stmt);
+ if (def_stmt_info == NULL)
+ {
+ def_stmt_info = new_stmt_vec_info (def_stmt, loop_vinfo, NULL);
+ set_vinfo_for_stmt (def_stmt, def_stmt_info);
+ }
+ gimple_set_bb (def_stmt, gimple_bb (orig_stmt));
STMT_VINFO_RELATED_STMT (def_stmt_info) = orig_stmt;
STMT_VINFO_DEF_TYPE (def_stmt_info)
= STMT_VINFO_DEF_TYPE (orig_stmt_info);
- STMT_VINFO_VECTYPE (def_stmt_info) = pattern_vectype;
+ if (STMT_VINFO_VECTYPE (def_stmt_info) == NULL_TREE)
+ STMT_VINFO_VECTYPE (def_stmt_info) = pattern_vectype;
}
}
Index: gcc-4_6-branch/gcc/tree-vect-stmts.c
===================================================================
--- gcc-4_6-branch.orig/gcc/tree-vect-stmts.c 2012-03-05 16:23:11.000000000 -0800
+++ gcc-4_6-branch/gcc/tree-vect-stmts.c 2012-03-05 16:23:47.748983031 -0800
@@ -655,20 +655,40 @@
tree rhs = gimple_assign_rhs1 (stmt);
unsigned int op_num;
tree op;
+ enum tree_code rhs_code;
switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)))
{
case GIMPLE_SINGLE_RHS:
- op_num = TREE_OPERAND_LENGTH (gimple_assign_rhs1 (stmt));
- for (i = 0; i < op_num; i++)
- {
- op = TREE_OPERAND (rhs, i);
- if (!process_use (stmt, op, loop_vinfo, live_p, relevant,
- &worklist))
- {
- VEC_free (gimple, heap, worklist);
- return false;
- }
- }
+ op = gimple_assign_rhs1 (stmt);
+ rhs_code = gimple_assign_rhs_code (stmt);
+ i = 0;
+ if (rhs_code == COND_EXPR
+ && COMPARISON_CLASS_P (TREE_OPERAND (op, 0)))
+ {
+ op = TREE_OPERAND (op, 0);
+ if (!process_use (stmt, TREE_OPERAND (op, 0),
+ loop_vinfo,
+ live_p, relevant, &worklist)
+ || !process_use (stmt, TREE_OPERAND (op, 1),
+ loop_vinfo,
+ live_p, relevant, &worklist))
+ {
+ VEC_free (gimple, heap, worklist);
+ return false;
+ }
+ i = 1;
+ }
+ op_num = TREE_OPERAND_LENGTH (gimple_assign_rhs1 (stmt));
+ for (i; i < op_num; i++)
+ {
+ op = TREE_OPERAND (rhs, i);
+ if (!process_use (stmt, op, loop_vinfo, live_p, relevant,
+ &worklist))
+ {
+ VEC_free (gimple, heap, worklist);
+ return false;
+ }
+ }
break;
case GIMPLE_BINARY_RHS:
Index: gcc-4_6-branch/gcc/tree-vectorizer.h
===================================================================
--- gcc-4_6-branch.orig/gcc/tree-vectorizer.h 2012-03-05 16:23:11.000000000 -0800
+++ gcc-4_6-branch/gcc/tree-vectorizer.h 2012-03-05 16:23:47.748983031 -0800
@@ -917,7 +917,7 @@
Additional pattern recognition functions can (and will) be added
in the future. */
typedef gimple (* vect_recog_func_ptr) (VEC (gimple, heap) **, tree *, tree *);
-#define NUM_PATTERNS 6
+#define NUM_PATTERNS 7
void vect_pattern_recog (loop_vec_info);
/* In tree-vectorizer.c. */
@@ -0,0 +1,805 @@
2011-11-22 Ira Rosen <ira.rosen@linaro.org>
Backport from mainline:
2011-11-06 Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-vectorizer.h (vectorizable_condition): Add argument.
* tree-vect-loop.c (vectorizable_reduction): Fail for condition
in SLP. Update calls to vectorizable_condition.
* tree-vect-stmts.c (vect_is_simple_cond): Add basic block info to
the arguments. Pass it to vect_is_simple_use_1.
(vectorizable_condition): Add slp_node to the arguments. Support
vectorization of basic blocks. Fail for reduction in SLP. Update
calls to vect_is_simple_cond and vect_is_simple_use. Support SLP:
call vect_get_slp_defs to get vector operands.
(vect_analyze_stmt): Update calls to vectorizable_condition.
(vect_transform_stmt): Likewise.
* tree-vect-slp.c (vect_create_new_slp_node): Handle COND_EXPR.
(vect_get_and_check_slp_defs): Handle COND_EXPR. Allow pattern
def stmts.
(vect_build_slp_tree): Handle COND_EXPR.
(vect_analyze_slp_instance): Push pattern statements to root node.
(vect_get_constant_vectors): Fix comments. Handle COND_EXPR.
gcc/testsuite/
* gcc.dg/vect/bb-slp-cond-1.c: New test.
* gcc.dg/vect/slp-cond-1.c: New test.
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-cond-1.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-cond-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-cond-1.c 2011-11-20 08:24:08 +0000
@@ -0,0 +1,46 @@
+/* { dg-require-effective-target vect_condition } */
+
+#include "tree-vect.h"
+
+#define N 128
+
+__attribute__((noinline, noclone)) void
+foo (int *a, int stride)
+{
+ int i;
+
+ for (i = 0; i < N/stride; i++, a += stride)
+ {
+ a[0] = a[0] ? 1 : 5;
+ a[1] = a[1] ? 2 : 6;
+ a[2] = a[2] ? 3 : 7;
+ a[3] = a[3] ? 4 : 8;
+ }
+}
+
+
+int a[N];
+int main ()
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ a[i] = i;
+
+ foo (a, 4);
+
+ for (i = 1; i < N; i++)
+ if (a[i] != i%4 + 1)
+ abort ();
+
+ if (a[0] != 5)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target vect_element_align } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== added file 'gcc/testsuite/gcc.dg/vect/slp-cond-1.c'
--- old/gcc/testsuite/gcc.dg/vect/slp-cond-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/slp-cond-1.c 2011-11-20 08:24:08 +0000
@@ -0,0 +1,126 @@
+/* { dg-require-effective-target vect_condition } */
+#include "tree-vect.h"
+
+#define N 32
+int a[N], b[N];
+int d[N], e[N];
+int k[N];
+
+__attribute__((noinline, noclone)) void
+f1 (void)
+{
+ int i;
+ for (i = 0; i < N/4; i++)
+ {
+ k[4*i] = a[4*i] < b[4*i] ? 17 : 0;
+ k[4*i+1] = a[4*i+1] < b[4*i+1] ? 17 : 0;
+ k[4*i+2] = a[4*i+2] < b[4*i+2] ? 17 : 0;
+ k[4*i+3] = a[4*i+3] < b[4*i+3] ? 17 : 0;
+ }
+}
+
+__attribute__((noinline, noclone)) void
+f2 (void)
+{
+ int i;
+ for (i = 0; i < N/2; ++i)
+ {
+ k[2*i] = a[2*i] < b[2*i] ? 0 : 24;
+ k[2*i+1] = a[2*i+1] < b[2*i+1] ? 7 : 4;
+ }
+}
+
+__attribute__((noinline, noclone)) void
+f3 (void)
+{
+ int i;
+ for (i = 0; i < N/2; ++i)
+ {
+ k[2*i] = a[2*i] < b[2*i] ? 51 : 12;
+ k[2*i+1] = a[2*i+1] > b[2*i+1] ? 51 : 12;
+ }
+}
+
+__attribute__((noinline, noclone)) void
+f4 (void)
+{
+ int i;
+ for (i = 0; i < N/2; ++i)
+ {
+ int d0 = d[2*i], e0 = e[2*i];
+ int d1 = d[2*i+1], e1 = e[2*i+1];
+ k[2*i] = a[2*i] >= b[2*i] ? d0 : e0;
+ k[2*i+1] = a[2*i+1] >= b[2*i+1] ? d1 : e1;
+ }
+}
+
+int
+main ()
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ switch (i % 9)
+ {
+ case 0: asm (""); a[i] = - i - 1; b[i] = i + 1; break;
+ case 1: a[i] = 0; b[i] = 0; break;
+ case 2: a[i] = i + 1; b[i] = - i - 1; break;
+ case 3: a[i] = i; b[i] = i + 7; break;
+ case 4: a[i] = i; b[i] = i; break;
+ case 5: a[i] = i + 16; b[i] = i + 3; break;
+ case 6: a[i] = - i - 5; b[i] = - i; break;
+ case 7: a[i] = - i; b[i] = - i; break;
+ case 8: a[i] = - i; b[i] = - i - 7; break;
+ }
+ d[i] = i;
+ e[i] = 2 * i;
+ }
+ f1 ();
+ for (i = 0; i < N; i++)
+ if (k[i] != ((i % 3) == 0 ? 17 : 0))
+ abort ();
+
+ f2 ();
+ for (i = 0; i < N; i++)
+ {
+ switch (i % 9)
+ {
+ case 0:
+ case 6:
+ if (k[i] != ((i/9 % 2) == 0 ? 0 : 7))
+ abort ();
+ break;
+ case 1:
+ case 5:
+ case 7:
+ if (k[i] != ((i/9 % 2) == 0 ? 4 : 24))
+ abort ();
+ break;
+ case 2:
+ case 4:
+ case 8:
+ if (k[i] != ((i/9 % 2) == 0 ? 24 : 4))
+ abort ();
+ break;
+ case 3:
+ if (k[i] != ((i/9 % 2) == 0 ? 7 : 0))
+ abort ();
+ break;
+ }
+ }
+
+ f3 ();
+
+ f4 ();
+ for (i = 0; i < N; i++)
+ if (k[i] != ((i % 3) == 0 ? e[i] : d[i]))
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 3 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/tree-vect-loop.c'
--- old/gcc/tree-vect-loop.c 2011-11-14 11:38:08 +0000
+++ new/gcc/tree-vect-loop.c 2011-11-20 08:24:08 +0000
@@ -4087,6 +4087,9 @@
gcc_unreachable ();
}
+ if (code == COND_EXPR && slp_node)
+ return false;
+
scalar_dest = gimple_assign_lhs (stmt);
scalar_type = TREE_TYPE (scalar_dest);
if (!POINTER_TYPE_P (scalar_type) && !INTEGRAL_TYPE_P (scalar_type)
@@ -4161,7 +4164,7 @@
if (code == COND_EXPR)
{
- if (!vectorizable_condition (stmt, gsi, NULL, ops[reduc_index], 0))
+ if (!vectorizable_condition (stmt, gsi, NULL, ops[reduc_index], 0, NULL))
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "unsupported condition in reduction");
@@ -4433,7 +4436,7 @@
gcc_assert (!slp_node);
vectorizable_condition (stmt, gsi, vec_stmt,
PHI_RESULT (VEC_index (gimple, phis, 0)),
- reduc_index);
+ reduc_index, NULL);
/* Multiple types are not supported for condition. */
break;
}
=== modified file 'gcc/tree-vect-slp.c'
--- old/gcc/tree-vect-slp.c 2011-11-14 11:38:08 +0000
+++ new/gcc/tree-vect-slp.c 2011-11-21 06:58:40 +0000
@@ -109,7 +109,11 @@
if (is_gimple_call (stmt))
nops = gimple_call_num_args (stmt);
else if (is_gimple_assign (stmt))
- nops = gimple_num_ops (stmt) - 1;
+ {
+ nops = gimple_num_ops (stmt) - 1;
+ if (gimple_assign_rhs_code (stmt) == COND_EXPR)
+ nops = 4;
+ }
else
return NULL;
@@ -190,20 +194,51 @@
bool different_types = false;
bool pattern = false;
slp_oprnd_info oprnd_info, oprnd0_info, oprnd1_info;
+ int op_idx = 1;
+ tree compare_rhs = NULL_TREE, rhs = NULL_TREE;
+ int cond_idx = -1;
if (loop_vinfo)
loop = LOOP_VINFO_LOOP (loop_vinfo);
if (is_gimple_call (stmt))
number_of_oprnds = gimple_call_num_args (stmt);
+ else if (is_gimple_assign (stmt))
+ {
+ number_of_oprnds = gimple_num_ops (stmt) - 1;
+ if (gimple_assign_rhs_code (stmt) == COND_EXPR)
+ {
+ number_of_oprnds = 4;
+ cond_idx = 0;
+ rhs = gimple_assign_rhs1 (stmt);
+ }
+ }
else
- number_of_oprnds = gimple_num_ops (stmt) - 1;
+ return false;
for (i = 0; i < number_of_oprnds; i++)
{
- oprnd = gimple_op (stmt, i + 1);
+ if (compare_rhs)
+ oprnd = compare_rhs;
+ else
+ oprnd = gimple_op (stmt, op_idx++);
+
oprnd_info = VEC_index (slp_oprnd_info, *oprnds_info, i);
+ if (-1 < cond_idx && cond_idx < 4)
+ {
+ if (compare_rhs)
+ compare_rhs = NULL_TREE;
+ else
+ oprnd = TREE_OPERAND (rhs, cond_idx++);
+ }
+
+ if (COMPARISON_CLASS_P (oprnd))
+ {
+ compare_rhs = TREE_OPERAND (oprnd, 1);
+ oprnd = TREE_OPERAND (oprnd, 0);
+ }
+
if (!vect_is_simple_use (oprnd, loop_vinfo, bb_vinfo, &def_stmt, &def,
&dt)
|| (!def_stmt && dt != vect_constant_def))
@@ -243,8 +278,7 @@
def_stmt = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (def_stmt));
dt = STMT_VINFO_DEF_TYPE (vinfo_for_stmt (def_stmt));
- if (dt == vect_unknown_def_type
- || STMT_VINFO_PATTERN_DEF_STMT (vinfo_for_stmt (def_stmt)))
+ if (dt == vect_unknown_def_type)
{
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "Unsupported pattern.");
@@ -423,6 +457,7 @@
VEC (gimple, heap) *stmts = SLP_TREE_SCALAR_STMTS (*node);
gimple stmt = VEC_index (gimple, stmts, 0);
enum tree_code first_stmt_code = ERROR_MARK, rhs_code = ERROR_MARK;
+ enum tree_code first_cond_code = ERROR_MARK;
tree lhs;
bool stop_recursion = false, need_same_oprnds = false;
tree vectype, scalar_type, first_op1 = NULL_TREE;
@@ -439,11 +474,18 @@
VEC (slp_oprnd_info, heap) *oprnds_info;
unsigned int nops;
slp_oprnd_info oprnd_info;
+ tree cond;
if (is_gimple_call (stmt))
nops = gimple_call_num_args (stmt);
+ else if (is_gimple_assign (stmt))
+ {
+ nops = gimple_num_ops (stmt) - 1;
+ if (gimple_assign_rhs_code (stmt) == COND_EXPR)
+ nops = 4;
+ }
else
- nops = gimple_num_ops (stmt) - 1;
+ return false;
oprnds_info = vect_create_oprnd_info (nops, group_size);
@@ -484,6 +526,22 @@
return false;
}
+ if (is_gimple_assign (stmt)
+ && gimple_assign_rhs_code (stmt) == COND_EXPR
+ && (cond = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0))
+ && !COMPARISON_CLASS_P (cond))
+ {
+ if (vect_print_dump_info (REPORT_SLP))
+ {
+ fprintf (vect_dump,
+ "Build SLP failed: condition is not comparison ");
+ print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM);
+ }
+
+ vect_free_oprnd_info (&oprnds_info);
+ return false;
+ }
+
scalar_type = vect_get_smallest_scalar_type (stmt, &dummy, &dummy);
vectype = get_vectype_for_scalar_type (scalar_type);
if (!vectype)
@@ -737,7 +795,8 @@
/* Not memory operation. */
if (TREE_CODE_CLASS (rhs_code) != tcc_binary
- && TREE_CODE_CLASS (rhs_code) != tcc_unary)
+ && TREE_CODE_CLASS (rhs_code) != tcc_unary
+ && rhs_code != COND_EXPR)
{
if (vect_print_dump_info (REPORT_SLP))
{
@@ -750,6 +809,26 @@
return false;
}
+ if (rhs_code == COND_EXPR)
+ {
+ tree cond_expr = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
+
+ if (i == 0)
+ first_cond_code = TREE_CODE (cond_expr);
+ else if (first_cond_code != TREE_CODE (cond_expr))
+ {
+ if (vect_print_dump_info (REPORT_SLP))
+ {
+ fprintf (vect_dump, "Build SLP failed: different"
+ " operation");
+ print_gimple_stmt (vect_dump, stmt, 0, TDF_SLIM);
+ }
+
+ vect_free_oprnd_info (&oprnds_info);
+ return false;
+ }
+ }
+
/* Find the def-stmts. */
if (!vect_get_and_check_slp_defs (loop_vinfo, bb_vinfo, *node, stmt,
ncopies_for_cost, (i == 0),
@@ -1395,7 +1474,12 @@
/* Collect the stores and store them in SLP_TREE_SCALAR_STMTS. */
while (next)
{
- VEC_safe_push (gimple, heap, scalar_stmts, next);
+ if (STMT_VINFO_IN_PATTERN_P (vinfo_for_stmt (next))
+ && STMT_VINFO_RELATED_STMT (vinfo_for_stmt (next)))
+ VEC_safe_push (gimple, heap, scalar_stmts,
+ STMT_VINFO_RELATED_STMT (vinfo_for_stmt (next)));
+ else
+ VEC_safe_push (gimple, heap, scalar_stmts, next);
next = DR_GROUP_NEXT_DR (vinfo_for_stmt (next));
}
}
@@ -1404,7 +1488,7 @@
/* Collect reduction statements. */
VEC (gimple, heap) *reductions = LOOP_VINFO_REDUCTIONS (loop_vinfo);
for (i = 0; VEC_iterate (gimple, reductions, i, next); i++)
- VEC_safe_push (gimple, heap, scalar_stmts, next);
+ VEC_safe_push (gimple, heap, scalar_stmts, next);
}
node = vect_create_new_slp_node (scalar_stmts);
@@ -2160,15 +2244,15 @@
For example, we have two scalar operands, s1 and s2 (e.g., group of
strided accesses of size two), while NUNITS is four (i.e., four scalars
- of this type can be packed in a vector). The output vector will contain
- two copies of each scalar operand: {s1, s2, s1, s2}. (NUMBER_OF_COPIES
+ of this type can be packed in a vector). The output vector will contain
+ two copies of each scalar operand: {s1, s2, s1, s2}. (NUMBER_OF_COPIES
will be 2).
If GROUP_SIZE > NUNITS, the scalars will be split into several vectors
containing the operands.
For example, NUNITS is four as before, and the group size is 8
- (s1, s2, ..., s8). We will create two vectors {s1, s2, s3, s4} and
+ (s1, s2, ..., s8). We will create two vectors {s1, s2, s3, s4} and
{s5, s6, s7, s8}. */
number_of_copies = least_common_multiple (nunits, group_size) / group_size;
@@ -2180,8 +2264,18 @@
{
if (is_store)
op = gimple_assign_rhs1 (stmt);
- else
+ else if (gimple_assign_rhs_code (stmt) != COND_EXPR)
op = gimple_op (stmt, op_num + 1);
+ else
+ {
+ if (op_num == 0 || op_num == 1)
+ {
+ tree cond = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
+ op = TREE_OPERAND (cond, op_num);
+ }
+ else
+ op = TREE_OPERAND (gimple_assign_rhs1 (stmt), op_num - 1);
+ }
if (reduc_index != -1)
{
=== modified file 'gcc/tree-vect-stmts.c'
--- old/gcc/tree-vect-stmts.c 2011-11-22 16:52:23 +0000
+++ new/gcc/tree-vect-stmts.c 2011-11-22 17:10:17 +0000
@@ -4816,7 +4816,7 @@
condition operands are supportable using vec_is_simple_use. */
static bool
-vect_is_simple_cond (tree cond, loop_vec_info loop_vinfo)
+vect_is_simple_cond (tree cond, loop_vec_info loop_vinfo, bb_vec_info bb_vinfo)
{
tree lhs, rhs;
tree def;
@@ -4831,7 +4831,7 @@
if (TREE_CODE (lhs) == SSA_NAME)
{
gimple lhs_def_stmt = SSA_NAME_DEF_STMT (lhs);
- if (!vect_is_simple_use (lhs, loop_vinfo, NULL, &lhs_def_stmt, &def,
+ if (!vect_is_simple_use (lhs, loop_vinfo, bb_vinfo, &lhs_def_stmt, &def,
&dt))
return false;
}
@@ -4842,7 +4842,7 @@
if (TREE_CODE (rhs) == SSA_NAME)
{
gimple rhs_def_stmt = SSA_NAME_DEF_STMT (rhs);
- if (!vect_is_simple_use (rhs, loop_vinfo, NULL, &rhs_def_stmt, &def,
+ if (!vect_is_simple_use (rhs, loop_vinfo, bb_vinfo, &rhs_def_stmt, &def,
&dt))
return false;
}
@@ -4868,7 +4868,8 @@
bool
vectorizable_condition (gimple stmt, gimple_stmt_iterator *gsi,
- gimple *vec_stmt, tree reduc_def, int reduc_index)
+ gimple *vec_stmt, tree reduc_def, int reduc_index,
+ slp_tree slp_node)
{
tree scalar_dest = NULL_TREE;
tree vec_dest = NULL_TREE;
@@ -4885,19 +4886,24 @@
tree def;
enum vect_def_type dt, dts[4];
int nunits = TYPE_VECTOR_SUBPARTS (vectype);
- int ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits;
+ int ncopies;
enum tree_code code;
stmt_vec_info prev_stmt_info = NULL;
- int j;
+ int i, j;
+ bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_info);
+ VEC (tree, heap) *vec_oprnds0 = NULL, *vec_oprnds1 = NULL;
+ VEC (tree, heap) *vec_oprnds2 = NULL, *vec_oprnds3 = NULL;
- /* FORNOW: unsupported in basic block SLP. */
- gcc_assert (loop_vinfo);
+ if (slp_node || PURE_SLP_STMT (stmt_info))
+ ncopies = 1;
+ else
+ ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits;
gcc_assert (ncopies >= 1);
- if (reduc_index && ncopies > 1)
+ if (reduc_index && (ncopies > 1 || STMT_SLP_TYPE (stmt_info)))
return false; /* FORNOW */
- if (!STMT_VINFO_RELEVANT_P (stmt_info))
+ if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
@@ -4905,10 +4911,6 @@
&& reduc_def))
return false;
- /* FORNOW: SLP not supported. */
- if (STMT_SLP_TYPE (stmt_info))
- return false;
-
/* FORNOW: not yet supported. */
if (STMT_VINFO_LIVE_P (stmt_info))
{
@@ -4932,7 +4934,7 @@
then_clause = TREE_OPERAND (op, 1);
else_clause = TREE_OPERAND (op, 2);
- if (!vect_is_simple_cond (cond_expr, loop_vinfo))
+ if (!vect_is_simple_cond (cond_expr, loop_vinfo, bb_vinfo))
return false;
/* We do not handle two different vector types for the condition
@@ -4944,7 +4946,7 @@
if (TREE_CODE (then_clause) == SSA_NAME)
{
gimple then_def_stmt = SSA_NAME_DEF_STMT (then_clause);
- if (!vect_is_simple_use (then_clause, loop_vinfo, NULL,
+ if (!vect_is_simple_use (then_clause, loop_vinfo, bb_vinfo,
&then_def_stmt, &def, &dt))
return false;
}
@@ -4956,7 +4958,7 @@
if (TREE_CODE (else_clause) == SSA_NAME)
{
gimple else_def_stmt = SSA_NAME_DEF_STMT (else_clause);
- if (!vect_is_simple_use (else_clause, loop_vinfo, NULL,
+ if (!vect_is_simple_use (else_clause, loop_vinfo, bb_vinfo,
&else_def_stmt, &def, &dt))
return false;
}
@@ -4974,7 +4976,15 @@
return expand_vec_cond_expr_p (TREE_TYPE (op), vec_mode);
}
- /* Transform */
+ /* Transform. */
+
+ if (!slp_node)
+ {
+ vec_oprnds0 = VEC_alloc (tree, heap, 1);
+ vec_oprnds1 = VEC_alloc (tree, heap, 1);
+ vec_oprnds2 = VEC_alloc (tree, heap, 1);
+ vec_oprnds3 = VEC_alloc (tree, heap, 1);
+ }
/* Handle def. */
scalar_dest = gimple_assign_lhs (stmt);
@@ -4983,67 +4993,118 @@
/* Handle cond expr. */
for (j = 0; j < ncopies; j++)
{
- gimple new_stmt;
+ gimple new_stmt = NULL;
if (j == 0)
{
- gimple gtemp;
- vec_cond_lhs =
+ if (slp_node)
+ {
+ VEC (tree, heap) *ops = VEC_alloc (tree, heap, 4);
+ VEC (slp_void_p, heap) *vec_defs;
+
+ vec_defs = VEC_alloc (slp_void_p, heap, 4);
+ VEC_safe_push (tree, heap, ops, TREE_OPERAND (cond_expr, 0));
+ VEC_safe_push (tree, heap, ops, TREE_OPERAND (cond_expr, 1));
+ VEC_safe_push (tree, heap, ops, then_clause);
+ VEC_safe_push (tree, heap, ops, else_clause);
+ vect_get_slp_defs (ops, slp_node, &vec_defs, -1);
+ vec_oprnds3 = (VEC (tree, heap) *) VEC_pop (slp_void_p, vec_defs);
+ vec_oprnds2 = (VEC (tree, heap) *) VEC_pop (slp_void_p, vec_defs);
+ vec_oprnds1 = (VEC (tree, heap) *) VEC_pop (slp_void_p, vec_defs);
+ vec_oprnds0 = (VEC (tree, heap) *) VEC_pop (slp_void_p, vec_defs);
+
+ VEC_free (tree, heap, ops);
+ VEC_free (slp_void_p, heap, vec_defs);
+ }
+ else
+ {
+ gimple gtemp;
+ vec_cond_lhs =
vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 0),
stmt, NULL);
- vect_is_simple_use (TREE_OPERAND (cond_expr, 0), loop_vinfo,
+ vect_is_simple_use (TREE_OPERAND (cond_expr, 0), loop_vinfo,
NULL, &gtemp, &def, &dts[0]);
- vec_cond_rhs =
- vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 1),
- stmt, NULL);
- vect_is_simple_use (TREE_OPERAND (cond_expr, 1), loop_vinfo,
- NULL, &gtemp, &def, &dts[1]);
- if (reduc_index == 1)
- vec_then_clause = reduc_def;
- else
- {
- vec_then_clause = vect_get_vec_def_for_operand (then_clause,
- stmt, NULL);
- vect_is_simple_use (then_clause, loop_vinfo,
- NULL, &gtemp, &def, &dts[2]);
- }
- if (reduc_index == 2)
- vec_else_clause = reduc_def;
- else
- {
- vec_else_clause = vect_get_vec_def_for_operand (else_clause,
- stmt, NULL);
- vect_is_simple_use (else_clause, loop_vinfo,
+
+ vec_cond_rhs =
+ vect_get_vec_def_for_operand (TREE_OPERAND (cond_expr, 1),
+ stmt, NULL);
+ vect_is_simple_use (TREE_OPERAND (cond_expr, 1), loop_vinfo,
+ NULL, &gtemp, &def, &dts[1]);
+ if (reduc_index == 1)
+ vec_then_clause = reduc_def;
+ else
+ {
+ vec_then_clause = vect_get_vec_def_for_operand (then_clause,
+ stmt, NULL);
+ vect_is_simple_use (then_clause, loop_vinfo,
+ NULL, &gtemp, &def, &dts[2]);
+ }
+ if (reduc_index == 2)
+ vec_else_clause = reduc_def;
+ else
+ {
+ vec_else_clause = vect_get_vec_def_for_operand (else_clause,
+ stmt, NULL);
+ vect_is_simple_use (else_clause, loop_vinfo,
NULL, &gtemp, &def, &dts[3]);
+ }
}
}
else
{
- vec_cond_lhs = vect_get_vec_def_for_stmt_copy (dts[0], vec_cond_lhs);
- vec_cond_rhs = vect_get_vec_def_for_stmt_copy (dts[1], vec_cond_rhs);
+ vec_cond_lhs = vect_get_vec_def_for_stmt_copy (dts[0],
+ VEC_pop (tree, vec_oprnds0));
+ vec_cond_rhs = vect_get_vec_def_for_stmt_copy (dts[1],
+ VEC_pop (tree, vec_oprnds1));
vec_then_clause = vect_get_vec_def_for_stmt_copy (dts[2],
- vec_then_clause);
+ VEC_pop (tree, vec_oprnds2));
vec_else_clause = vect_get_vec_def_for_stmt_copy (dts[3],
- vec_else_clause);
+ VEC_pop (tree, vec_oprnds3));
+ }
+
+ if (!slp_node)
+ {
+ VEC_quick_push (tree, vec_oprnds0, vec_cond_lhs);
+ VEC_quick_push (tree, vec_oprnds1, vec_cond_rhs);
+ VEC_quick_push (tree, vec_oprnds2, vec_then_clause);
+ VEC_quick_push (tree, vec_oprnds3, vec_else_clause);
}
/* Arguments are ready. Create the new vector stmt. */
- vec_compare = build2 (TREE_CODE (cond_expr), vectype,
- vec_cond_lhs, vec_cond_rhs);
- vec_cond_expr = build3 (VEC_COND_EXPR, vectype,
- vec_compare, vec_then_clause, vec_else_clause);
-
- new_stmt = gimple_build_assign (vec_dest, vec_cond_expr);
- new_temp = make_ssa_name (vec_dest, new_stmt);
- gimple_assign_set_lhs (new_stmt, new_temp);
- vect_finish_stmt_generation (stmt, new_stmt, gsi);
- if (j == 0)
- STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
- else
- STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
-
- prev_stmt_info = vinfo_for_stmt (new_stmt);
+ FOR_EACH_VEC_ELT (tree, vec_oprnds0, i, vec_cond_lhs)
+ {
+ vec_cond_rhs = VEC_index (tree, vec_oprnds1, i);
+ vec_then_clause = VEC_index (tree, vec_oprnds2, i);
+ vec_else_clause = VEC_index (tree, vec_oprnds3, i);
+
+ vec_compare = build2 (TREE_CODE (cond_expr), vectype,
+ vec_cond_lhs, vec_cond_rhs);
+ vec_cond_expr = build3 (VEC_COND_EXPR, vectype,
+ vec_compare, vec_then_clause, vec_else_clause);
+
+ new_stmt = gimple_build_assign (vec_dest, vec_cond_expr);
+ new_temp = make_ssa_name (vec_dest, new_stmt);
+ gimple_assign_set_lhs (new_stmt, new_temp);
+ vect_finish_stmt_generation (stmt, new_stmt, gsi);
+ if (slp_node)
+ VEC_quick_push (gimple, SLP_TREE_VEC_STMTS (slp_node), new_stmt);
+ }
+
+ if (slp_node)
+ continue;
+
+ if (j == 0)
+ STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
+ else
+ STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
+
+ prev_stmt_info = vinfo_for_stmt (new_stmt);
}
+ VEC_free (tree, heap, vec_oprnds0);
+ VEC_free (tree, heap, vec_oprnds1);
+ VEC_free (tree, heap, vec_oprnds2);
+ VEC_free (tree, heap, vec_oprnds3);
+
return true;
}
@@ -5217,7 +5278,7 @@
|| vectorizable_call (stmt, NULL, NULL)
|| vectorizable_store (stmt, NULL, NULL, NULL)
|| vectorizable_reduction (stmt, NULL, NULL, NULL)
- || vectorizable_condition (stmt, NULL, NULL, NULL, 0));
+ || vectorizable_condition (stmt, NULL, NULL, NULL, 0, NULL));
else
{
if (bb_vinfo)
@@ -5227,7 +5288,8 @@
|| vectorizable_operation (stmt, NULL, NULL, node)
|| vectorizable_assignment (stmt, NULL, NULL, node)
|| vectorizable_load (stmt, NULL, NULL, node, NULL)
- || vectorizable_store (stmt, NULL, NULL, node));
+ || vectorizable_store (stmt, NULL, NULL, node)
+ || vectorizable_condition (stmt, NULL, NULL, NULL, 0, node));
}
if (!ok)
@@ -5343,8 +5405,7 @@
break;
case condition_vec_info_type:
- gcc_assert (!slp_node);
- done = vectorizable_condition (stmt, gsi, &vec_stmt, NULL, 0);
+ done = vectorizable_condition (stmt, gsi, &vec_stmt, NULL, 0, slp_node);
gcc_assert (done);
break;
=== modified file 'gcc/tree-vectorizer.h'
--- old/gcc/tree-vectorizer.h 2011-11-22 16:52:23 +0000
+++ new/gcc/tree-vectorizer.h 2011-11-22 17:10:17 +0000
@@ -832,7 +832,7 @@
extern void vect_remove_stores (gimple);
extern bool vect_analyze_stmt (gimple, bool *, slp_tree);
extern bool vectorizable_condition (gimple, gimple_stmt_iterator *, gimple *,
- tree, int);
+ tree, int, slp_tree);
extern void vect_get_load_cost (struct data_reference *, int, bool,
unsigned int *, unsigned int *);
extern void vect_get_store_cost (struct data_reference *, int, unsigned int *);
@@ -0,0 +1,495 @@
2011-11-27 Ira Rosen <ira.rosen@linaro.org>
gcc/
* tree-vectorizer.h (vect_pattern_recog): Add new argument.
* tree-vect-loop.c (vect_analyze_loop_2): Update call to
vect_pattern_recog.
* tree-vect-patterns.c (widened_name_p): Pass basic block
info to vect_is_simple_use.
(vect_recog_dot_prod_pattern): Fail for basic blocks.
(vect_recog_widen_sum_pattern): Likewise.
(vect_handle_widen_op_by_const): Support basic blocks.
(vect_operation_fits_smaller_type,
vect_recog_over_widening_pattern): Likewise.
(vect_recog_mixed_size_cond_pattern): Support basic blocks.
Add printing.
(vect_mark_pattern_stmts): Update calls to new_stmt_vec_info.
(vect_pattern_recog_1): Check for reduction only in loops.
(vect_pattern_recog): Add new argument. Support basic blocks.
* tree-vect-stmts.c (vectorizable_conversion): Pass basic block
info to vect_is_simple_use_1.
* tree-vect-slp.c (vect_get_and_check_slp_defs): Support basic
blocks.
(vect_slp_analyze_bb_1): Call vect_pattern_recog.
gcc/testsuite/
* gcc.dg/vect/bb-slp-pattern-1.c: New test.
* gcc.dg/vect/bb-slp-pattern-2.c: New test.
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-pattern-1.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-pattern-1.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-pattern-1.c 2011-11-23 06:37:10 +0000
@@ -0,0 +1,55 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 8
+
+unsigned short X[N];
+unsigned short Y[N];
+unsigned int result[N];
+
+/* unsigned short->unsigned int widening-mult. */
+__attribute__ ((noinline, noclone)) void
+foo (void)
+{
+ result[0] = (unsigned int)(X[0] * Y[0]);
+ result[1] = (unsigned int)(X[1] * Y[1]);
+ result[2] = (unsigned int)(X[2] * Y[2]);
+ result[3] = (unsigned int)(X[3] * Y[3]);
+ result[4] = (unsigned int)(X[4] * Y[4]);
+ result[5] = (unsigned int)(X[5] * Y[5]);
+ result[6] = (unsigned int)(X[6] * Y[6]);
+ result[7] = (unsigned int)(X[7] * Y[7]);
+}
+
+int main (void)
+{
+ int i, tmp;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ X[i] = i;
+ Y[i] = 64-i;
+ }
+
+ foo ();
+
+ for (i = 0; i < N; i++)
+ {
+ __asm__ volatile ("");
+ tmp = X[i] * Y[i];
+ if (result[i] != tmp)
+ abort ();
+ }
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "slp" { target { vect_widen_mult_hi_to_si || vect_unpack } } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_widen_mult_pattern: detected" 8 "slp" { target vect_widen_mult_hi_to_si_pattern } } } */
+/* { dg-final { scan-tree-dump-times "pattern recognized" 8 "slp" { target vect_widen_mult_hi_to_si_pattern } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-pattern-2.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-pattern-2.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-pattern-2.c 2011-11-23 06:37:10 +0000
@@ -0,0 +1,53 @@
+/* { dg-require-effective-target vect_condition } */
+
+#include "tree-vect.h"
+
+#define N 128
+
+__attribute__((noinline, noclone)) void
+foo (short * __restrict__ a, int * __restrict__ b, int stride)
+{
+ int i;
+
+ for (i = 0; i < N/stride; i++, a += stride, b += stride)
+ {
+ a[0] = b[0] ? 1 : 7;
+ a[1] = b[1] ? 2 : 0;
+ a[2] = b[2] ? 3 : 0;
+ a[3] = b[3] ? 4 : 0;
+ a[4] = b[4] ? 5 : 0;
+ a[5] = b[5] ? 6 : 0;
+ a[6] = b[6] ? 7 : 0;
+ a[7] = b[7] ? 8 : 0;
+ }
+}
+
+short a[N];
+int b[N];
+int main ()
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ a[i] = i;
+ b[i] = -i;
+ }
+
+ foo (a, b, 8);
+
+ for (i = 1; i < N; i++)
+ if (a[i] != i%8 + 1)
+ abort ();
+
+ if (a[0] != 7)
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target { vect_element_align && vect_pack_trunc } } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== modified file 'gcc/tree-vect-loop.c'
--- old/gcc/tree-vect-loop.c 2011-11-20 08:24:08 +0000
+++ new/gcc/tree-vect-loop.c 2011-11-23 06:47:35 +0000
@@ -1458,7 +1458,7 @@
vect_analyze_scalar_cycles (loop_vinfo);
- vect_pattern_recog (loop_vinfo);
+ vect_pattern_recog (loop_vinfo, NULL);
/* Data-flow analysis to detect stmts that do not need to be vectorized. */
=== modified file 'gcc/tree-vect-patterns.c'
--- old/gcc/tree-vect-patterns.c 2011-11-20 09:11:09 +0000
+++ new/gcc/tree-vect-patterns.c 2011-11-23 07:49:33 +0000
@@ -83,11 +83,13 @@
tree oprnd0;
enum vect_def_type dt;
tree def;
+ bb_vec_info bb_vinfo;
stmt_vinfo = vinfo_for_stmt (use_stmt);
loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+ bb_vinfo = STMT_VINFO_BB_VINFO (stmt_vinfo);
- if (!vect_is_simple_use (name, loop_vinfo, NULL, def_stmt, &def, &dt))
+ if (!vect_is_simple_use (name, loop_vinfo, bb_vinfo, def_stmt, &def, &dt))
return false;
if (dt != vect_internal_def
@@ -111,7 +113,7 @@
|| (TYPE_PRECISION (type) < (TYPE_PRECISION (*half_type) * 2)))
return false;
- if (!vect_is_simple_use (oprnd0, loop_vinfo, NULL, &dummy_gimple, &dummy,
+ if (!vect_is_simple_use (oprnd0, loop_vinfo, bb_vinfo, &dummy_gimple, &dummy,
&dt))
return false;
@@ -188,9 +190,14 @@
gimple pattern_stmt;
tree prod_type;
loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
- struct loop *loop = LOOP_VINFO_LOOP (loop_info);
+ struct loop *loop;
tree var, rhs;
+ if (!loop_info)
+ return NULL;
+
+ loop = LOOP_VINFO_LOOP (loop_info);
+
if (!is_gimple_assign (last_stmt))
return NULL;
@@ -358,8 +365,16 @@
{
tree new_type, new_oprnd, tmp;
gimple new_stmt;
- loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (vinfo_for_stmt (stmt));
- struct loop *loop = LOOP_VINFO_LOOP (loop_info);
+ loop_vec_info loop_vinfo;
+ struct loop *loop = NULL;
+ bb_vec_info bb_vinfo;
+ stmt_vec_info stmt_vinfo;
+
+ stmt_vinfo = vinfo_for_stmt (stmt);
+ loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+ bb_vinfo = STMT_VINFO_BB_VINFO (stmt_vinfo);
+ if (loop_vinfo)
+ loop = LOOP_VINFO_LOOP (loop_vinfo);
if (code != MULT_EXPR && code != LSHIFT_EXPR)
return false;
@@ -377,7 +392,9 @@
if (TYPE_PRECISION (type) < (TYPE_PRECISION (*half_type) * 4)
|| !gimple_bb (def_stmt)
- || !flow_bb_inside_loop_p (loop, gimple_bb (def_stmt))
+ || (loop && !flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
+ || (!loop && gimple_bb (def_stmt) != BB_VINFO_BB (bb_vinfo)
+ && gimple_code (def_stmt) != GIMPLE_PHI)
|| !vinfo_for_stmt (def_stmt))
return false;
@@ -774,9 +791,14 @@
tree type, half_type;
gimple pattern_stmt;
loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
- struct loop *loop = LOOP_VINFO_LOOP (loop_info);
+ struct loop *loop;
tree var;
+ if (!loop_info)
+ return NULL;
+
+ loop = LOOP_VINFO_LOOP (loop_info);
+
if (!is_gimple_assign (last_stmt))
return NULL;
@@ -877,7 +899,11 @@
gimple def_stmt, new_stmt;
bool first = false;
loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (vinfo_for_stmt (stmt));
- struct loop *loop = LOOP_VINFO_LOOP (loop_info);
+ bb_vec_info bb_info = STMT_VINFO_BB_VINFO (vinfo_for_stmt (stmt));
+ struct loop *loop = NULL;
+
+ if (loop_info)
+ loop = LOOP_VINFO_LOOP (loop_info);
*new_def_stmt = NULL;
@@ -909,7 +935,9 @@
first = true;
if (!widened_name_p (oprnd, stmt, &half_type, &def_stmt, false)
|| !gimple_bb (def_stmt)
- || !flow_bb_inside_loop_p (loop, gimple_bb (def_stmt))
+ || (loop && !flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
+ || (!loop && gimple_bb (def_stmt) != BB_VINFO_BB (bb_info)
+ && gimple_code (def_stmt) != GIMPLE_PHI)
|| !vinfo_for_stmt (def_stmt))
return false;
}
@@ -1087,7 +1115,16 @@
int nuses = 0;
tree var = NULL_TREE, new_type = NULL_TREE, tmp, new_oprnd;
bool first;
- struct loop *loop = (gimple_bb (stmt))->loop_father;
+ loop_vec_info loop_vinfo;
+ struct loop *loop = NULL;
+ bb_vec_info bb_vinfo;
+ stmt_vec_info stmt_vinfo;
+
+ stmt_vinfo = vinfo_for_stmt (stmt);
+ loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+ bb_vinfo = STMT_VINFO_BB_VINFO (stmt_vinfo);
+ if (loop_vinfo)
+ loop = LOOP_VINFO_LOOP (loop_vinfo);
first = true;
while (1)
@@ -1120,7 +1157,8 @@
if (nuses != 1 || !is_gimple_assign (use_stmt)
|| !gimple_bb (use_stmt)
- || !flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
+ || (loop && !flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
+ || (!loop && gimple_bb (use_stmt) != BB_VINFO_BB (bb_vinfo)))
return NULL;
/* Create pattern statement for STMT. */
@@ -1485,6 +1523,7 @@
enum machine_mode cmpmode;
gimple pattern_stmt, def_stmt;
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+ bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_vinfo);
if (!is_gimple_assign (last_stmt)
|| gimple_assign_rhs_code (last_stmt) != COND_EXPR
@@ -1538,7 +1577,8 @@
tmp = build3 (COND_EXPR, comp_type, unshare_expr (cond_expr),
fold_convert (comp_type, then_clause),
fold_convert (comp_type, else_clause));
- def_stmt = gimple_build_assign (vect_recog_temp_ssa_var (comp_type, NULL), tmp);
+ def_stmt = gimple_build_assign (vect_recog_temp_ssa_var (comp_type, NULL),
+ tmp);
pattern_stmt
= gimple_build_assign_with_ops (NOP_EXPR,
@@ -1546,12 +1586,15 @@
gimple_assign_lhs (def_stmt), NULL_TREE);
STMT_VINFO_PATTERN_DEF_STMT (stmt_vinfo) = def_stmt;
- def_stmt_info = new_stmt_vec_info (def_stmt, loop_vinfo, NULL);
+ def_stmt_info = new_stmt_vec_info (def_stmt, loop_vinfo, bb_vinfo);
set_vinfo_for_stmt (def_stmt, def_stmt_info);
STMT_VINFO_VECTYPE (def_stmt_info) = comp_vectype;
*type_in = vectype;
*type_out = vectype;
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "vect_recog_mixed_size_cond_pattern: detected: ");
+
return pattern_stmt;
}
@@ -1565,10 +1608,11 @@
stmt_vec_info pattern_stmt_info, def_stmt_info;
stmt_vec_info orig_stmt_info = vinfo_for_stmt (orig_stmt);
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (orig_stmt_info);
+ bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (orig_stmt_info);
gimple def_stmt;
set_vinfo_for_stmt (pattern_stmt,
- new_stmt_vec_info (pattern_stmt, loop_vinfo, NULL));
+ new_stmt_vec_info (pattern_stmt, loop_vinfo, bb_vinfo));
gimple_set_bb (pattern_stmt, gimple_bb (orig_stmt));
pattern_stmt_info = vinfo_for_stmt (pattern_stmt);
@@ -1586,7 +1630,7 @@
def_stmt_info = vinfo_for_stmt (def_stmt);
if (def_stmt_info == NULL)
{
- def_stmt_info = new_stmt_vec_info (def_stmt, loop_vinfo, NULL);
+ def_stmt_info = new_stmt_vec_info (def_stmt, loop_vinfo, bb_vinfo);
set_vinfo_for_stmt (def_stmt, def_stmt_info);
}
gimple_set_bb (def_stmt, gimple_bb (orig_stmt));
@@ -1697,9 +1741,10 @@
/* Patterns cannot be vectorized using SLP, because they change the order of
computation. */
- FOR_EACH_VEC_ELT (gimple, LOOP_VINFO_REDUCTIONS (loop_vinfo), i, next)
- if (next == stmt)
- VEC_ordered_remove (gimple, LOOP_VINFO_REDUCTIONS (loop_vinfo), i);
+ if (loop_vinfo)
+ FOR_EACH_VEC_ELT (gimple, LOOP_VINFO_REDUCTIONS (loop_vinfo), i, next)
+ if (next == stmt)
+ VEC_ordered_remove (gimple, LOOP_VINFO_REDUCTIONS (loop_vinfo), i);
/* It is possible that additional pattern stmts are created and inserted in
STMTS_TO_REPLACE. We create a stmt_info for each of them, and mark the
@@ -1799,26 +1844,46 @@
be recorded in S3. */
void
-vect_pattern_recog (loop_vec_info loop_vinfo)
+vect_pattern_recog (loop_vec_info loop_vinfo, bb_vec_info bb_vinfo)
{
- struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
- unsigned int nbbs = loop->num_nodes;
+ struct loop *loop;
+ basic_block *bbs, bb;
+ unsigned int nbbs;
gimple_stmt_iterator si;
unsigned int i, j;
gimple (* vect_recog_func_ptr) (VEC (gimple, heap) **, tree *, tree *);
VEC (gimple, heap) *stmts_to_replace = VEC_alloc (gimple, heap, 1);
+ gimple stmt;
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "=== vect_pattern_recog ===");
- /* Scan through the loop stmts, applying the pattern recognition
+ if (loop_vinfo)
+ {
+ loop = LOOP_VINFO_LOOP (loop_vinfo);
+ bbs = LOOP_VINFO_BBS (loop_vinfo);
+ nbbs = loop->num_nodes;
+ }
+ else
+ {
+ bb = BB_VINFO_BB (bb_vinfo);
+ nbbs = 1;
+ bbs = XNEW (basic_block);
+ bbs[0] = bb;
+ }
+
+ /* Scan through the stmts, applying the pattern recognition
functions starting at each stmt visited: */
for (i = 0; i < nbbs; i++)
{
basic_block bb = bbs[i];
for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
{
+ if (bb_vinfo && (stmt = gsi_stmt (si))
+ && vinfo_for_stmt (stmt)
+ && !STMT_VINFO_VECTORIZABLE (vinfo_for_stmt (stmt)))
+ continue;
+
/* Scan over all generic vect_recog_xxx_pattern functions. */
for (j = 0; j < NUM_PATTERNS; j++)
{
@@ -1830,4 +1895,6 @@
}
VEC_free (gimple, heap, stmts_to_replace);
+ if (bb_vinfo)
+ free (bbs);
}
=== modified file 'gcc/tree-vect-slp.c'
--- old/gcc/tree-vect-slp.c 2011-11-21 06:58:40 +0000
+++ new/gcc/tree-vect-slp.c 2011-11-23 06:47:35 +0000
@@ -255,12 +255,14 @@
/* Check if DEF_STMT is a part of a pattern in LOOP and get the def stmt
from the pattern. Check that all the stmts of the node are in the
pattern. */
- if (loop && def_stmt && gimple_bb (def_stmt)
- && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt))
+ if (def_stmt && gimple_bb (def_stmt)
+ && ((loop && flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
+ || (!loop && gimple_bb (def_stmt) == BB_VINFO_BB (bb_vinfo)
+ && gimple_code (def_stmt) != GIMPLE_PHI))
&& vinfo_for_stmt (def_stmt)
&& STMT_VINFO_IN_PATTERN_P (vinfo_for_stmt (def_stmt))
- && !STMT_VINFO_RELEVANT (vinfo_for_stmt (def_stmt))
- && !STMT_VINFO_LIVE_P (vinfo_for_stmt (def_stmt)))
+ && !STMT_VINFO_RELEVANT (vinfo_for_stmt (def_stmt))
+ && !STMT_VINFO_LIVE_P (vinfo_for_stmt (def_stmt)))
{
pattern = true;
if (!first && !oprnd_info->first_pattern)
@@ -1972,6 +1974,8 @@
return NULL;
}
+ vect_pattern_recog (NULL, bb_vinfo);
+
if (!vect_analyze_data_ref_dependences (NULL, bb_vinfo, &max_vf,
&data_dependence_in_bb)
|| min_vf > max_vf
=== modified file 'gcc/tree-vect-stmts.c'
--- old/gcc/tree-vect-stmts.c 2011-11-22 17:10:17 +0000
+++ new/gcc/tree-vect-stmts.c 2011-11-23 06:47:35 +0000
@@ -3451,11 +3451,11 @@
/* For WIDEN_MULT_EXPR, if OP0 is a constant, use the type of
OP1. */
if (CONSTANT_CLASS_P (op0))
- ok = vect_is_simple_use_1 (op1, loop_vinfo, NULL,
+ ok = vect_is_simple_use_1 (op1, loop_vinfo, bb_vinfo,
&def_stmt, &def, &dt[1], &vectype_in);
else
- ok = vect_is_simple_use (op1, loop_vinfo, NULL, &def_stmt, &def,
- &dt[1]);
+ ok = vect_is_simple_use (op1, loop_vinfo, bb_vinfo, &def_stmt,
+ &def, &dt[1]);
if (!ok)
{
=== modified file 'gcc/tree-vectorizer.h'
--- old/gcc/tree-vectorizer.h 2011-11-22 17:10:17 +0000
+++ new/gcc/tree-vectorizer.h 2011-11-23 06:47:35 +0000
@@ -918,7 +918,7 @@
in the future. */
typedef gimple (* vect_recog_func_ptr) (VEC (gimple, heap) **, tree *, tree *);
#define NUM_PATTERNS 7
-void vect_pattern_recog (loop_vec_info);
+void vect_pattern_recog (loop_vec_info, bb_vec_info);
/* In tree-vectorizer.c. */
unsigned vectorize_loops (void);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,487 @@
2011-11-27 Ira Rosen <ira.rosen@linaro.org>
Needs to be merged upstream:
gcc/
* tree-vect-patterns.c (widened_name_p): Rename to ...
(type_conversion_p): ... this. Add new argument to determine
if it's a promotion or demotion operation. Check for
CONVERT_EXPR_CODE_P instead of NOP_EXPR.
(vect_recog_dot_prod_pattern): Call type_conversion_p instead
widened_name_p.
(vect_recog_widen_mult_pattern, vect_recog_widen_sum_pattern,
vect_operation_fits_smaller_type, vect_recog_widen_shift_pattern):
Likewise.
(vect_recog_mixed_size_cond_pattern): Likewise and allow
non-constant then and else clauses.
gcc/testsuite/
* gcc.dg/vect/bb-slp-cond-3.c: New test.
* gcc.dg/vect/bb-slp-cond-4.c: New test.
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-cond-3.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-cond-3.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-cond-3.c 2011-11-27 11:29:32 +0000
@@ -0,0 +1,85 @@
+/* { dg-require-effective-target vect_condition } */
+
+#include "tree-vect.h"
+
+#define N 64
+
+/* Comparison in int, then/else and result in unsigned char. */
+
+static inline unsigned char
+foo (int x, int y, int a, int b)
+{
+ if (x >= y)
+ return a;
+ else
+ return b;
+}
+
+__attribute__((noinline, noclone)) void
+bar (unsigned char * __restrict__ a, unsigned char * __restrict__ b,
+ unsigned char * __restrict__ c, unsigned char * __restrict__ d,
+ unsigned char * __restrict__ e, int stride, int w)
+{
+ int i;
+ for (i = 0; i < N/stride; i++, a += stride, b += stride, c += stride,
+ d += stride, e += stride)
+ {
+ e[0] = foo (c[0], d[0], a[0] * w, b[0] * w);
+ e[1] = foo (c[1], d[1], a[1] * w, b[1] * w);
+ e[2] = foo (c[2], d[2], a[2] * w, b[2] * w);
+ e[3] = foo (c[3], d[3], a[3] * w, b[3] * w);
+ e[4] = foo (c[4], d[4], a[4] * w, b[4] * w);
+ e[5] = foo (c[5], d[5], a[5] * w, b[5] * w);
+ e[6] = foo (c[6], d[6], a[6] * w, b[6] * w);
+ e[7] = foo (c[7], d[7], a[7] * w, b[7] * w);
+ e[8] = foo (c[8], d[8], a[8] * w, b[8] * w);
+ e[9] = foo (c[9], d[9], a[9] * w, b[9] * w);
+ e[10] = foo (c[10], d[10], a[10] * w, b[10] * w);
+ e[11] = foo (c[11], d[11], a[11] * w, b[11] * w);
+ e[12] = foo (c[12], d[12], a[12] * w, b[12] * w);
+ e[13] = foo (c[13], d[13], a[13] * w, b[13] * w);
+ e[14] = foo (c[14], d[14], a[14] * w, b[14] * w);
+ e[15] = foo (c[15], d[15], a[15] * w, b[15] * w);
+ }
+}
+
+
+unsigned char a[N], b[N], c[N], d[N], e[N];
+
+int main ()
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ a[i] = i;
+ b[i] = 5;
+ e[i] = 0;
+
+ switch (i % 9)
+ {
+ case 0: asm (""); c[i] = i; d[i] = i + 1; break;
+ case 1: c[i] = 0; d[i] = 0; break;
+ case 2: c[i] = i + 1; d[i] = i - 1; break;
+ case 3: c[i] = i; d[i] = i + 7; break;
+ case 4: c[i] = i; d[i] = i; break;
+ case 5: c[i] = i + 16; d[i] = i + 3; break;
+ case 6: c[i] = i - 5; d[i] = i; break;
+ case 7: c[i] = i; d[i] = i; break;
+ case 8: c[i] = i; d[i] = i - 7; break;
+ }
+ }
+
+ bar (a, b, c, d, e, 16, 2);
+ for (i = 0; i < N; i++)
+ if (e[i] != ((i % 3) == 0 ? 10 : 2 * i))
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target { vect_element_align && vect_int_mult } } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== added file 'gcc/testsuite/gcc.dg/vect/bb-slp-cond-4.c'
--- old/gcc/testsuite/gcc.dg/vect/bb-slp-cond-4.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/bb-slp-cond-4.c 2011-11-27 11:29:32 +0000
@@ -0,0 +1,85 @@
+/* { dg-require-effective-target vect_condition } */
+
+#include "tree-vect.h"
+
+#define N 64
+
+/* Comparison in short, then/else and result in int. */
+static inline int
+foo (short x, short y, int a, int b)
+{
+ if (x >= y)
+ return a;
+ else
+ return b;
+}
+
+__attribute__((noinline, noclone)) void
+bar (short * __restrict__ a, short * __restrict__ b,
+ short * __restrict__ c, short * __restrict__ d,
+ int * __restrict__ e, int stride, int w)
+{
+ int i;
+ for (i = 0; i < N/stride; i++, a += stride, b += stride, c += stride,
+ d += stride, e += stride)
+ {
+ e[0] = foo (c[0], d[0], a[0], b[0]);
+ e[1] = foo (c[1], d[1], a[1], b[1]);
+ e[2] = foo (c[2], d[2], a[2], b[2]);
+ e[3] = foo (c[3], d[3], a[3], b[3]);
+ e[4] = foo (c[4], d[4], a[4], b[4]);
+ e[5] = foo (c[5], d[5], a[5], b[5]);
+ e[6] = foo (c[6], d[6], a[6], b[6]);
+ e[7] = foo (c[7], d[7], a[7], b[7]);
+ e[8] = foo (c[8], d[8], a[8], b[8]);
+ e[9] = foo (c[9], d[9], a[9], b[9]);
+ e[10] = foo (c[10], d[10], a[10], b[10]);
+ e[11] = foo (c[11], d[11], a[11], b[11]);
+ e[12] = foo (c[12], d[12], a[12], b[12]);
+ e[13] = foo (c[13], d[13], a[13], b[13]);
+ e[14] = foo (c[14], d[14], a[14], b[14]);
+ e[15] = foo (c[15], d[15], a[15], b[15]);
+ }
+}
+
+
+short a[N], b[N], c[N], d[N];
+int e[N];
+
+int main ()
+{
+ int i;
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ a[i] = i;
+ b[i] = 5;
+ e[i] = 0;
+
+ switch (i % 9)
+ {
+ case 0: asm (""); c[i] = - i - 1; d[i] = i + 1; break;
+ case 1: c[i] = 0; d[i] = 0; break;
+ case 2: c[i] = i + 1; d[i] = - i - 1; break;
+ case 3: c[i] = i; d[i] = i + 7; break;
+ case 4: c[i] = i; d[i] = i; break;
+ case 5: c[i] = i + 16; d[i] = i + 3; break;
+ case 6: c[i] = - i - 5; d[i] = - i; break;
+ case 7: c[i] = - i; d[i] = - i; break;
+ case 8: c[i] = - i; d[i] = - i - 7; break;
+ }
+ }
+
+ bar (a, b, c, d, e, 16, 2);
+ for (i = 0; i < N; i++)
+ if (e[i] != ((i % 3) == 0 ? 5 : i))
+ abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "basic block vectorized using SLP" 1 "slp" { target vect_element_align } } } */
+/* { dg-final { cleanup-tree-dump "slp" } } */
+
=== modified file 'gcc/tree-vect-patterns.c'
--- old/gcc/tree-vect-patterns.c 2011-11-23 07:49:33 +0000
+++ new/gcc/tree-vect-patterns.c 2011-11-27 12:17:31 +0000
@@ -62,18 +62,16 @@
vect_recog_mixed_size_cond_pattern};
-/* Function widened_name_p
-
- Check whether NAME, an ssa-name used in USE_STMT,
- is a result of a type-promotion, such that:
- DEF_STMT: NAME = NOP (name0)
- where the type of name0 (HALF_TYPE) is smaller than the type of NAME.
+/* Check whether NAME, an ssa-name used in USE_STMT,
+ is a result of a type promotion or demotion, such that:
+ DEF_STMT: NAME = NOP (name0)
+ where the type of name0 (ORIG_TYPE) is smaller/bigger than the type of NAME.
If CHECK_SIGN is TRUE, check that either both types are signed or both are
unsigned. */
static bool
-widened_name_p (tree name, gimple use_stmt, tree *half_type, gimple *def_stmt,
- bool check_sign)
+type_conversion_p (tree name, gimple use_stmt, bool check_sign,
+ tree *orig_type, gimple *def_stmt, bool *promotion)
{
tree dummy;
gimple dummy_gimple;
@@ -96,21 +94,27 @@
&& dt != vect_external_def && dt != vect_constant_def)
return false;
- if (! *def_stmt)
+ if (!*def_stmt)
return false;
if (!is_gimple_assign (*def_stmt))
return false;
- if (gimple_assign_rhs_code (*def_stmt) != NOP_EXPR)
+ if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (*def_stmt)))
return false;
oprnd0 = gimple_assign_rhs1 (*def_stmt);
- *half_type = TREE_TYPE (oprnd0);
- if (!INTEGRAL_TYPE_P (type) || !INTEGRAL_TYPE_P (*half_type)
- || ((TYPE_UNSIGNED (type) != TYPE_UNSIGNED (*half_type)) && check_sign)
- || (TYPE_PRECISION (type) < (TYPE_PRECISION (*half_type) * 2)))
+ *orig_type = TREE_TYPE (oprnd0);
+ if (!INTEGRAL_TYPE_P (type) || !INTEGRAL_TYPE_P (*orig_type)
+ || ((TYPE_UNSIGNED (type) != TYPE_UNSIGNED (*orig_type)) && check_sign))
+ return false;
+
+ if (TYPE_PRECISION (type) >= (TYPE_PRECISION (*orig_type) * 2))
+ *promotion = true;
+ else if (TYPE_PRECISION (*orig_type) >= (TYPE_PRECISION (type) * 2))
+ *promotion = false;
+ else
return false;
if (!vect_is_simple_use (oprnd0, loop_vinfo, bb_vinfo, &dummy_gimple, &dummy,
@@ -192,6 +196,7 @@
loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
struct loop *loop;
tree var, rhs;
+ bool promotion;
if (!loop_info)
return NULL;
@@ -255,7 +260,9 @@
return NULL;
stmt = last_stmt;
- if (widened_name_p (oprnd0, stmt, &half_type, &def_stmt, true))
+ if (type_conversion_p (oprnd0, stmt, true, &half_type, &def_stmt,
+ &promotion)
+ && promotion)
{
stmt = def_stmt;
oprnd0 = gimple_assign_rhs1 (stmt);
@@ -310,10 +317,14 @@
if (!types_compatible_p (TREE_TYPE (oprnd0), prod_type)
|| !types_compatible_p (TREE_TYPE (oprnd1), prod_type))
return NULL;
- if (!widened_name_p (oprnd0, stmt, &half_type0, &def_stmt, true))
+ if (!type_conversion_p (oprnd0, stmt, true, &half_type0, &def_stmt,
+ &promotion)
+ || !promotion)
return NULL;
oprnd00 = gimple_assign_rhs1 (def_stmt);
- if (!widened_name_p (oprnd1, stmt, &half_type1, &def_stmt, true))
+ if (!type_conversion_p (oprnd0, stmt, true, &half_type1, &def_stmt,
+ &promotion)
+ || !promotion)
return NULL;
oprnd01 = gimple_assign_rhs1 (def_stmt);
if (!types_compatible_p (half_type0, half_type1))
@@ -526,7 +537,7 @@
enum tree_code dummy_code;
int dummy_int;
VEC (tree, heap) *dummy_vec;
- bool op1_ok;
+ bool op1_ok, promotion;
if (!is_gimple_assign (last_stmt))
return NULL;
@@ -546,12 +557,14 @@
return NULL;
/* Check argument 0. */
- if (!widened_name_p (oprnd0, last_stmt, &half_type0, &def_stmt0, false))
+ if (!type_conversion_p (oprnd0, last_stmt, false, &half_type0, &def_stmt0,
+ &promotion)
+ || !promotion)
return NULL;
- /* Check argument 1. */
- op1_ok = widened_name_p (oprnd1, last_stmt, &half_type1, &def_stmt1, false);
-
- if (op1_ok)
+ /* Check argument 1. */
+ op1_ok = type_conversion_p (oprnd1, last_stmt, false, &half_type1,
+ &def_stmt1, &promotion);
+ if (op1_ok && promotion)
{
oprnd0 = gimple_assign_rhs1 (def_stmt0);
oprnd1 = gimple_assign_rhs1 (def_stmt1);
@@ -793,6 +806,7 @@
loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
struct loop *loop;
tree var;
+ bool promotion;
if (!loop_info)
return NULL;
@@ -832,8 +846,10 @@
Left to check that oprnd0 is defined by a cast from type 'type' to type
'TYPE'. */
- if (!widened_name_p (oprnd0, last_stmt, &half_type, &stmt, true))
- return NULL;
+ if (!type_conversion_p (oprnd0, last_stmt, true, &half_type, &stmt,
+ &promotion)
+ || !promotion)
+ return NULL;
oprnd0 = gimple_assign_rhs1 (stmt);
*type_in = half_type;
@@ -899,6 +915,7 @@
gimple def_stmt, new_stmt;
bool first = false;
loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (vinfo_for_stmt (stmt));
+ bool promotion;
bb_vec_info bb_info = STMT_VINFO_BB_VINFO (vinfo_for_stmt (stmt));
struct loop *loop = NULL;
@@ -933,7 +950,9 @@
else
{
first = true;
- if (!widened_name_p (oprnd, stmt, &half_type, &def_stmt, false)
+ if (!type_conversion_p (oprnd, stmt, false, &half_type, &def_stmt,
+ &promotion)
+ || !promotion
|| !gimple_bb (def_stmt)
|| (loop && !flow_bb_inside_loop_p (loop, gimple_bb (def_stmt)))
|| (!loop && gimple_bb (def_stmt) != BB_VINFO_BB (bb_info)
@@ -1327,6 +1346,7 @@
VEC (tree, heap) * dummy_vec;
gimple use_stmt = NULL;
bool over_widen = false;
+ bool promotion;
if (!is_gimple_assign (last_stmt) || !vinfo_for_stmt (last_stmt))
return NULL;
@@ -1381,8 +1401,10 @@
return NULL;
/* Check operand 0: it has to be defined by a type promotion. */
- if (!widened_name_p (oprnd0, last_stmt, &half_type0, &def_stmt0, false))
- return NULL;
+ if (!type_conversion_p (oprnd0, last_stmt, false, &half_type0, &def_stmt0,
+ &promotion)
+ || !promotion)
+ return NULL;
/* Check operand 1: has to be positive. We check that it fits the type
in vect_handle_widen_op_by_const (). */
@@ -1492,9 +1514,9 @@
S1 a_T = x_t CMP y_t ? b_T : c_T;
where type 'TYPE' is an integral type which has different size
- from 'type'. b_T and c_T are constants and if 'TYPE' is wider
+ from 'type'. b_T and c_T are either constants (and if 'TYPE' is wider
than 'type', the constants need to fit into an integer type
- with the same width as 'type'.
+ with the same width as 'type') or results of conversion from 'type'.
Input:
@@ -1523,6 +1545,9 @@
enum machine_mode cmpmode;
gimple pattern_stmt, def_stmt;
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+ tree orig_type0 = NULL_TREE, orig_type1 = NULL_TREE;
+ gimple def_stmt0 = NULL, def_stmt1 = NULL;
+ bool promotion;
bb_vec_info bb_vinfo = STMT_VINFO_BB_VINFO (stmt_vinfo);
if (!is_gimple_assign (last_stmt)
@@ -1535,25 +1560,40 @@
then_clause = TREE_OPERAND (op, 1);
else_clause = TREE_OPERAND (op, 2);
- if (TREE_CODE (then_clause) != INTEGER_CST
- || TREE_CODE (else_clause) != INTEGER_CST)
- return NULL;
-
if (!COMPARISON_CLASS_P (cond_expr))
return NULL;
type = gimple_expr_type (last_stmt);
comp_type = TREE_TYPE (TREE_OPERAND (cond_expr, 0));
- if (!INTEGRAL_TYPE_P (comp_type)
- || !INTEGRAL_TYPE_P (type))
- return NULL;
-
comp_vectype = get_vectype_for_scalar_type (comp_type);
if (comp_vectype == NULL_TREE)
return NULL;
+ if (types_compatible_p (type, comp_type)
+ || !INTEGRAL_TYPE_P (comp_type)
+ || !INTEGRAL_TYPE_P (type))
+ return NULL;
+
+ if ((TREE_CODE (then_clause) != INTEGER_CST
+ && !type_conversion_p (then_clause, last_stmt, false, &orig_type0,
+ &def_stmt0, &promotion))
+ || (TREE_CODE (else_clause) != INTEGER_CST
+ && !type_conversion_p (else_clause, last_stmt, false, &orig_type1,
+ &def_stmt1, &promotion)))
+ return NULL;
+
+ if (orig_type0 && orig_type1
+ && (!types_compatible_p (orig_type0, orig_type1)
+ || !types_compatible_p (orig_type0, comp_type)))
+ return NULL;
+
+ if (orig_type0)
+ then_clause = gimple_assign_rhs1 (def_stmt0);
+
+ if (orig_type1)
+ else_clause = gimple_assign_rhs1 (def_stmt1);
+
cmpmode = GET_MODE_INNER (TYPE_MODE (comp_vectype));
-
if (GET_MODE_BITSIZE (TYPE_MODE (type)) == GET_MODE_BITSIZE (cmpmode))
return NULL;
@@ -1561,18 +1601,15 @@
if (vectype == NULL_TREE)
return NULL;
- if (types_compatible_p (vectype, comp_vectype))
- return NULL;
-
if (!expand_vec_cond_expr_p (comp_vectype, TYPE_MODE (comp_vectype)))
return NULL;
- if (GET_MODE_BITSIZE (TYPE_MODE (type)) > GET_MODE_BITSIZE (cmpmode))
- {
- if (!int_fits_type_p (then_clause, comp_type)
- || !int_fits_type_p (else_clause, comp_type))
- return NULL;
- }
+ if (GET_MODE_BITSIZE (TYPE_MODE (type)) > GET_MODE_BITSIZE (cmpmode)
+ && ((TREE_CODE (then_clause) == INTEGER_CST
+ && !int_fits_type_p (then_clause, comp_type))
+ || (TREE_CODE (else_clause) == INTEGER_CST
+ && !int_fits_type_p (else_clause, comp_type))))
+ return NULL;
tmp = build3 (COND_EXPR, comp_type, unshare_expr (cond_expr),
fold_convert (comp_type, then_clause),
@@ -0,0 +1,276 @@
2011-12-05 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline -A15 tuning.
2011-11-30 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* config/arm/arm.c (arm_issue_rate): Cortex-A15 can triple issue.
* config/arm/arm.md (mul64): New attribute.
(generic_sched): Cortex-A15 is not scheduled generically.
(cortex-a15.md): Include.
* config/arm/cortex-a15.md: New machine description.
* config/arm/t-arm (MD_INCLUDES): Add cortex-a15.md.
2011-11-30 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* config/arm/t-arm (MD_INCLUDES): Ensure all md files are listed.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2011-12-05 10:55:48 +0000
+++ new/gcc/config/arm/arm.c 2011-12-05 12:33:25 +0000
@@ -24056,6 +24056,9 @@
{
switch (arm_tune)
{
+ case cortexa15:
+ return 3;
+
case cortexr4:
case cortexr4f:
case cortexr5:
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2011-10-26 11:38:30 +0000
+++ new/gcc/config/arm/arm.md 2011-12-02 00:38:59 +0000
@@ -345,6 +345,13 @@
(const_string "mult")
(const_string "alu")))
+; Is this an (integer side) multiply with a 64-bit result?
+(define_attr "mul64" "no,yes"
+ (if_then_else
+ (eq_attr "insn" "smlalxy,umull,umulls,umlal,umlals,smull,smulls,smlal,smlals")
+ (const_string "yes")
+ (const_string "no")))
+
; Load scheduling, set from the arm_ld_sched variable
; initialized by arm_option_override()
(define_attr "ldsched" "no,yes" (const (symbol_ref "arm_ld_sched")))
@@ -511,7 +518,7 @@
(define_attr "generic_sched" "yes,no"
(const (if_then_else
- (ior (eq_attr "tune" "fa526,fa626,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1020e,arm1026ejs,arm1136js,arm1136jfs,cortexa5,cortexa8,cortexa9,cortexm4")
+ (ior (eq_attr "tune" "fa526,fa626,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1020e,arm1026ejs,arm1136js,arm1136jfs,cortexa5,cortexa8,cortexa9,cortexa15,cortexm4")
(eq_attr "tune_cortexr4" "yes"))
(const_string "no")
(const_string "yes"))))
@@ -537,6 +544,7 @@
(include "cortex-a5.md")
(include "cortex-a8.md")
(include "cortex-a9.md")
+(include "cortex-a15.md")
(include "cortex-r4.md")
(include "cortex-r4f.md")
(include "cortex-m4.md")
=== added file 'gcc/config/arm/cortex-a15.md'
--- old/gcc/config/arm/cortex-a15.md 1970-01-01 00:00:00 +0000
+++ new/gcc/config/arm/cortex-a15.md 2011-12-02 00:38:59 +0000
@@ -0,0 +1,186 @@
+;; ARM Cortex-A15 pipeline description
+;; Copyright (C) 2011 Free Software Foundation, Inc.
+;;
+;; Written by Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
+
+;; 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/>.
+
+(define_automaton "cortex_a15")
+
+;; The Cortex-A15 core is modelled as a triple issue pipeline that has
+;; the following dispatch units.
+;; 1. Two pipelines for simple integer operations: SX1, SX2
+;; 2. Two pipelines for Neon and FP data-processing operations: CX1, CX2
+;; 3. One pipeline for branch operations: BX
+;; 4. One pipeline for integer multiply and divide operations: MX
+;; 5. Two pipelines for load and store operations: LS1, LS2
+;;
+;; We can issue into three pipelines per-cycle.
+;;
+;; We assume that where we have unit pairs xx1 is always filled before xx2.
+
+;; The three issue units
+(define_cpu_unit "ca15_i0, ca15_i1, ca15_i2" "cortex_a15")
+
+(define_reservation "ca15_issue1" "(ca15_i0|ca15_i1|ca15_i2)")
+(define_reservation "ca15_issue2" "((ca15_i0+ca15_i1)|(ca15_i1+ca15_i2))")
+(define_reservation "ca15_issue3" "(ca15_i0+ca15_i1+ca15_i2)")
+(final_presence_set "ca15_i1" "ca15_i0")
+(final_presence_set "ca15_i2" "ca15_i1")
+
+;; The main dispatch units
+(define_cpu_unit "ca15_sx1, ca15_sx2" "cortex_a15")
+(define_cpu_unit "ca15_cx1, ca15_cx2" "cortex_a15")
+(define_cpu_unit "ca15_ls1, ca15_ls2" "cortex_a15")
+(define_cpu_unit "ca15_bx, ca15_mx" "cortex_a15")
+
+(define_reservation "ca15_ls" "(ca15_ls1|ca15_ls2)")
+
+;; The extended load-store pipeline
+(define_cpu_unit "ca15_ldr, ca15_str" "cortex_a15")
+
+;; The extended ALU pipeline
+(define_cpu_unit "ca15_sx1_alu, ca15_sx1_shf, ca15_sx1_sat" "cortex_a15")
+(define_cpu_unit "ca15_sx2_alu, ca15_sx2_shf, ca15_sx2_sat" "cortex_a15")
+
+;; Simple Execution Unit:
+;;
+;; Simple ALU without shift
+(define_insn_reservation "cortex_a15_alu" 2
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "alu")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue1,(ca15_sx1,ca15_sx1_alu)|(ca15_sx2,ca15_sx2_alu)")
+
+;; ALU ops with immediate shift
+(define_insn_reservation "cortex_a15_alu_shift" 3
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "alu_shift")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue1,(ca15_sx1,ca15_sx1+ca15_sx1_shf,ca15_sx1_alu)\
+ |(ca15_sx2,ca15_sx2+ca15_sx2_shf,ca15_sx2_alu)")
+
+;; ALU ops with register controlled shift
+(define_insn_reservation "cortex_a15_alu_shift_reg" 3
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "alu_shift_reg")
+ (eq_attr "neon_type" "none")))
+ "(ca15_issue2,ca15_sx1+ca15_sx2,ca15_sx1_shf,ca15_sx2_alu)\
+ |(ca15_issue1,(ca15_issue1+ca15_sx2,ca15_sx1+ca15_sx2_shf)\
+ |(ca15_issue1+ca15_sx1,ca15_sx1+ca15_sx1_shf),ca15_sx1_alu)")
+
+;; Multiply Execution Unit:
+;;
+;; 32-bit multiplies
+(define_insn_reservation "cortex_a15_mult32" 3
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "mult")
+ (and (eq_attr "neon_type" "none")
+ (eq_attr "mul64" "no"))))
+ "ca15_issue1,ca15_mx")
+
+;; 64-bit multiplies
+(define_insn_reservation "cortex_a15_mult64" 4
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "mult")
+ (and (eq_attr "neon_type" "none")
+ (eq_attr "mul64" "yes"))))
+ "ca15_issue1,ca15_mx*2")
+
+;; Integer divide
+(define_insn_reservation "cortex_a15_udiv" 9
+ (and (eq_attr "tune" "cortexa15")
+ (eq_attr "insn" "udiv"))
+ "ca15_issue1,ca15_mx")
+
+(define_insn_reservation "cortex_a15_sdiv" 10
+ (and (eq_attr "tune" "cortexa15")
+ (eq_attr "insn" "sdiv"))
+ "ca15_issue1,ca15_mx")
+
+;; Block all issue pipes for a cycle
+(define_insn_reservation "cortex_a15_block" 1
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "block")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue3")
+
+;; Branch execution Unit
+;;
+;; Branches take one issue slot.
+;; No latency as there is no result
+(define_insn_reservation "cortex_a15_branch" 0
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "branch")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue1,ca15_bx")
+
+
+;; We lie with calls. They take up all issue slots, and form a block in the
+;; pipeline. The result however is available the next cycle.
+;;
+;; Addition of new units requires this to be updated.
+(define_insn_reservation "cortex_a15_call" 1
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "call")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue3,\
+ ca15_sx1+ca15_sx2+ca15_bx+ca15_mx+ca15_cx1+ca15_cx2+ca15_ls1+ca15_ls2,\
+ ca15_sx1_alu+ca15_sx1_shf+ca15_sx1_sat+ca15_sx2_alu+ca15_sx2_shf\
+ +ca15_sx2_sat+ca15_ldr+ca15_str")
+
+;; Load-store execution Unit
+;;
+;; Loads of up to two words.
+(define_insn_reservation "cortex_a15_load1" 4
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "load_byte,load1,load2")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue1,ca15_ls,ca15_ldr,nothing")
+
+;; Loads of three or four words.
+(define_insn_reservation "cortex_a15_load3" 5
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "load3,load4")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue2,ca15_ls1+ca15_ls2,ca15_ldr,ca15_ldr,nothing")
+
+;; Stores of up to two words.
+(define_insn_reservation "cortex_a15_store1" 0
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "store1,store2")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue1,ca15_ls,ca15_str")
+
+;; Stores of three or four words.
+(define_insn_reservation "cortex_a15_store3" 0
+ (and (eq_attr "tune" "cortexa15")
+ (and (eq_attr "type" "store3,store4")
+ (eq_attr "neon_type" "none")))
+ "ca15_issue2,ca15_ls1+ca15_ls2,ca15_str,ca15_str")
+
+;; Simple execution unit bypasses
+(define_bypass 1 "cortex_a15_alu"
+ "cortex_a15_alu,cortex_a15_alu_shift,cortex_a15_alu_shift_reg")
+(define_bypass 2 "cortex_a15_alu_shift"
+ "cortex_a15_alu,cortex_a15_alu_shift,cortex_a15_alu_shift_reg")
+(define_bypass 2 "cortex_a15_alu_shift_reg"
+ "cortex_a15_alu,cortex_a15_alu_shift,cortex_a15_alu_shift_reg")
+(define_bypass 1 "cortex_a15_alu" "cortex_a15_load1,cortex_a15_load3")
+(define_bypass 2 "cortex_a15_alu_shift" "cortex_a15_load1,cortex_a15_load3")
+(define_bypass 2 "cortex_a15_alu_shift_reg"
+ "cortex_a15_load1,cortex_a15_load3")
=== modified file 'gcc/config/arm/t-arm'
--- old/gcc/config/arm/t-arm 2011-01-03 20:52:22 +0000
+++ new/gcc/config/arm/t-arm 2011-12-02 00:38:59 +0000
@@ -31,6 +31,16 @@
$(srcdir)/config/arm/fmp626.md \
$(srcdir)/config/arm/fa726te.md \
$(srcdir)/config/arm/arm926ejs.md \
+ $(srcdir)/config/arm/cortex-a15.md \
+ $(srcdir)/config/arm/cortex-a5.md \
+ $(srcdir)/config/arm/cortex-a8.md \
+ $(srcdir)/config/arm/cortex-a8-neon.md \
+ $(srcdir)/config/arm/cortex-a9.md \
+ $(srcdir)/config/arm/cortex-a9-neon.md \
+ $(srcdir)/config/arm/cortex-m4-fpu.md \
+ $(srcdir)/config/arm/cortex-m4.md \
+ $(srcdir)/config/arm/cortex-r4f.md \
+ $(srcdir)/config/arm/cortex-r4.md \
$(srcdir)/config/arm/cirrus.md \
$(srcdir)/config/arm/fpa.md \
$(srcdir)/config/arm/vec-common.md \
@@ -0,0 +1,69 @@
2011-12-20 Ira Rosen <ira.rosen@linaro.org>
Backport from mainline:
2011-11-29 Ira Rosen <ira.rosen@linaro.org>
PR tree-optimization/51301
gcc/
* tree-vect-patterns.c (vect_recog_over_widening_pattern): Check that
the last statement doesn't convert to a bigger type than the original
type of the computation.
gcc/testsuite/
* gcc.dg/vect/pr51301.c: New test.
=== added file 'gcc/testsuite/gcc.dg/vect/pr51301.c'
--- old/gcc/testsuite/gcc.dg/vect/pr51301.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/pr51301.c 2011-11-30 17:54:51 +0000
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+
+typedef signed char int8_t;
+typedef signed long long int64_t;
+int64_t
+f0a (int8_t * __restrict__ arg1)
+{
+ int idx;
+ int64_t result = 0;
+ for (idx = 0; idx < 416; idx += 1)
+ result += arg1[idx] << (arg1[idx] == arg1[idx]);
+ return result;
+}
+
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/tree-vect-patterns.c'
--- old/gcc/tree-vect-patterns.c 2011-11-27 12:17:31 +0000
+++ new/gcc/tree-vect-patterns.c 2011-12-20 07:47:44 +0000
@@ -1138,6 +1138,7 @@
struct loop *loop = NULL;
bb_vec_info bb_vinfo;
stmt_vec_info stmt_vinfo;
+ tree type = NULL;
stmt_vinfo = vinfo_for_stmt (stmt);
loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
@@ -1207,6 +1208,7 @@
print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
}
+ type = gimple_expr_type (stmt);
prev_stmt = stmt;
stmt = use_stmt;
@@ -1222,9 +1224,11 @@
{
use_lhs = gimple_assign_lhs (use_stmt);
use_type = TREE_TYPE (use_lhs);
- /* Support only type promotion or signedess change. */
+ /* Support only type promotion or signedess change. Check that USE_TYPE
+ is not bigger than the original type. */
if (!INTEGRAL_TYPE_P (use_type)
- || TYPE_PRECISION (new_type) > TYPE_PRECISION (use_type))
+ || TYPE_PRECISION (new_type) > TYPE_PRECISION (use_type)
+ || TYPE_PRECISION (type) < TYPE_PRECISION (use_type))
return NULL;
if (TYPE_UNSIGNED (new_type) != TYPE_UNSIGNED (use_type)
@@ -0,0 +1,22 @@
2012-01-05 Michael Hope <michael.hope@linaro.org>
Backport from mainline r182271:
2011-12-13 Revital Eres <revital.eres@linaro.org>
gcc/
* modulo-sched.c (mark_loop_unsched): Free bbs.
=== modified file 'gcc/modulo-sched.c'
--- old/gcc/modulo-sched.c 2011-10-30 05:31:00 +0000
+++ new/gcc/modulo-sched.c 2012-01-05 02:45:23 +0000
@@ -1204,6 +1204,8 @@
for (i = 0; i < loop->num_nodes; i++)
bbs[i]->flags |= BB_DISABLE_SCHEDULE;
+
+ free (bbs);
}
/* Return true if all the BBs of the loop are empty except the
@@ -0,0 +1,104 @@
2012-01-12 Ulrich Weigand <ulrich.weigand@linaro.org>
LP 879725
Backport from mainline:
2012-01-02 Revital Eres <revital.eres@linaro.org>
gcc/
* ddg.c (def_has_ccmode_p): New function.
(add_cross_iteration_register_deps,
create_ddg_dep_from_intra_loop_link): Call it.
gcc/testsuite/
* gcc.dg/sms-11.c: New file.
=== modified file 'gcc/ddg.c'
--- old/gcc/ddg.c 2011-10-02 06:56:53 +0000
+++ new/gcc/ddg.c 2012-01-10 16:05:14 +0000
@@ -166,6 +166,24 @@
return false;
}
+/* Return true if one of the definitions in INSN has MODE_CC. Otherwise
+ return false. */
+static bool
+def_has_ccmode_p (rtx insn)
+{
+ df_ref *def;
+
+ for (def = DF_INSN_DEFS (insn); *def; def++)
+ {
+ enum machine_mode mode = GET_MODE (DF_REF_REG (*def));
+
+ if (GET_MODE_CLASS (mode) == MODE_CC)
+ return true;
+ }
+
+ return false;
+}
+
/* Computes the dependence parameters (latency, distance etc.), creates
a ddg_edge and adds it to the given DDG. */
static void
@@ -202,6 +220,7 @@
whose register has multiple defs in the loop. */
if (flag_modulo_sched_allow_regmoves
&& (t == ANTI_DEP && dt == REG_DEP)
+ && !def_has_ccmode_p (dest_node->insn)
&& !autoinc_var_is_used_p (dest_node->insn, src_node->insn))
{
rtx set;
@@ -335,7 +354,8 @@
if (DF_REF_ID (last_def) != DF_REF_ID (first_def)
|| !flag_modulo_sched_allow_regmoves
|| JUMP_P (use_node->insn)
- || autoinc_var_is_used_p (DF_REF_INSN (last_def), use_insn))
+ || autoinc_var_is_used_p (DF_REF_INSN (last_def), use_insn)
+ || def_has_ccmode_p (DF_REF_INSN (last_def)))
create_ddg_dep_no_link (g, use_node, first_def_node, ANTI_DEP,
REG_DEP, 1);
=== added file 'gcc/testsuite/gcc.dg/sms-11.c'
--- old/gcc/testsuite/gcc.dg/sms-11.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/sms-11.c 2012-01-10 16:05:14 +0000
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fmodulo-sched -fmodulo-sched-allow-regmoves -fdump-rtl-sms" } */
+
+extern void abort (void);
+
+float out[4][4] = { 6, 6, 7, 5, 6, 7, 5, 5, 6, 4, 4, 4, 6, 2, 3, 4 };
+
+void
+invert (void)
+{
+ int i, j, k = 0, swap;
+ float tmp[4][4] = { 5, 6, 7, 5, 6, 7, 5, 5, 4, 4, 4, 4, 3, 2, 3, 4 };
+
+ for (i = 0; i < 4; i++)
+ {
+ for (j = i + 1; j < 4; j++)
+ if (tmp[j][i] > tmp[i][i])
+ swap = j;
+
+ if (swap != i)
+ tmp[i][k] = tmp[swap][k];
+ }
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ if (tmp[i][j] != out[i][j])
+ abort ();
+}
+
+int
+main ()
+{
+ invert ();
+ return 0;
+}
+
+/* { dg-final { cleanup-rtl-dump "sms" } } */
@@ -0,0 +1,76 @@
2012-01-18 Michael Hope <michael.hope@linaro.org>
Backport from mainline r183126:
2012-01-12 Ira Rosen <irar@il.ibm.com>
gcc/
PR tree-optimization/51799
* tree-vect-patterns.c (vect_recog_over_widening_pattern): Check
that the last operation is a type demotion.
gcc/testsuite/
* gcc.dg/vect/pr51799.c: New test.
* gcc.dg/vect/vect-widen-shift-u8.c: Expect two widening shift
patterns.
=== added file 'gcc/testsuite/gcc.dg/vect/pr51799.c'
--- old/gcc/testsuite/gcc.dg/vect/pr51799.c 1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.dg/vect/pr51799.c 2012-01-18 01:53:19 +0000
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned long uint32_t;
+void
+f0a (uint32_t * __restrict__ result, int8_t * __restrict__ arg1,
+ uint32_t * __restrict__ arg4, int8_t temp_6)
+{
+ int idx;
+ for (idx = 0; idx < 416; idx += 1)
+ {
+ result[idx] = (uint8_t)(((arg1[idx] << 7) + arg4[idx]) * temp_6);
+ }
+}
+
+/* { dg-final { cleanup-tree-dump "vect" } } */
=== modified file 'gcc/testsuite/gcc.dg/vect/vect-widen-shift-u8.c'
--- old/gcc/testsuite/gcc.dg/vect/vect-widen-shift-u8.c 2011-10-23 13:33:07 +0000
+++ new/gcc/testsuite/gcc.dg/vect/vect-widen-shift-u8.c 2012-01-18 01:53:19 +0000
@@ -59,7 +59,6 @@
return 0;
}
-/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern: detected" 1 "vect" { target vect_widen_shift } } } */
+/* { dg-final { scan-tree-dump-times "vect_recog_widen_shift_pattern: detected" 2 "vect" { target vect_widen_shift } } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
-
=== modified file 'gcc/tree-vect-patterns.c'
--- old/gcc/tree-vect-patterns.c 2011-12-20 07:47:44 +0000
+++ new/gcc/tree-vect-patterns.c 2012-01-18 01:53:19 +0000
@@ -1224,13 +1224,15 @@
{
use_lhs = gimple_assign_lhs (use_stmt);
use_type = TREE_TYPE (use_lhs);
- /* Support only type promotion or signedess change. Check that USE_TYPE
- is not bigger than the original type. */
+ /* Support only type demotion or signedess change. */
if (!INTEGRAL_TYPE_P (use_type)
- || TYPE_PRECISION (new_type) > TYPE_PRECISION (use_type)
- || TYPE_PRECISION (type) < TYPE_PRECISION (use_type))
+ || TYPE_PRECISION (type) <= TYPE_PRECISION (use_type))
return NULL;
+ /* Check that NEW_TYPE is not bigger than the conversion result. */
+ if (TYPE_PRECISION (new_type) > TYPE_PRECISION (use_type))
+ return NULL;
+
if (TYPE_UNSIGNED (new_type) != TYPE_UNSIGNED (use_type)
|| TYPE_PRECISION (new_type) != TYPE_PRECISION (use_type))
{
@@ -0,0 +1,45 @@
2012-01-16 Michael Hope <michael.hope@linaro.org>
Backport from mainline r183011:
2012-01-09 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* config/arm/arm-cores.def (cortex-a15): Use cortex_a15_tune for
tuning parameters.
* config/arm/arm.c (arm_cortex_a15_tune): New static variable.
=== modified file 'gcc/config/arm/arm-cores.def'
--- old/gcc/config/arm/arm-cores.def 2011-10-19 16:46:51 +0000
+++ new/gcc/config/arm/arm-cores.def 2012-01-15 22:02:31 +0000
@@ -128,7 +128,7 @@
ARM_CORE("cortex-a5", cortexa5, 7A, FL_LDSCHED, cortex_a5)
ARM_CORE("cortex-a8", cortexa8, 7A, FL_LDSCHED, cortex)
ARM_CORE("cortex-a9", cortexa9, 7A, FL_LDSCHED, cortex_a9)
-ARM_CORE("cortex-a15", cortexa15, 7A, FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex)
+ARM_CORE("cortex-a15", cortexa15, 7A, FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex_a15)
ARM_CORE("cortex-r4", cortexr4, 7R, FL_LDSCHED, cortex)
ARM_CORE("cortex-r4f", cortexr4f, 7R, FL_LDSCHED, cortex)
ARM_CORE("cortex-r5", cortexr5, 7R, FL_LDSCHED | FL_ARM_DIV, cortex)
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2012-01-05 15:35:39 +0000
+++ new/gcc/config/arm/arm.c 2012-01-15 22:02:31 +0000
@@ -983,6 +983,17 @@
arm_default_branch_cost
};
+const struct tune_params arm_cortex_a15_tune =
+{
+ arm_9e_rtx_costs,
+ NULL,
+ 1, /* Constant limit. */
+ 1, /* Max cond insns. */
+ ARM_PREFETCH_NOT_BENEFICIAL, /* TODO: Calculate correct values. */
+ false, /* Prefer constant pool. */
+ arm_cortex_a5_branch_cost
+};
+
const struct tune_params arm_fa726te_tune =
{
arm_9e_rtx_costs,
@@ -0,0 +1,47 @@
2012-01-16 Michael Hope <michael.hope@linaro.org>
Backport from mainline r182561:
2011-12-20 Richard Henderson <rth@redhat.com>
gcc/
* config/arm/arm.md (*arm_cmpdi_unsigned): Enable for thumb2.
* config/arm/arm.c (arm_select_cc_mode): Use it.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2012-01-15 22:02:31 +0000
+++ new/gcc/config/arm/arm.c 2012-01-23 00:06:27 +0000
@@ -11602,7 +11602,7 @@
return CC_Zmode;
/* We can do an equality test in three Thumb instructions. */
- if (!TARGET_ARM)
+ if (!TARGET_32BIT)
return CC_Zmode;
/* FALLTHROUGH */
@@ -11614,7 +11614,7 @@
/* DImode unsigned comparisons can be implemented by cmp +
cmpeq without a scratch register. Not worth doing in
Thumb-2. */
- if (TARGET_ARM)
+ if (TARGET_32BIT)
return CC_CZmode;
/* FALLTHROUGH */
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2012-01-05 15:35:39 +0000
+++ new/gcc/config/arm/arm.md 2012-01-15 21:02:00 +0000
@@ -7515,8 +7515,8 @@
[(set (reg:CC_CZ CC_REGNUM)
(compare:CC_CZ (match_operand:DI 0 "s_register_operand" "r")
(match_operand:DI 1 "arm_di_operand" "rDi")))]
- "TARGET_ARM"
- "cmp%?\\t%R0, %R1\;cmpeq\\t%Q0, %Q1"
+ "TARGET_32BIT"
+ "cmp\\t%R0, %R1\;it eq\;cmpeq\\t%Q0, %Q1"
[(set_attr "conds" "set")
(set_attr "length" "8")]
)
@@ -0,0 +1,63 @@
2012-01-16 Michael Hope <michael.hope@linaro.org>
Backport from mainline r181210:
gcc/
2011-11-07 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
* config/arm/arm-cores.def: Add -mcpu=cortex-a7.
* config/arm/arm-tables.opt: Regenerate.
* config/arm/arm-tune.md: Likewise.
* config/arm/bpabi.h (BE8_LINK_SPEC): Add Cortex A-7.
* doc/invoke.texi: Document -mcpu=cortex-a7.
=== modified file 'gcc/config/arm/arm-cores.def'
--- old/gcc/config/arm/arm-cores.def 2012-01-15 22:02:31 +0000
+++ new/gcc/config/arm/arm-cores.def 2012-01-23 00:36:02 +0000
@@ -126,6 +126,7 @@
ARM_CORE("arm1156t2f-s", arm1156t2fs, 6T2, FL_LDSCHED | FL_VFPV2, v6t2)
ARM_CORE("generic-armv7-a", genericv7a, 7A, FL_LDSCHED, cortex)
ARM_CORE("cortex-a5", cortexa5, 7A, FL_LDSCHED, cortex_a5)
+ARM_CORE("cortex-a7", cortexa7, 7A, FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex)
ARM_CORE("cortex-a8", cortexa8, 7A, FL_LDSCHED, cortex)
ARM_CORE("cortex-a9", cortexa9, 7A, FL_LDSCHED, cortex_a9)
ARM_CORE("cortex-a15", cortexa15, 7A, FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex_a15)
=== modified file 'gcc/config/arm/arm-tune.md'
--- old/gcc/config/arm/arm-tune.md 2011-10-19 16:46:51 +0000
+++ new/gcc/config/arm/arm-tune.md 2012-01-15 22:43:29 +0000
@@ -1,5 +1,5 @@
;; -*- buffer-read-only: t -*-
;; Generated automatically by gentune.sh from arm-cores.def
(define_attr "tune"
- "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,fa526,fa626,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,genericv7a,cortexa5,cortexa8,cortexa9,cortexa15,cortexr4,cortexr4f,cortexr5,cortexm4,cortexm3,cortexm1,cortexm0"
+ "arm2,arm250,arm3,arm6,arm60,arm600,arm610,arm620,arm7,arm7d,arm7di,arm70,arm700,arm700i,arm710,arm720,arm710c,arm7100,arm7500,arm7500fe,arm7m,arm7dm,arm7dmi,arm8,arm810,strongarm,strongarm110,strongarm1100,strongarm1110,fa526,fa626,arm7tdmi,arm7tdmis,arm710t,arm720t,arm740t,arm9,arm9tdmi,arm920,arm920t,arm922t,arm940t,ep9312,arm10tdmi,arm1020t,arm9e,arm946es,arm966es,arm968es,arm10e,arm1020e,arm1022e,xscale,iwmmxt,iwmmxt2,fa606te,fa626te,fmp626,fa726te,arm926ejs,arm1026ejs,arm1136js,arm1136jfs,arm1176jzs,arm1176jzfs,mpcorenovfp,mpcore,arm1156t2s,arm1156t2fs,genericv7a,cortexa5,cortexa7,cortexa8,cortexa9,cortexa15,cortexr4,cortexr4f,cortexr5,cortexm4,cortexm3,cortexm1,cortexm0"
(const (symbol_ref "((enum attr_tune) arm_tune)")))
=== modified file 'gcc/config/arm/bpabi.h'
--- old/gcc/config/arm/bpabi.h 2011-11-02 21:02:53 +0000
+++ new/gcc/config/arm/bpabi.h 2012-01-15 22:43:29 +0000
@@ -56,6 +56,7 @@
"|march=armv4|mcpu=fa526|mcpu=fa626:--fix-v4bx}"
#define BE8_LINK_SPEC " %{mbig-endian:%{march=armv7-a|mcpu=cortex-a5"\
+ "|mcpu=cortex-a7"\
"|mcpu=cortex-a8|mcpu=cortex-a9|mcpu=cortex-a15|mcpu=generic-armv7-a"\
":%{!r:--be8}}}"
=== modified file 'gcc/doc/invoke.texi'
--- old/gcc/doc/invoke.texi 2012-01-05 15:35:39 +0000
+++ new/gcc/doc/invoke.texi 2012-01-15 22:43:29 +0000
@@ -10202,8 +10202,8 @@
@samp{arm10e}, @samp{arm1020e}, @samp{arm1022e},
@samp{arm1136j-s}, @samp{arm1136jf-s}, @samp{mpcore}, @samp{mpcorenovfp},
@samp{arm1156t2-s}, @samp{arm1156t2f-s}, @samp{arm1176jz-s}, @samp{arm1176jzf-s},
-@samp{cortex-a5}, @samp{cortex-a8}, @samp{cortex-a9}, @samp{cortex-a15},
-@samp{cortex-r4}, @samp{cortex-r4f}, @samp{cortex-r5},
+@samp{cortex-a5}, @samp{cortex-a7}, @samp{cortex-a8}, @samp{cortex-a9},
+@samp{cortex-a15}, @samp{cortex-r4}, @samp{cortex-r4f}, @samp{cortex-r5},
@samp{cortex-m4}, @samp{cortex-m3},
@samp{cortex-m1},
@samp{cortex-m0},
@@ -0,0 +1,25 @@
2012-01-20 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline
2012-01-20 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
PR target/51819
* config/arm/arm.c (arm_print_operand): Correct output of alignment
hints for neon loads and stores.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2012-01-23 00:06:27 +0000
+++ new/gcc/config/arm/arm.c 2012-01-23 18:54:21 +0000
@@ -17463,9 +17463,9 @@
/* Only certain alignment specifiers are supported by the hardware. */
if (memsize == 16 && (align % 32) == 0)
align_bits = 256;
- else if ((memsize == 8 || memsize == 16) && (align % 16) == 0)
+ else if (memsize == 16 && (align % 16) == 0)
align_bits = 128;
- else if ((align % 8) == 0)
+ else if (memsize >= 8 && (align % 8) == 0)
align_bits = 64;
else
align_bits = 0;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,28 @@
2012-02-20 Andrew Stubbs <ams@codesourcery.com>
gcc/
* config/arm/arm.c (arm_print_operand): Avoid null-pointer
dereference from MEM_SIZE.
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2012-02-09 00:47:59 +0000
+++ new/gcc/config/arm/arm.c 2012-02-20 15:32:26 +0000
@@ -17446,6 +17446,7 @@
rtx addr;
bool postinc = FALSE;
unsigned align, memsize, align_bits;
+ rtx memsize_rtx;
gcc_assert (GET_CODE (x) == MEM);
addr = XEXP (x, 0);
@@ -17460,7 +17461,8 @@
instruction (for some alignments) as an aid to the memory subsystem
of the target. */
align = MEM_ALIGN (x) >> 3;
- memsize = INTVAL (MEM_SIZE (x));
+ memsize_rtx = MEM_SIZE (x);
+ memsize = memsize_rtx ? INTVAL (memsize_rtx) : 0;
/* Only certain alignment specifiers are supported by the hardware. */
if (memsize == 16 && (align % 32) == 0)
@@ -0,0 +1,126 @@
2012-02-24 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline.
2011-12-05 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
gcc/
* config/arm/arm.c (vfp3_const_double_for_fract_bits): Define.
* config/arm/arm-protos.h (vfp3_const_double_for_fract_bits): Declare.
* config/arm/constraints.md ("Dt"): New constraint.
* config/arm/predicates.md (const_double_vcvt_power_of_two_reciprocal):
New.
* config/arm/vfp.md (*arm_combine_vcvt_f32_s32): New.
(*arm_combine_vcvt_f32_u32): New.
LP:#900426
2011-12-06 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
* config/arm/vfp.md (*combine_vcvt_f64_<FCVTI32typename>): Fix
formatting character for vmov.f64 case.
2012-02-24 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
gcc/
* config/arm/arm.c (arm_print_operand): Remove wrongly merged code.
(vfp3_const_double_for_fract_bits): Likewise.
=== modified file 'gcc/config/arm/arm-protos.h'
--- old/gcc/config/arm/arm-protos.h 2011-12-06 10:42:29 +0000
+++ new/gcc/config/arm/arm-protos.h 2012-02-22 13:31:54 +0000
@@ -238,6 +238,7 @@
};
extern const struct tune_params *current_tune;
+extern int vfp3_const_double_for_fract_bits (rtx);
#endif /* RTX_CODE */
#endif /* ! GCC_ARM_PROTOS_H */
=== modified file 'gcc/config/arm/constraints.md'
--- old/gcc/config/arm/constraints.md 2011-12-06 10:42:29 +0000
+++ new/gcc/config/arm/constraints.md 2012-02-22 13:31:54 +0000
@@ -29,7 +29,7 @@
;; in Thumb-1 state: I, J, K, L, M, N, O
;; The following multi-letter normal constraints have been used:
-;; in ARM/Thumb-2 state: Da, Db, Dc, Dn, Dl, DL, Dv, Dy, Di, Dz
+;; in ARM/Thumb-2 state: Da, Db, Dc, Dn, Dl, DL, Dv, Dy, Di, Dt, Dz
;; in Thumb-1 state: Pa, Pb, Pc, Pd
;; in Thumb-2 state: Pj, PJ, Ps, Pt, Pu, Pv, Pw, Px, Py
@@ -291,6 +291,12 @@
(and (match_code "const_double")
(match_test "TARGET_32BIT && TARGET_VFP_DOUBLE && vfp3_const_double_rtx (op)")))
+(define_constraint "Dt"
+ "@internal
+ In ARM/ Thumb2 a const_double which can be used with a vcvt.f32.s32 with fract bits operation"
+ (and (match_code "const_double")
+ (match_test "TARGET_32BIT && TARGET_VFP && vfp3_const_double_for_fract_bits (op)")))
+
(define_memory_constraint "Ut"
"@internal
In ARM/Thumb-2 state an address valid for loading/storing opaque structure
=== modified file 'gcc/config/arm/predicates.md'
--- old/gcc/config/arm/predicates.md 2011-12-06 10:42:29 +0000
+++ new/gcc/config/arm/predicates.md 2012-02-22 13:31:54 +0000
@@ -725,6 +725,11 @@
return true;
})
+(define_predicate "const_double_vcvt_power_of_two_reciprocal"
+ (and (match_code "const_double")
+ (match_test "TARGET_32BIT && TARGET_VFP
+ && vfp3_const_double_for_fract_bits (op)")))
+
(define_special_predicate "neon_struct_operand"
(and (match_code "mem")
(match_test "TARGET_32BIT && neon_vector_mem_operand (op, 2)")))
=== modified file 'gcc/config/arm/vfp.md'
--- old/gcc/config/arm/vfp.md 2011-12-06 10:42:29 +0000
+++ new/gcc/config/arm/vfp.md 2012-02-22 13:31:54 +0000
@@ -1131,9 +1131,40 @@
(set_attr "type" "fcmpd")]
)
+;; Fixed point to floating point conversions.
+(define_code_iterator FCVT [unsigned_float float])
+(define_code_attr FCVTI32typename [(unsigned_float "u32") (float "s32")])
+
+(define_insn "*combine_vcvt_f32_<FCVTI32typename>"
+ [(set (match_operand:SF 0 "s_register_operand" "=t")
+ (mult:SF (FCVT:SF (match_operand:SI 1 "s_register_operand" "0"))
+ (match_operand 2
+ "const_double_vcvt_power_of_two_reciprocal" "Dt")))]
+ "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP3 && !flag_rounding_math"
+ "vcvt.f32.<FCVTI32typename>\\t%0, %1, %v2"
+ [(set_attr "predicable" "no")
+ (set_attr "type" "f_cvt")]
+)
+
+;; Not the ideal way of implementing this. Ideally we would be able to split
+;; this into a move to a DP register and then a vcvt.f64.i32
+(define_insn "*combine_vcvt_f64_<FCVTI32typename>"
+ [(set (match_operand:DF 0 "s_register_operand" "=x,x,w")
+ (mult:DF (FCVT:DF (match_operand:SI 1 "s_register_operand" "r,t,r"))
+ (match_operand 2
+ "const_double_vcvt_power_of_two_reciprocal" "Dt,Dt,Dt")))]
+ "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP3 && !flag_rounding_math
+ && !TARGET_VFP_SINGLE"
+ "@
+ vmov.f32\\t%0, %1\;vcvt.f64.<FCVTI32typename>\\t%P0, %P0, %v2
+ vmov.f32\\t%0, %1\;vcvt.f64.<FCVTI32typename>\\t%P0, %P0, %v2
+ vmov.f64\\t%P0, %1, %1\; vcvt.f64.<FCVTI32typename>\\t%P0, %P0, %v2"
+ [(set_attr "predicable" "no")
+ (set_attr "type" "f_cvt")
+ (set_attr "length" "8")]
+)
;; Store multiple insn used in function prologue.
-
(define_insn "*push_multi_vfp"
[(match_parallel 2 "multi_register_push"
[(set (match_operand:BLK 0 "memory_operand" "=m")
@@ -0,0 +1,80 @@
2012-02-24 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
LP:#922474
gcc/
* config/arm/sync.md (sync_lock_releasedi): Define.
(arm_sync_lock_releasedi): Likewise.
gcc/testsuite
Backport from mainline.
2012-01-30 Greta Yorsh <Greta.Yorsh@arm.com>
* gcc.target/arm/di-longlong64-sync-withldrexd.c: Accept
new code generated for __sync_lock_release.
=== modified file 'gcc/config/arm/arm.md'
--- old/gcc/config/arm/arm.md 2012-02-01 14:13:07 +0000
+++ new/gcc/config/arm/arm.md 2012-02-22 18:37:56 +0000
@@ -157,6 +157,7 @@
(VUNSPEC_SYNC_OP 23) ; Represent a sync_<op>
(VUNSPEC_SYNC_NEW_OP 24) ; Represent a sync_new_<op>
(VUNSPEC_SYNC_OLD_OP 25) ; Represent a sync_old_<op>
+ (VUNSPEC_SYNC_RELEASE 26) ; Represent a sync_lock_release.
]
)
=== modified file 'gcc/config/arm/sync.md'
--- old/gcc/config/arm/sync.md 2011-10-14 15:47:15 +0000
+++ new/gcc/config/arm/sync.md 2012-02-22 18:37:56 +0000
@@ -494,3 +494,36 @@
(set_attr "conds" "unconditional")
(set_attr "predicable" "no")])
+(define_expand "sync_lock_releasedi"
+ [(match_operand:DI 0 "memory_operand")
+ (match_operand:DI 1 "s_register_operand")]
+ "TARGET_HAVE_LDREXD && ARM_DOUBLEWORD_ALIGN && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ struct arm_sync_generator generator;
+ rtx tmp1 = gen_reg_rtx (DImode);
+ generator.op = arm_sync_generator_omn;
+ generator.u.omn = gen_arm_sync_lock_releasedi;
+ arm_expand_sync (DImode, &generator, operands[1], operands[0], NULL, tmp1);
+ DONE;
+ }
+)
+
+(define_insn "arm_sync_lock_releasedi"
+ [(set (match_operand:DI 2 "s_register_operand" "=&r")
+ (unspec_volatile:DI [(match_operand:DI 1 "arm_sync_memory_operand" "+Q")
+ (match_operand:DI 0 "s_register_operand" "r")]
+ VUNSPEC_SYNC_RELEASE))
+ (clobber (reg:CC CC_REGNUM))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "TARGET_HAVE_LDREXD && ARM_DOUBLEWORD_ALIGN && TARGET_HAVE_MEMORY_BARRIER"
+ {
+ return arm_output_sync_insn (insn, operands);
+ }
+ [(set_attr "sync_memory" "1")
+ (set_attr "sync_result" "2")
+ (set_attr "sync_t1" "2")
+ (set_attr "sync_t2" "3")
+ (set_attr "sync_new_value" "0")
+ (set_attr "conds" "clob")
+ (set_attr "predicable" "no")]
+)
=== modified file 'gcc/testsuite/gcc.target/arm/di-longlong64-sync-withldrexd.c'
--- old/gcc/testsuite/gcc.target/arm/di-longlong64-sync-withldrexd.c 2011-10-14 15:56:32 +0000
+++ new/gcc/testsuite/gcc.target/arm/di-longlong64-sync-withldrexd.c 2012-02-22 18:37:56 +0000
@@ -10,8 +10,8 @@
#include "../../gcc.dg/di-longlong64-sync-1.c"
/* We should be using ldrexd, strexd and no helpers or shorter ldrex. */
-/* { dg-final { scan-assembler-times "\tldrexd" 46 } } */
-/* { dg-final { scan-assembler-times "\tstrexd" 46 } } */
+/* { dg-final { scan-assembler-times "\tldrexd" 48 } } */
+/* { dg-final { scan-assembler-times "\tstrexd" 48 } } */
/* { dg-final { scan-assembler-not "__sync_" } } */
/* { dg-final { scan-assembler-not "ldrex\t" } } */
/* { dg-final { scan-assembler-not "strex\t" } } */
@@ -0,0 +1,46 @@
2012-02-24 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
Backport from mainline.
gcc/
2012-02-21 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
Revert r183011
* config/arm/arm-cores.def (cortex-a15): Use generic Cortex tuning
parameters.
* config/arm/arm.c (arm_cortex_a15_tune): Remove.
=== modified file 'gcc/config/arm/arm-cores.def'
--- old/gcc/config/arm/arm-cores.def 2012-01-23 00:36:02 +0000
+++ new/gcc/config/arm/arm-cores.def 2012-02-22 15:53:56 +0000
@@ -129,7 +129,7 @@
ARM_CORE("cortex-a7", cortexa7, 7A, FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex)
ARM_CORE("cortex-a8", cortexa8, 7A, FL_LDSCHED, cortex)
ARM_CORE("cortex-a9", cortexa9, 7A, FL_LDSCHED, cortex_a9)
-ARM_CORE("cortex-a15", cortexa15, 7A, FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex_a15)
+ARM_CORE("cortex-a15", cortexa15, 7A, FL_LDSCHED | FL_THUMB_DIV | FL_ARM_DIV, cortex)
ARM_CORE("cortex-r4", cortexr4, 7R, FL_LDSCHED, cortex)
ARM_CORE("cortex-r4f", cortexr4f, 7R, FL_LDSCHED, cortex)
ARM_CORE("cortex-r5", cortexr5, 7R, FL_LDSCHED | FL_ARM_DIV, cortex)
=== modified file 'gcc/config/arm/arm.c'
--- old/gcc/config/arm/arm.c 2012-02-24 16:20:29 +0000
+++ new/gcc/config/arm/arm.c 2012-02-24 17:33:58 +0000
@@ -988,17 +988,6 @@
arm_default_branch_cost
};
-const struct tune_params arm_cortex_a15_tune =
-{
- arm_9e_rtx_costs,
- NULL,
- 1, /* Constant limit. */
- 1, /* Max cond insns. */
- ARM_PREFETCH_NOT_BENEFICIAL, /* TODO: Calculate correct values. */
- false, /* Prefer constant pool. */
- arm_cortex_a5_branch_cost
-};
-
const struct tune_params arm_fa726te_tune =
{
arm_9e_rtx_costs,