diff mbox series

[RFC,v2,18/19] selftest: oelib: add tune.py

Message ID 20260930-riscv-tuning-rework-v2-18-9e29f3531d0e@baylibre.com
State Under Review
Headers show
Series riscv: add new ISA extensions and profile support | expand

Commit Message

Trevor Gamblin Sept. 30, 2026, 4:38 p.m. UTC
Add a basic suite for meta/lib/oe/tune.py to test:

- riscv_isa_to_tune() logic/expansion/parsing
- riscv_implied() rules handling
- Profile compatibility/nesting (e.g. rva22 is a superset of rva20)
- riscv_pkgarch() profile naming/matching, including zifencei
- Include testing of vector subsets when 'v' isn't specified, since
  these are technically valid

AI-Generated: Uses Claude Opus 5.5

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
---
 meta/lib/oeqa/selftest/cases/oelib/tune.py | 88 ++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)
diff mbox series

Patch

diff --git a/meta/lib/oeqa/selftest/cases/oelib/tune.py b/meta/lib/oeqa/selftest/cases/oelib/tune.py
new file mode 100644
index 0000000000..ff9b895fce
--- /dev/null
+++ b/meta/lib/oeqa/selftest/cases/oelib/tune.py
@@ -0,0 +1,88 @@ 
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: MIT
+#
+
+from unittest.case import TestCase
+from oe.tune import RISCV_PROFILES, riscv_isa_to_tune, riscv_implied, riscv_pkgarch
+
+def features(isa):
+    return set(riscv_isa_to_tune(isa).split())
+
+class TestRiscvIsaToTune(TestCase):
+    def test_abbreviation(self):
+        self.assertEqual(riscv_isa_to_tune('rv64gc'), 'rv 64 i m a f d c zicsr zifencei')
+        self.assertEqual(riscv_isa_to_tune('rv32gcv'), 'rv 32 i m a f d c v zicsr zifencei')
+
+    def test_explicit(self):
+        self.assertEqual(riscv_isa_to_tune('rv32imac_zicsr_zifencei'), 'rv 32 i m a c zicsr zifencei')
+        self.assertEqual(riscv_isa_to_tune('RV64IMAFD_Zicsr'), 'rv 64 i m a f d zicsr')
+
+    def test_profile(self):
+        for name, isa in RISCV_PROFILES.items():
+            self.assertEqual(riscv_isa_to_tune(name), riscv_isa_to_tune(isa))
+
+    def test_not_riscv(self):
+        self.assertEqual(riscv_isa_to_tune('x86_64'), 'x86_64')
+
+class TestRiscvImplied(TestCase):
+    def test_implied(self):
+        self.assertEqual(riscv_implied({'m'}), {'zmmul'})
+        self.assertEqual(riscv_implied({'c', 'd'}), {'zca', 'zcd'})
+        self.assertEqual(riscv_implied({'za64rs'}), {'za128rs'})
+        self.assertIn('zve64d', riscv_implied({'v'}))
+        # vector subsets, without v
+        self.assertEqual(riscv_implied({'zve64d', 'zvl128b'}),
+                         {'zve32f', 'zve32x', 'zve64f', 'zve64x', 'zvl32b', 'zvl64b'})
+
+    def test_zicsr_kept(self):
+        # Dropping zicsr would rename the existing non-profile package archs
+        self.assertNotIn('zicsr', riscv_implied({'f', 'd'}))
+
+    def test_profiles_nest(self):
+        # Later profiles are supersets of earlier ones, which tune-riscv.inc
+        # relies on for PACKAGE_EXTRA_ARCHS
+        names = ['rva20u64', 'rva22u64', 'rva23u64']
+        for lower, higher in zip(names, names[1:]):
+            h = features(higher)
+            self.assertLessEqual(features(lower), h | riscv_implied(h), '%s is not a subset of %s' % (lower, higher))
+
+class TestRiscvPkgarch(TestCase):
+    def test_no_features(self):
+        self.assertEqual(riscv_pkgarch('', 'riscv64imafdc'), 'riscv64imafdc')
+
+    def test_profiles(self):
+        for name in RISCV_PROFILES:
+            self.assertEqual(riscv_pkgarch(riscv_isa_to_tune(name), 'unused'), name)
+            self.assertEqual(riscv_pkgarch(riscv_isa_to_tune(name) + ' zifencei', 'unused'), name + '_zifencei')
+
+    def test_existing_names_unchanged(self):
+        self.assertEqual(riscv_pkgarch(riscv_isa_to_tune('rv64gc'), 'riscv64imafdc_zicsr_zifencei'),
+                         'riscv64imafdc_zicsr_zifencei')
+        self.assertEqual(riscv_pkgarch(riscv_isa_to_tune('rv32imac_zicsr_zifencei'), 'riscv32imac_zicsr_zifencei'),
+                         'riscv32imac_zicsr_zifencei')
+
+    def test_most_specific_profile(self):
+        # rva23u64 without supm isn't rva23u64, but still contains all of rva22u64
+        f = riscv_isa_to_tune('rva23u64').replace(' supm', '')
+        pkgarch = riscv_pkgarch(f, 'unused')
+        self.assertTrue(pkgarch.startswith('rva22u64_v_'), pkgarch)
+        # implied by v, so left out
+        self.assertNotIn('zve', pkgarch)
+
+    def test_implied_not_listed(self):
+        # b is implied by zba/zbb/zbs, so leaving it out still matches the profile
+        f = riscv_isa_to_tune('rva22u64').replace(' b ', ' ')
+        self.assertEqual(riscv_pkgarch(f, 'unused'), 'rva22u64')
+
+    def test_exact_drops_implied(self):
+        f = riscv_isa_to_tune('rv32imafdcv_zmmul_zaamo_zalrsc_zca_zcd_zve32x_zvl32b_zicsr_zifencei')
+        exact = 'riscv32imafdcv_zicsr_zifencei_zmmul_zaamo_zalrsc_zca_zcd_zve32x_zvl32b'
+        self.assertEqual(riscv_pkgarch(f, exact), 'riscv32imafdcv_zicsr_zifencei')
+
+    def test_exact_keeps_bitmanip(self):
+        # b is never written out in the exact pkgarch, so zba/zbb/zbs must stay
+        f = riscv_isa_to_tune('rv64gc_zba_zbb_zbs')
+        exact = 'riscv64imafdc_zicsr_zifencei_zba_zbb_zbs'
+        self.assertEqual(riscv_pkgarch(f, exact), exact)