diff options
author | Khem Raj <raj.khem@gmail.com> | 2012-03-06 17:21:34 +0000 |
---|---|---|
committer | Khem Raj <raj.khem@gmail.com> | 2012-03-08 18:57:24 -0800 |
commit | f256ccfb85b8b14b9b72991d5be1d3ec02f828a8 (patch) | |
tree | 543109c7ccfc9b40e76662d1fccef5e257ff360c /meta-oe/recipes-devtools | |
parent | 8a728abad7307e968a03b333811fc1f816ba18b4 (diff) | |
download | meta-openembedded-f256ccfb85b8b14b9b72991d5be1d3ec02f828a8.tar.gz |
gcc-4.6: Adjust to match gcc 4.6.3 from OE-Core
Update linaro patches
Signed-off-by: Khem Raj <raj.khem@gmail.com>
Diffstat (limited to 'meta-oe/recipes-devtools')
18 files changed, 3197 insertions, 780 deletions
diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/fix_linaro_106872.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/fix_linaro_106872.patch new file mode 100644 index 0000000000..ef33afff70 --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/fix_linaro_106872.patch @@ -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" diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106740.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106740.patch deleted file mode 100644 index 11a1da6709..0000000000 --- a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106740.patch +++ /dev/null @@ -1,294 +0,0 @@ -2011-05-04 Richard Sandiford <richard.sandiford@linaro.org> - - Backport from mainline: - - 2011-03-29 Richard Sandiford <richard.sandiford@linaro.org> - - PR debug/48190 - * dwarf2out.c (dw_loc_list_node): Add resolved_addr and replaced. - (cached_dw_loc_list_def): New structure. - (cached_dw_loc_list): New typedef. - (cached_dw_loc_list_table): New variable. - (cached_dw_loc_list_table_hash): New function. - (cached_dw_loc_list_table_eq): Likewise. - (add_location_or_const_value_attribute): Take a bool cache_p. - Cache the list when the parameter is true. - (gen_formal_parameter_die): Update caller. - (gen_variable_die): Likewise. - (dwarf2out_finish): Likewise. - (dwarf2out_abstract_function): Nullify cached_dw_loc_list_table - while generating debug info for the decl. - (dwarf2out_function_decl): Clear cached_dw_loc_list_table. - (dwarf2out_init): Initialize cached_dw_loc_list_table. - (resolve_addr): Cache the result of resolving a chain of - location lists. - -=== modified file 'gcc/dwarf2out.c' ---- old/gcc/dwarf2out.c 2011-03-29 22:47:59 +0000 -+++ new/gcc/dwarf2out.c 2011-05-04 13:20:12 +0000 -@@ -4427,6 +4427,11 @@ - const char *section; /* Section this loclist is relative to */ - dw_loc_descr_ref expr; - hashval_t hash; -+ /* True if all addresses in this and subsequent lists are known to be -+ resolved. */ -+ bool resolved_addr; -+ /* True if this list has been replaced by dw_loc_next. */ -+ bool replaced; - bool emitted; - } dw_loc_list_node; - -@@ -6087,6 +6092,19 @@ - /* Table of decl location linked lists. */ - static GTY ((param_is (var_loc_list))) htab_t decl_loc_table; - -+/* A cached location list. */ -+struct GTY (()) cached_dw_loc_list_def { -+ /* The DECL_UID of the decl that this entry describes. */ -+ unsigned int decl_id; -+ -+ /* The cached location list. */ -+ dw_loc_list_ref loc_list; -+}; -+typedef struct cached_dw_loc_list_def cached_dw_loc_list; -+ -+/* Table of cached location lists. */ -+static GTY ((param_is (cached_dw_loc_list))) htab_t cached_dw_loc_list_table; -+ - /* A pointer to the base of a list of references to DIE's that - are uniquely identified by their tag, presence/absence of - children DIE's, and list of attribute/value pairs. */ -@@ -6434,7 +6452,7 @@ - static void insert_double (double_int, unsigned char *); - static void insert_float (const_rtx, unsigned char *); - static rtx rtl_for_decl_location (tree); --static bool add_location_or_const_value_attribute (dw_die_ref, tree, -+static bool add_location_or_const_value_attribute (dw_die_ref, tree, bool, - enum dwarf_attribute); - static bool tree_add_const_value_attribute (dw_die_ref, tree); - static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree); -@@ -8168,6 +8186,24 @@ - htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl)); - } - -+/* Returns a hash value for X (which really is a cached_dw_loc_list_list). */ -+ -+static hashval_t -+cached_dw_loc_list_table_hash (const void *x) -+{ -+ return (hashval_t) ((const cached_dw_loc_list *) x)->decl_id; -+} -+ -+/* Return nonzero if decl_id of cached_dw_loc_list X is the same as -+ UID of decl *Y. */ -+ -+static int -+cached_dw_loc_list_table_eq (const void *x, const void *y) -+{ -+ return (((const cached_dw_loc_list *) x)->decl_id -+ == DECL_UID ((const_tree) y)); -+} -+ - /* Equate a DIE to a particular declaration. */ - - static void -@@ -16965,15 +17001,22 @@ - these things can crop up in other ways also.) Note that one type of - constant value which can be passed into an inlined function is a constant - pointer. This can happen for example if an actual argument in an inlined -- function call evaluates to a compile-time constant address. */ -+ function call evaluates to a compile-time constant address. -+ -+ CACHE_P is true if it is worth caching the location list for DECL, -+ so that future calls can reuse it rather than regenerate it from scratch. -+ This is true for BLOCK_NONLOCALIZED_VARS in inlined subroutines, -+ since we will need to refer to them each time the function is inlined. */ - - static bool --add_location_or_const_value_attribute (dw_die_ref die, tree decl, -+add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p, - enum dwarf_attribute attr) - { - rtx rtl; - dw_loc_list_ref list; - var_loc_list *loc_list; -+ cached_dw_loc_list *cache; -+ void **slot; - - if (TREE_CODE (decl) == ERROR_MARK) - return false; -@@ -17010,7 +17053,33 @@ - && add_const_value_attribute (die, rtl)) - return true; - } -- list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2); -+ /* If this decl is from BLOCK_NONLOCALIZED_VARS, we might need its -+ list several times. See if we've already cached the contents. */ -+ list = NULL; -+ if (loc_list == NULL || cached_dw_loc_list_table == NULL) -+ cache_p = false; -+ if (cache_p) -+ { -+ cache = (cached_dw_loc_list *) -+ htab_find_with_hash (cached_dw_loc_list_table, decl, DECL_UID (decl)); -+ if (cache) -+ list = cache->loc_list; -+ } -+ if (list == NULL) -+ { -+ list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2); -+ /* It is usually worth caching this result if the decl is from -+ BLOCK_NONLOCALIZED_VARS and if the list has at least two elements. */ -+ if (cache_p && list && list->dw_loc_next) -+ { -+ slot = htab_find_slot_with_hash (cached_dw_loc_list_table, decl, -+ DECL_UID (decl), INSERT); -+ cache = ggc_alloc_cleared_cached_dw_loc_list (); -+ cache->decl_id = DECL_UID (decl); -+ cache->loc_list = list; -+ *slot = cache; -+ } -+ } - if (list) - { - add_AT_location_description (die, attr, list); -@@ -18702,7 +18771,7 @@ - equate_decl_number_to_die (node, parm_die); - if (! DECL_ABSTRACT (node_or_origin)) - add_location_or_const_value_attribute (parm_die, node_or_origin, -- DW_AT_location); -+ node == NULL, DW_AT_location); - - break; - -@@ -18887,6 +18956,7 @@ - tree context; - int was_abstract; - htab_t old_decl_loc_table; -+ htab_t old_cached_dw_loc_list_table; - - /* Make sure we have the actual abstract inline, not a clone. */ - decl = DECL_ORIGIN (decl); -@@ -18901,6 +18971,8 @@ - get locations in abstract instantces. */ - old_decl_loc_table = decl_loc_table; - decl_loc_table = NULL; -+ old_cached_dw_loc_list_table = cached_dw_loc_list_table; -+ cached_dw_loc_list_table = NULL; - - /* Be sure we've emitted the in-class declaration DIE (if any) first, so - we don't get confused by DECL_ABSTRACT. */ -@@ -18925,6 +18997,7 @@ - - current_function_decl = save_fn; - decl_loc_table = old_decl_loc_table; -+ cached_dw_loc_list_table = old_cached_dw_loc_list_table; - pop_cfun (); - } - -@@ -19709,9 +19782,8 @@ - && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin))) - defer_location (decl_or_origin, var_die); - else -- add_location_or_const_value_attribute (var_die, -- decl_or_origin, -- DW_AT_location); -+ add_location_or_const_value_attribute (var_die, decl_or_origin, -+ decl == NULL, DW_AT_location); - add_pubname (decl_or_origin, var_die); - } - else -@@ -21498,6 +21570,7 @@ - dwarf2out_decl (decl); - - htab_empty (decl_loc_table); -+ htab_empty (cached_dw_loc_list_table); - } - - /* Output a marker (i.e. a label) for the beginning of the generated code for -@@ -22230,6 +22303,11 @@ - decl_loc_table = htab_create_ggc (10, decl_loc_table_hash, - decl_loc_table_eq, NULL); - -+ /* Allocate the cached_dw_loc_list_table. */ -+ cached_dw_loc_list_table -+ = htab_create_ggc (10, cached_dw_loc_list_table_hash, -+ cached_dw_loc_list_table_eq, NULL); -+ - /* Allocate the initial hunk of the decl_scope_table. */ - decl_scope_table = VEC_alloc (tree, gc, 256); - -@@ -22870,30 +22948,53 @@ - { - dw_die_ref c; - dw_attr_ref a; -- dw_loc_list_ref *curr; -+ dw_loc_list_ref *curr, *start, loc; - unsigned ix; - - FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a) - switch (AT_class (a)) - { - case dw_val_class_loc_list: -- curr = AT_loc_list_ptr (a); -- while (*curr) -+ start = curr = AT_loc_list_ptr (a); -+ loc = *curr; -+ gcc_assert (loc); -+ /* The same list can be referenced more than once. See if we have -+ already recorded the result from a previous pass. */ -+ if (loc->replaced) -+ *curr = loc->dw_loc_next; -+ else if (!loc->resolved_addr) - { -- if (!resolve_addr_in_expr ((*curr)->expr)) -+ /* As things stand, we do not expect or allow one die to -+ reference a suffix of another die's location list chain. -+ References must be identical or completely separate. -+ There is therefore no need to cache the result of this -+ pass on any list other than the first; doing so -+ would lead to unnecessary writes. */ -+ while (*curr) - { -- dw_loc_list_ref next = (*curr)->dw_loc_next; -- if (next && (*curr)->ll_symbol) -+ gcc_assert (!(*curr)->replaced && !(*curr)->resolved_addr); -+ if (!resolve_addr_in_expr ((*curr)->expr)) - { -- gcc_assert (!next->ll_symbol); -- next->ll_symbol = (*curr)->ll_symbol; -+ dw_loc_list_ref next = (*curr)->dw_loc_next; -+ if (next && (*curr)->ll_symbol) -+ { -+ gcc_assert (!next->ll_symbol); -+ next->ll_symbol = (*curr)->ll_symbol; -+ } -+ *curr = next; - } -- *curr = next; -+ else -+ curr = &(*curr)->dw_loc_next; - } -+ if (loc == *start) -+ loc->resolved_addr = 1; - else -- curr = &(*curr)->dw_loc_next; -+ { -+ loc->replaced = 1; -+ loc->dw_loc_next = *start; -+ } - } -- if (!AT_loc_list (a)) -+ if (!*start) - { - remove_AT (die, a->dw_attr); - ix--; -@@ -23322,6 +23423,7 @@ - add_location_or_const_value_attribute ( - VEC_index (deferred_locations, deferred_locations_list, i)->die, - VEC_index (deferred_locations, deferred_locations_list, i)->variable, -+ false, - DW_AT_location); - } - - diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106741.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106741.patch index f53b26a888..6e76c21272 100644 --- a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106741.patch +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106741.patch @@ -19,8 +19,8 @@ === modified file 'gcc/combine.c' Index: gcc-4_6-branch/gcc/combine.c =================================================================== ---- gcc-4_6-branch.orig/gcc/combine.c 2011-09-16 19:58:21.000000000 -0700 -+++ gcc-4_6-branch/gcc/combine.c 2011-09-16 20:05:36.626650681 -0700 +--- 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); @@ -32,7 +32,7 @@ Index: gcc-4_6-branch/gcc/combine.c static rtx simplify_if_then_else (rtx); static rtx simplify_set (rtx); static rtx simplify_logical (rtx); -@@ -3112,12 +3112,12 @@ +@@ -3119,12 +3119,12 @@ if (i1) { subst_low_luid = DF_INSN_LUID (i1); @@ -47,7 +47,7 @@ Index: gcc-4_6-branch/gcc/combine.c } } -@@ -3129,7 +3129,7 @@ +@@ -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. */ @@ -56,7 +56,7 @@ Index: gcc-4_6-branch/gcc/combine.c (i1_feeds_i2_n && i1dest_in_i1src) || ((i0_feeds_i2_n || (i0_feeds_i1_n && i1_feeds_i2_n)) && i0dest_in_i0src)); -@@ -3168,7 +3168,7 @@ +@@ -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. */ @@ -65,7 +65,7 @@ Index: gcc-4_6-branch/gcc/combine.c i0_feeds_i1_n && i0dest_in_i0src); substed_i1 = 1; -@@ -3198,7 +3198,7 @@ +@@ -3214,7 +3214,7 @@ n_occurrences = 0; subst_low_luid = DF_INSN_LUID (i0); @@ -74,16 +74,16 @@ Index: gcc-4_6-branch/gcc/combine.c substed_i0 = 1; } -@@ -3260,7 +3260,7 @@ +@@ -3276,7 +3276,7 @@ { rtx t = i1pat; if (i0_feeds_i1_n) -- t = subst (t, i0dest, i0src, 0, 0); -+ t = subst (t, i0dest, i0src, 0, 0, 0); +- 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; } -@@ -3268,10 +3268,10 @@ +@@ -3284,10 +3284,10 @@ { rtx t = i2pat; if (i1_feeds_i2_n) @@ -91,12 +91,12 @@ Index: gcc-4_6-branch/gcc/combine.c + 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, 0, 0); -+ t = subst (t, i0dest, i0src, 0, 0, 0); +- 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; } -@@ -4943,11 +4943,13 @@ +@@ -4959,11 +4959,13 @@ IN_DEST is nonzero if we are processing the SET_DEST of a SET. @@ -111,7 +111,7 @@ Index: gcc-4_6-branch/gcc/combine.c { enum rtx_code code = GET_CODE (x); enum machine_mode op0_mode = VOIDmode; -@@ -5008,7 +5010,7 @@ +@@ -5024,7 +5026,7 @@ && GET_CODE (XVECEXP (x, 0, 0)) == SET && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS) { @@ -120,7 +120,7 @@ Index: gcc-4_6-branch/gcc/combine.c /* If this substitution failed, this whole thing fails. */ if (GET_CODE (new_rtx) == CLOBBER -@@ -5025,7 +5027,7 @@ +@@ -5041,7 +5043,7 @@ && GET_CODE (dest) != CC0 && GET_CODE (dest) != PC) { @@ -129,7 +129,7 @@ Index: gcc-4_6-branch/gcc/combine.c /* If this substitution failed, this whole thing fails. */ if (GET_CODE (new_rtx) == CLOBBER -@@ -5071,8 +5073,8 @@ +@@ -5087,8 +5089,8 @@ } else { @@ -140,7 +140,7 @@ Index: gcc-4_6-branch/gcc/combine.c /* If this substitution failed, this whole thing fails. */ -@@ -5149,7 +5151,9 @@ +@@ -5165,7 +5167,9 @@ && (code == SUBREG || code == STRICT_LOW_PART || code == ZERO_EXTRACT)) || code == SET) @@ -151,7 +151,7 @@ Index: gcc-4_6-branch/gcc/combine.c /* If we found that we will have to reject this combination, indicate that by returning the CLOBBER ourselves, rather than -@@ -5206,7 +5210,7 @@ +@@ -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) @@ -160,7 +160,7 @@ Index: gcc-4_6-branch/gcc/combine.c if (GET_CODE (x) == code) break; -@@ -5226,10 +5230,12 @@ +@@ -5242,10 +5246,12 @@ expression. OP0_MODE is the original mode of XEXP (x, 0). IN_DEST is nonzero @@ -175,7 +175,7 @@ Index: gcc-4_6-branch/gcc/combine.c { enum rtx_code code = GET_CODE (x); enum machine_mode mode = GET_MODE (x); -@@ -5284,8 +5290,8 @@ +@@ -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. */ @@ -186,7 +186,7 @@ Index: gcc-4_6-branch/gcc/combine.c /* If true_rtx and false_rtx are not general_operands, an if_then_else is unlikely to be simpler. */ -@@ -5629,7 +5635,7 @@ +@@ -5645,7 +5651,7 @@ { /* Try to simplify the expression further. */ rtx tor = simplify_gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1)); @@ -195,7 +195,7 @@ Index: gcc-4_6-branch/gcc/combine.c /* If we could, great. If not, do not go ahead with the IOR replacement, since PLUS appears in many special purpose -@@ -5722,7 +5728,16 @@ +@@ -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. */ @@ -213,7 +213,7 @@ Index: gcc-4_6-branch/gcc/combine.c && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT && op1 == const0_rtx && mode == GET_MODE (op0) -@@ -5768,7 +5783,10 @@ +@@ -5784,7 +5799,10 @@ /* If STORE_FLAG_VALUE is -1, we have cases similar to those above. */ @@ -225,7 +225,7 @@ Index: gcc-4_6-branch/gcc/combine.c && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT && op1 == const0_rtx && (num_sign_bit_copies (op0, mode) -@@ -5966,11 +5984,11 @@ +@@ -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), @@ -239,7 +239,7 @@ Index: gcc-4_6-branch/gcc/combine.c SUBST (XEXP (x, 1), swapped ? false_rtx : true_rtx); SUBST (XEXP (x, 2), swapped ? true_rtx : false_rtx); -@@ -6187,11 +6205,11 @@ +@@ -6203,11 +6221,11 @@ { temp = subst (simplify_gen_relational (true_code, m, VOIDmode, cond_op0, cond_op1), diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106827.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106827.patch index d49ebab600..28caa40076 100644 --- a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106827.patch +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106827.patch @@ -37,8 +37,10 @@ * config/arm/arm.md (*arm_movqi_insn): Compute attr "length". === modified file 'gcc/config/arm/arm-protos.h' ---- old/gcc/config/arm/arm-protos.h 2011-10-03 09:46:40 +0000 -+++ new/gcc/config/arm/arm-protos.h 2011-10-11 01:56:19 +0000 +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, @@ -47,10 +49,10 @@ extern int arm_const_double_rtx (rtx); extern int neg_const_double_rtx_ok_for_fpa (rtx); extern int vfp3_const_double_rtx (rtx); - -=== modified file 'gcc/config/arm/arm.c' ---- old/gcc/config/arm/arm.c 2011-10-03 09:46:40 +0000 -+++ new/gcc/config/arm/arm.c 2011-10-11 02:31:01 +0000 +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; } @@ -80,7 +82,7 @@ if (TARGET_THUMB1 && flag_schedule_insns) { /* Don't warn since it's on by default in -O2. */ -@@ -6106,7 +6128,7 @@ +@@ -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. */ @@ -89,7 +91,7 @@ thumb1_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p) { /* ??? Not clear if this is right. Experiment. */ -@@ -22226,6 +22248,10 @@ +@@ -22251,6 +22273,10 @@ val = 6; asm_fprintf (asm_out_file, "\t.eabi_attribute 30, %d\n", val); @@ -100,22 +102,22 @@ /* Tag_ABI_FP_16bit_format. */ if (arm_fp16_format) asm_fprintf (asm_out_file, "\t.eabi_attribute 38, %d\n", - -=== modified file 'gcc/config/arm/arm.md' ---- old/gcc/config/arm/arm.md 2011-10-03 09:47:33 +0000 -+++ new/gcc/config/arm/arm.md 2011-10-11 02:31:01 +0000 -@@ -113,6 +113,10 @@ - (UNSPEC_SYMBOL_OFFSET 27) ; The offset of the start of the symbol from +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_UNALIGNED_LOAD 29) ; Used to represent ldr/ldrh instructions that access + (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 30) ; Same for str/strh. ++ (UNSPEC_UNALIGNED_STORE 31) ; Same for str/strh. ] ) -@@ -2463,10 +2467,10 @@ +@@ -2461,10 +2465,10 @@ ;;; this insv pattern, so this pattern needs to be reevalutated. (define_expand "insv" @@ -130,51 +132,59 @@ "TARGET_ARM || arm_arch_thumb2" " { -@@ -2477,35 +2481,70 @@ +@@ -2475,35 +2479,70 @@ if (arm_arch_thumb2) { - bool use_bfi = TRUE; - - 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])); + 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; @@ -198,24 +208,9 @@ + + emit_insn (gen_insv_t2 (operands[0], operands[1], operands[2], + operands[3])); - 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; -- } -+ } ++ DONE; ++ } + } + else + FAIL; } @@ -226,7 +221,7 @@ target = copy_rtx (operands[0]); /* Avoid using a subreg as a subtarget, and avoid writing a paradoxical subreg as the final target. */ -@@ -3697,12 +3736,10 @@ +@@ -3695,12 +3734,10 @@ ;; to reduce register pressure later on. (define_expand "extzv" @@ -243,7 +238,7 @@ "TARGET_THUMB1 || arm_arch_thumb2" " { -@@ -3711,10 +3748,57 @@ +@@ -3709,10 +3746,57 @@ if (arm_arch_thumb2) { @@ -304,7 +299,7 @@ operands[3] = GEN_INT (rshift); -@@ -3724,12 +3808,154 @@ +@@ -3722,12 +3806,154 @@ DONE; } @@ -462,7 +457,7 @@ [(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") -@@ -6038,8 +6264,8 @@ +@@ -6069,8 +6295,8 @@ (define_insn "*arm_movqi_insn" @@ -473,7 +468,7 @@ "TARGET_32BIT && ( register_operand (operands[0], QImode) || register_operand (operands[1], QImode))" -@@ -6047,10 +6273,14 @@ +@@ -6078,10 +6304,14 @@ mov%?\\t%0, %1 mvn%?\\t%0, #%B1 ldr%(b%)\\t%0, %1 @@ -491,10 +486,10 @@ ) (define_insn "*thumb1_movqi_insn" - -=== modified file 'gcc/config/arm/arm.opt' ---- old/gcc/config/arm/arm.opt 2011-09-19 07:44:24 +0000 -+++ new/gcc/config/arm/arm.opt 2011-10-11 02:31:01 +0000 +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 @@ -503,10 +498,10 @@ +munaligned-access +Target Report Var(unaligned_access) Init(2) +Enable unaligned word and halfword accesses to packed data. - -=== modified file 'gcc/config/arm/constraints.md' ---- old/gcc/config/arm/constraints.md 2011-09-12 14:14:00 +0000 -+++ new/gcc/config/arm/constraints.md 2011-10-11 02:31:01 +0000 +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 @@ -543,10 +538,10 @@ ;; We used to have constraint letters for S and R in ARM state, but ;; all uses of these now appear to have been removed. - -=== modified file 'gcc/expmed.c' ---- old/gcc/expmed.c 2011-05-22 19:02:59 +0000 -+++ new/gcc/expmed.c 2011-10-11 02:31:01 +0000 +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 @@ -625,4 +620,3 @@ if (xtarget == 0) xtarget = xspec_target = gen_reg_rtx (tmode); - diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106842.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106842.patch index 74f139d33a..2cf2741ba6 100644 --- a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106842.patch +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106842.patch @@ -48,8 +48,10 @@ Return true for NEON. === modified file 'gcc/testsuite/gcc.dg/vect/pr30858.c' ---- old/gcc/testsuite/gcc.dg/vect/pr30858.c 2007-02-22 08:16:18 +0000 -+++ new/gcc/testsuite/gcc.dg/vect/pr30858.c 2011-11-20 09:11:09 +0000 +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 @@ } @@ -58,10 +60,10 @@ +/* { 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" } } */ - -=== added file 'gcc/testsuite/gcc.dg/vect/vect-cond-8a.c' ---- old/gcc/testsuite/gcc.dg/vect/vect-cond-8a.c 1970-01-01 00:00:00 +0000 -+++ new/gcc/testsuite/gcc.dg/vect/vect-cond-8a.c 2011-11-20 09:11:09 +0000 +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 } */ + @@ -138,24 +140,10 @@ + +/* { dg-final { scan-tree-dump-times "note: vectorized 1 loops" 3 "vect" } } */ +/* { dg-final { cleanup-tree-dump "vect" } } */ - -=== modified file 'gcc/testsuite/lib/target-supports.exp' ---- old/gcc/testsuite/lib/target-supports.exp 2011-11-21 01:45:54 +0000 -+++ new/gcc/testsuite/lib/target-supports.exp 2011-11-22 16:52:23 +0000 -@@ -3150,7 +3150,8 @@ - || [istarget ia64-*-*] - || [istarget i?86-*-*] - || [istarget spu-*-*] -- || [istarget x86_64-*-*] } { -+ || [istarget x86_64-*-*] -+ || ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok]) } { - set et_vect_cond_saved 1 - } - } - -=== modified file 'gcc/tree-vect-patterns.c' ---- old/gcc/tree-vect-patterns.c 2011-10-23 13:33:07 +0000 -+++ new/gcc/tree-vect-patterns.c 2011-11-20 09:11:09 +0000 +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) **, @@ -299,14 +287,14 @@ 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)); -+ def_stmt_info = vinfo_for_stmt (def_stmt); +- 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)); -- def_stmt_info = vinfo_for_stmt (def_stmt); ++ 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); @@ -316,10 +304,10 @@ } } - -=== modified file 'gcc/tree-vect-stmts.c' ---- old/gcc/tree-vect-stmts.c 2011-11-14 11:38:08 +0000 -+++ new/gcc/tree-vect-stmts.c 2011-11-22 16:52:23 +0000 +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; @@ -372,10 +360,10 @@ break; case GIMPLE_BINARY_RHS: - -=== modified file 'gcc/tree-vectorizer.h' ---- old/gcc/tree-vectorizer.h 2011-11-14 11:38:08 +0000 -+++ new/gcc/tree-vectorizer.h 2011-11-22 16:52:23 +0000 +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. */ @@ -385,4 +373,3 @@ void vect_pattern_recog (loop_vec_info); /* In tree-vectorizer.c. */ - diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106854.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106854.patch deleted file mode 100644 index 208ba0e78a..0000000000 --- a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106854.patch +++ /dev/null @@ -1,354 +0,0 @@ -2011-12-30 Richard Sandiford <richard.sandiford@linaro.org> - - gcc/ - Backport from mainline: - - 2011-10-12 Richard Sandiford <richard.sandiford@linaro.org> - - * expr.h (copy_blkmode_to_reg): Declare. - * expr.c (copy_blkmode_to_reg): New function. - (expand_assignment): Don't expand register RESULT_DECLs before - the lhs. Use copy_blkmode_to_reg to copy BLKmode values into a - RESULT_DECL register. - (expand_expr_real_1): Handle BLKmode decls when looking for promotion. - * stmt.c (expand_return): Move BLKmode-to-register code into - copy_blkmode_to_reg. - -=== modified file 'gcc/expr.c' ---- old/gcc/expr.c 2011-10-23 13:33:07 +0000 -+++ new/gcc/expr.c 2011-12-30 09:41:30 +0000 -@@ -2180,6 +2180,111 @@ - return tgtblk; - } - -+/* Copy BLKmode value SRC into a register of mode MODE. Return the -+ register if it contains any data, otherwise return null. -+ -+ This is used on targets that return BLKmode values in registers. */ -+ -+rtx -+copy_blkmode_to_reg (enum machine_mode mode, tree src) -+{ -+ int i, n_regs; -+ unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0, bytes; -+ unsigned int bitsize; -+ rtx *dst_words, dst, x, src_word = NULL_RTX, dst_word = NULL_RTX; -+ enum machine_mode dst_mode; -+ -+ gcc_assert (TYPE_MODE (TREE_TYPE (src)) == BLKmode); -+ -+ x = expand_normal (src); -+ -+ bytes = int_size_in_bytes (TREE_TYPE (src)); -+ if (bytes == 0) -+ return NULL_RTX; -+ -+ /* If the structure doesn't take up a whole number of words, see -+ whether the register value should be padded on the left or on -+ the right. Set PADDING_CORRECTION to the number of padding -+ bits needed on the left side. -+ -+ In most ABIs, the structure will be returned at the least end of -+ the register, which translates to right padding on little-endian -+ targets and left padding on big-endian targets. The opposite -+ holds if the structure is returned at the most significant -+ end of the register. */ -+ if (bytes % UNITS_PER_WORD != 0 -+ && (targetm.calls.return_in_msb (TREE_TYPE (src)) -+ ? !BYTES_BIG_ENDIAN -+ : BYTES_BIG_ENDIAN)) -+ padding_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) -+ * BITS_PER_UNIT)); -+ -+ n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; -+ dst_words = XALLOCAVEC (rtx, n_regs); -+ bitsize = MIN (TYPE_ALIGN (TREE_TYPE (src)), BITS_PER_WORD); -+ -+ /* Copy the structure BITSIZE bits at a time. */ -+ for (bitpos = 0, xbitpos = padding_correction; -+ bitpos < bytes * BITS_PER_UNIT; -+ bitpos += bitsize, xbitpos += bitsize) -+ { -+ /* We need a new destination pseudo each time xbitpos is -+ on a word boundary and when xbitpos == padding_correction -+ (the first time through). */ -+ if (xbitpos % BITS_PER_WORD == 0 -+ || xbitpos == padding_correction) -+ { -+ /* Generate an appropriate register. */ -+ dst_word = gen_reg_rtx (word_mode); -+ dst_words[xbitpos / BITS_PER_WORD] = dst_word; -+ -+ /* Clear the destination before we move anything into it. */ -+ emit_move_insn (dst_word, CONST0_RTX (word_mode)); -+ } -+ -+ /* We need a new source operand each time bitpos is on a word -+ boundary. */ -+ if (bitpos % BITS_PER_WORD == 0) -+ src_word = operand_subword_force (x, bitpos / BITS_PER_WORD, BLKmode); -+ -+ /* Use bitpos for the source extraction (left justified) and -+ xbitpos for the destination store (right justified). */ -+ store_bit_field (dst_word, bitsize, xbitpos % BITS_PER_WORD, word_mode, -+ extract_bit_field (src_word, bitsize, -+ bitpos % BITS_PER_WORD, 1, false, -+ NULL_RTX, word_mode, word_mode)); -+ } -+ -+ if (mode == BLKmode) -+ { -+ /* Find the smallest integer mode large enough to hold the -+ entire structure. */ -+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); -+ mode != VOIDmode; -+ mode = GET_MODE_WIDER_MODE (mode)) -+ /* Have we found a large enough mode? */ -+ if (GET_MODE_SIZE (mode) >= bytes) -+ break; -+ -+ /* A suitable mode should have been found. */ -+ gcc_assert (mode != VOIDmode); -+ } -+ -+ if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode)) -+ dst_mode = word_mode; -+ else -+ dst_mode = mode; -+ dst = gen_reg_rtx (dst_mode); -+ -+ for (i = 0; i < n_regs; i++) -+ emit_move_insn (operand_subword (dst, i, 0, dst_mode), dst_words[i]); -+ -+ if (mode != dst_mode) -+ dst = gen_lowpart (mode, dst); -+ -+ return dst; -+} -+ - /* Add a USE expression for REG to the (possibly empty) list pointed - to by CALL_FUSAGE. REG must denote a hard register. */ - -@@ -4382,7 +4487,9 @@ - if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from, from) - && COMPLETE_TYPE_P (TREE_TYPE (from)) - && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST -- && ! (((TREE_CODE (to) == VAR_DECL || TREE_CODE (to) == PARM_DECL) -+ && ! (((TREE_CODE (to) == VAR_DECL -+ || TREE_CODE (to) == PARM_DECL -+ || TREE_CODE (to) == RESULT_DECL) - && REG_P (DECL_RTL (to))) - || TREE_CODE (to) == SSA_NAME)) - { -@@ -4428,12 +4535,15 @@ - rtx temp; - - push_temp_slots (); -- temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL); -+ if (REG_P (to_rtx) && TYPE_MODE (TREE_TYPE (from)) == BLKmode) -+ temp = copy_blkmode_to_reg (GET_MODE (to_rtx), from); -+ else -+ temp = expand_expr (from, NULL_RTX, GET_MODE (to_rtx), EXPAND_NORMAL); - - if (GET_CODE (to_rtx) == PARALLEL) - emit_group_load (to_rtx, temp, TREE_TYPE (from), - int_size_in_bytes (TREE_TYPE (from))); -- else -+ else if (temp) - emit_move_insn (to_rtx, temp); - - preserve_temp_slots (to_rtx); -@@ -8567,10 +8677,15 @@ - return temp; - } - -- /* If the mode of DECL_RTL does not match that of the decl, it -- must be a promoted value. We return a SUBREG of the wanted mode, -- but mark it so that we know that it was already extended. */ -- if (REG_P (decl_rtl) && GET_MODE (decl_rtl) != DECL_MODE (exp)) -+ /* If the mode of DECL_RTL does not match that of the decl, -+ there are two cases: we are dealing with a BLKmode value -+ that is returned in a register, or we are dealing with -+ a promoted value. In the latter case, return a SUBREG -+ of the wanted mode, but mark it so that we know that it -+ was already extended. */ -+ if (REG_P (decl_rtl) -+ && DECL_MODE (exp) != BLKmode -+ && GET_MODE (decl_rtl) != DECL_MODE (exp)) - { - enum machine_mode pmode; - - -=== modified file 'gcc/expr.h' ---- old/gcc/expr.h 2011-03-03 21:56:58 +0000 -+++ new/gcc/expr.h 2011-10-12 08:01:43 +0000 -@@ -324,6 +324,8 @@ - /* Copy BLKmode object from a set of registers. */ - extern rtx copy_blkmode_from_reg (rtx, rtx, tree); - -+extern rtx copy_blkmode_to_reg (enum machine_mode, tree); -+ - /* Mark REG as holding a parameter for the next CALL_INSN. */ - extern void use_reg (rtx *, rtx); - - -=== modified file 'gcc/stmt.c' ---- old/gcc/stmt.c 2011-03-03 21:56:58 +0000 -+++ new/gcc/stmt.c 2011-10-12 08:01:43 +0000 -@@ -1684,119 +1684,21 @@ - expand_value_return (result_rtl); - - /* If the result is an aggregate that is being returned in one (or more) -- registers, load the registers here. The compiler currently can't handle -- copying a BLKmode value into registers. We could put this code in a -- more general area (for use by everyone instead of just function -- call/return), but until this feature is generally usable it is kept here -- (and in expand_call). */ -+ registers, load the registers here. */ - - else if (retval_rhs != 0 - && TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode - && REG_P (result_rtl)) - { -- int i; -- unsigned HOST_WIDE_INT bitpos, xbitpos; -- unsigned HOST_WIDE_INT padding_correction = 0; -- unsigned HOST_WIDE_INT bytes -- = int_size_in_bytes (TREE_TYPE (retval_rhs)); -- int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; -- unsigned int bitsize -- = MIN (TYPE_ALIGN (TREE_TYPE (retval_rhs)), BITS_PER_WORD); -- rtx *result_pseudos = XALLOCAVEC (rtx, n_regs); -- rtx result_reg, src = NULL_RTX, dst = NULL_RTX; -- rtx result_val = expand_normal (retval_rhs); -- enum machine_mode tmpmode, result_reg_mode; -- -- if (bytes == 0) -- { -- expand_null_return (); -- return; -- } -- -- /* If the structure doesn't take up a whole number of words, see -- whether the register value should be padded on the left or on -- the right. Set PADDING_CORRECTION to the number of padding -- bits needed on the left side. -- -- In most ABIs, the structure will be returned at the least end of -- the register, which translates to right padding on little-endian -- targets and left padding on big-endian targets. The opposite -- holds if the structure is returned at the most significant -- end of the register. */ -- if (bytes % UNITS_PER_WORD != 0 -- && (targetm.calls.return_in_msb (TREE_TYPE (retval_rhs)) -- ? !BYTES_BIG_ENDIAN -- : BYTES_BIG_ENDIAN)) -- padding_correction = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) -- * BITS_PER_UNIT)); -- -- /* Copy the structure BITSIZE bits at a time. */ -- for (bitpos = 0, xbitpos = padding_correction; -- bitpos < bytes * BITS_PER_UNIT; -- bitpos += bitsize, xbitpos += bitsize) -- { -- /* We need a new destination pseudo each time xbitpos is -- on a word boundary and when xbitpos == padding_correction -- (the first time through). */ -- if (xbitpos % BITS_PER_WORD == 0 -- || xbitpos == padding_correction) -- { -- /* Generate an appropriate register. */ -- dst = gen_reg_rtx (word_mode); -- result_pseudos[xbitpos / BITS_PER_WORD] = dst; -- -- /* Clear the destination before we move anything into it. */ -- emit_move_insn (dst, CONST0_RTX (GET_MODE (dst))); -- } -- -- /* We need a new source operand each time bitpos is on a word -- boundary. */ -- if (bitpos % BITS_PER_WORD == 0) -- src = operand_subword_force (result_val, -- bitpos / BITS_PER_WORD, -- BLKmode); -- -- /* Use bitpos for the source extraction (left justified) and -- xbitpos for the destination store (right justified). */ -- store_bit_field (dst, bitsize, xbitpos % BITS_PER_WORD, word_mode, -- extract_bit_field (src, bitsize, -- bitpos % BITS_PER_WORD, 1, false, -- NULL_RTX, word_mode, word_mode)); -- } -- -- tmpmode = GET_MODE (result_rtl); -- if (tmpmode == BLKmode) -- { -- /* Find the smallest integer mode large enough to hold the -- entire structure and use that mode instead of BLKmode -- on the USE insn for the return register. */ -- for (tmpmode = GET_CLASS_NARROWEST_MODE (MODE_INT); -- tmpmode != VOIDmode; -- tmpmode = GET_MODE_WIDER_MODE (tmpmode)) -- /* Have we found a large enough mode? */ -- if (GET_MODE_SIZE (tmpmode) >= bytes) -- break; -- -- /* A suitable mode should have been found. */ -- gcc_assert (tmpmode != VOIDmode); -- -- PUT_MODE (result_rtl, tmpmode); -- } -- -- if (GET_MODE_SIZE (tmpmode) < GET_MODE_SIZE (word_mode)) -- result_reg_mode = word_mode; -+ val = copy_blkmode_to_reg (GET_MODE (result_rtl), retval_rhs); -+ if (val) -+ { -+ /* Use the mode of the result value on the return register. */ -+ PUT_MODE (result_rtl, GET_MODE (val)); -+ expand_value_return (val); -+ } - else -- result_reg_mode = tmpmode; -- result_reg = gen_reg_rtx (result_reg_mode); -- -- for (i = 0; i < n_regs; i++) -- emit_move_insn (operand_subword (result_reg, i, 0, result_reg_mode), -- result_pseudos[i]); -- -- if (tmpmode != result_reg_mode) -- result_reg = gen_lowpart (tmpmode, result_reg); -- -- expand_value_return (result_reg); -+ expand_null_return (); - } - else if (retval_rhs != 0 - && !VOID_TYPE_P (TREE_TYPE (retval_rhs)) - -=== added file 'gcc/testsuite/g++.dg/pr48660.C' ---- old/gcc/testsuite/g++.dg/pr48660.C 1970-01-01 00:00:00 +0000 -+++ new/gcc/testsuite/g++.dg/pr48660.C 2011-10-12 08:01:43 +0000 -@@ -0,0 +1,22 @@ -+template<int N> struct val { char a[N]; }; -+ -+class Base -+{ -+public: -+ virtual val<1> get1() const = 0; -+ virtual val<2> get2() const = 0; -+ virtual val<3> get3() const = 0; -+ virtual val<4> get4() const = 0; -+}; -+ -+class Derived : public virtual Base -+{ -+public: -+ virtual val<1> get1() const { return foo->get1(); } -+ virtual val<2> get2() const { return foo->get2(); } -+ virtual val<3> get3() const { return foo->get3(); } -+ virtual val<4> get4() const { return foo->get4(); } -+ Base *foo; -+}; -+ -+Base* make() { return new Derived; } - diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106860.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106860.patch new file mode 100644 index 0000000000..895d6a6cff --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106860.patch @@ -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" } } */ + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106861.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106861.patch new file mode 100644 index 0000000000..0199f7b89b --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106861.patch @@ -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)) + { + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106862.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106862.patch new file mode 100644 index 0000000000..a20d889a56 --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106862.patch @@ -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, + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106863.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106863.patch new file mode 100644 index 0000000000..e93493f17f --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106863.patch @@ -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")] + ) + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106864.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106864.patch new file mode 100644 index 0000000000..f15f37a583 --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106864.patch @@ -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}, + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106865.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106865.patch new file mode 100644 index 0000000000..5b0735b004 --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106865.patch @@ -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; + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106869.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106869.patch new file mode 100644 index 0000000000..de3d2ff4cf --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106869.patch @@ -0,0 +1,2389 @@ +2012-02-08 Ulrich Weigand <ulrich.weigand@linaro.org> + + gcc/ + * config/arm/arm.c (arm_option_optimization_table): Enable + -fsched-pressure using -fsched-pressure-algorithm=model by + default when optimizing. + +2012-02-08 Richard Sandiford <richard.sandiford@linaro.org> + + gcc/ + * sched-deps.c (fixup_sched_groups): Rename to... + (chain_to_prev_insn): ...this. + (chain_to_prev_insn_p): New function. + (deps_analyze_insn): Use it instead of SCHED_GROUP_P. + +2012-02-08 Richard Sandiford <richard.sandiford@linaro.org> + + gcc/ + * sched-int.h (_haifa_insn_data): Move priority_status. + Add model_index. + (INSN_MODEL_INDEX): New macro. + * haifa-sched.c (insn_delay): New function. + (sched_regno_pressure_class): Update commentary. + (mark_regno_birth_or_death): Pass the liveness bitmap and + pressure array as arguments, instead of using curr_reg_live and + curr_reg_pressure. Only update the pressure if the bit in the + liveness set has changed. + (initiate_reg_pressure_info): Always trust the live-in set for + SCHED_PRESSURE_MODEL. + (initiate_bb_reg_pressure_info): Update call to + mark_regno_birth_or_death. + (dep_list_size): Take the list as argument. + (calculate_reg_deaths): New function, extracted from... + (setup_insn_reg_pressure_info): ...here. + (MODEL_BAR): New macro. + (model_pressure_data, model_insn_info, model_pressure_limit) + (model_pressure_group): New structures. + (model_schedule, model_worklist, model_insns, model_num_insns) + (model_curr_point, model_before_pressure, model_next_priority): + New variables. + (MODEL_PRESSURE_DATA, MODEL_MAX_PRESSURE, MODEL_REF_PRESSURE) + (MODEL_INSN_INFO, MODEL_INSN): New macros. + (model_index, model_update_limit_points_in_group): New functions. + (model_update_limit_points, model_last_use_except): Likewise. + (model_start_update_pressure, model_update_pressure): Likewise. + (model_recompute, model_spill_cost, model_excess_group_cost): Likewise. + (model_excess_cost, model_dump_pressure_points): Likewise. + (model_set_excess_costs): Likewise. + (rank_for_schedule): Extend SCHED_PRIORITY_WEIGHTED ordering to + SCHED_PRIORITY_MODEL. Use insn_delay. Use the order in the model + schedule as an alternative tie-breaker. Update the call to + dep_list_size. + (ready_sort): Call model_set_excess_costs. + (update_register_pressure): Update call to mark_regno_birth_or_death. + Rely on that function to check liveness rather than doing it here. + (model_classify_pressure, model_order_p, model_add_to_worklist_at) + (model_remove_from_worklist, model_add_to_worklist, model_promote_insn) + (model_add_to_schedule, model_analyze_insns, model_init_pressure_group) + (model_record_pressure, model_record_pressures): New functions. + (model_record_final_pressures, model_add_successors_to_worklist) + (model_promote_predecessors, model_choose_insn): Likewise. + (model_reset_queue_indices, model_dump_pressure_summary): Likewise. + (model_start_schedule, model_finalize_pressure_group): Likewise. + (model_end_schedule): Likewise. + (schedule_insn): Say when we're scheduling the next instruction + in the model schedule. + (schedule_insn): Handle SCHED_PRESSURE_MODEL. + (queue_to_ready): Do not add instructions that are + MAX_SCHED_READY_INSNS beyond the current point of the model schedule. + Always allow the next instruction in the model schedule to be added. + (debug_ready_list): Print the INSN_REG_PRESSURE_EXCESS_COST_CHANGE + and delay for SCHED_PRESSURE_MODEL too. + (prune_ready_list): Extend SCHED_PRIORITY_WEIGHTED handling to + SCHED_PRIORITY_MODEL, but also take the DFA into account. + (schedule_block): Call model_start_schedule and model_end_schedule. + Extend SCHED_PRIORITY_WEIGHTED stall handling to SCHED_PRIORITY_MODEL. + (sched_init): Extend INSN_REG_PRESSURE_EXCESS_COST_CHANGE handling + to SCHED_PRESSURE_MODEL, but don't allocate saved_reg_live or + region_ref_regs. + (sched_finish): Update accordingly. + (fix_tick_ready): Extend INSN_REG_PRESSURE_EXCESS_COST_CHANGE handling + to SCHED_PRESSURE_MODEL. + (add_jump_dependencies): Update call to dep_list_size. + (haifa_finish_h_i_d): Fix leak of max_reg_pressure. + (haifa_init_insn): Extend INSN_REG_PRESSURE_EXCESS_COST_CHANGE handling + to SCHED_PRESSURE_MODEL. + * sched-deps.c (init_insn_reg_pressure_info): Likewise, but don't + allocate INSN_MAX_REG_PRESSURE for SCHED_PRESSURE_MODEL. + (sched_analyze_insn): Extend INSN_REG_PRESSURE_EXCESS_COST_CHANGE + handling to SCHED_PRESSURE_MODEL. + +2012-02-08 Richard Sandiford <richard.sandiford@linaro.org> + + gcc/ + * common.opt (fsched-pressure-algorithm=): New option. + * flag-types.h (sched_pressure_algorithm): New enum. + * sched-int.h (sched_pressure_p): Replace with... + (sched_pressure): ...this new variable. + * haifa-sched.c (sched_pressure_p): Replace with... + (sched_pressure): ...this new variable. + (sched_regno_pressure_class, rank_for_schedule, ready_sort) + (update_reg_and_insn_max_reg_pressure, schedule_insn) + (debug_ready_list, schedule_block, sched_init, sched_finish) + (fix_tick_ready, haifa_init_insn): Update accordingly. + * sched-deps.c (init_insn_reg_pressure_info): Likewise. + * sched-rgn.c (schedule_region): Likewise. + +2012-02-08 Richard Sandiford <richard.sandiford@linaro.org> + + gcc/ + Backport from mainline: + + 2011-04-01 Bernd Schmidt <bernds@codesourcery.com> + + * haifa-sched.c (prune_ready_list): New function, broken out of + schedule_block. + (schedule_block): Use it. + +=== modified file 'gcc/common.opt' +--- old/gcc/common.opt 2011-04-11 15:26:47 +0000 ++++ new/gcc/common.opt 2012-02-08 23:38:13 +0000 +@@ -1614,6 +1614,19 @@ + Common Report Var(flag_sched_pressure) Init(0) Optimization + Enable register pressure sensitive insn scheduling + ++fsched-pressure-algorithm= ++Common Joined RejectNegative Enum(sched_pressure_algorithm) Var(flag_sched_pressure_algorithm) Init(SCHED_PRESSURE_WEIGHTED) ++-fira-algorithm=[CB|priority] Set the used IRA algorithm ++ ++Enum ++Name(sched_pressure_algorithm) Type(enum sched_pressure_algorithm) UnknownError(unknown %<fsched-pressure%> algorithm %qs) ++ ++EnumValue ++Enum(sched_pressure_algorithm) String(weighted) Value(SCHED_PRESSURE_WEIGHTED) ++ ++EnumValue ++Enum(sched_pressure_algorithm) String(model) Value(SCHED_PRESSURE_MODEL) ++ + fsched-spec + Common Report Var(flag_schedule_speculative) Init(1) Optimization + Allow speculative motion of non-loads + +=== modified file 'gcc/config/arm/arm.c' +--- old/gcc/config/arm/arm.c 2012-02-01 14:13:07 +0000 ++++ new/gcc/config/arm/arm.c 2012-02-09 00:47:59 +0000 +@@ -311,6 +311,11 @@ + /* Set default optimization options. */ + static const struct default_options arm_option_optimization_table[] = + { ++ /* Enable -fsched-pressure using -fsched-pressure-algorithm=model ++ by default when optimizing. */ ++ { OPT_LEVELS_1_PLUS, OPT_fsched_pressure, NULL, 1 }, ++ { OPT_LEVELS_1_PLUS, OPT_fsched_pressure_algorithm_, ++ NULL, SCHED_PRESSURE_MODEL }, + /* Enable section anchors by default at -O1 or higher. */ + { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 }, + { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, + +=== modified file 'gcc/flag-types.h' +--- old/gcc/flag-types.h 2010-11-24 13:28:38 +0000 ++++ new/gcc/flag-types.h 2012-02-08 23:38:13 +0000 +@@ -106,6 +106,14 @@ + }; + #endif + ++/* The algorithm used to implement -fsched-pressure. */ ++enum sched_pressure_algorithm ++{ ++ SCHED_PRESSURE_NONE, ++ SCHED_PRESSURE_WEIGHTED, ++ SCHED_PRESSURE_MODEL ++}; ++ + /* The algorithm used for the integrated register allocator (IRA). */ + enum ira_algorithm + { + +=== modified file 'gcc/haifa-sched.c' +--- old/gcc/haifa-sched.c 2011-02-19 20:59:23 +0000 ++++ new/gcc/haifa-sched.c 2012-02-08 23:39:02 +0000 +@@ -348,6 +348,14 @@ + /* Create empty basic block after the specified block. */ + basic_block (* sched_create_empty_bb) (basic_block); + ++/* Return the number of cycles until INSN is expected to be ready. ++ Return zero if it already is. */ ++static int ++insn_delay (rtx insn) ++{ ++ return MAX (INSN_TICK (insn) - clock_var, 0); ++} ++ + static int + may_trap_exp (const_rtx x, int is_store) + { +@@ -571,10 +579,10 @@ + + /* Do register pressure sensitive insn scheduling if the flag is set + up. */ +-bool sched_pressure_p; ++enum sched_pressure_algorithm sched_pressure; + + /* Map regno -> its cover class. The map defined only when +- SCHED_PRESSURE_P is true. */ ++ SCHED_PRESSURE != SCHED_PRESSURE_NONE. */ + enum reg_class *sched_regno_cover_class; + + /* The current register pressure. Only elements corresponding cover +@@ -602,10 +610,12 @@ + bitmap_clear (region_ref_regs); + } + +-/* Update current register pressure related info after birth (if +- BIRTH_P) or death of register REGNO. */ +-static void +-mark_regno_birth_or_death (int regno, bool birth_p) ++/* PRESSURE[CL] describes the pressure on register class CL. Update it ++ for the birth (if BIRTH_P) or death (if !BIRTH_P) of register REGNO. ++ LIVE tracks the set of live registers; if it is null, assume that ++ every birth or death is genuine. */ ++static inline void ++mark_regno_birth_or_death (bitmap live, int *pressure, int regno, bool birth_p) + { + enum reg_class cover_class; + +@@ -616,15 +626,17 @@ + { + if (birth_p) + { +- bitmap_set_bit (curr_reg_live, regno); +- curr_reg_pressure[cover_class] +- += ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)]; ++ if (!live || bitmap_set_bit (live, regno)) ++ pressure[cover_class] ++ += (ira_reg_class_nregs ++ [cover_class][PSEUDO_REGNO_MODE (regno)]); + } + else + { +- bitmap_clear_bit (curr_reg_live, regno); +- curr_reg_pressure[cover_class] +- -= ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)]; ++ if (!live || bitmap_clear_bit (live, regno)) ++ pressure[cover_class] ++ -= (ira_reg_class_nregs ++ [cover_class][PSEUDO_REGNO_MODE (regno)]); + } + } + } +@@ -633,13 +645,13 @@ + { + if (birth_p) + { +- bitmap_set_bit (curr_reg_live, regno); +- curr_reg_pressure[cover_class]++; ++ if (!live || bitmap_set_bit (live, regno)) ++ pressure[cover_class]++; + } + else + { +- bitmap_clear_bit (curr_reg_live, regno); +- curr_reg_pressure[cover_class]--; ++ if (!live || bitmap_clear_bit (live, regno)) ++ pressure[cover_class]--; + } + } + } +@@ -657,8 +669,10 @@ + curr_reg_pressure[ira_reg_class_cover[i]] = 0; + bitmap_clear (curr_reg_live); + EXECUTE_IF_SET_IN_BITMAP (live, 0, j, bi) +- if (current_nr_blocks == 1 || bitmap_bit_p (region_ref_regs, j)) +- mark_regno_birth_or_death (j, true); ++ if (sched_pressure == SCHED_PRESSURE_MODEL ++ || current_nr_blocks == 1 ++ || bitmap_bit_p (region_ref_regs, j)) ++ mark_regno_birth_or_death (curr_reg_live, curr_reg_pressure, j, true); + } + + /* Mark registers in X as mentioned in the current region. */ +@@ -712,7 +726,8 @@ + if (regno == INVALID_REGNUM) + break; + if (! bitmap_bit_p (df_get_live_in (bb), regno)) +- mark_regno_birth_or_death (regno, true); ++ mark_regno_birth_or_death (curr_reg_live, curr_reg_pressure, ++ regno, true); + } + #endif + } +@@ -956,19 +971,19 @@ + return true; + } + +-/* Compute the number of nondebug forward deps of an insn. */ ++/* Compute the number of nondebug deps in list LIST for INSN. */ + + static int +-dep_list_size (rtx insn) ++dep_list_size (rtx insn, sd_list_types_def list) + { + sd_iterator_def sd_it; + dep_t dep; + int dbgcount = 0, nodbgcount = 0; + + if (!MAY_HAVE_DEBUG_INSNS) +- return sd_lists_size (insn, SD_LIST_FORW); ++ return sd_lists_size (insn, list); + +- FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep) ++ FOR_EACH_DEP (insn, list, sd_it, dep) + { + if (DEBUG_INSN_P (DEP_CON (dep))) + dbgcount++; +@@ -976,7 +991,7 @@ + nodbgcount++; + } + +- gcc_assert (dbgcount + nodbgcount == sd_lists_size (insn, SD_LIST_FORW)); ++ gcc_assert (dbgcount + nodbgcount == sd_lists_size (insn, list)); + + return nodbgcount; + } +@@ -995,7 +1010,7 @@ + { + int this_priority = -1; + +- if (dep_list_size (insn) == 0) ++ if (dep_list_size (insn, SD_LIST_FORW) == 0) + /* ??? We should set INSN_PRIORITY to insn_cost when and insn has + some forward deps but all of them are ignored by + contributes_to_priority hook. At the moment we set priority of +@@ -1091,6 +1106,22 @@ + qsort (READY, N_READY, sizeof (rtx), rank_for_schedule); } \ + while (0) + ++/* For each cover class CL, set DEATH[CL] to the number of registers ++ in that class that die in INSN. */ ++ ++static void ++calculate_reg_deaths (rtx insn, int *death) ++{ ++ int i; ++ struct reg_use_data *use; ++ ++ for (i = 0; i < ira_reg_class_cover_size; i++) ++ death[ira_reg_class_cover[i]] = 0; ++ for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) ++ if (dying_use_p (use)) ++ mark_regno_birth_or_death (0, death, use->regno, true); ++} ++ + /* Setup info about the current register pressure impact of scheduling + INSN at the current scheduling point. */ + static void +@@ -1102,23 +1133,12 @@ + enum reg_class cl; + struct reg_pressure_data *pressure_info; + int *max_reg_pressure; +- struct reg_use_data *use; + static int death[N_REG_CLASSES]; + + gcc_checking_assert (!DEBUG_INSN_P (insn)); + + excess_cost_change = 0; +- for (i = 0; i < ira_reg_class_cover_size; i++) +- death[ira_reg_class_cover[i]] = 0; +- for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) +- if (dying_use_p (use)) +- { +- cl = sched_regno_cover_class[use->regno]; +- if (use->regno < FIRST_PSEUDO_REGISTER) +- death[cl]++; +- else +- death[cl] += ira_reg_class_nregs[cl][PSEUDO_REGNO_MODE (use->regno)]; +- } ++ calculate_reg_deaths (insn, death); + pressure_info = INSN_REG_PRESSURE (insn); + max_reg_pressure = INSN_MAX_REG_PRESSURE (insn); + gcc_assert (pressure_info != NULL && max_reg_pressure != NULL); +@@ -1139,7 +1159,765 @@ + } + INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insn) = excess_cost_change; + } +- ++ ++/* This is the first page of code related to SCHED_PRESSURE_MODEL. ++ It tries to make the scheduler take register pressure into account ++ without introducing too many unnecessary stalls. It hooks into the ++ main scheduling algorithm at several points: ++ ++ - Before scheduling starts, model_start_schedule constructs a ++ "model schedule" for the current block. This model schedule is ++ chosen solely to keep register pressure down. It does not take the ++ target's pipeline or the original instruction order into account, ++ except as a tie-breaker. It also doesn't work to a particular ++ pressure limit. ++ ++ This model schedule gives us an idea of what pressure can be ++ achieved for the block gives us an example of a schedule that ++ keeps to that pressure. It also makes the final schedule less ++ dependent on the original instruction order. This is important ++ because the original order can either be "wide" (many values live ++ at once, such as in user-scheduled code) or "narrow" (few values ++ live at once, such as after loop unrolling, where several ++ iterations are executed sequentially). ++ ++ We do not apply this model schedule to the rtx stream. We simply ++ record it in model_schedule. We also compute the maximum pressure, ++ MP, that was seen during this schedule. ++ ++ - Instructions are added to the ready queue even if they require ++ a stall. The length of the stall is instead computed as: ++ ++ MAX (INSN_TICK (INSN) - clock_var, 0) ++ ++ (= insn_delay). This allows rank_for_schedule to choose between ++ introducing a deliberate stall or increasing pressure. ++ ++ - Before sorting the ready queue, model_set_excess_costs assigns ++ a pressure-based cost to each ready instruction in the queue. ++ This is the instruction's INSN_REG_PRESSURE_EXCESS_COST_CHANGE ++ (ECC for short) and is effectively measured in cycles. ++ ++ - rank_for_schedule ranks instructions based on: ++ ++ ECC (insn) + insn_delay (insn) ++ ++ then as: ++ ++ insn_delay (insn) ++ ++ So, for example, an instruction X1 with an ECC of 1 that can issue ++ now will win over an instruction X0 with an ECC of zero that would ++ introduce a stall of one cycle. However, an instruction X2 with an ++ ECC of 2 that can issue now will lose to X0. ++ ++ - When an instruction is scheduled, model_recompute updates the model ++ schedule with the new pressures (some of which might now exceed the ++ original maximum pressure MP). model_update_limit_points then searches ++ for the new point of maximum pressure, if not already known. */ ++ ++/* Used to separate high-verbosity debug information for SCHED_PRESSURE_MODEL ++ from surrounding debug information. */ ++#define MODEL_BAR \ ++ ";;\t\t+------------------------------------------------------\n" ++ ++/* Information about the pressure on a particular register class at a ++ particular point of the model schedule. */ ++struct model_pressure_data { ++ /* The pressure at this point of the model schedule, or -1 if the ++ point is associated with an instruction that has already been ++ scheduled. */ ++ int ref_pressure; ++ ++ /* The maximum pressure during or after this point of the model schedule. */ ++ int max_pressure; ++}; ++ ++/* Per-instruction information that is used while building the model ++ schedule. Here, "schedule" refers to the model schedule rather ++ than the main schedule. */ ++struct model_insn_info { ++ /* The instruction itself. */ ++ rtx insn; ++ ++ /* If this instruction is in model_worklist, these fields link to the ++ previous (higher-priority) and next (lower-priority) instructions ++ in the list. */ ++ struct model_insn_info *prev; ++ struct model_insn_info *next; ++ ++ /* While constructing the schedule, QUEUE_INDEX describes whether an ++ instruction has already been added to the schedule (QUEUE_SCHEDULED), ++ is in model_worklist (QUEUE_READY), or neither (QUEUE_NOWHERE). ++ old_queue records the value that QUEUE_INDEX had before scheduling ++ started, so that we can restore it once the schedule is complete. */ ++ int old_queue; ++ ++ /* The relative importance of an unscheduled instruction. Higher ++ values indicate greater importance. */ ++ unsigned int model_priority; ++ ++ /* The length of the longest path of satisfied true dependencies ++ that leads to this instruction. */ ++ unsigned int depth; ++ ++ /* The length of the longest path of dependencies of any kind ++ that leads from this instruction. */ ++ unsigned int alap; ++ ++ /* The number of predecessor nodes that must still be scheduled. */ ++ int unscheduled_preds; ++}; ++ ++/* Information about the pressure limit for a particular register class. ++ This structure is used when applying a model schedule to the main ++ schedule. */ ++struct model_pressure_limit { ++ /* The maximum register pressure seen in the original model schedule. */ ++ int orig_pressure; ++ ++ /* The maximum register pressure seen in the current model schedule ++ (which excludes instructions that have already been scheduled). */ ++ int pressure; ++ ++ /* The point of the current model schedule at which PRESSURE is first ++ reached. It is set to -1 if the value needs to be recomputed. */ ++ int point; ++}; ++ ++/* Describes a particular way of measuring register pressure. */ ++struct model_pressure_group { ++ /* Index CCI describes the maximum pressure on ira_reg_class_cover[CCI]. */ ++ struct model_pressure_limit limits[N_REG_CLASSES]; ++ ++ /* Index (POINT * ira_num_pressure_classes + CCI) describes the pressure ++ on register class ira_reg_class_cover[CCI] at point POINT of the ++ current model schedule. A POINT of model_num_insns describes the ++ pressure at the end of the schedule. */ ++ struct model_pressure_data *model; ++}; ++ ++/* Index POINT gives the instruction at point POINT of the model schedule. ++ This array doesn't change during main scheduling. */ ++static VEC (rtx, heap) *model_schedule; ++ ++/* The list of instructions in the model worklist, sorted in order of ++ decreasing priority. */ ++static struct model_insn_info *model_worklist; ++ ++/* Index I describes the instruction with INSN_LUID I. */ ++static struct model_insn_info *model_insns; ++ ++/* The number of instructions in the model schedule. */ ++static int model_num_insns; ++ ++/* The index of the first instruction in model_schedule that hasn't yet been ++ added to the main schedule, or model_num_insns if all of them have. */ ++static int model_curr_point; ++ ++/* Describes the pressure before each instruction in the model schedule. */ ++static struct model_pressure_group model_before_pressure; ++ ++/* The first unused model_priority value (as used in model_insn_info). */ ++static unsigned int model_next_priority; ++ ++ ++/* The model_pressure_data for ira_reg_class_cover[CCI] in GROUP ++ at point POINT of the model schedule. */ ++#define MODEL_PRESSURE_DATA(GROUP, POINT, CCI) \ ++ (&(GROUP)->model[(POINT) * ira_reg_class_cover_size + (CCI)]) ++ ++/* The maximum pressure on ira_reg_class_cover[CCI] in GROUP at or ++ after point POINT of the model schedule. */ ++#define MODEL_MAX_PRESSURE(GROUP, POINT, CCI) \ ++ (MODEL_PRESSURE_DATA (GROUP, POINT, CCI)->max_pressure) ++ ++/* The pressure on ira_reg_class_cover[CCI] in GROUP at point POINT ++ of the model schedule. */ ++#define MODEL_REF_PRESSURE(GROUP, POINT, CCI) \ ++ (MODEL_PRESSURE_DATA (GROUP, POINT, CCI)->ref_pressure) ++ ++/* Information about INSN that is used when creating the model schedule. */ ++#define MODEL_INSN_INFO(INSN) \ ++ (&model_insns[INSN_LUID (INSN)]) ++ ++/* The instruction at point POINT of the model schedule. */ ++#define MODEL_INSN(POINT) \ ++ (VEC_index (rtx, model_schedule, POINT)) ++ ++ ++/* Return INSN's index in the model schedule, or model_num_insns if it ++ doesn't belong to that schedule. */ ++ ++static int ++model_index (rtx insn) ++{ ++ if (INSN_MODEL_INDEX (insn) == 0) ++ return model_num_insns; ++ return INSN_MODEL_INDEX (insn) - 1; ++} ++ ++/* Make sure that GROUP->limits is up-to-date for the current point ++ of the model schedule. */ ++ ++static void ++model_update_limit_points_in_group (struct model_pressure_group *group) ++{ ++ int cci, max_pressure, point; ++ ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ /* We may have passed the final point at which the pressure in ++ group->limits[cci].pressure was reached. Update the limit if so. */ ++ max_pressure = MODEL_MAX_PRESSURE (group, model_curr_point, cci); ++ group->limits[cci].pressure = max_pressure; ++ ++ /* Find the point at which MAX_PRESSURE is first reached. We need ++ to search in three cases: ++ ++ - We've already moved past the previous pressure point. ++ In this case we search forward from model_curr_point. ++ ++ - We scheduled the previous point of maximum pressure ahead of ++ its position in the model schedule, but doing so didn't bring ++ the pressure point earlier. In this case we search forward ++ from that previous pressure point. ++ ++ - Scheduling an instruction early caused the maximum pressure ++ to decrease. In this case we will have set the pressure ++ point to -1, and we search forward from model_curr_point. */ ++ point = MAX (group->limits[cci].point, model_curr_point); ++ while (point < model_num_insns ++ && MODEL_REF_PRESSURE (group, point, cci) < max_pressure) ++ point++; ++ group->limits[cci].point = point; ++ ++ gcc_assert (MODEL_REF_PRESSURE (group, point, cci) == max_pressure); ++ gcc_assert (MODEL_MAX_PRESSURE (group, point, cci) == max_pressure); ++ } ++} ++ ++/* Make sure that all register-pressure limits are up-to-date for the ++ current position in the model schedule. */ ++ ++static void ++model_update_limit_points (void) ++{ ++ model_update_limit_points_in_group (&model_before_pressure); ++} ++ ++/* Return the model_index of the last unscheduled use in chain USE ++ outside of USE's instruction. Return -1 if there are no other uses, ++ or model_num_insns if the register is live at the end of the block. */ ++ ++static int ++model_last_use_except (struct reg_use_data *use) ++{ ++ struct reg_use_data *next; ++ int last, index; ++ ++ last = -1; ++ for (next = use->next_regno_use; next != use; next = next->next_regno_use) ++ if (NONDEBUG_INSN_P (next->insn) ++ && QUEUE_INDEX (next->insn) != QUEUE_SCHEDULED) ++ { ++ index = model_index (next->insn); ++ if (index == model_num_insns) ++ return model_num_insns; ++ if (last < index) ++ last = index; ++ } ++ return last; ++} ++ ++/* An instruction with model_index POINT has just been scheduled, and it ++ adds DELTA to the pressure on ira_reg_class_cover[CCI] after POINT - 1. ++ Update MODEL_REF_PRESSURE (GROUP, POINT, CCI) and ++ MODEL_MAX_PRESSURE (GROUP, POINT, CCI) accordingly. */ ++ ++static void ++model_start_update_pressure (struct model_pressure_group *group, ++ int point, int cci, int delta) ++{ ++ int next_max_pressure; ++ ++ if (point == model_num_insns) ++ { ++ /* The instruction wasn't part of the model schedule; it was moved ++ from a different block. Update the pressure for the end of ++ the model schedule. */ ++ MODEL_REF_PRESSURE (group, point, cci) += delta; ++ MODEL_MAX_PRESSURE (group, point, cci) += delta; ++ } ++ else ++ { ++ /* Record that this instruction has been scheduled. Nothing now ++ changes between POINT and POINT + 1, so get the maximum pressure ++ from the latter. If the maximum pressure decreases, the new ++ pressure point may be before POINT. */ ++ MODEL_REF_PRESSURE (group, point, cci) = -1; ++ next_max_pressure = MODEL_MAX_PRESSURE (group, point + 1, cci); ++ if (MODEL_MAX_PRESSURE (group, point, cci) > next_max_pressure) ++ { ++ MODEL_MAX_PRESSURE (group, point, cci) = next_max_pressure; ++ if (group->limits[cci].point == point) ++ group->limits[cci].point = -1; ++ } ++ } ++} ++ ++/* Record that scheduling a later instruction has changed the pressure ++ at point POINT of the model schedule by DELTA (which might be 0). ++ Update GROUP accordingly. Return nonzero if these changes might ++ trigger changes to previous points as well. */ ++ ++static int ++model_update_pressure (struct model_pressure_group *group, ++ int point, int cci, int delta) ++{ ++ int ref_pressure, max_pressure, next_max_pressure; ++ ++ /* If POINT hasn't yet been scheduled, update its pressure. */ ++ ref_pressure = MODEL_REF_PRESSURE (group, point, cci); ++ if (ref_pressure >= 0 && delta != 0) ++ { ++ ref_pressure += delta; ++ MODEL_REF_PRESSURE (group, point, cci) = ref_pressure; ++ ++ /* Check whether the maximum pressure in the overall schedule ++ has increased. (This means that the MODEL_MAX_PRESSURE of ++ every point <= POINT will need to increae too; see below.) */ ++ if (group->limits[cci].pressure < ref_pressure) ++ group->limits[cci].pressure = ref_pressure; ++ ++ /* If we are at maximum pressure, and the maximum pressure ++ point was previously unknown or later than POINT, ++ bring it forward. */ ++ if (group->limits[cci].pressure == ref_pressure ++ && !IN_RANGE (group->limits[cci].point, 0, point)) ++ group->limits[cci].point = point; ++ ++ /* If POINT used to be the point of maximum pressure, but isn't ++ any longer, we need to recalculate it using a forward walk. */ ++ if (group->limits[cci].pressure > ref_pressure ++ && group->limits[cci].point == point) ++ group->limits[cci].point = -1; ++ } ++ ++ /* Update the maximum pressure at POINT. Changes here might also ++ affect the maximum pressure at POINT - 1. */ ++ next_max_pressure = MODEL_MAX_PRESSURE (group, point + 1, cci); ++ max_pressure = MAX (ref_pressure, next_max_pressure); ++ if (MODEL_MAX_PRESSURE (group, point, cci) != max_pressure) ++ { ++ MODEL_MAX_PRESSURE (group, point, cci) = max_pressure; ++ return 1; ++ } ++ return 0; ++} ++ ++/* INSN has just been scheduled. Update the model schedule accordingly. */ ++ ++static void ++model_recompute (rtx insn) ++{ ++ struct { ++ int last_use; ++ int regno; ++ } uses[FIRST_PSEUDO_REGISTER + MAX_RECOG_OPERANDS]; ++ struct reg_use_data *use; ++ struct reg_pressure_data *reg_pressure; ++ int delta[N_REG_CLASSES]; ++ int cci, point, mix, new_last, cl, ref_pressure, queue; ++ unsigned int i, num_uses, num_pending_births; ++ bool print_p; ++ ++ /* The destinations of INSN were previously live from POINT onwards, but are ++ now live from model_curr_point onwards. Set up DELTA accordingly. */ ++ point = model_index (insn); ++ reg_pressure = INSN_REG_PRESSURE (insn); ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ delta[cl] = reg_pressure[cci].set_increase; ++ } ++ ++ /* Record which registers previously died at POINT, but which now die ++ before POINT. Adjust DELTA so that it represents the effect of ++ this change after POINT - 1. Set NUM_PENDING_BIRTHS to the number of ++ registers that will be born in the range [model_curr_point, POINT). */ ++ num_uses = 0; ++ num_pending_births = 0; ++ for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) ++ { ++ new_last = model_last_use_except (use); ++ if (new_last < point) ++ { ++ gcc_assert (num_uses < ARRAY_SIZE (uses)); ++ uses[num_uses].last_use = new_last; ++ uses[num_uses].regno = use->regno; ++ /* This register is no longer live after POINT - 1. */ ++ mark_regno_birth_or_death (NULL, delta, use->regno, false); ++ num_uses++; ++ if (new_last >= 0) ++ num_pending_births++; ++ } ++ } ++ ++ /* Update the MODEL_REF_PRESSURE and MODEL_MAX_PRESSURE for POINT. ++ Also set each group pressure limit for POINT. */ ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ model_start_update_pressure (&model_before_pressure, ++ point, cci, delta[cl]); ++ } ++ ++ /* Walk the model schedule backwards, starting immediately before POINT. */ ++ print_p = false; ++ if (point != model_curr_point) ++ do ++ { ++ point--; ++ insn = MODEL_INSN (point); ++ queue = QUEUE_INDEX (insn); ++ ++ if (queue != QUEUE_SCHEDULED) ++ { ++ /* DELTA describes the effect of the move on the register pressure ++ after POINT. Make it describe the effect on the pressure ++ before POINT. */ ++ i = 0; ++ while (i < num_uses) ++ { ++ if (uses[i].last_use == point) ++ { ++ /* This register is now live again. */ ++ mark_regno_birth_or_death (NULL, delta, ++ uses[i].regno, true); ++ ++ /* Remove this use from the array. */ ++ uses[i] = uses[num_uses - 1]; ++ num_uses--; ++ num_pending_births--; ++ } ++ else ++ i++; ++ } ++ ++ if (sched_verbose >= 5) ++ { ++ char buf[2048]; ++ ++ if (!print_p) ++ { ++ fprintf (sched_dump, MODEL_BAR); ++ fprintf (sched_dump, ";;\t\t| New pressure for model" ++ " schedule\n"); ++ fprintf (sched_dump, MODEL_BAR); ++ print_p = true; ++ } ++ ++ print_pattern (buf, PATTERN (insn), 0); ++ fprintf (sched_dump, ";;\t\t| %3d %4d %-30s ", ++ point, INSN_UID (insn), buf); ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ ref_pressure = MODEL_REF_PRESSURE (&model_before_pressure, ++ point, cci); ++ fprintf (sched_dump, " %s:[%d->%d]", ++ reg_class_names[ira_reg_class_cover[cci]], ++ ref_pressure, ref_pressure + delta[cl]); ++ } ++ fprintf (sched_dump, "\n"); ++ } ++ } ++ ++ /* Adjust the pressure at POINT. Set MIX to nonzero if POINT - 1 ++ might have changed as well. */ ++ mix = num_pending_births; ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ mix |= delta[cl]; ++ mix |= model_update_pressure (&model_before_pressure, ++ point, cci, delta[cl]); ++ } ++ } ++ while (mix && point > model_curr_point); ++ ++ if (print_p) ++ fprintf (sched_dump, MODEL_BAR); ++} ++ ++/* model_spill_cost (CL, P, P') returns the cost of increasing the ++ pressure on CL from P to P'. We use this to calculate a "base ECC", ++ baseECC (CL, X), for each cover class CL and each instruction X. ++ Supposing X changes the pressure on CL from P to P', and that the ++ maximum pressure on CL in the current model schedule is MP', then: ++ ++ * if X occurs before or at the next point of maximum pressure in ++ the model schedule and P' > MP', then: ++ ++ baseECC (CL, X) = model_spill_cost (CL, MP, P') ++ ++ The idea is that the pressure after scheduling a fixed set of ++ instructions -- in this case, the set up to and including the ++ next maximum pressure point -- is going to be the same regardless ++ of the order; we simply want to keep the intermediate pressure ++ under control. Thus X has a cost of zero unless scheduling it ++ now would exceed MP'. ++ ++ If all increases in the set are by the same amount, no zero-cost ++ instruction will ever cause the pressure to exceed MP'. However, ++ if X is instead moved past an instruction X' with pressure in the ++ range (MP' - (P' - P), MP'), the pressure at X' will increase ++ beyond MP'. Since baseECC is very much a heuristic anyway, ++ it doesn't seem worth the overhead of tracking cases like these. ++ ++ The cost of exceeding MP' is always based on the original maximum ++ pressure MP. This is so that going 2 registers over the original ++ limit has the same cost regardless of whether it comes from two ++ separate +1 deltas or from a single +2 delta. ++ ++ * if X occurs after the next point of maximum pressure in the model ++ schedule and P' > P, then: ++ ++ baseECC (CL, X) = model_spill_cost (CL, MP, MP' + (P' - P)) ++ ++ That is, if we move X forward across a point of maximum pressure, ++ and if X increases the pressure by P' - P, then we conservatively ++ assume that scheduling X next would increase the maximum pressure ++ by P' - P. Again, the cost of doing this is based on the original ++ maximum pressure MP, for the same reason as above. ++ ++ * if P' < P, P > MP, and X occurs at or after the next point of ++ maximum pressure, then: ++ ++ baseECC (CL, X) = -model_spill_cost (CL, MAX (MP, P'), P) ++ ++ That is, if we have already exceeded the original maximum pressure MP, ++ and if X might reduce the maximum pressure again -- or at least push ++ it further back, and thus allow more scheduling freedom -- it is given ++ a negative cost to reflect the improvement. ++ ++ * otherwise, ++ ++ baseECC (CL, X) = 0 ++ ++ In this case, X is not expected to affect the maximum pressure MP', ++ so it has zero cost. ++ ++ We then create a combined value baseECC (X) that is the sum of ++ baseECC (CL, X) for each cover class CL. ++ ++ baseECC (X) could itself be used as the ECC value described above. ++ However, this is often too conservative, in the sense that it ++ tends to make high-priority instructions that increase pressure ++ wait too long in cases where introducing a spill would be better. ++ For this reason the final ECC is a priority-adjusted form of ++ baseECC (X). Specifically, we calculate: ++ ++ P (X) = INSN_PRIORITY (X) - insn_delay (X) - baseECC (X) ++ baseP = MAX { P (X) | baseECC (X) <= 0 } ++ ++ Then: ++ ++ ECC (X) = MAX (MIN (baseP - P (X), baseECC (X)), 0) ++ ++ Thus an instruction's effect on pressure is ignored if it has a high ++ enough priority relative to the ones that don't increase pressure. ++ Negative values of baseECC (X) do not increase the priority of X ++ itself, but they do make it harder for other instructions to ++ increase the pressure further. ++ ++ This pressure cost is deliberately timid. The intention has been ++ to choose a heuristic that rarely interferes with the normal list ++ scheduler in cases where that scheduler would produce good code. ++ We simply want to curb some of its worst excesses. */ ++ ++/* Return the cost of increasing the pressure in class CL from FROM to TO. ++ ++ Here we use the very simplistic cost model that every register above ++ ira_available_class_regs[CL] has a spill cost of 1. We could use other ++ measures instead, such as one based on MEMORY_MOVE_COST. However: ++ ++ (1) In order for an instruction to be scheduled, the higher cost ++ would need to be justified in a single saving of that many stalls. ++ This is overly pessimistic, because the benefit of spilling is ++ often to avoid a sequence of several short stalls rather than ++ a single long one. ++ ++ (2) The cost is still arbitrary. Because we are not allocating ++ registers during scheduling, we have no way of knowing for ++ sure how many memory accesses will be required by each spill, ++ where the spills will be placed within the block, or even ++ which block(s) will contain the spills. ++ ++ So a higher cost than 1 is often too conservative in practice, ++ forcing blocks to contain unnecessary stalls instead of spill code. ++ The simple cost below seems to be the best compromise. It reduces ++ the interference with the normal list scheduler, which helps make ++ it more suitable for a default-on option. */ ++ ++static int ++model_spill_cost (int cl, int from, int to) ++{ ++ from = MAX (from, ira_available_class_regs[cl]); ++ return MAX (to, from) - from; ++} ++ ++/* Return baseECC (ira_reg_class_cover[CCI], POINT), given that ++ P = curr_reg_pressure[ira_reg_class_cover[CCI]] and that ++ P' = P + DELTA. */ ++ ++static int ++model_excess_group_cost (struct model_pressure_group *group, ++ int point, int cci, int delta) ++{ ++ int pressure, cl; ++ ++ cl = ira_reg_class_cover[cci]; ++ if (delta < 0 && point >= group->limits[cci].point) ++ { ++ pressure = MAX (group->limits[cci].orig_pressure, ++ curr_reg_pressure[cl] + delta); ++ return -model_spill_cost (cl, pressure, curr_reg_pressure[cl]); ++ } ++ ++ if (delta > 0) ++ { ++ if (point > group->limits[cci].point) ++ pressure = group->limits[cci].pressure + delta; ++ else ++ pressure = curr_reg_pressure[cl] + delta; ++ ++ if (pressure > group->limits[cci].pressure) ++ return model_spill_cost (cl, group->limits[cci].orig_pressure, ++ pressure); ++ } ++ ++ return 0; ++} ++ ++/* Return baseECC (MODEL_INSN (INSN)). Dump the costs to sched_dump ++ if PRINT_P. */ ++ ++static int ++model_excess_cost (rtx insn, bool print_p) ++{ ++ int point, cci, cl, cost, this_cost, delta; ++ struct reg_pressure_data *insn_reg_pressure; ++ int insn_death[N_REG_CLASSES]; ++ ++ calculate_reg_deaths (insn, insn_death); ++ point = model_index (insn); ++ insn_reg_pressure = INSN_REG_PRESSURE (insn); ++ cost = 0; ++ ++ if (print_p) ++ fprintf (sched_dump, ";;\t\t| %3d %4d | %4d %+3d |", point, ++ INSN_UID (insn), INSN_PRIORITY (insn), insn_delay (insn)); ++ ++ /* Sum up the individual costs for each register class. */ ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ delta = insn_reg_pressure[cci].set_increase - insn_death[cl]; ++ this_cost = model_excess_group_cost (&model_before_pressure, ++ point, cci, delta); ++ cost += this_cost; ++ if (print_p) ++ fprintf (sched_dump, " %s:[%d base cost %d]", ++ reg_class_names[cl], delta, this_cost); ++ } ++ ++ if (print_p) ++ fprintf (sched_dump, "\n"); ++ ++ return cost; ++} ++ ++/* Dump the next points of maximum pressure for GROUP. */ ++ ++static void ++model_dump_pressure_points (struct model_pressure_group *group) ++{ ++ int cci, cl; ++ ++ fprintf (sched_dump, ";;\t\t| pressure points"); ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ fprintf (sched_dump, " %s:[%d->%d at ", reg_class_names[cl], ++ curr_reg_pressure[cl], group->limits[cci].pressure); ++ if (group->limits[cci].point < model_num_insns) ++ fprintf (sched_dump, "%d:%d]", group->limits[cci].point, ++ INSN_UID (MODEL_INSN (group->limits[cci].point))); ++ else ++ fprintf (sched_dump, "end]"); ++ } ++ fprintf (sched_dump, "\n"); ++} ++ ++/* Set INSN_REG_PRESSURE_EXCESS_COST_CHANGE for INSNS[0...COUNT-1]. */ ++ ++static void ++model_set_excess_costs (rtx *insns, int count) ++{ ++ int i, cost, priority_base, priority; ++ bool print_p; ++ ++ /* Record the baseECC value for each instruction in the model schedule, ++ except that negative costs are converted to zero ones now rather thatn ++ later. Do not assign a cost to debug instructions, since they must ++ not change code-generation decisions. Experiments suggest we also ++ get better results by not assigning a cost to instructions from ++ a different block. ++ ++ Set PRIORITY_BASE to baseP in the block comment above. This is the ++ maximum priority of the "cheap" instructions, which should always ++ include the next model instruction. */ ++ priority_base = 0; ++ print_p = false; ++ for (i = 0; i < count; i++) ++ if (INSN_MODEL_INDEX (insns[i])) ++ { ++ if (sched_verbose >= 6 && !print_p) ++ { ++ fprintf (sched_dump, MODEL_BAR); ++ fprintf (sched_dump, ";;\t\t| Pressure costs for ready queue\n"); ++ model_dump_pressure_points (&model_before_pressure); ++ fprintf (sched_dump, MODEL_BAR); ++ print_p = true; ++ } ++ cost = model_excess_cost (insns[i], print_p); ++ if (cost <= 0) ++ { ++ priority = INSN_PRIORITY (insns[i]) - insn_delay (insns[i]) - cost; ++ priority_base = MAX (priority_base, priority); ++ cost = 0; ++ } ++ INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insns[i]) = cost; ++ } ++ if (print_p) ++ fprintf (sched_dump, MODEL_BAR); ++ ++ /* Use MAX (baseECC, 0) and baseP to calculcate ECC for each ++ instruction. */ ++ for (i = 0; i < count; i++) ++ { ++ cost = INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insns[i]); ++ priority = INSN_PRIORITY (insns[i]) - insn_delay (insns[i]); ++ if (cost > 0 && priority > priority_base) ++ { ++ cost += priority_base - priority; ++ INSN_REG_PRESSURE_EXCESS_COST_CHANGE (insns[i]) = MAX (cost, 0); ++ } ++ } ++} ++ + /* Returns a positive value if x is preferred; returns a negative value if + y is preferred. Should never return 0, since that will make the sort + unstable. */ +@@ -1170,23 +1948,20 @@ + /* Make sure that priority of TMP and TMP2 are initialized. */ + gcc_assert (INSN_PRIORITY_KNOWN (tmp) && INSN_PRIORITY_KNOWN (tmp2)); + +- if (sched_pressure_p) ++ if (sched_pressure != SCHED_PRESSURE_NONE) + { + int diff; + + /* Prefer insn whose scheduling results in the smallest register + pressure excess. */ + if ((diff = (INSN_REG_PRESSURE_EXCESS_COST_CHANGE (tmp) +- + (INSN_TICK (tmp) > clock_var +- ? INSN_TICK (tmp) - clock_var : 0) ++ + insn_delay (tmp) + - INSN_REG_PRESSURE_EXCESS_COST_CHANGE (tmp2) +- - (INSN_TICK (tmp2) > clock_var +- ? INSN_TICK (tmp2) - clock_var : 0))) != 0) ++ - insn_delay (tmp2)))) + return diff; + } + +- +- if (sched_pressure_p ++ if (sched_pressure != SCHED_PRESSURE_NONE + && (INSN_TICK (tmp2) > clock_var || INSN_TICK (tmp) > clock_var)) + { + if (INSN_TICK (tmp) <= clock_var) +@@ -1277,11 +2052,22 @@ + return val; + } + ++ /* Prefer instructions that occur earlier in the model schedule. */ ++ if (sched_pressure == SCHED_PRESSURE_MODEL) ++ { ++ int diff; ++ ++ diff = model_index (tmp) - model_index (tmp2); ++ if (diff != 0) ++ return diff; ++ } ++ + /* Prefer the insn which has more later insns that depend on it. + This gives the scheduler more freedom when scheduling later + instructions at the expense of added register pressure. */ + +- val = (dep_list_size (tmp2) - dep_list_size (tmp)); ++ val = (dep_list_size (tmp2, SD_LIST_FORW) ++ - dep_list_size (tmp, SD_LIST_FORW)); + + if (flag_sched_dep_count_heuristic && val != 0) + return val; +@@ -1480,12 +2266,15 @@ + int i; + rtx *first = ready_lastpos (ready); + +- if (sched_pressure_p) ++ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) + { + for (i = 0; i < ready->n_ready; i++) + if (!DEBUG_INSN_P (first[i])) + setup_insn_reg_pressure_info (first[i]); + } ++ if (sched_pressure == SCHED_PRESSURE_MODEL ++ && model_curr_point < model_num_insns) ++ model_set_excess_costs (first, ready->n_ready); + SCHED_SORT (first, ready->n_ready); + } + +@@ -1551,10 +2340,12 @@ + gcc_checking_assert (!DEBUG_INSN_P (insn)); + + for (use = INSN_REG_USE_LIST (insn); use != NULL; use = use->next_insn_use) +- if (dying_use_p (use) && bitmap_bit_p (curr_reg_live, use->regno)) +- mark_regno_birth_or_death (use->regno, false); ++ if (dying_use_p (use)) ++ mark_regno_birth_or_death (curr_reg_live, curr_reg_pressure, ++ use->regno, false); + for (set = INSN_REG_SET_LIST (insn); set != NULL; set = set->next_insn_set) +- mark_regno_birth_or_death (set->regno, true); ++ mark_regno_birth_or_death (curr_reg_live, curr_reg_pressure, ++ set->regno, true); + } + + /* Set up or update (if UPDATE_P) max register pressure (see its +@@ -1626,11 +2417,618 @@ + void + sched_setup_bb_reg_pressure_info (basic_block bb, rtx after) + { +- gcc_assert (sched_pressure_p); ++ gcc_assert (sched_pressure == SCHED_PRESSURE_WEIGHTED); + initiate_bb_reg_pressure_info (bb); + setup_insn_max_reg_pressure (after, false); + } +- ++ ++/* Return (in order): ++ ++ - positive if INSN adversely affects the pressure on one ++ register class ++ ++ - negative if INSN reduces the pressure on one register class ++ ++ - 0 if INSN doesn't affect the pressure on any register class. */ ++ ++static int ++model_classify_pressure (struct model_insn_info *insn) ++{ ++ struct reg_pressure_data *reg_pressure; ++ int death[N_REG_CLASSES]; ++ int cci, cl, sum; ++ ++ calculate_reg_deaths (insn->insn, death); ++ reg_pressure = INSN_REG_PRESSURE (insn->insn); ++ sum = 0; ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ if (death[cl] < reg_pressure[cci].set_increase) ++ return 1; ++ sum += reg_pressure[cci].set_increase - death[cl]; ++ } ++ return sum; ++} ++ ++/* Return true if INSN1 should come before INSN2 in the model schedule. */ ++ ++static int ++model_order_p (struct model_insn_info *insn1, struct model_insn_info *insn2) ++{ ++ unsigned int height1, height2; ++ unsigned int priority1, priority2; ++ ++ /* Prefer instructions with a higher model priority. */ ++ if (insn1->model_priority != insn2->model_priority) ++ return insn1->model_priority > insn2->model_priority; ++ ++ /* Combine the length of the longest path of satisfied true dependencies ++ that leads to each instruction (depth) with the length of the longest ++ path of any dependencies that leads from the instruction (alap). ++ Prefer instructions with the greatest combined length. If the combined ++ lengths are equal, prefer instructions with the greatest depth. ++ ++ The idea is that, if we have a set S of "equal" instructions that each ++ have ALAP value X, and we pick one such instruction I, any true-dependent ++ successors of I that have ALAP value X - 1 should be preferred over S. ++ This encourages the schedule to be "narrow" rather than "wide". ++ However, if I is a low-priority instruction that we decided to ++ schedule because of its model_classify_pressure, and if there ++ is a set of higher-priority instructions T, the aforementioned ++ successors of I should not have the edge over T. */ ++ height1 = insn1->depth + insn1->alap; ++ height2 = insn2->depth + insn2->alap; ++ if (height1 != height2) ++ return height1 > height2; ++ if (insn1->depth != insn2->depth) ++ return insn1->depth > insn2->depth; ++ ++ /* We have no real preference between INSN1 an INSN2 as far as attempts ++ to reduce pressure go. Prefer instructions with higher priorities. */ ++ priority1 = INSN_PRIORITY (insn1->insn); ++ priority2 = INSN_PRIORITY (insn2->insn); ++ if (priority1 != priority2) ++ return priority1 > priority2; ++ ++ /* Use the original rtl sequence as a tie-breaker. */ ++ return insn1 < insn2; ++} ++ ++/* Add INSN to the model worklist immediately after PREV. Add it to the ++ beginning of the list if PREV is null. */ ++ ++static void ++model_add_to_worklist_at (struct model_insn_info *insn, ++ struct model_insn_info *prev) ++{ ++ gcc_assert (QUEUE_INDEX (insn->insn) == QUEUE_NOWHERE); ++ QUEUE_INDEX (insn->insn) = QUEUE_READY; ++ ++ insn->prev = prev; ++ if (prev) ++ { ++ insn->next = prev->next; ++ prev->next = insn; ++ } ++ else ++ { ++ insn->next = model_worklist; ++ model_worklist = insn; ++ } ++ if (insn->next) ++ insn->next->prev = insn; ++} ++ ++/* Remove INSN from the model worklist. */ ++ ++static void ++model_remove_from_worklist (struct model_insn_info *insn) ++{ ++ gcc_assert (QUEUE_INDEX (insn->insn) == QUEUE_READY); ++ QUEUE_INDEX (insn->insn) = QUEUE_NOWHERE; ++ ++ if (insn->prev) ++ insn->prev->next = insn->next; ++ else ++ model_worklist = insn->next; ++ if (insn->next) ++ insn->next->prev = insn->prev; ++} ++ ++/* Add INSN to the model worklist. Start looking for a suitable position ++ between neighbors PREV and NEXT, testing at most MAX_SCHED_READY_INSNS ++ insns either side. A null PREV indicates the beginning of the list and ++ a null NEXT indicates the end. */ ++ ++static void ++model_add_to_worklist (struct model_insn_info *insn, ++ struct model_insn_info *prev, ++ struct model_insn_info *next) ++{ ++ int count; ++ ++ count = MAX_SCHED_READY_INSNS; ++ if (count > 0 && prev && model_order_p (insn, prev)) ++ do ++ { ++ count--; ++ prev = prev->prev; ++ } ++ while (count > 0 && prev && model_order_p (insn, prev)); ++ else ++ while (count > 0 && next && model_order_p (next, insn)) ++ { ++ count--; ++ prev = next; ++ next = next->next; ++ } ++ model_add_to_worklist_at (insn, prev); ++} ++ ++/* INSN may now have a higher priority (in the model_order_p sense) ++ than before. Move it up the worklist if necessary. */ ++ ++static void ++model_promote_insn (struct model_insn_info *insn) ++{ ++ struct model_insn_info *prev; ++ int count; ++ ++ prev = insn->prev; ++ count = MAX_SCHED_READY_INSNS; ++ while (count > 0 && prev && model_order_p (insn, prev)) ++ { ++ count--; ++ prev = prev->prev; ++ } ++ if (prev != insn->prev) ++ { ++ model_remove_from_worklist (insn); ++ model_add_to_worklist_at (insn, prev); ++ } ++} ++ ++/* Add INSN to the end of the model schedule. */ ++ ++static void ++model_add_to_schedule (rtx insn) ++{ ++ unsigned int point; ++ ++ gcc_assert (QUEUE_INDEX (insn) == QUEUE_NOWHERE); ++ QUEUE_INDEX (insn) = QUEUE_SCHEDULED; ++ ++ point = VEC_length (rtx, model_schedule); ++ VEC_quick_push (rtx, model_schedule, insn); ++ INSN_MODEL_INDEX (insn) = point + 1; ++} ++ ++/* Analyze the instructions that are to be scheduled, setting up ++ MODEL_INSN_INFO (...) and model_num_insns accordingly. Add ready ++ instructions to model_worklist. */ ++ ++static void ++model_analyze_insns (void) ++{ ++ rtx start, end, iter; ++ sd_iterator_def sd_it; ++ dep_t dep; ++ struct model_insn_info *insn, *con; ++ ++ model_num_insns = 0; ++ start = PREV_INSN (current_sched_info->next_tail); ++ end = current_sched_info->prev_head; ++ for (iter = start; iter != end; iter = PREV_INSN (iter)) ++ if (NONDEBUG_INSN_P (iter)) ++ { ++ insn = MODEL_INSN_INFO (iter); ++ insn->insn = iter; ++ FOR_EACH_DEP (iter, SD_LIST_FORW, sd_it, dep) ++ { ++ con = MODEL_INSN_INFO (DEP_CON (dep)); ++ if (con->insn && insn->alap < con->alap + 1) ++ insn->alap = con->alap + 1; ++ } ++ ++ insn->old_queue = QUEUE_INDEX (iter); ++ QUEUE_INDEX (iter) = QUEUE_NOWHERE; ++ ++ insn->unscheduled_preds = dep_list_size (iter, SD_LIST_HARD_BACK); ++ if (insn->unscheduled_preds == 0) ++ model_add_to_worklist (insn, NULL, model_worklist); ++ ++ model_num_insns++; ++ } ++} ++ ++/* The global state describes the register pressure at the start of the ++ model schedule. Initialize GROUP accordingly. */ ++ ++static void ++model_init_pressure_group (struct model_pressure_group *group) ++{ ++ int cci, cl; ++ ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ group->limits[cci].pressure = curr_reg_pressure[cl]; ++ group->limits[cci].point = 0; ++ } ++ /* Use index model_num_insns to record the state after the last ++ instruction in the model schedule. */ ++ group->model = XNEWVEC (struct model_pressure_data, ++ (model_num_insns + 1) * ira_reg_class_cover_size); ++} ++ ++/* Record that MODEL_REF_PRESSURE (GROUP, POINT, CCI) is PRESSURE. ++ Update the maximum pressure for the whole schedule. */ ++ ++static void ++model_record_pressure (struct model_pressure_group *group, ++ int point, int cci, int pressure) ++{ ++ MODEL_REF_PRESSURE (group, point, cci) = pressure; ++ if (group->limits[cci].pressure < pressure) ++ { ++ group->limits[cci].pressure = pressure; ++ group->limits[cci].point = point; ++ } ++} ++ ++/* INSN has just been added to the end of the model schedule. Record its ++ register-pressure information. */ ++ ++static void ++model_record_pressures (struct model_insn_info *insn) ++{ ++ struct reg_pressure_data *reg_pressure; ++ int point, cci, cl, delta; ++ int death[N_REG_CLASSES]; ++ ++ point = model_index (insn->insn); ++ if (sched_verbose >= 2) ++ { ++ char buf[2048]; ++ ++ if (point == 0) ++ { ++ fprintf (sched_dump, "\n;;\tModel schedule:\n;;\n"); ++ fprintf (sched_dump, ";;\t| idx insn | mpri hght dpth prio |\n"); ++ } ++ print_pattern (buf, PATTERN (insn->insn), 0); ++ fprintf (sched_dump, ";;\t| %3d %4d | %4d %4d %4d %4d | %-30s ", ++ point, INSN_UID (insn->insn), insn->model_priority, ++ insn->depth + insn->alap, insn->depth, ++ INSN_PRIORITY (insn->insn), buf); ++ } ++ calculate_reg_deaths (insn->insn, death); ++ reg_pressure = INSN_REG_PRESSURE (insn->insn); ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ delta = reg_pressure[cci].set_increase - death[cl]; ++ if (sched_verbose >= 2) ++ fprintf (sched_dump, " %s:[%d,%+d]", reg_class_names[cl], ++ curr_reg_pressure[cl], delta); ++ model_record_pressure (&model_before_pressure, point, cci, ++ curr_reg_pressure[cl]); ++ } ++ if (sched_verbose >= 2) ++ fprintf (sched_dump, "\n"); ++} ++ ++/* All instructions have been added to the model schedule. Record the ++ final register pressure in GROUP and set up all MODEL_MAX_PRESSUREs. */ ++ ++static void ++model_record_final_pressures (struct model_pressure_group *group) ++{ ++ int point, cci, max_pressure, ref_pressure, cl; ++ ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ /* Record the final pressure for this class. */ ++ cl = ira_reg_class_cover[cci]; ++ point = model_num_insns; ++ ref_pressure = curr_reg_pressure[cl]; ++ model_record_pressure (group, point, cci, ref_pressure); ++ ++ /* Record the original maximum pressure. */ ++ group->limits[cci].orig_pressure = group->limits[cci].pressure; ++ ++ /* Update the MODEL_MAX_PRESSURE for every point of the schedule. */ ++ max_pressure = ref_pressure; ++ MODEL_MAX_PRESSURE (group, point, cci) = max_pressure; ++ while (point > 0) ++ { ++ point--; ++ ref_pressure = MODEL_REF_PRESSURE (group, point, cci); ++ max_pressure = MAX (max_pressure, ref_pressure); ++ MODEL_MAX_PRESSURE (group, point, cci) = max_pressure; ++ } ++ } ++} ++ ++/* Update all successors of INSN, given that INSN has just been scheduled. */ ++ ++static void ++model_add_successors_to_worklist (struct model_insn_info *insn) ++{ ++ sd_iterator_def sd_it; ++ struct model_insn_info *con; ++ dep_t dep; ++ ++ FOR_EACH_DEP (insn->insn, SD_LIST_FORW, sd_it, dep) ++ { ++ con = MODEL_INSN_INFO (DEP_CON (dep)); ++ /* Ignore debug instructions, and instructions from other blocks. */ ++ if (con->insn) ++ { ++ con->unscheduled_preds--; ++ ++ /* Update the depth field of each true-dependent successor. ++ Increasing the depth gives them a higher priority than ++ before. */ ++ if (DEP_TYPE (dep) == REG_DEP_TRUE && con->depth < insn->depth + 1) ++ { ++ con->depth = insn->depth + 1; ++ if (QUEUE_INDEX (con->insn) == QUEUE_READY) ++ model_promote_insn (con); ++ } ++ ++ /* If this is a true dependency, or if there are no remaining ++ dependencies for CON (meaning that CON only had non-true ++ dependencies), make sure that CON is on the worklist. ++ We don't bother otherwise because it would tend to fill the ++ worklist with a lot of low-priority instructions that are not ++ yet ready to issue. */ ++ if ((con->depth > 0 || con->unscheduled_preds == 0) ++ && QUEUE_INDEX (con->insn) == QUEUE_NOWHERE) ++ model_add_to_worklist (con, insn, insn->next); ++ } ++ } ++} ++ ++/* Give INSN a higher priority than any current instruction, then give ++ unscheduled predecessors of INSN a higher priority still. If any of ++ those predecessors are not on the model worklist, do the same for its ++ predecessors, and so on. */ ++ ++static void ++model_promote_predecessors (struct model_insn_info *insn) ++{ ++ struct model_insn_info *pro, *first; ++ sd_iterator_def sd_it; ++ dep_t dep; ++ ++ if (sched_verbose >= 7) ++ fprintf (sched_dump, ";;\t+--- priority of %d = %d, priority of", ++ INSN_UID (insn->insn), model_next_priority); ++ insn->model_priority = model_next_priority++; ++ model_remove_from_worklist (insn); ++ model_add_to_worklist_at (insn, NULL); ++ ++ first = NULL; ++ for (;;) ++ { ++ FOR_EACH_DEP (insn->insn, SD_LIST_HARD_BACK, sd_it, dep) ++ { ++ pro = MODEL_INSN_INFO (DEP_PRO (dep)); ++ /* The first test is to ignore debug instructions, and instructions ++ from other blocks. */ ++ if (pro->insn ++ && pro->model_priority != model_next_priority ++ && QUEUE_INDEX (pro->insn) != QUEUE_SCHEDULED) ++ { ++ pro->model_priority = model_next_priority; ++ if (sched_verbose >= 7) ++ fprintf (sched_dump, " %d", INSN_UID (pro->insn)); ++ if (QUEUE_INDEX (pro->insn) == QUEUE_READY) ++ { ++ /* PRO is already in the worklist, but it now has ++ a higher priority than before. Move it at the ++ appropriate place. */ ++ model_remove_from_worklist (pro); ++ model_add_to_worklist (pro, NULL, model_worklist); ++ } ++ else ++ { ++ /* PRO isn't in the worklist. Recursively process ++ its predecessors until we find one that is. */ ++ pro->next = first; ++ first = pro; ++ } ++ } ++ } ++ if (!first) ++ break; ++ insn = first; ++ first = insn->next; ++ } ++ if (sched_verbose >= 7) ++ fprintf (sched_dump, " = %d\n", model_next_priority); ++ model_next_priority++; ++} ++ ++/* Pick one instruction from model_worklist and process it. */ ++ ++static void ++model_choose_insn (void) ++{ ++ struct model_insn_info *insn, *fallback; ++ int count; ++ ++ if (sched_verbose >= 7) ++ { ++ fprintf (sched_dump, ";;\t+--- worklist:\n"); ++ insn = model_worklist; ++ count = MAX_SCHED_READY_INSNS; ++ while (count > 0 && insn) ++ { ++ fprintf (sched_dump, ";;\t+--- %d [%d, %d, %d, %d]\n", ++ INSN_UID (insn->insn), insn->model_priority, ++ insn->depth + insn->alap, insn->depth, ++ INSN_PRIORITY (insn->insn)); ++ count--; ++ insn = insn->next; ++ } ++ } ++ ++ /* Look for a ready instruction whose model_classify_priority is zero ++ or negative, picking the highest-priority one. Adding such an ++ instruction to the schedule now should do no harm, and may actually ++ do some good. ++ ++ Failing that, see whether there is an instruction with the highest ++ extant model_priority that is not yet ready, but which would reduce ++ pressure if it became ready. This is designed to catch cases like: ++ ++ (set (mem (reg R1)) (reg R2)) ++ ++ where the instruction is the last remaining use of R1 and where the ++ value of R2 is not yet available (or vice versa). The death of R1 ++ means that this instruction already reduces pressure. It is of ++ course possible that the computation of R2 involves other registers ++ that are hard to kill, but such cases are rare enough for this ++ heuristic to be a win in general. ++ ++ Failing that, just pick the highest-priority instruction in the ++ worklist. */ ++ count = MAX_SCHED_READY_INSNS; ++ insn = model_worklist; ++ fallback = 0; ++ for (;;) ++ { ++ if (count == 0 || !insn) ++ { ++ insn = fallback ? fallback : model_worklist; ++ break; ++ } ++ if (insn->unscheduled_preds) ++ { ++ if (model_worklist->model_priority == insn->model_priority ++ && !fallback ++ && model_classify_pressure (insn) < 0) ++ fallback = insn; ++ } ++ else ++ { ++ if (model_classify_pressure (insn) <= 0) ++ break; ++ } ++ count--; ++ insn = insn->next; ++ } ++ ++ if (sched_verbose >= 7 && insn != model_worklist) ++ { ++ if (insn->unscheduled_preds) ++ fprintf (sched_dump, ";;\t+--- promoting insn %d, with dependencies\n", ++ INSN_UID (insn->insn)); ++ else ++ fprintf (sched_dump, ";;\t+--- promoting insn %d, which is ready\n", ++ INSN_UID (insn->insn)); ++ } ++ if (insn->unscheduled_preds) ++ /* INSN isn't yet ready to issue. Give all its predecessors the ++ highest priority. */ ++ model_promote_predecessors (insn); ++ else ++ { ++ /* INSN is ready. Add it to the end of model_schedule and ++ process its successors. */ ++ model_add_successors_to_worklist (insn); ++ model_remove_from_worklist (insn); ++ model_add_to_schedule (insn->insn); ++ model_record_pressures (insn); ++ update_register_pressure (insn->insn); ++ } ++} ++ ++/* Restore all QUEUE_INDEXs to the values that they had before ++ model_start_schedule was called. */ ++ ++static void ++model_reset_queue_indices (void) ++{ ++ unsigned int i; ++ rtx insn; ++ ++ FOR_EACH_VEC_ELT (rtx, model_schedule, i, insn) ++ QUEUE_INDEX (insn) = MODEL_INSN_INFO (insn)->old_queue; ++} ++ ++/* We have calculated the model schedule and spill costs. Print a summary ++ to sched_dump. */ ++ ++static void ++model_dump_pressure_summary (void) ++{ ++ int cci, cl; ++ ++ fprintf (sched_dump, ";; Pressure summary:"); ++ for (cci = 0; cci < ira_reg_class_cover_size; cci++) ++ { ++ cl = ira_reg_class_cover[cci]; ++ fprintf (sched_dump, " %s:%d", reg_class_names[cl], ++ model_before_pressure.limits[cci].pressure); ++ } ++ fprintf (sched_dump, "\n\n"); ++} ++ ++/* Initialize the SCHED_PRESSURE_MODEL information for the current ++ scheduling region. */ ++ ++static void ++model_start_schedule (void) ++{ ++ basic_block bb; ++ ++ model_next_priority = 1; ++ model_schedule = VEC_alloc (rtx, heap, sched_max_luid); ++ model_insns = XCNEWVEC (struct model_insn_info, sched_max_luid); ++ ++ bb = BLOCK_FOR_INSN (NEXT_INSN (current_sched_info->prev_head)); ++ initiate_reg_pressure_info (df_get_live_in (bb)); ++ ++ model_analyze_insns (); ++ model_init_pressure_group (&model_before_pressure); ++ while (model_worklist) ++ model_choose_insn (); ++ gcc_assert (model_num_insns == (int) VEC_length (rtx, model_schedule)); ++ if (sched_verbose >= 2) ++ fprintf (sched_dump, "\n"); ++ ++ model_record_final_pressures (&model_before_pressure); ++ model_reset_queue_indices (); ++ ++ XDELETEVEC (model_insns); ++ ++ model_curr_point = 0; ++ initiate_reg_pressure_info (df_get_live_in (bb)); ++ if (sched_verbose >= 1) ++ model_dump_pressure_summary (); ++} ++ ++/* Free the information associated with GROUP. */ ++ ++static void ++model_finalize_pressure_group (struct model_pressure_group *group) ++{ ++ XDELETEVEC (group->model); ++} ++ ++/* Free the information created by model_start_schedule. */ ++ ++static void ++model_end_schedule (void) ++{ ++ model_finalize_pressure_group (&model_before_pressure); ++ VEC_free (rtx, heap, model_schedule); ++} ++ + /* INSN is the "currently executing insn". Launch each insn which was + waiting on INSN. READY is the ready list which contains the insns + that are ready to fire. CLOCK is the current cycle. The function +@@ -1667,10 +3065,14 @@ + reg_class_names[ira_reg_class_cover[i]], + pressure_info[i].set_increase, pressure_info[i].change); + } ++ if (sched_pressure == SCHED_PRESSURE_MODEL ++ && model_curr_point < model_num_insns ++ && model_index (insn) == model_curr_point) ++ fprintf (sched_dump, ":model %d", model_curr_point); + fputc ('\n', sched_dump); + } + +- if (sched_pressure_p && !DEBUG_INSN_P (insn)) ++ if (sched_pressure == SCHED_PRESSURE_WEIGHTED && !DEBUG_INSN_P (insn)) + update_reg_and_insn_max_reg_pressure (insn); + + /* Scheduling instruction should have all its dependencies resolved and +@@ -1728,6 +3130,24 @@ + gcc_assert (QUEUE_INDEX (insn) == QUEUE_NOWHERE); + QUEUE_INDEX (insn) = QUEUE_SCHEDULED; + ++ if (sched_pressure == SCHED_PRESSURE_MODEL ++ && model_curr_point < model_num_insns ++ && NONDEBUG_INSN_P (insn)) ++ { ++ if (model_index (insn) == model_curr_point) ++ do ++ model_curr_point++; ++ while (model_curr_point < model_num_insns ++ && (QUEUE_INDEX (MODEL_INSN (model_curr_point)) ++ == QUEUE_SCHEDULED)); ++ else ++ model_recompute (insn); ++ model_update_limit_points (); ++ update_register_pressure (insn); ++ if (sched_verbose >= 2) ++ print_curr_reg_pressure (); ++ } ++ + gcc_assert (INSN_TICK (insn) >= MIN_TICK); + if (INSN_TICK (insn) > clock_var) + /* INSN has been prematurely moved from the queue to the ready list. +@@ -2056,7 +3476,16 @@ + /* If the ready list is full, delay the insn for 1 cycle. + See the comment in schedule_block for the rationale. */ + if (!reload_completed +- && ready->n_ready - ready->n_debug > MAX_SCHED_READY_INSNS ++ && (ready->n_ready - ready->n_debug > MAX_SCHED_READY_INSNS ++ || (sched_pressure == SCHED_PRESSURE_MODEL ++ /* Limit pressure recalculations to MAX_SCHED_READY_INSNS ++ instructions too. */ ++ && model_index (insn) > (model_curr_point ++ + MAX_SCHED_READY_INSNS))) ++ && !(sched_pressure == SCHED_PRESSURE_MODEL ++ && model_curr_point < model_num_insns ++ /* Always allow the next model instruction to issue. */ ++ && model_index (insn) == model_curr_point) + && !SCHED_GROUP_P (insn) + && insn != skip_insn) + { +@@ -2293,12 +3722,12 @@ + fprintf (sched_dump, " %s:%d", + (*current_sched_info->print_insn) (p[i], 0), + INSN_LUID (p[i])); +- if (sched_pressure_p) ++ if (sched_pressure != SCHED_PRESSURE_NONE) + fprintf (sched_dump, "(cost=%d", + INSN_REG_PRESSURE_EXCESS_COST_CHANGE (p[i])); + if (INSN_TICK (p[i]) > clock_var) + fprintf (sched_dump, ":delay=%d", INSN_TICK (p[i]) - clock_var); +- if (sched_pressure_p) ++ if (sched_pressure != SCHED_PRESSURE_NONE) + fprintf (sched_dump, ")"); + } + fprintf (sched_dump, "\n"); +@@ -2609,8 +4038,8 @@ + { + if (state_dead_lock_p (state) + || insn_finishes_cycle_p (insn)) +- /* We won't issue any more instructions in the next +- choice_state. */ ++ /* We won't issue any more instructions in the next ++ choice_state. */ + top->rest = 0; + else + top->rest--; +@@ -2813,6 +4242,59 @@ + } + } + ++/* Examine all insns on the ready list and queue those which can't be ++ issued in this cycle. TEMP_STATE is temporary scheduler state we ++ can use as scratch space. If FIRST_CYCLE_INSN_P is true, no insns ++ have been issued for the current cycle, which means it is valid to ++ issue an asm statement. */ ++ ++static void ++prune_ready_list (state_t temp_state, bool first_cycle_insn_p) ++{ ++ int i; ++ ++ restart: ++ for (i = 0; i < ready.n_ready; i++) ++ { ++ rtx insn = ready_element (&ready, i); ++ int cost = 0; ++ ++ if (recog_memoized (insn) < 0) ++ { ++ if (!first_cycle_insn_p ++ && (GET_CODE (PATTERN (insn)) == ASM_INPUT ++ || asm_noperands (PATTERN (insn)) >= 0)) ++ cost = 1; ++ } ++ else if (sched_pressure != SCHED_PRESSURE_NONE) ++ { ++ if (sched_pressure == SCHED_PRESSURE_MODEL ++ && INSN_TICK (insn) <= clock_var) ++ { ++ memcpy (temp_state, curr_state, dfa_state_size); ++ if (state_transition (temp_state, insn) >= 0) ++ INSN_TICK (insn) = clock_var + 1; ++ } ++ cost = 0; ++ } ++ else ++ { ++ memcpy (temp_state, curr_state, dfa_state_size); ++ cost = state_transition (temp_state, insn); ++ if (cost < 0) ++ cost = 0; ++ else if (cost == 0) ++ cost = 1; ++ } ++ if (cost >= 1) ++ { ++ ready_remove (&ready, i); ++ queue_insn (insn, cost); ++ goto restart; ++ } ++ } ++} ++ + /* Use forward list scheduling to rearrange insns of block pointed to by + TARGET_BB, possibly bringing insns from subsequent blocks in the same + region. */ +@@ -2882,6 +4364,9 @@ + in try_ready () (which is called through init_ready_list ()). */ + (*current_sched_info->init_ready_list) (); + ++ if (sched_pressure == SCHED_PRESSURE_MODEL) ++ model_start_schedule (); ++ + /* The algorithm is O(n^2) in the number of ready insns at any given + time in the worst case. Before reload we are more likely to have + big lists so truncate them to a reasonable size. */ +@@ -2963,6 +4448,10 @@ + } + while (advance > 0); + ++ prune_ready_list (temp_state, true); ++ if (ready.n_ready == 0) ++ continue; ++ + if (sort_p) + { + /* Sort the ready list based on priority. */ +@@ -3040,7 +4529,7 @@ + fprintf (sched_dump, ";;\tReady list (t = %3d): ", + clock_var); + debug_ready_list (&ready); +- if (sched_pressure_p) ++ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) + print_curr_reg_pressure (); + } + +@@ -3084,7 +4573,8 @@ + else + insn = ready_remove_first (&ready); + +- if (sched_pressure_p && INSN_TICK (insn) > clock_var) ++ if (sched_pressure != SCHED_PRESSURE_NONE ++ && INSN_TICK (insn) > clock_var) + { + ready_add (&ready, insn, true); + advance = 1; +@@ -3112,44 +4602,6 @@ + } + + sort_p = TRUE; +- memcpy (temp_state, curr_state, dfa_state_size); +- if (recog_memoized (insn) < 0) +- { +- asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT +- || asm_noperands (PATTERN (insn)) >= 0); +- if (!first_cycle_insn_p && asm_p) +- /* This is asm insn which is tried to be issued on the +- cycle not first. Issue it on the next cycle. */ +- cost = 1; +- else +- /* A USE insn, or something else we don't need to +- understand. We can't pass these directly to +- state_transition because it will trigger a +- fatal error for unrecognizable insns. */ +- cost = 0; +- } +- else if (sched_pressure_p) +- cost = 0; +- else +- { +- cost = state_transition (temp_state, insn); +- if (cost < 0) +- cost = 0; +- else if (cost == 0) +- cost = 1; +- } +- +- if (cost >= 1) +- { +- queue_insn (insn, cost); +- if (SCHED_GROUP_P (insn)) +- { +- advance = cost; +- break; +- } +- +- continue; +- } + + if (current_sched_info->can_schedule_ready_p + && ! (*current_sched_info->can_schedule_ready_p) (insn)) +@@ -3200,11 +4652,17 @@ + reemit_notes (insn); + last_scheduled_insn = insn; + +- if (memcmp (curr_state, temp_state, dfa_state_size) != 0) +- { +- cycle_issued_insns++; +- memcpy (curr_state, temp_state, dfa_state_size); +- } ++ if (recog_memoized (insn) >= 0) ++ { ++ cost = state_transition (curr_state, insn); ++ if (sched_pressure != SCHED_PRESSURE_WEIGHTED) ++ gcc_assert (cost < 0); ++ cycle_issued_insns++; ++ asm_p = false; ++ } ++ else ++ asm_p = (GET_CODE (PATTERN (insn)) == ASM_INPUT ++ || asm_noperands (PATTERN (insn)) >= 0); + + if (targetm.sched.variable_issue) + can_issue_more = +@@ -3225,6 +4683,9 @@ + + first_cycle_insn_p = false; + ++ if (ready.n_ready > 0) ++ prune_ready_list (temp_state, false); ++ + /* Sort the ready list based on priority. This must be + redone here, as schedule_insn may have readied additional + insns that will not be sorted correctly. */ +@@ -3321,6 +4782,9 @@ + } + } + ++ if (sched_pressure == SCHED_PRESSURE_MODEL) ++ model_end_schedule (); ++ + if (sched_verbose) + fprintf (sched_dump, ";; total time = %d\n", clock_var); + +@@ -3424,10 +4888,14 @@ + if (targetm.sched.dispatch (NULL_RTX, IS_DISPATCH_ON)) + targetm.sched.dispatch_do (NULL_RTX, DISPATCH_INIT); + +- sched_pressure_p = (flag_sched_pressure && ! reload_completed +- && common_sched_info->sched_pass_id == SCHED_RGN_PASS); ++ if (flag_sched_pressure ++ && !reload_completed ++ && common_sched_info->sched_pass_id == SCHED_RGN_PASS) ++ sched_pressure = flag_sched_pressure_algorithm; ++ else ++ sched_pressure = SCHED_PRESSURE_NONE; + +- if (sched_pressure_p) ++ if (sched_pressure != SCHED_PRESSURE_NONE) + ira_setup_eliminable_regset (); + + /* Initialize SPEC_INFO. */ +@@ -3504,7 +4972,7 @@ + if (targetm.sched.init_global) + targetm.sched.init_global (sched_dump, sched_verbose, get_max_uid () + 1); + +- if (sched_pressure_p) ++ if (sched_pressure != SCHED_PRESSURE_NONE) + { + int i, max_regno = max_reg_num (); + +@@ -3517,8 +4985,11 @@ + ? ira_class_translate[REGNO_REG_CLASS (i)] + : reg_cover_class (i)); + curr_reg_live = BITMAP_ALLOC (NULL); +- saved_reg_live = BITMAP_ALLOC (NULL); +- region_ref_regs = BITMAP_ALLOC (NULL); ++ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) ++ { ++ saved_reg_live = BITMAP_ALLOC (NULL); ++ region_ref_regs = BITMAP_ALLOC (NULL); ++ } + } + + curr_state = xmalloc (dfa_state_size); +@@ -3618,12 +5089,15 @@ + sched_finish (void) + { + haifa_finish_h_i_d (); +- if (sched_pressure_p) ++ if (sched_pressure != SCHED_PRESSURE_NONE) + { ++ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) ++ { ++ BITMAP_FREE (region_ref_regs); ++ BITMAP_FREE (saved_reg_live); ++ } ++ BITMAP_FREE (curr_reg_live); + free (sched_regno_cover_class); +- BITMAP_FREE (region_ref_regs); +- BITMAP_FREE (saved_reg_live); +- BITMAP_FREE (curr_reg_live); + } + free (curr_state); + +@@ -3936,7 +5410,7 @@ + INSN_TICK (next) = tick; + + delay = tick - clock_var; +- if (delay <= 0 || sched_pressure_p) ++ if (delay <= 0 || sched_pressure != SCHED_PRESSURE_NONE) + delay = QUEUE_READY; + + change_queue_index (next, delay); +@@ -5185,7 +6659,7 @@ + if (insn == jump) + break; + +- if (dep_list_size (insn) == 0) ++ if (dep_list_size (insn, SD_LIST_FORW) == 0) + { + dep_def _new_dep, *new_dep = &_new_dep; + +@@ -5556,6 +7030,7 @@ + + FOR_EACH_VEC_ELT (haifa_insn_data_def, h_i_d, i, data) + { ++ free (data->max_reg_pressure); + if (data->reg_pressure != NULL) + free (data->reg_pressure); + for (use = data->reg_use_list; use != NULL; use = next) + +=== modified file 'gcc/sched-deps.c' +--- old/gcc/sched-deps.c 2011-12-08 13:33:58 +0000 ++++ new/gcc/sched-deps.c 2012-02-08 23:39:45 +0000 +@@ -450,7 +450,7 @@ + static void add_dependence_list_and_free (struct deps_desc *, rtx, + rtx *, int, enum reg_note); + static void delete_all_dependences (rtx); +-static void fixup_sched_groups (rtx); ++static void chain_to_prev_insn (rtx); + + static void flush_pending_lists (struct deps_desc *, rtx, int, int); + static void sched_analyze_1 (struct deps_desc *, rtx, rtx); +@@ -1490,7 +1490,7 @@ + the previous nonnote insn. */ + + static void +-fixup_sched_groups (rtx insn) ++chain_to_prev_insn (rtx insn) + { + sd_iterator_def sd_it; + dep_t dep; +@@ -1999,7 +1999,7 @@ + static struct reg_pressure_data *pressure_info; + rtx link; + +- gcc_assert (sched_pressure_p); ++ gcc_assert (sched_pressure != SCHED_PRESSURE_NONE); + + if (! INSN_P (insn)) + return; +@@ -2030,8 +2030,9 @@ + len = sizeof (struct reg_pressure_data) * ira_reg_class_cover_size; + pressure_info + = INSN_REG_PRESSURE (insn) = (struct reg_pressure_data *) xmalloc (len); +- INSN_MAX_REG_PRESSURE (insn) = (int *) xcalloc (ira_reg_class_cover_size +- * sizeof (int), 1); ++ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) ++ INSN_MAX_REG_PRESSURE (insn) = (int *) xcalloc (ira_reg_class_cover_size ++ * sizeof (int), 1); + for (i = 0; i < ira_reg_class_cover_size; i++) + { + cl = ira_reg_class_cover[i]; +@@ -2775,7 +2776,7 @@ + || (NONJUMP_INSN_P (insn) && control_flow_insn_p (insn))) + reg_pending_barrier = MOVE_BARRIER; + +- if (sched_pressure_p) ++ if (sched_pressure != SCHED_PRESSURE_NONE) + { + setup_insn_reg_uses (deps, insn); + setup_insn_reg_pressure_info (insn); +@@ -3076,7 +3077,7 @@ + instructions that follow seem like they should be part + of the call group. + +- Also, if we did, fixup_sched_groups() would move the ++ Also, if we did, chain_to_prev_insn would move the + deps of the debug insn to the call insn, modifying + non-debug post-dependency counts of the debug insn + dependencies and otherwise messing with the scheduling +@@ -3222,6 +3223,37 @@ + return true; + } + ++/* Return true if INSN should be made dependent on the previous instruction ++ group, and if all INSN's dependencies should be moved to the first ++ instruction of that group. */ ++ ++static bool ++chain_to_prev_insn_p (rtx insn) ++{ ++ rtx prev, x; ++ ++ /* INSN forms a group with the previous instruction. */ ++ if (SCHED_GROUP_P (insn)) ++ return true; ++ ++ /* If the previous instruction clobbers a register R and this one sets ++ part of R, the clobber was added specifically to help us track the ++ liveness of R. There's no point scheduling the clobber and leaving ++ INSN behind, especially if we move the clobber to another block. */ ++ prev = prev_nonnote_nondebug_insn (insn); ++ if (prev ++ && INSN_P (prev) ++ && BLOCK_FOR_INSN (prev) == BLOCK_FOR_INSN (insn) ++ && GET_CODE (PATTERN (prev)) == CLOBBER) ++ { ++ x = XEXP (PATTERN (prev), 0); ++ if (set_of (x, insn)) ++ return true; ++ } ++ ++ return false; ++} ++ + /* Analyze INSN with DEPS as a context. */ + void + deps_analyze_insn (struct deps_desc *deps, rtx insn) +@@ -3358,8 +3390,9 @@ + + /* Fixup the dependencies in the sched group. */ + if ((NONJUMP_INSN_P (insn) || JUMP_P (insn)) +- && SCHED_GROUP_P (insn) && !sel_sched_p ()) +- fixup_sched_groups (insn); ++ && chain_to_prev_insn_p (insn) ++ && !sel_sched_p ()) ++ chain_to_prev_insn (insn); + } + + /* Initialize DEPS for the new block beginning with HEAD. */ + +=== modified file 'gcc/sched-int.h' +--- old/gcc/sched-int.h 2011-02-02 04:31:35 +0000 ++++ new/gcc/sched-int.h 2012-02-08 23:39:02 +0000 +@@ -651,7 +651,7 @@ + + /* Do register pressure sensitive insn scheduling if the flag is set + up. */ +-extern bool sched_pressure_p; ++extern enum sched_pressure_algorithm sched_pressure; + + /* Map regno -> its cover class. The map defined only when + SCHED_PRESSURE_P is true. */ +@@ -773,16 +773,16 @@ + + short cost; + ++ /* '> 0' if priority is valid, ++ '== 0' if priority was not yet computed, ++ '< 0' if priority in invalid and should be recomputed. */ ++ signed char priority_status; ++ + /* Set if there's DEF-USE dependence between some speculatively + moved load insn and this one. */ + unsigned int fed_by_spec_load : 1; + unsigned int is_load_insn : 1; + +- /* '> 0' if priority is valid, +- '== 0' if priority was not yet computed, +- '< 0' if priority in invalid and should be recomputed. */ +- signed char priority_status; +- + /* What speculations are necessary to apply to schedule the instruction. */ + ds_t todo_spec; + +@@ -817,6 +817,7 @@ + /* Info about how scheduling the insn changes cost of register + pressure excess (between source and target). */ + int reg_pressure_excess_cost_change; ++ int model_index; + }; + + typedef struct _haifa_insn_data haifa_insn_data_def; +@@ -839,6 +840,7 @@ + #define INSN_REG_PRESSURE_EXCESS_COST_CHANGE(INSN) \ + (HID (INSN)->reg_pressure_excess_cost_change) + #define INSN_PRIORITY_STATUS(INSN) (HID (INSN)->priority_status) ++#define INSN_MODEL_INDEX(INSN) (HID (INSN)->model_index) + + typedef struct _haifa_deps_insn_data haifa_deps_insn_data_def; + typedef haifa_deps_insn_data_def *haifa_deps_insn_data_t; + +=== modified file 'gcc/sched-rgn.c' +--- old/gcc/sched-rgn.c 2011-06-04 10:15:48 +0000 ++++ new/gcc/sched-rgn.c 2012-02-08 23:38:13 +0000 +@@ -2943,7 +2943,7 @@ + + sched_extend_ready_list (rgn_n_insns); + +- if (sched_pressure_p) ++ if (sched_pressure == SCHED_PRESSURE_WEIGHTED) + { + sched_init_region_reg_pressure_info (); + for (bb = 0; bb < current_nr_blocks; bb++) + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106870.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106870.patch new file mode 100644 index 0000000000..1a5448403e --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106870.patch @@ -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) + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106872.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106872.patch new file mode 100644 index 0000000000..9bfd969df6 --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106872.patch @@ -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") + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106873.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106873.patch new file mode 100644 index 0000000000..5ce71a5138 --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106873.patch @@ -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" } } */ + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106874.patch b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106874.patch new file mode 100644 index 0000000000..092650dc9d --- /dev/null +++ b/meta-oe/recipes-devtools/gcc/gcc-4.6/linaro/gcc-4.6-linaro-r106874.patch @@ -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, + diff --git a/meta-oe/recipes-devtools/gcc/gcc-4_6-branch-linaro-backports.inc b/meta-oe/recipes-devtools/gcc/gcc-4_6-branch-linaro-backports.inc index e42aeeaadf..90a857d9af 100644 --- a/meta-oe/recipes-devtools/gcc/gcc-4_6-branch-linaro-backports.inc +++ b/meta-oe/recipes-devtools/gcc/gcc-4_6-branch-linaro-backports.inc @@ -4,7 +4,6 @@ file://linaro/gcc-4.6-linaro-r106733.patch \ file://linaro/gcc-4.6-linaro-r106737.patch \ file://linaro/gcc-4.6-linaro-r106738.patch \ file://linaro/gcc-4.6-linaro-r106739.patch \ -file://linaro/gcc-4.6-linaro-r106740.patch \ file://linaro/gcc-4.6-linaro-r106741.patch \ file://linaro/gcc-4.6-linaro-r106742.patch \ file://linaro/gcc-4.6-linaro-r106744.patch \ @@ -81,6 +80,17 @@ file://linaro/gcc-4.6-linaro-r106845.patch \ file://linaro/gcc-4.6-linaro-r106846.patch \ file://linaro/gcc-4.6-linaro-r106848.patch \ file://linaro/gcc-4.6-linaro-r106853.patch \ -file://linaro/gcc-4.6-linaro-r106854.patch \ file://linaro/gcc-4.6-linaro-r106855.patch \ +file://linaro/gcc-4.6-linaro-r106860.patch \ +file://linaro/gcc-4.6-linaro-r106861.patch \ +file://linaro/gcc-4.6-linaro-r106862.patch \ +file://linaro/gcc-4.6-linaro-r106863.patch \ +file://linaro/gcc-4.6-linaro-r106864.patch \ +file://linaro/gcc-4.6-linaro-r106865.patch \ +file://linaro/gcc-4.6-linaro-r106869.patch \ +file://linaro/gcc-4.6-linaro-r106870.patch \ +file://linaro/gcc-4.6-linaro-r106872.patch \ +file://linaro/gcc-4.6-linaro-r106873.patch \ +file://linaro/gcc-4.6-linaro-r106874.patch \ +file://linaro/fix_linaro_106872.patch \ " |