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> 2000-11-07 H.J. Lu <hjl@gnu.org>
* doc/as.texinfo (.symver): Updated for versioned symbol * 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 /* These are the routines required to output the various types of
unwind records. */ 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 { typedef struct unw_rec_list {
unwind_record r; unwind_record r;
unsigned long slot_number; unsigned long slot_number;
fragS *slot_frag;
struct unw_rec_list *next; struct unw_rec_list *next;
} unw_rec_list; } unw_rec_list;
@ -573,6 +583,7 @@ typedef struct unw_rec_list {
static struct static struct
{ {
unsigned long next_slot_number; unsigned long next_slot_number;
fragS *next_slot_frag;
/* Maintain a list of unwind entries for the current function. */ /* Maintain a list of unwind entries for the current function. */
unw_rec_list *list; 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 int calc_record_size PARAMS ((unw_rec_list *));
static void set_imask PARAMS ((unw_rec_list *, unsigned long, unsigned long, unsigned int)); static void set_imask PARAMS ((unw_rec_list *, unsigned long, unsigned long, unsigned int));
static int count_bits PARAMS ((unsigned long)); 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 void fixup_unw_records PARAMS ((unw_rec_list *));
static int output_unw_records PARAMS ((unw_rec_list *, void **)); static int output_unw_records PARAMS ((unw_rec_list *, void **));
static int convert_expr_to_ab_reg PARAMS ((expressionS *, unsigned int *, unsigned int *)); 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 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 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))); + ((slot_addr & 0x3) - (first_addr & 0x3)));
return index;
} }
/* Given a complete record list, process any records which have /* Given a complete record list, process any records which have
@ -2424,12 +2470,14 @@ fixup_unw_records (list)
{ {
unw_rec_list *ptr, *region = 0; unw_rec_list *ptr, *region = 0;
unsigned long first_addr = 0, rlen = 0, t; unsigned long first_addr = 0, rlen = 0, t;
fragS *first_frag = 0;
for (ptr = list; ptr; ptr = ptr->next) for (ptr = list; ptr; ptr = ptr->next)
{ {
if (ptr->slot_number == SLOT_NUM_NOT_SET) if (ptr->slot_number == SLOT_NUM_NOT_SET)
as_bad (" Insn slot not set in unwind record."); 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) switch (ptr->r.type)
{ {
case prologue: case prologue:
@ -2439,17 +2487,21 @@ fixup_unw_records (list)
unw_rec_list *last; unw_rec_list *last;
int size, dir_len = 0; int size, dir_len = 0;
unsigned long last_addr; unsigned long last_addr;
fragS *last_frag;
first_addr = ptr->slot_number; first_addr = ptr->slot_number;
first_frag = ptr->slot_frag;
ptr->slot_number = 0; ptr->slot_number = 0;
/* Find either the next body/prologue start, or the end of /* Find either the next body/prologue start, or the end of
the list, and determine the size of the region. */ the list, and determine the size of the region. */
last_addr = unwind.next_slot_number; last_addr = unwind.next_slot_number;
last_frag = unwind.next_slot_frag;
for (last = ptr->next; last != NULL; last = last->next) for (last = ptr->next; last != NULL; last = last->next)
if (last->r.type == prologue || last->r.type == prologue_gr if (last->r.type == prologue || last->r.type == prologue_gr
|| last->r.type == body) || last->r.type == body)
{ {
last_addr = last->slot_number; last_addr = last->slot_number;
last_frag = last->slot_frag;
break; break;
} }
else if (!last->next) else if (!last->next)
@ -2460,6 +2512,7 @@ fixup_unw_records (list)
if (ptr->r.type != body) if (ptr->r.type != body)
{ {
last_addr = last->slot_number; last_addr = last->slot_number;
last_frag = last->slot_frag;
switch (last->r.type) switch (last->r.type)
{ {
case frgr_mem: case frgr_mem:
@ -2484,7 +2537,8 @@ fixup_unw_records (list)
} }
break; 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; rlen = ptr->r.record.r.rlen = size;
region = ptr; region = ptr;
break; break;
@ -5293,7 +5347,10 @@ emit_one_bundle ()
for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next) for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next)
if (ptr->r.type == prologue || ptr->r.type == prologue_gr if (ptr->r.type == prologue || ptr->r.type == prologue_gr
|| ptr->r.type == body) || ptr->r.type == body)
{
ptr->slot_number = (unsigned long) f + i; ptr->slot_number = (unsigned long) f + i;
ptr->slot_frag = frag_now;
}
if (idesc->flags & IA64_OPCODE_SLOT2) if (idesc->flags & IA64_OPCODE_SLOT2)
{ {
@ -5498,9 +5555,11 @@ emit_one_bundle ()
for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next) for (ptr = md.slot[curr].unwind_record; ptr; ptr = ptr->next)
if (ptr->r.type != prologue && ptr->r.type != prologue_gr if (ptr->r.type != prologue && ptr->r.type != prologue_gr
&& ptr->r.type != body) && ptr->r.type != body)
{
ptr->slot_number = (unsigned long) f + i; ptr->slot_number = (unsigned long) f + i;
ptr->slot_frag = frag_now;
}
md.slot[curr].unwind_record = NULL; 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) 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 + 0, t0, 8);
number_to_chars_littleendian (f + 8, t1, 8); number_to_chars_littleendian (f + 8, t1, 8);
unwind.next_slot_number = (unsigned long) f + 16;
unwind.next_slot_frag = frag_now;
} }
int int