[PATCH 3/3] RISC-V: Add ZCMT relaxation linker tests

Jerry Zhang Jian jerry.zhangjian@sifive.com
Mon Jan 12 13:29:34 GMT 2026


From: Kito Cheng <kito.cheng@sifive.com>

Add ld tests to cover ZCMT relaxation, no-relax cases, multiple local
symbols, dump output for table jump entries, benefit-based ranking,
JVT overflow handling, RV32 cm.jt, shared library, and no-zcmt cases.

Signed-off-by: Kito Cheng <kito.cheng@sifive.com>
Co-Authored-by: Jerry Zhang Jian <jerry.zhangjian@sifive.com>
Co-Authored-by: Hau Hsu <hau.hsu@sifive.com>
Co-Authored-by: Charlie Keaney <charlie.keaney@embecosm.com>
Co-Authored-by: Mary Bennett <mary.bennett@embecosm.com>
Co-Authored-by: Nandni Jamnadas <nandni.jamnadas@embecosm.com>
Co-Authored-by: Sinan Lin <sinan.lin@linux.alibaba.com>
Co-Authored-by: Simon Cook <simon.cook@embecosm.com>
Co-Authored-by: Shihua Liao <shihua@iscas.ac.cn>
Co-Authored-by: Yulong Shi <yulong@iscas.ac.cn>
---
 ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp    | 14 +++++
 .../ld-riscv-elf/table-jump-benefit.d         | 18 +++++++
 .../ld-riscv-elf/table-jump-benefit.s         | 52 +++++++++++++++++++
 .../ld-riscv-elf/table-jump-dump-unknown.d    | 24 +++++++++
 ld/testsuite/ld-riscv-elf/table-jump-jalt.d   | 18 +++++++
 ld/testsuite/ld-riscv-elf/table-jump-jt.d     | 23 ++++++++
 .../table-jump-multiple-local-sym-2.s         | 12 +++++
 .../table-jump-multiple-local-sym.d           | 16 ++++++
 .../table-jump-multiple-local-sym.s           | 18 +++++++
 .../ld-riscv-elf/table-jump-no-relax-zcmt.d   | 17 ++++++
 .../ld-riscv-elf/table-jump-no-relo-1.s       |  7 +++
 .../ld-riscv-elf/table-jump-no-relo-2.s       | 12 +++++
 .../ld-riscv-elf/table-jump-no-relo.d         | 16 ++++++
 .../ld-riscv-elf/table-jump-no-zcmt.d         | 17 ++++++
 .../ld-riscv-elf/table-jump-no-zcmt.s         | 17 ++++++
 .../ld-riscv-elf/table-jump-overflow.d        | 19 +++++++
 .../ld-riscv-elf/table-jump-overflow.s        | 50 ++++++++++++++++++
 .../ld-riscv-elf/table-jump-relax-zcmt.d      | 23 ++++++++
 ld/testsuite/ld-riscv-elf/table-jump-rv32.d   | 16 ++++++
 ld/testsuite/ld-riscv-elf/table-jump-rv32.s   | 24 +++++++++
 ld/testsuite/ld-riscv-elf/table-jump-shared.d | 13 +++++
 ld/testsuite/ld-riscv-elf/table-jump-shared.s | 16 ++++++
 ld/testsuite/ld-riscv-elf/table-jump.ld       | 17 ++++++
 ld/testsuite/ld-riscv-elf/table-jump.s        | 37 +++++++++++++
 24 files changed, 496 insertions(+)
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-benefit.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-benefit.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-dump-unknown.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-jalt.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-jt.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-relo-1.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-relo-2.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-relo.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-overflow.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-overflow.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-relax-zcmt.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-rv32.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-rv32.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-shared.d
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump-shared.s
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump.ld
 create mode 100644 ld/testsuite/ld-riscv-elf/table-jump.s

diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index b0d510ac8da..cbf13d8d98b 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -339,4 +339,18 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "tls"
     run_dump_test "tlsbin"
     run_dump_test "absolute-no-relative"
+
+    # Zcmt (jump table) tests
+    run_dump_test "table-jump-jalt"
+    run_dump_test "table-jump-jt"
+    run_dump_test "table-jump-dump-unknown"
+    run_dump_test "table-jump-no-relo"
+    run_dump_test "table-jump-relax-zcmt"
+    run_dump_test "table-jump-no-relax-zcmt"
+    run_dump_test "table-jump-multiple-local-sym"
+    run_dump_test "table-jump-benefit"
+    run_dump_test "table-jump-no-zcmt"
+    run_dump_test "table-jump-overflow"
+    run_dump_test "table-jump-rv32"
+    run_dump_test "table-jump-shared"
 }
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-benefit.d b/ld/testsuite/ld-riscv-elf/table-jump-benefit.d
new file mode 100644
index 00000000000..012ed07d2c7
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-benefit.d
@@ -0,0 +1,18 @@
+#source: table-jump-benefit.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+[ 	]+...
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[32\]:[ 	]+func_d
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[33\]:[ 	]+func_c
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[34\]:[ 	]+func_b
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[35\]:[ 	]+func_a
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+32 # [0-9a-f]+ <func_d>
+#pass
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-benefit.s b/ld/testsuite/ld-riscv-elf/table-jump-benefit.s
new file mode 100644
index 00000000000..54c592ba0d7
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-benefit.s
@@ -0,0 +1,52 @@
+	.section .text
+
+	.globl _start
+	.type	_start, %function
+_start:
+	# Test benefit ranking: higher frequency functions should
+	# be prioritized for JVT entry allocation.
+	# Use reverse alphabetical order to verify sorting by benefit,
+	# not by name.
+
+	# func_d called 80 times - highest benefit
+	.rept 80
+	call func_d
+	.endr
+
+	# func_c called 50 times - medium benefit
+	.rept 50
+	call func_c
+	.endr
+
+	# func_b called 20 times - lower benefit
+	.rept 20
+	call func_b
+	.endr
+
+	# func_a called 5 times - lowest benefit
+	.rept 5
+	call func_a
+	.endr
+
+	ret
+
+	.globl func_a
+	.type	func_a, %function
+func_a:
+	ret
+
+	.globl func_b
+	.type	func_b, %function
+func_b:
+	ret
+
+	.globl func_c
+	.type	func_c, %function
+func_c:
+	ret
+
+	.globl func_d
+	.type	func_d, %function
+func_d:
+	ret
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-dump-unknown.d b/ld/testsuite/ld-riscv-elf/table-jump-dump-unknown.d
new file mode 100644
index 00000000000..b8f5b1a7729
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-dump-unknown.d
@@ -0,0 +1,24 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT=1
+#ld: -Ttable-jump.ld --strip-all --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <.riscv.jvt>:
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jt\[0]:[ 	]+<unknown>
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jt\[1]:[ 	]+<unknown>
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <.text>:
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0
+.*:[ 	]+[0-9a-f]+[ 	]+ret
+.*:[ 	]+[0-9a-f]+[ 	]+ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-jalt.d b/ld/testsuite/ld-riscv-elf/table-jump-jalt.d
new file mode 100644
index 00000000000..098e65fc403
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-jalt.d
@@ -0,0 +1,18 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JALT=1
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+[ 	]+...
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[32\]:[ 	]+foo_global
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[33\]:[ 	]+foo_local
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+32 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+33 # [0-9a-f]+ <foo_local>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+32 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+33 # [0-9a-f]+ <foo_local>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-jt.d b/ld/testsuite/ld-riscv-elf/table-jump-jt.d
new file mode 100644
index 00000000000..0abbbb5ee5f
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-jt.d
@@ -0,0 +1,23 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT=1
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jt\[0\]:[ 	]+foo_global
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jt\[1\]:[ 	]+foo_local
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1 # [0-9a-f]+ <foo_local>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1 # [0-9a-f]+ <foo_local>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1 # [0-9a-f]+ <foo_local>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1 # [0-9a-f]+ <foo_local>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1 # [0-9a-f]+ <foo_local>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s
new file mode 100644
index 00000000000..bf106b88f2d
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym-2.s
@@ -0,0 +1,12 @@
+    .section .text
+    .type   bar, %function
+bar:
+    .rept 70
+    call foo_local
+    call foo_global
+    .endr
+    ret
+
+    .type   foo_local, %function
+foo_local:
+    ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d
new file mode 100644
index 00000000000..07dbd3978be
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.d
@@ -0,0 +1,16 @@
+#source: table-jump-multiple-local-sym.s
+#source: table-jump-multiple-local-sym-2.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+[ 	]+...
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[32\]:[ 	]+foo_global
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[33\]:[ 	]+foo_local
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[34\]:[ 	]+foo_local
+
+Disassembly of section .text:
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s
new file mode 100644
index 00000000000..ccc2525e2f7
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-multiple-local-sym.s
@@ -0,0 +1,18 @@
+    .section .text
+
+    .globl _start
+    .type   _start, %function
+_start:
+    .rept 70
+    call foo_global
+    call foo_local
+    .endr
+
+    .globl  foo_global
+    .type   foo_global, %function
+foo_global:
+    ret
+
+    .type   foo_local, %function
+foo_local:
+    ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d b/ld/testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d
new file mode 100644
index 00000000000..a551a05c97e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-relax-zcmt.d
@@ -0,0 +1,17 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT_JALT=1
+#ld: -Ttable-jump.ld --no-relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+j[ 	]+[0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+j[ 	]+[0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+j[ 	]+[0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+j[ 	]+[0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+j[ 	]+[0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <foo_global>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-relo-1.s b/ld/testsuite/ld-riscv-elf/table-jump-no-relo-1.s
new file mode 100644
index 00000000000..d3e9b7ce4dd
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-relo-1.s
@@ -0,0 +1,7 @@
+    .section .text
+
+    .globl _start
+    .type	_start, %function
+_start:
+L0: j L0
+    ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-relo-2.s b/ld/testsuite/ld-riscv-elf/table-jump-no-relo-2.s
new file mode 100644
index 00000000000..f68cdaf423b
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-relo-2.s
@@ -0,0 +1,12 @@
+    .section .text
+
+    .globl foo
+    .type  foo, %function
+foo:
+    call bar
+
+
+    .globl bar
+    .type  bar, %function
+bar:
+    ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-relo.d b/ld/testsuite/ld-riscv-elf/table-jump-no-relo.d
new file mode 100644
index 00000000000..9ff45cb2616
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-relo.d
@@ -0,0 +1,16 @@
+#source: table-jump-no-relo-1.s
+#source: table-jump-no-relo-2.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+j[ 	]+[0-9a-f]+ <_start>
+.*:[ 	]+[0-9a-f]+[ 	]+ret
+
+0+[0-9a-f]+ <foo>:
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <bar>
+
+0+[0-9a-f]+ <bar>:
+.*:[ 	]+[0-9a-f]+[ 	]+ret
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.d b/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.d
new file mode 100644
index 00000000000..d65a6b9c47c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.d
@@ -0,0 +1,17 @@
+#source: table-jump-no-zcmt.s
+#as: -march=rv64ic
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+# All calls should remain as jal (not converted to cm.jalt)
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <foo>
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <foo>
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <foo>
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <foo>
+#...
+0+[0-9a-f]+ <foo>:
+.*:[ 	]+[0-9a-f]+[ 	]+ret
+#pass
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.s b/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.s
new file mode 100644
index 00000000000..630e4f5c87e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-no-zcmt.s
@@ -0,0 +1,17 @@
+	.section .text
+
+	.globl _start
+	.type	_start, %function
+_start:
+	# This file is assembled without zcmt extension
+	# The linker should NOT generate JVT section
+	.rept 50
+	call foo
+	.endr
+	ret
+
+	.globl foo
+	.type	foo, %function
+foo:
+	ret
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-overflow.d b/ld/testsuite/ld-riscv-elf/table-jump-overflow.d
new file mode 100644
index 00000000000..aa88ec93962
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-overflow.d
@@ -0,0 +1,19 @@
+#source: table-jump-overflow.s
+#as: -march=rv64ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+#...
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[32\]:[ 	]+func_top
+#...
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[255\]:[ 	]+func_[0-9]+
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+32 # [0-9a-f]+ <func_top>
+#...
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <func_overflow>
+#pass
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-overflow.s b/ld/testsuite/ld-riscv-elf/table-jump-overflow.s
new file mode 100644
index 00000000000..88aee0c669a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-overflow.s
@@ -0,0 +1,50 @@
+	.altmacro
+	.section .text
+
+	# Test JVT overflow: cm.jalt has 224 entries (index 32-255)
+	# func_top: called 10x (highest benefit), guaranteed jvt.jalt[32]
+	# func_0 to func_222: called 2x each, fill remaining 223 JVT slots
+	# func_overflow: called 1x (lowest benefit), overflows, remains jal
+
+	.macro call2 n
+	call func_\n
+	call func_\n
+	.endm
+
+	.macro defn n
+	.type func_\n, %function
+func_\n:	ret
+	.endm
+
+	.globl _start
+	.type	_start, %function
+_start:
+	# func_top: highest benefit, guaranteed first JVT entry
+	.rept 10
+	call func_top
+	.endr
+
+	# 223 functions with 2 calls each (fill remaining JVT entries)
+	.set i, 0
+	.rept 223
+	call2 %i
+	.set i, i+1
+	.endr
+
+	# func_overflow: lowest benefit, will not fit in JVT
+	call func_overflow
+	ret
+
+	# Define functions
+	.type func_top, %function
+func_top:	ret
+
+	.set i, 0
+	.rept 223
+	defn %i
+	.set i, i+1
+	.endr
+
+	.type func_overflow, %function
+func_overflow:	ret
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-relax-zcmt.d b/ld/testsuite/ld-riscv-elf/table-jump-relax-zcmt.d
new file mode 100644
index 00000000000..1adb1b289ce
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-relax-zcmt.d
@@ -0,0 +1,23 @@
+#source: table-jump.s
+#as: -march=rv64ic_zcmt --defsym TEST_CM_JT_JALT=1
+#ld: -Ttable-jump.ld --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jt\[0\]:[ 	]+foo_global
+[ 	]+...
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jalt\[32\]:[ 	]+foo_global
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+32 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+32 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+32 # [0-9a-f]+ <foo_global>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jalt[ 	]+32 # [0-9a-f]+ <foo_global>
+#...
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-rv32.d b/ld/testsuite/ld-riscv-elf/table-jump-rv32.d
new file mode 100644
index 00000000000..d3db1ba4e41
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-rv32.d
@@ -0,0 +1,16 @@
+#source: table-jump-rv32.s
+#as: -march=rv32ic_zcmt
+#ld: -Ttable-jump.ld --relax-zcmt -melf32lriscv
+#objdump: -d
+#...
+Disassembly of section .riscv.jvt:
+0+[0-9a-f]+ <__jvt_base\$>:
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jt\[0\]:[ 	]+foo_global
+.*:[ 	]+[0-9a-f]+[ 	]+jvt.jt\[1\]:[ 	]+foo_local
+#...
+Disassembly of section .text:
+0+[0-9a-f]+ <_start>:
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+1 # [0-9a-f]+ <foo_local>
+.*:[ 	]+[0-9a-f]+[ 	]+cm.jt[ 	]+0 # [0-9a-f]+ <foo_global>
+#pass
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-rv32.s b/ld/testsuite/ld-riscv-elf/table-jump-rv32.s
new file mode 100644
index 00000000000..0e5c062ac55
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-rv32.s
@@ -0,0 +1,24 @@
+	.section .text
+
+	# Test RV32 ZCMT relaxation for cm.jt
+	# jal x0 (no link) -> cm.jt (index 0-31)
+	# JVT entry cost: 4 bytes (RV32), benefit = 2 per call
+	# Threshold: 3*2=6 > 4 (just profitable)
+
+	.globl _start
+	.type	_start, %function
+_start:
+	.rept 3
+	jal x0, foo_local
+	jal x0, foo_global
+	.endr
+
+	.globl  foo_global
+	.type	foo_global, %function
+foo_global:
+	ret
+
+	.type	foo_local, %function
+foo_local:
+	ret
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-shared.d b/ld/testsuite/ld-riscv-elf/table-jump-shared.d
new file mode 100644
index 00000000000..a1e7554adf9
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-shared.d
@@ -0,0 +1,13 @@
+#source: table-jump-shared.s
+#as: -march=rv64ic_zcmt -fpic
+#ld: -shared --relax-zcmt
+#objdump: -d
+#...
+Disassembly of section .text:
+#...
+0+[0-9a-f]+ <foo>:
+#  Calls should NOT be cm.jalt in shared library (should be jal to PLT)
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <bar@plt>
+.*:[ 	]+[0-9a-f]+[ 	]+jal[ 	]+[0-9a-f]+ <bar@plt>
+#pass
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump-shared.s b/ld/testsuite/ld-riscv-elf/table-jump-shared.s
new file mode 100644
index 00000000000..6e75a70437a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump-shared.s
@@ -0,0 +1,16 @@
+	.section .text
+
+	.globl foo
+	.type	foo, %function
+foo:
+	# Shared library: JVT relaxation should be disabled
+	.rept 50
+	call bar
+	.endr
+	ret
+
+	.globl bar
+	.type	bar, %function
+bar:
+	ret
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump.ld b/ld/testsuite/ld-riscv-elf/table-jump.ld
new file mode 100644
index 00000000000..7742d653bf7
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump.ld
@@ -0,0 +1,17 @@
+ENTRY(_start)
+SECTIONS
+{
+	.got  0x1000 : {
+		*(.got)
+	}
+	.riscv.jvt : {
+		*(.riscv.jvt)
+	}
+	.data 0x2000: {
+		*(.data)
+	}
+	.text 0x3000 : {
+		*(.text)
+	}
+}
+
diff --git a/ld/testsuite/ld-riscv-elf/table-jump.s b/ld/testsuite/ld-riscv-elf/table-jump.s
new file mode 100644
index 00000000000..d4802d50021
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/table-jump.s
@@ -0,0 +1,37 @@
+    .section .text
+
+    .globl _start
+	.type	_start, %function
+_start:
+.ifdef TEST_CM_JT
+    .rept 5
+    jal x0, foo_local
+    jal x0, foo_global
+    .endr
+.endif
+
+.ifdef TEST_CM_JALT
+    .rept 70
+    call foo_global
+    call foo_local
+    .endr
+.endif
+
+.ifdef TEST_CM_JT_JALT
+    .rept 5
+    jal x0, foo_global
+    .endr
+    .rept 70
+    call foo_global
+    .endr
+.endif
+
+    .globl  foo_global
+	.type	foo_global, %function
+foo_global:
+    ret
+
+	.type	foo_local, %function
+foo_local:
+    ret
+
-- 
2.51.0



More information about the Binutils mailing list