Add a test suite to ensure that all RISC-V tunes (default or 'unusual') yield valid pkgarch combinations and that PACKAGES_EXTRA_ARCHS lists only compatible tunings.
AI-Generated: Uses Claude Opus 5.5 Signed-off-by: Trevor Gamblin <[email protected]> --- meta/lib/oeqa/selftest/cases/riscvtune.py | 96 +++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/meta/lib/oeqa/selftest/cases/riscvtune.py b/meta/lib/oeqa/selftest/cases/riscvtune.py new file mode 100644 index 0000000000..2716b5bd02 --- /dev/null +++ b/meta/lib/oeqa/selftest/cases/riscvtune.py @@ -0,0 +1,96 @@ +# +# Copyright OpenEmbedded Contributors +# +# SPDX-License-Identifier: MIT +# + +from oe.tune import riscv_implied, riscv_isa_to_tune +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars + +class RiscvTuneTests(OESelftestTestCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.orig_machine = get_bb_var('MACHINE') + + def machine_config(self, machine): + # Builds set up by bitbake-setup select the machine with a builtin + # fragment, which is fatal alongside a MACHINE assignment, so drop it + return 'OE_FRAGMENTS:remove = "machine/%s"\nMACHINE = "%s"\n' % (self.orig_machine, machine) + + def test_riscv_default_tunes(self): + """ + Parse every RISC-V tune and check it yields a usable package arch, and + that PACKAGE_EXTRA_ARCHS only lists archs of other tunes whose + extensions are all available in this one. + """ + self.write_config(self.machine_config('qemuriscv64')) + tunes = get_bb_var('AVAILTUNES').split() + + vars = {} + for tune in tunes: + machine = 'qemuriscv32' if 'riscv32' in tune else 'qemuriscv64' + self.write_config(self.machine_config(machine) + 'DEFAULTTUNE = "%s"\n' % tune) + vars[tune] = get_bb_vars(['TUNE_FEATURES', 'TUNE_PKGARCH', 'PACKAGE_EXTRA_ARCHS', 'PACKAGE_ARCHS']) + + pkgarch_features = {v['TUNE_PKGARCH']: set(v['TUNE_FEATURES'].split()) for v in vars.values()} + + for tune, v in vars.items(): + with self.subTest(tune=tune): + self.assertTrue(v['TUNE_FEATURES'], 'empty TUNE_FEATURES') + self.assertTrue(v['TUNE_PKGARCH'], 'empty TUNE_PKGARCH') + self.assertIn(v['TUNE_PKGARCH'], v['PACKAGE_ARCHS'].split()) + # sstate/package names get unwieldy past this + self.assertLessEqual(len(v['TUNE_PKGARCH']), 64, v['TUNE_PKGARCH']) + + features = set(v['TUNE_FEATURES'].split()) + features |= riscv_implied(features) + for arch in v['PACKAGE_EXTRA_ARCHS'].split(): + self.assertIn(arch, pkgarch_features, '%s is not the package arch of any tune' % arch) + self.assertLessEqual(pkgarch_features[arch], features, '%s needs extensions %s lacks' % (arch, tune)) + + # Profile tunes are named after the profile + for profile in ['rva20u64', 'rva22u64', 'rva23u64']: + self.assertEqual(vars[profile]['TUNE_PKGARCH'], profile + '_zifencei') + + # Legacy tune names behave exactly like the tunes they alias + for alias, target in [('riscv64', 'riscv64gc'), ('riscv32', 'riscv32gc')]: + with self.subTest(alias=alias): + self.assertIn(alias, tunes) + self.assertEqual(vars[alias], vars[target]) + + def test_riscv_unusual_tunes(self): + """ + Define custom tunes with unusual extension combinations, as a BSP + might, and check each one builds: the sanity checks accept the + package arch, gcc and binutils accept the -march string, and the + package arch fits in the sstate object names. + """ + def profile(name, drop=None): + return ' '.join(f for f in riscv_isa_to_tune(name).split() if f != drop) + ' zifencei' + tunes = { + # no float (lp64 ABI), with bitmanip + 'rv64-nofloat-bitmanip': riscv_isa_to_tune('rv64imac_zicsr_zifencei_zba_zbb_zbs'), + # no profile, scalar extensions on top of gc + 'rv64gc-scalar-extras': riscv_isa_to_tune('rv64gc_zicbom_zicboz_zicond_zfa_zfhmin'), + # profile plus vector crypto extensions + 'rva20-vector-crypto': profile('rva20u64') + ' v zvbb zvkt', + # a profile missing one extension, falling back to the previous one + 'rva22-no-zkt': profile('rva22u64', 'zkt'), + # rva23u64 without the full vector extension + 'rva23-no-v': profile('rva23u64', 'v'), + } + + config = self.machine_config('qemuriscv64') + for tune, features in tunes.items(): + config += 'AVAILTUNES += "%s"\n' % tune + config += 'TUNE_FEATURES:tune-%s = "%s"\n' % (tune, features) + config += 'PACKAGE_EXTRA_ARCHS:tune-%s = "${TUNE_RISCV_PKGARCH}"\n' % tune + + for tune in tunes: + with self.subTest(tune=tune): + self.write_config(config + 'DEFAULTTUNE = "%s"\n' % tune) + # small, and compiled with TUNE_CCARGS. It has no do_build, and + # populate_sysroot also writes an sstate object. + bitbake('libgcc-initial -c populate_sysroot') -- 2.55.0
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#246999): https://lists.openembedded.org/g/openembedded-core/message/246999 Mute This Topic: https://lists.openembedded.org/mt/121511810/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
