commit 1c77dc34f3deae2c10b151591972398f24ffee0d
parent 16efeb49a0c9ac08749fd6e0d7f28d74632d4541
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 12:32:15 -0700
test/parse: pin rv32 corpus runner to ilp32f (match bare harness)
The parse corpus E lane on rv32 (parse-runner --emit -> kit ld with the
bare reset stub + runtime -> qemu-system-riscv32, test/lib/exec_bare.sh)
failed every case with "incompatible ELF e_flags (0x1 vs 0x3)".
kit_test_target_init sets the rv32 spec's float_abi to SINGLE, but the
runners build a target via kit_target_new with an empty -mabi, and the
RISC-V float-ABI resolver re-derives the ABI from the resolved -march F/D
bits in that case (it does not honor a bare spec->float_abi). Commit
b436d6ef dropped F from the rv32 default -march (soft-float is the FPU-less
MCU default), so the request silently downgraded to SOFT and the emitted
object's e_flags regressed from 0x3 (RVC|SINGLE) to 0x1 (RVC) — rejected by
the freestanding link's cross-input ABI guard against the hard-single stub.
Add a shared kit_test_target_isa_abi helper that yields the ISA/ABI a runner
must thread into KitTargetOptions so the resolved float ABI matches the spec
intent (rv32 -> rv32imafc_zicsr_zifencei / ilp32f; empty, hence no-op, for
every other arch), and call it from the parse- and asm-runner target setup.
This is the C-API analog of commit 7b5e7555's scripts/cross_test.sh fix, and
mirrors test/smoke/rv32.sh.
Verified: parse corpus E lane on rv32 (qemu-system-riscv32, -O0/-O1) now
932/0/64 (the 64 skips are the pre-existing i128/ldbl128/asm/atomic
intentional-unsupported set); emitted object e_flags == 0x3. aa64 parse
lanes unaffected (helper is a no-op off rv32).
Diffstat:
3 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/test/asm/harness/asm_runner.c b/test/asm/harness/asm_runner.c
@@ -267,6 +267,9 @@ static KitStatus compiler_new_for_target(KitTargetSpec spec, KitContext* ctx,
if (compiler_out) *compiler_out = NULL;
memset(&opts, 0, sizeof opts);
opts.spec = spec;
+ /* Thread the ISA/ABI the resolver needs to honor the spec's float_abi (rv32
+ * -> ilp32f), so the emitted object's e_flags match the bare harness. */
+ kit_test_target_isa_abi(&spec, &opts.isa, &opts.abi);
st = kit_target_new(ctx, &opts, target_out);
if (st != KIT_OK) return st;
st = kit_compiler_new(*target_out, ctx, compiler_out);
diff --git a/test/lib/kit_test_target.h b/test/lib/kit_test_target.h
@@ -106,4 +106,32 @@ static inline int kit_test_target_init(KitTargetSpec* t) {
return -1;
}
+/* ISA/ABI strings a runner must thread into KitTargetOptions so the *resolved*
+ * float ABI matches the spec's float_abi intent.
+ *
+ * RISC-V has a float-ABI axis that kit_target_new re-derives from the resolved
+ * -march/-mabi (F/D feature bits) when no -mabi is given — it does NOT honor a
+ * bare spec->float_abi byte. Since the rv32 default -march dropped F (soft is
+ * the FPU-less MCU default), kit_test_target_init's KIT_FLOAT_ABI_SINGLE
+ * request is otherwise silently downgraded to SOFT, and the emitted object's
+ * ELF e_flags regress from 0x3 (RVC|SINGLE) to 0x1 (RVC) — incompatible with
+ * the freestanding bare harness (test/lib/exec_bare.sh), whose reset stub +
+ * runtime are hard-single. Pin rv32 to rv32imafc/ilp32f to match.
+ *
+ * Mirrors scripts/cross_test.sh:freestanding_abi_flags and test/smoke/rv32.sh.
+ * No other arch has this axis (soft-float is their no-F default, which the
+ * resolver already produces), so both slices stay empty. */
+static inline void kit_test_target_isa_abi(const KitTargetSpec* t,
+ KitSlice* isa, KitSlice* abi) {
+ KitSlice empty;
+ empty.s = NULL;
+ empty.len = 0;
+ *isa = empty;
+ *abi = empty;
+ if (t->arch == KIT_ARCH_RV32 && t->float_abi == KIT_FLOAT_ABI_SINGLE) {
+ *isa = kit_slice_cstr("rv32imafc_zicsr_zifencei");
+ *abi = kit_slice_cstr("ilp32f");
+ }
+}
+
#endif
diff --git a/test/parse/harness/parse_runner.c b/test/parse/harness/parse_runner.c
@@ -319,6 +319,9 @@ static KitStatus compiler_new_for_target(KitTargetSpec spec, KitContext* ctx,
if (compiler_out) *compiler_out = NULL;
memset(&opts, 0, sizeof opts);
opts.spec = spec;
+ /* Thread the ISA/ABI the resolver needs to honor the spec's float_abi (rv32
+ * -> ilp32f), so the emitted object's e_flags match the bare harness. */
+ kit_test_target_isa_abi(&spec, &opts.isa, &opts.abi);
st = kit_target_new(ctx, &opts, target_out);
if (st != KIT_OK) return st;
st = kit_compiler_new(*target_out, ctx, compiler_out);