From: Kito Cheng Date: Mon, 12 Jan 2026 08:26:32 +0000 (+0800) Subject: RISC-V: Add second-pass relaxation for JAL to C.J/C.JAL X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=44c39324673cd9bb18db67234253f288497d66a1;p=thirdparty%2Fbinutils-gdb.git RISC-V: Add second-pass relaxation for JAL to C.J/C.JAL When linker relaxation converts CALL (auipc+jalr, 8 bytes) to JAL (4 bytes), further relaxation to C.J or C.JAL (2 bytes) may become possible as code shrinks and jump distances decrease. This patch adds _bfd_riscv_relax_jal to perform this second-pass relaxation. To enable this, we introduce R_RISCV_DELETE_AND_RELAX, a new internal relocation that combines piecewise deletion with preservation of relaxation capability. When _bfd_riscv_relax_call relaxes CALL to JAL, it marks the deletion as R_RISCV_DELETE_AND_RELAX instead of R_RISCV_DELETE. After the piecewise deletion is resolved, R_RISCV_DELETE_AND_RELAX is converted back to R_RISCV_RELAX at the JAL instruction offset, allowing _bfd_riscv_relax_jal to further relax JAL to C.J/C.JAL. C.JAL is only available on RV32 (rd=ra), while C.J is available on both RV32 and RV64 (rd=x0). Changes since v1: - Use R_RISCV_DELETE_AND_RELAX with piecewise deletion instead of calling _riscv_relax_delete_immediate directly, to maintain relaxation performance. - Add preserve_relax parameter to riscv_relax_delete_bytes to simplify the logic in _bfd_riscv_relax_call. --- diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 4447eea0682..d3963ec9a58 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -2133,6 +2133,7 @@ perform_relocation (const reloc_howto_type *howto, break; case R_RISCV_DELETE: + case R_RISCV_DELETE_AND_RELAX: return bfd_reloc_ok; default: @@ -2793,6 +2794,7 @@ riscv_elf_relocate_section (bfd *output_bfd, case R_RISCV_SET32: case R_RISCV_32_PCREL: case R_RISCV_DELETE: + case R_RISCV_DELETE_AND_RELAX: /* These require no special handling beyond perform_relocation. */ break; @@ -4770,12 +4772,14 @@ typedef bool (*relax_delete_t) (bfd *, asection *, bfd_vma, size_t, struct bfd_link_info *, riscv_pcgp_relocs *, - Elf_Internal_Rela *); + Elf_Internal_Rela *, + bool preserve_relax); static relax_delete_t riscv_relax_delete_bytes; /* Do not delete some bytes from a section while relaxing. - Just mark the deleted bytes as R_RISCV_DELETE. */ + Just mark the deleted bytes as R_RISCV_DELETE. If PRESERVE_RELAX is true, + use R_RISCV_DELETE_AND_RELAX to preserve the ability to further relax. */ static bool _riscv_relax_delete_piecewise (bfd *abfd ATTRIBUTE_UNUSED, @@ -4784,11 +4788,13 @@ _riscv_relax_delete_piecewise (bfd *abfd ATTRIBUTE_UNUSED, size_t count, struct bfd_link_info *link_info ATTRIBUTE_UNUSED, riscv_pcgp_relocs *p ATTRIBUTE_UNUSED, - Elf_Internal_Rela *rel) + Elf_Internal_Rela *rel, + bool preserve_relax) { if (rel == NULL) return false; - rel->r_info = ELFNN_R_INFO (0, R_RISCV_DELETE); + rel->r_info = ELFNN_R_INFO (0, preserve_relax + ? R_RISCV_DELETE_AND_RELAX : R_RISCV_DELETE); rel->r_offset = addr; rel->r_addend = count; return true; @@ -4803,7 +4809,8 @@ _riscv_relax_delete_immediate (bfd *abfd, size_t count, struct bfd_link_info *link_info, riscv_pcgp_relocs *p, - Elf_Internal_Rela *rel) + Elf_Internal_Rela *rel, + bool preserve_relax ATTRIBUTE_UNUSED) { if (rel != NULL) rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); @@ -4811,7 +4818,15 @@ _riscv_relax_delete_immediate (bfd *abfd, link_info, p, 0, sec->size); } -/* Delete the bytes for R_RISCV_DELETE relocs. */ +/* Return true if TYPE is a delete relocation. */ + +static bool +riscv_is_delete_reloc (unsigned int type) +{ + return type == R_RISCV_DELETE || type == R_RISCV_DELETE_AND_RELAX; +} + +/* Delete the bytes for R_RISCV_DELETE and R_RISCV_DELETE_AND_RELAX relocs. */ static bool riscv_relax_resolve_delete_relocs (bfd *abfd, @@ -4825,10 +4840,11 @@ riscv_relax_resolve_delete_relocs (bfd *abfd, for (i = 0; i < sec->reloc_count; i++) { Elf_Internal_Rela *rel = relocs + i; - if (ELFNN_R_TYPE (rel->r_info) != R_RISCV_DELETE) + unsigned int type = ELFNN_R_TYPE (rel->r_info); + if (!riscv_is_delete_reloc (type)) continue; - /* Find the next R_RISCV_DELETE reloc if possible. */ + /* Find the next delete reloc if possible. */ Elf_Internal_Rela *rel_next = NULL; unsigned int start = rel - relocs; for (i = start; i < sec->reloc_count; i++) @@ -4837,8 +4853,8 @@ riscv_relax_resolve_delete_relocs (bfd *abfd, relocs are in sequential order. We can skip the relocs prior to this one, making this search linear time. */ rel_next = relocs + i; - if (ELFNN_R_TYPE ((rel_next)->r_info) == R_RISCV_DELETE - && (rel_next)->r_offset > rel->r_offset) + if (riscv_is_delete_reloc (ELFNN_R_TYPE (rel_next->r_info)) + && rel_next->r_offset > rel->r_offset) { BFD_ASSERT (rel_next - rel > 0); break; @@ -4853,7 +4869,18 @@ riscv_relax_resolve_delete_relocs (bfd *abfd, return false; delete_total += rel->r_addend; - rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); + + if (type == R_RISCV_DELETE_AND_RELAX) + { + /* Convert to R_RISCV_RELAX at the instruction offset. + The deletion started after the instruction, so subtract + the number of deleted bytes to get back to the instruction. */ + rel->r_info = ELFNN_R_INFO (0, R_RISCV_RELAX); + rel->r_offset -= rel->r_addend; + rel->r_addend = 0; + } + else + rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); /* Skip ahead to the next delete reloc. */ i = rel_next != NULL ? (unsigned int) (rel_next - relocs - 1) @@ -4941,10 +4968,75 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec, /* Replace the AUIPC. */ riscv_put_insn (8 * len, auipc, contents + rel->r_offset); - /* Delete unnecessary JALR and reuse the R_RISCV_RELAX reloc. */ + /* Delete unnecessary JALR and reuse the R_RISCV_RELAX reloc. + For JAL, use R_RISCV_DELETE_AND_RELAX to preserve the ability to + further relax to C.J/C.JAL in a second pass. */ *again = true; return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + len, 8 - len, - link_info, pcgp_relocs, rel + 1); + link_info, pcgp_relocs, rel + 1, + r_type == R_RISCV_JAL); +} + +/* Relax JAL to C.J or C.JAL. */ + +static bool +_bfd_riscv_relax_jal (bfd *abfd, asection *sec, asection *sym_sec, + struct bfd_link_info *link_info, + Elf_Internal_Rela *rel, + bfd_vma symval, + bfd_vma max_alignment, + bfd_vma reserve_size ATTRIBUTE_UNUSED, + bool *again, + riscv_pcgp_relocs *pcgp_relocs, + bool undefined_weak ATTRIBUTE_UNUSED) +{ + bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; + bfd_vma foff = symval - (sec_addr (sec) + rel->r_offset); + bool rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC; + + /* Can't relax to compressed instruction without RVC. */ + if (!rvc) + return true; + + bfd_vma jal = bfd_getl32 (contents + rel->r_offset); + int rd = (jal >> OP_SH_RD) & OP_MASK_RD; + + /* C.J exists on RV32 and RV64, but C.JAL is RV32-only. */ + if (!(rd == 0 || (rd == X_RA && ARCH_SIZE == 32))) + return true; + + /* If the jump crosses section boundaries, an alignment directive could + cause the PC-relative offset to later increase, so we need to add in the + max alignment of any section inclusive from the jump to the target. + Otherwise, we only need to use the alignment of the current section. */ + if (VALID_CJTYPE_IMM (foff)) + { + if (sym_sec->output_section == sec->output_section + && sym_sec->output_section != bfd_abs_section_ptr) + max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power; + foff += ((bfd_signed_vma) foff < 0 ? -max_alignment : max_alignment); + } + + /* See if this jump can be shortened. */ + if (!VALID_CJTYPE_IMM (foff)) + return true; + + /* Shorten the jump. */ + BFD_ASSERT (rel->r_offset + 4 <= sec->size); + + /* Relax to C.J[AL] rd, addr. */ + int r_type = R_RISCV_RVC_JUMP; + bfd_vma insn = (rd == 0) ? MATCH_C_J : MATCH_C_JAL; + + /* Replace the R_RISCV_JAL reloc. */ + rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), r_type); + /* Replace the JAL with C.J or C.JAL. */ + riscv_put_insn (8 * 2, insn, contents + rel->r_offset); + + /* Delete 2 bytes and reuse the R_RISCV_RELAX reloc. */ + *again = true; + return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + 2, 2, + link_info, pcgp_relocs, rel + 1, false); } /* Traverse all output sections and return the max alignment. @@ -5060,7 +5152,7 @@ _bfd_riscv_relax_lui (bfd *abfd, /* Delete unnecessary LUI and reuse the reloc. */ *again = true; return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, - link_info, pcgp_relocs, rel); + link_info, pcgp_relocs, rel, false); default: abort (); @@ -5093,7 +5185,7 @@ _bfd_riscv_relax_lui (bfd *abfd, /* Delete extra bytes and reuse the R_RISCV_RELAX reloc. */ *again = true; return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + 2, 2, - link_info, pcgp_relocs, rel + 1); + link_info, pcgp_relocs, rel + 1, false); } return true; @@ -5134,7 +5226,7 @@ _bfd_riscv_relax_tls_le (bfd *abfd, /* Delete unnecessary instruction and reuse the reloc. */ *again = true; return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info, - pcgp_relocs, rel); + pcgp_relocs, rel, false); default: abort (); @@ -5198,7 +5290,7 @@ _bfd_riscv_relax_align (bfd *abfd, asection *sec, /* Delete excess bytes. */ return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + nop_bytes, rel->r_addend - nop_bytes, link_info, - NULL, NULL); + NULL, NULL, false); } /* Relax PC-relative references to GP-relative references. */ @@ -5345,7 +5437,7 @@ _bfd_riscv_relax_pc (bfd *abfd ATTRIBUTE_UNUSED, /* Delete unnecessary AUIPC and reuse the reloc. */ *again = true; riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info, - pcgp_relocs, rel); + pcgp_relocs, rel, false); return true; default: @@ -5459,6 +5551,8 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, || type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S)) relax_func = _bfd_riscv_relax_pc; + else if (type == R_RISCV_JAL) + relax_func = _bfd_riscv_relax_jal; else continue; riscv_relax_delete_bytes = _riscv_relax_delete_piecewise; diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c index b0f635114e1..ee962b4f6f1 100644 --- a/bfd/elfxx-riscv.c +++ b/bfd/elfxx-riscv.c @@ -884,6 +884,9 @@ static const reloc_howto_type howto_table_internal[] = /* R_RISCV_DELETE. */ EMPTY_HOWTO (0), + /* R_RISCV_DELETE_AND_RELAX. */ + EMPTY_HOWTO (0), + /* High 6 bits of 18-bit absolute address. */ HOWTO (R_RISCV_RVC_LUI, /* type */ 0, /* rightshift */ diff --git a/include/elf/riscv.h b/include/elf/riscv.h index 49d6cbf57c4..f6ca3d4acd8 100644 --- a/include/elf/riscv.h +++ b/include/elf/riscv.h @@ -98,12 +98,13 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type) END_RELOC_NUMBERS (R_RISCV_max) /* Internal relocations used exclusively by the relaxation pass. */ -#define R_RISCV_DELETE (R_RISCV_max) -#define R_RISCV_RVC_LUI (R_RISCV_max + 1) -#define R_RISCV_GPREL_I (R_RISCV_max + 2) -#define R_RISCV_GPREL_S (R_RISCV_max + 3) -#define R_RISCV_TPREL_I (R_RISCV_max + 4) -#define R_RISCV_TPREL_S (R_RISCV_max + 5) +#define R_RISCV_DELETE (R_RISCV_max) +#define R_RISCV_DELETE_AND_RELAX (R_RISCV_max + 1) +#define R_RISCV_RVC_LUI (R_RISCV_max + 2) +#define R_RISCV_GPREL_I (R_RISCV_max + 3) +#define R_RISCV_GPREL_S (R_RISCV_max + 4) +#define R_RISCV_TPREL_I (R_RISCV_max + 5) +#define R_RISCV_TPREL_S (R_RISCV_max + 6) /* Processor specific flags for the ELF header e_flags field. */ diff --git a/ld/testsuite/ld-riscv-elf/j-to-cj-32.d b/ld/testsuite/ld-riscv-elf/j-to-cj-32.d new file mode 100644 index 00000000000..964e0522f19 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/j-to-cj-32.d @@ -0,0 +1,33 @@ +#name: j to c.j second-pass relaxation (RV32) +#source: j-to-cj.s +#as: -march=rv32ic +#ld: -melf32lriscv --relax +#objdump: -d -M no-aliases + +# This test verifies that the linker performs second-pass relaxation +# to convert j (jal x0) to c.j when distance shrinks due to other relaxations. +# +# Expected: All tails including critical should become c.j (2 bytes) +# +# c.j opcode: 2 bytes (4 hex digits) +# j opcode: 4 bytes (8 hex digits) + +.*:[ ]+file format .* + +Disassembly of section \.text: + +.* <_start>: +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* + +.* : +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +#... diff --git a/ld/testsuite/ld-riscv-elf/j-to-cj-64.d b/ld/testsuite/ld-riscv-elf/j-to-cj-64.d new file mode 100644 index 00000000000..6b9c0f08757 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/j-to-cj-64.d @@ -0,0 +1,34 @@ +#name: j to c.j second-pass relaxation (RV64) +#source: j-to-cj.s +#as: -march=rv64ic +#ld: -melf64lriscv --relax +#objdump: -d -M no-aliases + +# This test verifies that the linker performs second-pass relaxation +# to convert j (jal x0) to c.j when distance shrinks due to other relaxations. +# +# Expected: All tails including critical should become c.j (2 bytes) +# c.j is available on both RV32 and RV64. +# +# c.j opcode: 2 bytes (4 hex digits) +# j opcode: 4 bytes (8 hex digits) + +.*:[ ]+file format .* + +Disassembly of section \.text: + +.* <_start>: +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* + +.* : +.*:[ ]+[0-9a-f]{4}[ ]+c\.j[ ]+.* +#... diff --git a/ld/testsuite/ld-riscv-elf/j-to-cj.s b/ld/testsuite/ld-riscv-elf/j-to-cj.s new file mode 100644 index 00000000000..39f1590713e --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/j-to-cj.s @@ -0,0 +1,59 @@ +# Test case: j -> c.j second-pass relaxation +# +# This test verifies that the linker performs a second relaxation pass +# to convert j (jal x0) instructions to c.j when the distance shrinks +# due to other relaxations. +# +# c.j range: +/-2046 bytes (12-bit signed offset, LSB=0) +# Available on both RV32C and RV64C +# +# Scenario: +# 1. Multiple tails that relax from auipc+jalr (8B) to j (4B) +# 2. After first pass: critical tail to target is ~2050 bytes (> c.j range) +# 3. If second pass runs (j -> c.j for other tails), shrinkage +# brings critical tail distance under 2046 bytes +# +# Expected behavior with two-pass relaxation: +# - All tails to f1-f10 become c.j +# - Critical tail also becomes c.j + + .text + .globl _start +_start: + tail f1 + tail f2 + tail f3 + tail f4 + tail f5 + tail f6 + tail f7 + tail f8 + tail f9 + tail f10 + +critical: + # This tail should become c.j with two-pass relaxation + tail target + + # Padding: 505 * 4 = 2020 bytes + # After 1st pass (tail->j): distance = 4 + 2020 + 20 + 2 = 2046 (borderline) + # After 2nd pass (j->c.j): distance = 2 + 2020 + 20 + 2 = 2044 (can c.j) + .option norvc + .rept 505 + nop + .endr + .option rvc + +f1: ret +f2: ret +f3: ret +f4: ret +f5: ret +f6: ret +f7: ret +f8: ret +f9: ret +f10: ret + +target: + ret diff --git a/ld/testsuite/ld-riscv-elf/jal-to-cjal.d b/ld/testsuite/ld-riscv-elf/jal-to-cjal.d new file mode 100644 index 00000000000..6d448e23375 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/jal-to-cjal.d @@ -0,0 +1,34 @@ +#name: jal to c.jal second-pass relaxation +#source: jal-to-cjal.s +#as: -march=rv32ic +#ld: -melf32lriscv --relax +#objdump: -d -M no-aliases + +# This test verifies that the linker performs second-pass relaxation +# to convert jal to c.jal when distance shrinks due to other relaxations. +# +# Expected: All calls including critical should become c.jal (2 bytes) +# Current trunk behavior: All calls remain as jal (4 bytes) +# +# c.jal opcode: 2 bytes (4 hex digits) +# jal opcode: 4 bytes (8 hex digits) + +.*:[ ]+file format .* + +Disassembly of section \.text: + +.* <_start>: +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* + +.* : +.*:[ ]+[0-9a-f]{4}[ ]+c\.jal[ ]+.* +#... diff --git a/ld/testsuite/ld-riscv-elf/jal-to-cjal.s b/ld/testsuite/ld-riscv-elf/jal-to-cjal.s new file mode 100644 index 00000000000..4570b87f320 --- /dev/null +++ b/ld/testsuite/ld-riscv-elf/jal-to-cjal.s @@ -0,0 +1,59 @@ +# Test case: jal -> c.jal second-pass relaxation +# +# This test verifies that the linker performs a second relaxation pass +# to convert jal instructions to c.jal when the distance shrinks +# due to other relaxations. +# +# c.jal range: +/-2046 bytes (12-bit signed offset, LSB=0) +# Only available in RV32C (not RV64C) +# +# Scenario: +# 1. Multiple calls that relax from auipc+jalr (8B) to jal (4B) +# 2. After first pass: critical call to target is ~2050 bytes (> c.jal range) +# 3. If second pass runs (jal -> c.jal for other calls), shrinkage +# brings critical call distance under 2046 bytes +# +# Expected behavior with two-pass relaxation: +# - All calls to f1-f10 become c.jal +# - Critical call also becomes c.jal + + .text + .globl _start +_start: + call f1 + call f2 + call f3 + call f4 + call f5 + call f6 + call f7 + call f8 + call f9 + call f10 + +critical: + # This call should become c.jal with two-pass relaxation + call target + + # Padding: 505 * 4 = 2020 bytes + # After 1st pass (call->jal): distance = 4 + 2020 + 20 + 2 = 2046 (borderline) + # After 2nd pass (jal->c.jal): distance = 2 + 2020 + 20 + 2 = 2044 (can c.jal) + .option norvc + .rept 505 + nop + .endr + .option rvc + +f1: ret +f2: ret +f3: ret +f4: ret +f5: ret +f6: ret +f7: ret +f8: ret +f9: ret +f10: ret + +target: + ret diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp index f6706b2c6a3..8e26ccff10a 100644 --- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp +++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp @@ -121,6 +121,9 @@ proc run_relax_twice_test {} { if [istarget "riscv*-*-*"] { run_dump_test "align-small-region" run_dump_test "call-relax" + run_dump_test "jal-to-cjal" + run_dump_test "j-to-cj-32" + run_dump_test "j-to-cj-64" run_dump_test "pcgp-relax-01" run_dump_test "pcgp-relax-01-norelaxgp" run_dump_test "pcgp-relax-02"