Part of the CH32V pipeline audit (#1102).
What happens
Every CH32V board JSON carries the ISA/ABI for its core, e.g. genericCH32V203C8T6.json:
"march": "rv32imacxw",
"mabi": "ilp32",
but nothing reads these fields. BoardConfig (fbuild-config) has no march/mabi members (grep: zero hits outside the JSON assets), and get_ch32v_config_for_mcu() in crates/fbuild-build-mcu/src/ch32v/mcu_config.rs returns the CH32V003 base config for every series:
// All CH32V variants currently share the CH32V003 config as a base,
// with march/mabi overridden from the board JSON extra_flags. <-- this override does not exist
let json = match mcu {
"ch32v003" => CH32V003_JSON,
_ => CH32V003_JSON,
};
configs/ch32v003.json pins -march=rv32ec_zicsr -mabi=ilp32e, and extra_flags only ever contributes -D defines (BoardConfig::get_defines). Net effect: CH32V103, V203, V208, V303, V307, X035 and L103 — all RV32IMAC-class QingKe V3/V4 cores per WCH's datasheets — are compiled and linked as RV32EC with the ilp32e ABI.
Why it matters — worked example
int32_t c = a * b; on a CH32V203 (144 MHz, hardware multiplier) compiles to a call into libgcc's software __mulsi3 instead of a single mul instruction — a ~20x slowdown on multiply-heavy code (filters, LED color math). Division is worse. On top of that only registers x0–x15 are ever allocated, and the C++ -isystem multilib path (derived in orchestrator.rs from the same base config) selects the rv32ec/ilp32e headers, so the whole toolchain is consistently building for the wrong ISA. Builds pass and binaries run (RV32EC is a subset of RV32IMAC), which is why CI never noticed.
Notes for the fix
- Parse
build.march/build.mabi into BoardConfig and inject them (overriding the base config's pair) into compile + link + the multilib get_cxx_system_includes() call.
- The JSON value
rv32imacxw is a MounRiver-ism: the xw (WCH compressed) extension is not accepted by the xPack riscv-none-elf-gcc fbuild installs — strip xw (use rv32imac, or rv32imac_zicsr per toolchain version) or translate when building the flag, otherwise the wire-up will break every non-003 board at configure time.
get_ch32v_config_for_mcu(mcu: &str) is actually called with the series string — rename the parameter while touching this.
Severity: HIGH (large silent performance/codegen regression on 7 of 8 supported series; misleading comment claims the override exists).
Part of the CH32V pipeline audit (#1102).
What happens
Every CH32V board JSON carries the ISA/ABI for its core, e.g.
genericCH32V203C8T6.json:but nothing reads these fields.
BoardConfig(fbuild-config) has nomarch/mabimembers (grep: zero hits outside the JSON assets), andget_ch32v_config_for_mcu()incrates/fbuild-build-mcu/src/ch32v/mcu_config.rsreturns the CH32V003 base config for every series:configs/ch32v003.jsonpins-march=rv32ec_zicsr -mabi=ilp32e, andextra_flagsonly ever contributes-Ddefines (BoardConfig::get_defines). Net effect: CH32V103, V203, V208, V303, V307, X035 and L103 — all RV32IMAC-class QingKe V3/V4 cores per WCH's datasheets — are compiled and linked as RV32EC with the ilp32e ABI.Why it matters — worked example
int32_t c = a * b;on a CH32V203 (144 MHz, hardware multiplier) compiles to a call into libgcc's software__mulsi3instead of a singlemulinstruction — a ~20x slowdown on multiply-heavy code (filters, LED color math). Division is worse. On top of that only registers x0–x15 are ever allocated, and the C++-isystemmultilib path (derived inorchestrator.rsfrom the same base config) selects therv32ec/ilp32eheaders, so the whole toolchain is consistently building for the wrong ISA. Builds pass and binaries run (RV32EC is a subset of RV32IMAC), which is why CI never noticed.Notes for the fix
build.march/build.mabiintoBoardConfigand inject them (overriding the base config's pair) into compile + link + the multilibget_cxx_system_includes()call.rv32imacxwis a MounRiver-ism: thexw(WCH compressed) extension is not accepted by the xPackriscv-none-elf-gccfbuild installs — stripxw(userv32imac, orrv32imac_zicsrper toolchain version) or translate when building the flag, otherwise the wire-up will break every non-003 board at configure time.get_ch32v_config_for_mcu(mcu: &str)is actually called with the series string — rename the parameter while touching this.Severity: HIGH (large silent performance/codegen regression on 7 of 8 supported series; misleading comment claims the override exists).