aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYvan Roux <yvan.roux@linaro.org>2015-10-29 21:33:58 +0100
committerLinaro Code Review <review@review.linaro.org>2015-10-30 09:17:16 +0000
commitede2bc0bb8687ec7f0a7039067d700685f162dfa (patch)
tree314d2e35d9f930119f4432ce83dcccf801a65600
parentbc579c355a3f0d15576d01fd65c8c6fb3c7f4314 (diff)
gcc/
Backport from trunk r227382. 2015-09-01 Vladimir Makarov <vmakarov@redhat.com> PR target/61578 * lra-lives.c (process_bb_lives): Process move pseudos with the same value for copies and preferences * lra-constraints.c (match_reload): Create match reload pseudo with the same value from single dying input pseudo. gcc/ Backport from trunk r228097. 2015-09-24 Vladimir Makarov <vmakarov@redhat.com> PR target/61578 * ira-color.c (update_allocno_cost): Add parameter. (update_costs_from_allocno): Decrease conflict cost. Pass the new parameter. gcc/ Backport from trunk r228153. 2015-09-25 Vladimir Makarov <vmakarov@redhat.com> PR target/61578 * lra-constarints.c (match_reload): Check presence of the input pseudo in the output pseudo. gcc/ Backport from trunk r228396. 2015-10-02 Vladimir Makarov <vmakarov@redhat.com> PR rtl-optimization/67756 * lra-constraints.c (match_reload): Add a new parameter. Use it for creating a pseudo with the same value. (curr_insn_transform): Pass a new argument to match_reload. gcc/testsuite/ Backport from trunk r228396. 2015-10-02 Vladimir Makarov <vmakarov@redhat.com> PR rtl-optimization/67756 * gcc.target/arm/pr67756.c: New. gcc/testsuite/ Backport from trunk r228445. 2015-10-03 Bernd Edlinger <bernd.edlinger@hotmail.de> * gcc.target/arm/pr67756.c: Fixed warnings. Change-Id: I14c44b8447f4c7d95698b7028273bf3918769900
-rw-r--r--gcc/ira-color.c25
-rw-r--r--gcc/lra-constraints.c44
-rw-r--r--gcc/lra-lives.c21
-rw-r--r--gcc/testsuite/gcc.target/arm/pr67756.c64
4 files changed, 127 insertions, 27 deletions
diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index e104f00d3ac..cca2a4f26cd 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -1331,10 +1331,12 @@ get_next_update_cost (ira_allocno_t *allocno, ira_allocno_t *from, int *divisor)
return true;
}
-/* Increase costs of HARD_REGNO by UPDATE_COST for ALLOCNO. Return
- true if we really modified the cost. */
+/* Increase costs of HARD_REGNO by UPDATE_COST and conflict cost by
+ UPDATE_CONFLICT_COST for ALLOCNO. Return true if we really
+ modified the cost. */
static bool
-update_allocno_cost (ira_allocno_t allocno, int hard_regno, int update_cost)
+update_allocno_cost (ira_allocno_t allocno, int hard_regno,
+ int update_cost, int update_conflict_cost)
{
int i;
enum reg_class aclass = ALLOCNO_CLASS (allocno);
@@ -1350,7 +1352,7 @@ update_allocno_cost (ira_allocno_t allocno, int hard_regno, int update_cost)
(&ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (allocno),
aclass, 0, ALLOCNO_CONFLICT_HARD_REG_COSTS (allocno));
ALLOCNO_UPDATED_HARD_REG_COSTS (allocno)[i] += update_cost;
- ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (allocno)[i] += update_cost;
+ ALLOCNO_UPDATED_CONFLICT_HARD_REG_COSTS (allocno)[i] += update_conflict_cost;
return true;
}
@@ -1362,7 +1364,7 @@ static void
update_costs_from_allocno (ira_allocno_t allocno, int hard_regno,
int divisor, bool decr_p, bool record_p)
{
- int cost, update_cost;
+ int cost, update_cost, update_conflict_cost;
machine_mode mode;
enum reg_class rclass, aclass;
ira_allocno_t another_allocno, from = NULL;
@@ -1403,11 +1405,20 @@ update_costs_from_allocno (ira_allocno_t allocno, int hard_regno,
if (decr_p)
cost = -cost;
- update_cost = cp->freq * cost / divisor;
+ update_conflict_cost = update_cost = cp->freq * cost / divisor;
+
+ if (ALLOCNO_COLOR_DATA (another_allocno) != NULL
+ && (ALLOCNO_COLOR_DATA (allocno)->first_thread_allocno
+ != ALLOCNO_COLOR_DATA (another_allocno)->first_thread_allocno))
+ /* Decrease conflict cost of ANOTHER_ALLOCNO if it is not
+ in the same allocation thread. */
+ update_conflict_cost /= COST_HOP_DIVISOR;
+
if (update_cost == 0)
continue;
- if (! update_allocno_cost (another_allocno, hard_regno, update_cost))
+ if (! update_allocno_cost (another_allocno, hard_regno,
+ update_cost, update_conflict_cost))
continue;
queue_update_cost (another_allocno, allocno, divisor * COST_HOP_DIVISOR);
if (record_p && ALLOCNO_COLOR_DATA (another_allocno) != NULL)
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index bf153afcbda..d9786c599b9 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -867,10 +867,11 @@ narrow_reload_pseudo_class (rtx reg, enum reg_class cl)
numbers with end marker -1) with reg class GOAL_CLASS. Add input
and output reloads correspondingly to the lists *BEFORE and *AFTER.
OUT might be negative. In this case we generate input reloads for
- matched input operands INS. */
+ matched input operands INS. EARLY_CLOBBER_P is a flag that the
+ output operand is early clobbered for chosen alternative. */
static void
match_reload (signed char out, signed char *ins, enum reg_class goal_class,
- rtx_insn **before, rtx_insn **after)
+ rtx_insn **before, rtx_insn **after, bool early_clobber_p)
{
int i, in;
rtx new_in_reg, new_out_reg, reg, clobber;
@@ -940,20 +941,34 @@ match_reload (signed char out, signed char *ins, enum reg_class goal_class,
they live in the same place. When we create a pseudo we
assign value of original pseudo (if any) from which we
created the new pseudo. If we create the pseudo from the
- input pseudo, the new pseudo will no conflict with the input
- pseudo which is wrong when the input pseudo lives after the
- insn and as the new pseudo value is changed by the insn
- output. Therefore we create the new pseudo from the output.
+ input pseudo, the new pseudo will have no conflict with the
+ input pseudo which is wrong when the input pseudo lives after
+ the insn and as the new pseudo value is changed by the insn
+ output. Therefore we create the new pseudo from the output
+ except the case when we have single matched dying input
+ pseudo.
We cannot reuse the current output register because we might
have a situation like "a <- a op b", where the constraints
force the second input operand ("b") to match the output
operand ("a"). "b" must then be copied into a new register
- so that it doesn't clobber the current value of "a". */
+ so that it doesn't clobber the current value of "a".
+
+ We can not use the same value if the output pseudo is
+ early clobbered or the input pseudo is mentioned in the
+ output, e.g. as an address part in memory, because
+ output reload will actually extend the pseudo liveness.
+ We don't care about eliminable hard regs here as we are
+ interesting only in pseudos. */
new_in_reg = new_out_reg
- = lra_create_new_reg_with_unique_value (outmode, out_rtx,
- goal_class, "");
+ = (! early_clobber_p && ins[1] < 0 && REG_P (in_rtx)
+ && (int) REGNO (in_rtx) < lra_new_regno_start
+ && find_regno_note (curr_insn, REG_DEAD, REGNO (in_rtx))
+ && (out < 0 || regno_use_in (REGNO (in_rtx), out_rtx) == NULL_RTX)
+ ? lra_create_new_reg (inmode, in_rtx, goal_class, "")
+ : lra_create_new_reg_with_unique_value (outmode, out_rtx,
+ goal_class, ""));
}
/* In operand can be got from transformations before processing insn
constraints. One example of such transformations is subreg
@@ -3876,13 +3891,18 @@ curr_insn_transform (bool check_only_p)
match_inputs[0] = i;
match_inputs[1] = -1;
match_reload (goal_alt_matched[i][0], match_inputs,
- goal_alt[i], &before, &after);
+ goal_alt[i], &before, &after,
+ curr_static_id->operand_alternative
+ [goal_alt_number * n_operands + goal_alt_matched[i][0]]
+ .earlyclobber);
}
else if (curr_static_id->operand[i].type == OP_OUT
&& (curr_static_id->operand[goal_alt_matched[i][0]].type
== OP_IN))
/* Generate reloads for output and matched inputs. */
- match_reload (i, goal_alt_matched[i], goal_alt[i], &before, &after);
+ match_reload (i, goal_alt_matched[i], goal_alt[i], &before, &after,
+ curr_static_id->operand_alternative
+ [goal_alt_number * n_operands + i].earlyclobber);
else if (curr_static_id->operand[i].type == OP_IN
&& (curr_static_id->operand[goal_alt_matched[i][0]].type
== OP_IN))
@@ -3892,7 +3912,7 @@ curr_insn_transform (bool check_only_p)
for (j = 0; (k = goal_alt_matched[i][j]) >= 0; j++)
match_inputs[j + 1] = k;
match_inputs[j + 1] = -1;
- match_reload (-1, match_inputs, goal_alt[i], &before, &after);
+ match_reload (-1, match_inputs, goal_alt[i], &before, &after, false);
}
else
/* We must generate code in any case when function
diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c
index fd9e29cce66..a6846dfc9a4 100644
--- a/gcc/lra-lives.c
+++ b/gcc/lra-lives.c
@@ -777,28 +777,33 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
lra_hard_reg_usage[reg->regno] += freq;
call_p = CALL_P (curr_insn);
+ src_regno = (set != NULL_RTX && REG_P (SET_SRC (set))
+ ? REGNO (SET_SRC (set)) : -1);
+ dst_regno = (set != NULL_RTX && REG_P (SET_DEST (set))
+ ? REGNO (SET_DEST (set)) : -1);
if (complete_info_p
- && set != NULL_RTX
- && REG_P (SET_DEST (set)) && REG_P (SET_SRC (set))
+ && src_regno >= 0 && dst_regno >= 0
/* Check that source regno does not conflict with
destination regno to exclude most impossible
preferences. */
- && ((((src_regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
- && ! sparseset_bit_p (pseudos_live, src_regno))
+ && (((src_regno >= FIRST_PSEUDO_REGISTER
+ && (! sparseset_bit_p (pseudos_live, src_regno)
+ || (dst_regno >= FIRST_PSEUDO_REGISTER
+ && lra_reg_val_equal_p (src_regno,
+ lra_reg_info[dst_regno].val,
+ lra_reg_info[dst_regno].offset))))
|| (src_regno < FIRST_PSEUDO_REGISTER
&& ! TEST_HARD_REG_BIT (hard_regs_live, src_regno)))
/* It might be 'inheritance pseudo <- reload pseudo'. */
|| (src_regno >= lra_constraint_new_regno_start
- && ((int) REGNO (SET_DEST (set))
- >= lra_constraint_new_regno_start)
+ && dst_regno >= lra_constraint_new_regno_start
/* Remember to skip special cases where src/dest regnos are
the same, e.g. insn SET pattern has matching constraints
like =r,0. */
- && src_regno != (int) REGNO (SET_DEST (set)))))
+ && src_regno != dst_regno)))
{
int hard_regno = -1, regno = -1;
- dst_regno = REGNO (SET_DEST (set));
if (dst_regno >= lra_constraint_new_regno_start
&& src_regno >= lra_constraint_new_regno_start)
{
diff --git a/gcc/testsuite/gcc.target/arm/pr67756.c b/gcc/testsuite/gcc.target/arm/pr67756.c
new file mode 100644
index 00000000000..d2e1a8270d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr67756.c
@@ -0,0 +1,64 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_hard_vfp_ok } */
+/* { dg-options "-O2 -mapcs -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16" } */
+
+int inode_permission (), try_break_deleg ();
+int mutex_lock (), mutex_unlock ();
+struct mutex
+{
+};
+struct dentry
+{
+ struct inode *d_inode;
+};
+struct inode
+{
+ const struct inode_operations *i_op;
+ struct super_block *i_sb;
+ union
+ {
+ const unsigned int i_nlink;
+ };
+ unsigned long i_state;
+ struct mutex i_mutex;
+};
+struct super_block
+{
+ unsigned int s_max_links;
+};
+struct inode_operations
+{
+ int (*link) (struct dentry *, struct inode *, struct dentry *);
+} __attribute__ ((__aligned__ ((1 << 6))));
+static inline __attribute__ ((always_inline))
+__attribute__ ((no_instrument_function))
+int may_create (struct inode *dir, struct dentry *child)
+{
+ if (child->d_inode)
+ return -17;
+ return inode_permission (dir, 0x00000002 | 0x00000001);
+}
+
+int
+vfs_link (struct dentry *old_dentry, struct inode *dir,
+ struct dentry *new_dentry, struct inode **delegated_inode)
+{
+ struct inode *inode = old_dentry->d_inode;
+ unsigned max_links = dir->i_sb->s_max_links;
+ int error;
+ error = may_create (dir, new_dentry);
+ if (error)
+ return error;
+ mutex_lock (&inode->i_mutex);
+ if (inode->i_nlink == 0 && !(inode->i_state & (1 << 10)))
+ error = -2;
+ else if (max_links && inode->i_nlink >= max_links)
+ error = -31;
+ else
+ {
+ error = try_break_deleg (inode, delegated_inode);
+ error = dir->i_op->link (old_dentry, dir, new_dentry);
+ }
+ mutex_unlock (&inode->i_mutex);
+ return error;
+}