Skip to content

Commit

Permalink
improve zcmt
Browse files Browse the repository at this point in the history
1) fix issues for JAL relocation
2) trim unused slot at the table jump section
3) skip to generate table jump instructions if no size saving.
4) fix a bug that size saving of a relocation is calculated multiple
times.
  • Loading branch information
linsinan1995 authored and jeremybennett committed Aug 30, 2022
1 parent 34356d3 commit 1ac492b
Showing 1 changed file with 136 additions and 39 deletions.
175 changes: 136 additions & 39 deletions bfd/elfnn-riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,15 @@ typedef struct
uintNN_t *tbj_indexes;
asection *tablejump_sec;
bfd *tablejump_sec_owner;
/* end_idx is used to calculate size of used slots at table jump section,
and it is set to -1 if the profiling stage completed. */
int end_idx;
unsigned int total_saving;

/* debug use. */
unsigned int *savings;
const char **names;
} riscv_table_jump_htab_t;

typedef struct
{
bfd_vma address;
Expand Down Expand Up @@ -360,6 +363,8 @@ riscv_init_table_jump_htab (riscv_table_jump_htab_t *htab)
htab->names = bfd_zmalloc (sizeof (const char *) * 256);
htab->savings = bfd_zmalloc (sizeof (unsigned int) * 256);
htab->tbj_indexes = bfd_zmalloc (RISCV_ELF_WORD_BYTES * 256);
htab->end_idx = 0;
htab->total_saving = 0;

htab->tbljt_htab = htab_create (50, riscv_table_jump_htab_hash,
riscv_table_jump_htab_entry_eq, free);
Expand Down Expand Up @@ -388,7 +393,6 @@ riscv_update_table_jump_entry (htab_t htab,
const char *name)
{
riscv_table_jump_htab_entry search = {addr, 0, NULL, 0};

riscv_table_jump_htab_entry *entry = htab_find (htab, &search);

if (entry == NULL)
Expand Down Expand Up @@ -4475,6 +4479,9 @@ riscv_get_symbol_name (bfd *abfd, Elf_Internal_Rela *rel)
Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
const char *name;

if (!symtab_hdr->contents)
return NULL;

if (ELFNN_R_SYM (rel->r_info) < symtab_hdr->sh_info)
{
/* A local symbol. */
Expand Down Expand Up @@ -4513,8 +4520,12 @@ _bfd_riscv_table_jump_mark (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
bool undefined_weak ATTRIBUTE_UNUSED)
{
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
bfd_vma jal = bfd_getl32 (contents + rel->r_offset + 4);
int rd = (jal >> OP_SH_RD) & OP_MASK_RD;
bfd_vma location = ELFNN_R_TYPE (rel->r_info) == R_RISCV_JAL ?
contents + rel->r_offset
: contents + rel->r_offset + 4;
bfd_vma target = bfd_getl32 (location);
int rd = (target >> OP_SH_RD) & OP_MASK_RD;
const char *name = riscv_get_symbol_name (abfd, rel);
htab_t tbljal_htab = riscv_get_table_jump_htab (link_info, rd);

/* Check if it uses a valid link register. */
Expand All @@ -4527,8 +4538,8 @@ _bfd_riscv_table_jump_mark (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
/* entry->index == 0 when the entry is not used as a table jump entry. */
if (entry != NULL && entry->index > 0)
{
jal = MATCH_TABLE_JUMP | ENCODE_ZCMP_TABLE_JUMP_INDEX (entry->index-1);
bfd_putl32 (jal, contents + rel->r_offset);
target = MATCH_TABLE_JUMP | ENCODE_ZCMP_TABLE_JUMP_INDEX (entry->index-1);
bfd_putl32 (target, contents + rel->r_offset);
}
return true;
}
Expand Down Expand Up @@ -4575,7 +4586,6 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
auipc = bfd_getl32 (contents + rel->r_offset);
jalr = bfd_getl32 (contents + rel->r_offset + 4);


/* Relax a table jump instruction that is marked. */
if (link_info->relax_pass == 1
&& ((auipc ^ MATCH_TABLE_JUMP) & MASK_CM_JALT) == 0)
Expand Down Expand Up @@ -4612,19 +4622,20 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
}

/* Table jump profiling stage. It will be moved out of the relax_call function. */
if (link_info->relax_pass == 0
&& link_info->relax_trip == 0)
if (link_info->relax_pass == 0)
{
/* Early stop to prevent _bfd_riscv_relax_call to delete bytes in pass 0. */
if (link_info->relax_trip != 0)
return true;

htab_t tbljal_htab = riscv_get_table_jump_htab (link_info, rd);
const char *name = riscv_get_symbol_name (abfd, rel);
unsigned int benefit = VALID_JTYPE_IMM (foff) ? len - 2 : 8 - 2;
unsigned int benefit = len - 2;

if (tbljal_htab == NULL
|| name == NULL
|| benefit == 0)
return true;

*again = true;
return true;

return riscv_update_table_jump_entry (tbljal_htab, symval, benefit, name);
}
Expand Down Expand Up @@ -5044,20 +5055,24 @@ _bfd_riscv_record_jal (bfd *abfd,
htab_t tbljal_htab = riscv_get_table_jump_htab (link_info, rd);
const char *name = riscv_get_symbol_name (abfd, rel);

struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (link_info);
riscv_table_jump_htab_t *tbj_htab = htab->table_jump_htab;

if (link_info->relax_pass == 1
&& ((jal ^ MATCH_TABLE_JUMP) & MASK_CM_JALT) == 0)
&& ((jal ^ MATCH_TABLE_JUMP) & MASK_CM_JALT) == 0)
{
rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), R_RISCV_TABLE_JUMP);
*again = true;
return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + 2, 2, link_info, pcgp_relocs);
return riscv_relax_delete_bytes (abfd, sec,
rel->r_offset + 2, 2, link_info, pcgp_relocs);
}

if (tbljal_htab == NULL
|| name == NULL)
|| name == NULL
|| (link_info->relax_pass == 0 && link_info->relax_trip > 0)
|| link_info->relax_pass > 0)
return true;

*again = true;

return riscv_update_table_jump_entry (tbljal_htab, symval, 2, name);
}

Expand Down Expand Up @@ -5128,7 +5143,7 @@ riscv_record_table_jump_index (htab_t htab, riscv_table_jump_args *args)
unsigned int idx;
riscv_table_jump_htab_t *tbj_htab = args->htab;
riscv_table_jump_htab_entry search;
riscv_table_jump_htab_entry *entry;
riscv_table_jump_htab_entry *entry = NULL;

for (idx = args->start; idx <= args->end && tbj_htab->tbj_indexes[idx]; idx++)
{
Expand All @@ -5138,8 +5153,13 @@ riscv_record_table_jump_index (htab_t htab, riscv_table_jump_args *args)

BFD_ASSERT (entry != NULL);
entry->index = idx + 1;
tbj_htab->total_saving += tbj_htab->savings[idx];
}

/* True if there is at least one entry in table jump section. */
if (entry && entry->index)
tbj_htab->end_idx = entry->index;

return true;
}

Expand Down Expand Up @@ -5216,10 +5236,10 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
Elf_Internal_Rela *relocs;
bool ret = false;
unsigned int i;
bfd_vma max_alignment, reserve_size = 0;
bfd_vma max_alignment, reserve_size = 0, used_bytes, trimmed_bytes;
riscv_pcgp_relocs pcgp_relocs;
riscv_table_jump_htab_t *table_jump_htab = htab->table_jump_htab;
static bool print_tablejump_result = true;
struct elf_link_hash_entry *jvt_sym;

*again = false;

Expand Down Expand Up @@ -5255,15 +5275,85 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
else
max_alignment = _bfd_riscv_get_max_alignment (sec);

/* relax_trip 0:
Record symbol address and expected size saving of each relocation
that can be replaced by table jump instructions.
relax_trip 1:
Rank the best 64 relocations to replace for cm.jt and the best 192
relocations for cm.jalt in terms of the total size saved.
relax_trip 2:
Check if table jump can reduce the size, and delete the whole table
jump section if the size will not be reduced.
If table jump can save size, and then we replace all targeted
instructions/instruction pairs(e.g. auipc+jalr) to table jump
instructions with the index encoded.
relax_trip 3: Trim unused slots in the table jump section. */

if (info->relax_pass == 0
&& info->relax_trip > 0
&& riscv_use_table_jump (info)
&& print_tablejump_result)
&& riscv_use_table_jump (info))
{
print_tablejump_result = false;
riscv_table_jump_args args = {table_jump_htab, 0, 0};
/* Avoid size savings of relocations to be recoreded multiple times. */
if (info->relax_trip == 0 && *(htab->data_segment_phase) != 0)
return true;
/* Rank the entries, and calculate the expected total saving. */
else if (info->relax_trip == 1)
{
*again = true;
/* Profiling stage finished. */
if (table_jump_htab->end_idx != 0)
return true;

riscv_table_jump_profiling (table_jump_htab, &args);
riscv_table_jump_args args = {table_jump_htab, 0, 0};
/* Estimate size savings if table jump is used. */
riscv_table_jump_profiling (table_jump_htab, &args);
return true;
}
/* Skip generating table jump instructions if they do not help reduce code size. */
else if (info->relax_trip == 2)
{
/* Check if table jump can save size. Skip generating table
jump instruction if not. */
if (table_jump_htab->total_saving <=
table_jump_htab->end_idx * RISCV_ELF_WORD_BYTES
&& table_jump_htab->tablejump_sec->size > 0)
{
jvt_sym = elf_link_hash_lookup (elf_hash_table (info),
RISCV_TABLE_JUMP_BASE_SYMBOL,
false, false, true);
jvt_sym->root.u.def.section = bfd_abs_section_ptr;
return riscv_relax_delete_bytes (table_jump_htab->tablejump_sec_owner,
table_jump_htab->tablejump_sec,
0, table_jump_htab->tablejump_sec->size, info, NULL);
}
else if (table_jump_htab->tablejump_sec->size == 0)
return true;
else if (table_jump_htab->tablejump_sec->size > 0)
*again = true;
}
/* Trim the unused slot at the table jump section.
TODO: skip generating entries if its saving is less than RISCV_ELF_WORD_BYTES.
We should skip those insns at the relax trip 2 without deleting bytes. */
else if (info->relax_trip == 3)
{
/* Table jump entry section is trimmed. */
if (table_jump_htab->end_idx < 0)
return true;

used_bytes = table_jump_htab->end_idx * RISCV_ELF_WORD_BYTES;
trimmed_bytes = (256 - table_jump_htab->end_idx) * RISCV_ELF_WORD_BYTES;
/* Trim unused slots. */
if (!riscv_relax_delete_bytes (table_jump_htab->tablejump_sec_owner,
table_jump_htab->tablejump_sec,
used_bytes, trimmed_bytes, info, NULL))
return false;
/* Mark table jump profiling stage as completed. */
table_jump_htab->end_idx = -1;
return true;
}
}

/* Examine and consider relaxing each reloc. */
Expand All @@ -5283,21 +5373,27 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
if (!riscv_use_table_jump (info))
return true;

if (type == R_RISCV_CALL)
relax_func = _bfd_riscv_relax_call;
else if (type == R_RISCV_JAL)
relax_func = _bfd_riscv_record_jal;
else
continue;

if (info->relax_trip > 0)
if (info->relax_trip == 0)
{
if (type == R_RISCV_CALL
|| type == R_RISCV_CALL_PLT)
relax_func = _bfd_riscv_relax_call;
else if (type == R_RISCV_JAL)
relax_func = _bfd_riscv_record_jal;
else
continue;
*again = true;
}
else if (info->relax_trip == 2)
relax_func = _bfd_riscv_table_jump_mark;
}
else if (info->relax_pass == 1)
{
if (type == R_RISCV_CALL
|| type == R_RISCV_CALL_PLT)
relax_func = _bfd_riscv_relax_call;
else if (type == R_RISCV_JAL)
relax_func = _bfd_riscv_record_jal;
else if (type == R_RISCV_HI20
|| type == R_RISCV_LO12_I
|| type == R_RISCV_LO12_S)
Expand All @@ -5316,13 +5412,14 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
continue;

/* Only relax this reloc if it is paired with R_RISCV_RELAX. */
if (i == sec->reloc_count - 1
|| ELFNN_R_TYPE ((rel + 1)->r_info) != R_RISCV_RELAX
|| rel->r_offset != (rel + 1)->r_offset)
if (type != R_RISCV_JAL && (i == sec->reloc_count - 1
|| ELFNN_R_TYPE ((rel + 1)->r_info) != R_RISCV_RELAX
|| rel->r_offset != (rel + 1)->r_offset))
continue;

/* Skip over the R_RISCV_RELAX. */
i++;
if (type != R_RISCV_JAL)
i++;
}
else if (info->relax_pass == 2 && type == R_RISCV_DELETE)
relax_func = _bfd_riscv_relax_delete;
Expand Down

0 comments on commit 1ac492b

Please sign in to comment.