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;
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
- = (ins[1] < 0 && REG_P (in_rtx)
+ = (! 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))
- /* We can not use the same value if the pseudo is mentioned
- in the output, e.g. as an address part in memory,
- becuase output reload will actually extend the pseudo
- liveness. We don't care about eliminable hard regs here
- as we are interesting only in pseudos. */
&& (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,
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))
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
--- /dev/null
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_hard_vfp_ok } */
+/* { dg-options "-O2 -mapcs -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16" } */
+
+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;
+}