ffi 0.2: fold Pair64 + Quad32 back into small-struct baseline
Now that emit_llvm.zig bridges the struct<->[2 x i64] ABI mismatch
(previous commit), the 9..16-byte integer-only shapes round-trip
cleanly. Extended `examples/ffi-02-small-struct.sx` to cover all
four aggregate ABI slots in one place:
Vec2 — 8 B, two f32 (register pair, float)
Vec4f — 16 B, four f32 (HFA — homogeneous float aggregate)
Pair64 — 16 B, two s64 (9..16 B int — [2 x i64] coercion slot)
Quad32 — 16 B, four s32 (same slot as Pair64)
Vendor helpers (`vendors/ffi_structs/{ffi_structs.h,ffi_structs.c}`)
grow `ffi_pair64_*` + `ffi_quad32_*` companions. Snapshot updated
to capture the full output. 89/89 regression tests pass.
`examples/101-ffi-medium-struct.sx` keeps a minimal focused repro
of the Pair64 case so the issue's emergence-and-fix history stays
greppable.
This commit is contained in:
@@ -1,27 +1,30 @@
|
||||
// Phase 0 baseline (PLAN-FFI.md step 0.2): small structs (≤16 bytes)
|
||||
// passed by value into a C `#foreign` fn and returned by value. Two
|
||||
// shapes that exercise different aggregate ABI paths today:
|
||||
// Vec2 — 8 bytes, two f32 (float register pair on AAPCS64)
|
||||
// Vec4f — 16 bytes, four f32 (HFA — homogeneous float aggregate)
|
||||
// passed by value into a C `#foreign` fn and returned by value. Four
|
||||
// shapes that exercise distinct aggregate ABI paths:
|
||||
// Vec2 — 8 B, two f32 (register pair, float)
|
||||
// Vec4f — 16 B, four f32 (HFA — homogeneous float aggregate)
|
||||
// Pair64 — 16 B, two s64 (9..16 B int — [2 x i64] coercion slot)
|
||||
// Quad32 — 16 B, four s32 (9..16 B int — same slot as Pair64)
|
||||
//
|
||||
// 16-byte integer-only structs (e.g. `{ s64, s64 }`, `{ s32, s32, s32, s32 }`)
|
||||
// are *not* covered here: sx's `#foreign` decl currently lowers them
|
||||
// as `[2 x i64]` while the call site uses the struct type, tripping
|
||||
// the LLVM verifier. Repro pinned in `examples/issue-0036.sx`; once
|
||||
// that bug closes, fold those shapes back into this baseline.
|
||||
// Pair64 / Quad32 were originally excluded (LLVM verifier rejected the
|
||||
// struct<->[2 x i64] type mismatch — see git history for issue-0036);
|
||||
// folded back in once emit_llvm.zig's coerceArg learned to bridge
|
||||
// struct <-> array via the abi.struct2arr / abi.arr2struct branches.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
// `#source` only — c_import would rewrite struct-typed params/returns
|
||||
// in the .h to *void (its "struct/opaque pointer → *void" default),
|
||||
// which would link but pass through the wrong ABI. The sx declarations
|
||||
// below match the C signatures exactly.
|
||||
// in the .h to *void (its struct/opaque pointer default), losing the
|
||||
// by-value ABI. The hand-written #foreign decls below keep sx's
|
||||
// struct types end-to-end.
|
||||
#import c {
|
||||
#source "vendors/ffi_structs/ffi_structs.c";
|
||||
};
|
||||
|
||||
Vec2 :: struct { x: f32; y: f32; }
|
||||
Vec4f :: struct { x: f32; y: f32; z: f32; w: f32; }
|
||||
Vec2 :: struct { x: f32; y: f32; }
|
||||
Vec4f :: struct { x: f32; y: f32; z: f32; w: f32; }
|
||||
Pair64 :: struct { a: s64; b: s64; }
|
||||
Quad32 :: struct { a: s32; b: s32; c: s32; d: s32; }
|
||||
|
||||
ffi_vec2_make :: (x: f32, y: f32) -> Vec2 #foreign;
|
||||
ffi_vec2_swap :: (v: Vec2) -> Vec2 #foreign;
|
||||
@@ -31,20 +34,42 @@ ffi_vec4f_make :: (x: f32, y: f32, z: f32, w: f32) -> Vec4f #foreign;
|
||||
ffi_vec4f_reverse :: (v: Vec4f) -> Vec4f #foreign;
|
||||
ffi_vec4f_sum :: (v: Vec4f) -> f32 #foreign;
|
||||
|
||||
ffi_pair64_make :: (a: s64, b: s64) -> Pair64 #foreign;
|
||||
ffi_pair64_swap :: (p: Pair64) -> Pair64 #foreign;
|
||||
ffi_pair64_sum :: (p: Pair64) -> s64 #foreign;
|
||||
|
||||
ffi_quad32_make :: (a: s32, b: s32, c: s32, d: s32) -> Quad32 #foreign;
|
||||
ffi_quad32_reverse :: (q: Quad32) -> Quad32 #foreign;
|
||||
ffi_quad32_sum :: (q: Quad32) -> s32 #foreign;
|
||||
|
||||
main :: () -> s32 {
|
||||
// ── Vec2 (8 bytes, float pair) ─────────────────────────────────
|
||||
v := ffi_vec2_make(1.5, 2.5);
|
||||
print("vec2 make = ({}, {})\n", v.x, v.y);
|
||||
print("vec2 make = ({}, {})\n", v.x, v.y);
|
||||
w := ffi_vec2_swap(v);
|
||||
print("vec2 swap = ({}, {})\n", w.x, w.y);
|
||||
print("vec2 sum = {}\n", ffi_vec2_sum(v));
|
||||
print("vec2 swap = ({}, {})\n", w.x, w.y);
|
||||
print("vec2 sum = {}\n", ffi_vec2_sum(v));
|
||||
|
||||
// ── Vec4f (16 bytes, HFA) ──────────────────────────────────────
|
||||
f := ffi_vec4f_make(1.0, 2.0, 3.0, 4.0);
|
||||
print("vec4f make = ({}, {}, {}, {})\n", f.x, f.y, f.z, f.w);
|
||||
print("vec4f make = ({}, {}, {}, {})\n", f.x, f.y, f.z, f.w);
|
||||
g := ffi_vec4f_reverse(f);
|
||||
print("vec4f rev = ({}, {}, {}, {})\n", g.x, g.y, g.z, g.w);
|
||||
print("vec4f sum = {}\n", ffi_vec4f_sum(f));
|
||||
print("vec4f rev = ({}, {}, {}, {})\n", g.x, g.y, g.z, g.w);
|
||||
print("vec4f sum = {}\n", ffi_vec4f_sum(f));
|
||||
|
||||
// ── Pair64 (16 bytes, 2×s64 — [2 x i64] coercion path) ─────────
|
||||
p := ffi_pair64_make(100, 200);
|
||||
print("pair64 make = ({}, {})\n", p.a, p.b);
|
||||
pp := ffi_pair64_swap(p);
|
||||
print("pair64 swap = ({}, {})\n", pp.a, pp.b);
|
||||
print("pair64 sum = {}\n", ffi_pair64_sum(p));
|
||||
|
||||
// ── Quad32 (16 bytes, 4×s32 — same coercion path as Pair64) ────
|
||||
q := ffi_quad32_make(10, 20, 30, 40);
|
||||
print("quad32 make = ({}, {}, {}, {})\n", q.a, q.b, q.c, q.d);
|
||||
r := ffi_quad32_reverse(q);
|
||||
print("quad32 rev = ({}, {}, {}, {})\n", r.a, r.b, r.c, r.d);
|
||||
print("quad32 sum = {}\n", ffi_quad32_sum(q));
|
||||
|
||||
0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user