Correct unwind region length calculations.

* config/tc-ia64.c (struct unw_rec_list): Add slot_frag field.
	(struct unwind): Add next_slot_frag field.
	(slot_index): New parameters slot_frag and first_frag.  Add code
	to add in frag sizes when different.  Add comments.
	(fixup_unw_records): New locals first_frag and last_frag.  Pass new
	arguments to slot_index.
	(emit_one_bundle): Set slot_frag field.  Set next_slot_number after
	loop end.  Set next_slot_frag field.
This commit is contained in:
Jim Wilson 2000-11-08 20:55:21 +00:00
parent 2765b7984f
commit f5a30c2e6e
2 changed files with 85 additions and 12 deletions

View File

@ -1,3 +1,14 @@
2000-11-08 Jim Wilson <wilson@redhat.com>
* config/tc-ia64.c (struct unw_rec_list): Add slot_frag field.
(struct unwind): Add next_slot_frag field.
(slot_index): New parameters slot_frag and first_frag. Add code
to add in frag sizes when different. Add comments.
(fixup_unw_records): New locals first_frag and last_frag. Pass new
arguments to slot_index.
(emit_one_bundle): Set slot_frag field. Set next_slot_number after
loop end. Set next_slot_frag field.
2000-11-07 H.J. Lu <hjl@gnu.org>
* doc/as.texinfo (.symver): Updated for versioned symbol

View File

@ -562,9 +562,19 @@ static struct gr {
/* These are the routines required to output the various types of
unwind records. */
/* A slot_number is a frag address plus the slot index (0-2). We use the
frag address here so that if there is a section switch in the middle of
a function, then instructions emitted to a different section are not
counted. Since there may be more than one frag for a function, this
means we also need to keep track of which frag this address belongs to
so we can compute inter-frag distances. This also nicely solves the
problem with nops emitted for align directives, which can't easily be
counted, but can easily be derived from frag sizes. */
typedef struct unw_rec_list {
unwind_record r;
unsigned long slot_number;
fragS *slot_frag;
struct unw_rec_list *next;
} unw_rec_list;
@ -573,6 +583,7 @@ typedef struct unw_rec_list {
static struct
{
unsigned long next_slot_number;
fragS *next_slot_frag;
/* Maintain a list of unwind entries for the current function. */
unw_rec_list *list;
@ -793,7 +804,8 @@ static void process_unw_records PARAMS ((unw_rec_list *, vbyte_func));
static int calc_record_size PARAMS ((unw_rec_list *));
static void set_imask PARAMS ((unw_rec_list *, unsigned long, unsigned long, unsigned int));
static int count_bits PARAMS ((unsigned long));
static unsigned long slot_index PARAMS ((unsigned long, unsigned long));
static unsigned long slot_index PARAMS ((unsigned long, fragS *,
unsigned long, fragS *));
static void fixup_unw_records PARAMS ((unw_rec_list *));
static int output_unw_records PARAMS ((unw_rec_list *, void **));
static int convert_expr_to_ab_reg PARAMS ((expressionS *, unsigned int *, unsigned int *));
@ -2406,11 +2418,45 @@ count_bits (unsigned long mask)
return n;
}
/* Return the number of instruction slots from FIRST_ADDR to SLOT_ADDR.
SLOT_FRAG is the frag containing SLOT_ADDR, and FIRST_FRAG is the frag
containing FIRST_ADDR. */
unsigned long
slot_index (unsigned long slot_addr, unsigned long first_addr)
slot_index (slot_addr, slot_frag, first_addr, first_frag)
unsigned long slot_addr;
fragS *slot_frag;
unsigned long first_addr;
fragS *first_frag;
{
return (3 * ((slot_addr >> 4) - (first_addr >> 4))
unsigned long index = 0;
/* First time we are called, the initial address and frag are invalid. */
if (first_addr == 0)
return 0;
/* If the two addresses are in different frags, then we need to add in
the remaining size of this frag, and then the entire size of intermediate
frags. */
while (slot_frag != first_frag)
{
unsigned long start_addr = (unsigned long) &first_frag->fr_literal;
/* Add in the full size of the frag converted to instruction slots. */
index += 3 * (first_frag->fr_fix >> 4);
/* Subtract away the initial part before first_addr. */
index -= (3 * ((first_addr >> 4) - (start_addr >> 4))
+ ((first_addr & 0x3) - (start_addr & 0x3)));
/* Move to the beginning of the next frag. */
first_frag = first_frag->fr_next;
first_addr = (unsigned long) &first_frag->fr_literal;
}
/* Add in the used part of the last frag. */
index += (3 * ((slot_addr >> 4) - (first_addr >> 4))
+ ((slot_addr & 0x3) - (first_addr & 0x3)));
return index;
}
/* Given a complete record list, process any records which have
@ -2424,12 +2470,14 @@ fixup_unw_records (list)
{
unw_rec_list *ptr, *region = 0;
unsigned long first_addr = 0, rlen = 0, t;
fragS *first_frag = 0;
for (ptr = list; ptr; ptr = ptr->next)
{
if (ptr->slot_number == SLOT_NUM_NOT_SET)
as_bad (" Insn slot not set in unwind record.");
t = slot_index (ptr->slot_number, first_addr);
t = slot_index (ptr->slot_number, ptr->slot_frag,
first_addr, first_frag);
switch (ptr->r.type)
{
case prologue:
@ -2439,17 +2487,21 @@ fixup_unw_records (list)
unw_rec_list *last;
int size, dir_len = 0;
unsigned long last_addr;
fragS *last_frag;
first_addr = ptr->slot_number;
first_frag = ptr->slot_frag;
ptr->slot_number = 0;
/* Find either the next body/prologue start, or the end of
the list, and determine the size of the region. */
last_addr = unwind.next_slot_number;
last_frag = unwind.next_slot_frag;
for (last = ptr->next; last != NULL; last = last->next)
if (last->r.type == prologue || last->r.type == prologue_gr
|| last->r.type == body)
{
last_addr = last->slot_number;
last_frag = last->slot_frag;
break;
}
else if (!last->next)
@ -2460,6 +2512,7 @@ fixup_unw_records (list)
if (ptr->r.type != body)
{
last_addr = last->slot_number;
last_frag = last->slot_frag;
switch (last->r.type)
{
case frgr_mem:
@ -2484,7 +2537,8 @@ fixup_unw_records (list)
}
break;
}
size = slot_index (last_addr, first_addr) + dir_len;
size = (slot_index (last_addr, last_frag, first_addr, first_frag)
+ dir_len);
rlen = ptr->r.record.r.rlen = size;
region = ptr;
break;
@ -5293,7 +5347,10 @@ emit_one_bundle ()
for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next)
if (ptr->r.type == prologue || ptr->r.type == prologue_gr
|| ptr->r.type == body)
{
ptr->slot_number = (unsigned long) f + i;
ptr->slot_frag = frag_now;
}
if (idesc->flags & IA64_OPCODE_SLOT2)
{
@ -5498,9 +5555,11 @@ emit_one_bundle ()
for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next)
if (ptr->r.type != prologue && ptr->r.type != prologue_gr
&& ptr->r.type != body)
{
ptr->slot_number = (unsigned long) f + i;
ptr->slot_frag = frag_now;
}
md.slot[curr].unwind_record = NULL;
unwind.next_slot_number = (unsigned long) f + i + ((i == 2)?(0x10-2):1);
if (required_unit == IA64_UNIT_L)
{
@ -5566,6 +5625,9 @@ emit_one_bundle ()
number_to_chars_littleendian (f + 0, t0, 8);
number_to_chars_littleendian (f + 8, t1, 8);
unwind.next_slot_number = (unsigned long) f + 16;
unwind.next_slot_frag = frag_now;
}
int