aboutsummaryrefslogtreecommitdiff
path: root/gcc/final.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/final.c')
-rw-r--r--gcc/final.c117
1 files changed, 96 insertions, 21 deletions
diff --git a/gcc/final.c b/gcc/final.c
index aceeb7cfb13..a683501f503 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -304,6 +304,7 @@ dbr_sequence_length (void)
`insn_current_length'. */
static int *insn_lengths;
+static char *uid_lock_length;
VEC(int,heap) *insn_addresses_;
@@ -438,6 +439,20 @@ get_attr_length (rtx insn)
return get_attr_length_1 (insn, insn_default_length);
}
+#ifdef HAVE_ATTR_lock_length
+int
+get_attr_lock_length (rtx insn)
+{
+ if (uid_lock_length && insn_lengths_max_uid > INSN_UID (insn))
+ return uid_lock_length[INSN_UID (insn)];
+ return get_attr_length_1 (insn, insn_min_lock_length);
+}
+#define INSN_VARIABLE_LENGTH_P(INSN) \
+ (insn_variable_length_p (INSN) || insn_variable_lock_length_p (INSN))
+#else
+#define INSN_VARIABLE_LENGTH_P(INSN) (insn_variable_length_p (INSN))
+#endif
+
/* Obtain the current length of an insn. If branch shortening has been done,
get its actual length. Otherwise, get its minimum length. */
int
@@ -839,6 +854,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
rtx body;
int uid;
rtx align_tab[MAX_CODE_ALIGN];
+ int (*length_fun) (rtx);
#endif
@@ -849,6 +865,10 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
free (uid_shuid);
uid_shuid = XNEWVEC (int, max_uid);
+#ifdef HAVE_ATTR_lock_length
+ uid_lock_length = XNEWVEC (char, max_uid);
+ memset (uid_lock_length, 0, max_uid);
+#endif
if (max_labelno != max_label_num ())
{
@@ -1041,6 +1061,10 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
#endif /* CASE_VECTOR_SHORTEN_MODE */
/* Compute initial lengths, addresses, and varying flags for each insn. */
+ length_fun = insn_default_length;
+#ifdef HAVE_ATTR_lock_length
+ length_fun = insn_min_length;
+#endif
for (insn_current_address = 0, insn = first;
insn != 0;
insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
@@ -1105,26 +1129,32 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
inner_length = (asm_insn_count (PATTERN (inner_insn))
* insn_default_length (inner_insn));
else
- inner_length = insn_default_length (inner_insn);
+ inner_length = length_fun (inner_insn);
insn_lengths[inner_uid] = inner_length;
if (const_delay_slots)
{
if ((varying_length[inner_uid]
- = insn_variable_length_p (inner_insn)) != 0)
+ = INSN_VARIABLE_LENGTH_P (inner_insn)) != 0)
varying_length[uid] = 1;
INSN_ADDRESSES (inner_uid) = (insn_current_address
+ insn_lengths[uid]);
}
else
- varying_length[inner_uid] = 0;
+ {
+ /* We'd need to make this code a bit more complicated
+ to properly support non-const-delay-slots with the
+ lock_length attribute. */
+ gcc_assert (length_fun == &insn_default_length);
+ varying_length[inner_uid] = 0;
+ }
insn_lengths[uid] += inner_length;
}
}
else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
{
- insn_lengths[uid] = insn_default_length (insn);
- varying_length[uid] = insn_variable_length_p (insn);
+ insn_lengths[uid] = length_fun (insn);
+ varying_length[uid] = INSN_VARIABLE_LENGTH_P (insn);
}
/* If needed, do any adjustment. */
@@ -1194,6 +1224,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
rtx prev;
int rel_align = 0;
addr_diff_vec_flags flags;
+ enum machine_mode vec_mode;
/* Avoid automatic aggregate initialization. */
flags = ADDR_DIFF_VEC_FLAGS (body);
@@ -1272,9 +1303,15 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
else
max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
}
- PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
- max_addr - rel_addr,
- body));
+ vec_mode = CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
+ max_addr - rel_addr, body);
+ if (!uid_lock_length
+ || !uid_lock_length[uid]
+ || (GET_MODE_SIZE (vec_mode)
+ >= GET_MODE_SIZE (GET_MODE (body))))
+ PUT_MODE (body, vec_mode);
+ if (uid_lock_length)
+ uid_lock_length[uid] = 1;
if (JUMP_TABLES_IN_TEXT_SECTION
|| readonly_data_section == text_section)
{
@@ -1334,18 +1371,44 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
else
inner_length = insn_current_length (inner_insn);
- if (inner_length != insn_lengths[inner_uid])
+ /* We can't record lengths of delay slot insns. */
+ if (i == 0 && inner_length != insn_lengths[inner_uid])
{
- insn_lengths[inner_uid] = inner_length;
- something_changed = 1;
+#ifdef HAVE_ATTR_lock_length
+ int lock_length = insn_current_lock_length (inner_insn);
+
+ if (lock_length > uid_lock_length[inner_uid])
+ uid_lock_length[inner_uid] = lock_length;
+ else
+ lock_length = uid_lock_length[inner_uid];
+ if (inner_length < lock_length)
+ inner_length = lock_length;
+ if (inner_length != insn_lengths[inner_uid])
+#endif
+ {
+ insn_lengths[inner_uid] = inner_length;
+ something_changed = 1;
+ }
}
- insn_current_address += insn_lengths[inner_uid];
+ insn_current_address += inner_length;
new_length += inner_length;
}
}
else
{
new_length = insn_current_length (insn);
+#ifdef HAVE_ATTR_lock_length
+ {
+ int lock_length = insn_current_lock_length (insn);
+
+ if (lock_length > uid_lock_length[uid])
+ uid_lock_length[uid] = lock_length;
+ else
+ lock_length = uid_lock_length[uid];
+ if (new_length < lock_length)
+ new_length = lock_length;
+ }
+#endif
insn_current_address += new_length;
}
@@ -1362,12 +1425,17 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
something_changed = 1;
}
}
+#ifndef HAVE_ATTR_lock_length
/* For a non-optimizing compile, do only a single pass. */
if (!optimize)
break;
+#endif
}
free (varying_length);
+ if (uid_lock_length)
+ free (uid_lock_length);
+ uid_lock_length = 0;
#endif /* HAVE_ATTR_length */
}
@@ -1375,26 +1443,33 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
#ifdef HAVE_ATTR_length
/* Given the body of an INSN known to be generated by an ASM statement, return
the number of machine instructions likely to be generated for this insn.
- This is used to compute its length. */
+ This is used to compute its length.
+ Note that an empty asm body like in execute/20001009-2.c has length zero. */
static int
asm_insn_count (rtx body)
{
const char *templ;
- int count = 1;
+ int count = 0;
+ int text;
if (GET_CODE (body) == ASM_INPUT)
templ = XSTR (body, 0);
else
templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
- if (!*templ)
- return 0;
-
- for (; *templ; templ++)
- if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ)
- || *templ == '\n')
- count++;
+ for (text = 0; *templ; templ++)
+ {
+ if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ)
+ || *templ == '\n')
+ {
+ count += text;
+ text = 0;
+ }
+ else
+ text = 1;
+ }
+ count += text;
return count;
}