ffi #foreign: C-variadic tail via args: ..T
Trailing `args: ..T` on a #foreign declaration now lowers to the C calling convention's `...` instead of sx-side slice-packing. Drops the per-arity #foreign-shim workaround for callers of variadic C APIs (__android_log_print, printf-family, etc.). Closes issue-0043. - IR: Function.is_variadic on inst.Function; declareFunction drops the variadic param from the IR signature for foreign+variadic decls. - emit_llvm: LLVMFunctionType receives is_var_arg=1 when the flag is set; call lowering passes extras through unchanged. - Lowering: packVariadicCallArgs early-outs for foreign+variadic (no slice-pack); new promoteCVariadicArgs applies C default argument promotion (bool/s8/s16/u8/u16 -> s32, f32 -> f64) to extras past the fixed param count. - Test: examples/ffi-foreign-cvariadic.sx + .c exercise s64/f64/s32 returns through C va_arg over s32/f64/*u8 element types. 134 host + 6 cross tests pass on the WIP-less baseline.
This commit is contained in:
30
examples/ffi-foreign-cvariadic.c
Normal file
30
examples/ffi-foreign-cvariadic.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
long long sx_ffi_sum_ints(int n, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, n);
|
||||
long long total = 0;
|
||||
for (int i = 0; i < n; i++) total += va_arg(ap, int);
|
||||
va_end(ap);
|
||||
return total;
|
||||
}
|
||||
|
||||
double sx_ffi_avg_doubles(int n, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, n);
|
||||
double total = 0.0;
|
||||
for (int i = 0; i < n; i++) total += va_arg(ap, double);
|
||||
va_end(ap);
|
||||
if (n == 0) return 0.0;
|
||||
return total / n;
|
||||
}
|
||||
|
||||
int sx_ffi_count_args(const char *tag, ...) {
|
||||
(void) tag;
|
||||
va_list ap;
|
||||
va_start(ap, tag);
|
||||
int count = 0;
|
||||
while (va_arg(ap, const char *) != 0) count++;
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
28
examples/ffi-foreign-cvariadic.sx
Normal file
28
examples/ffi-foreign-cvariadic.sx
Normal file
@@ -0,0 +1,28 @@
|
||||
// `#foreign` C-variadic tail: trailing `args: ..T` on a foreign fn maps
|
||||
// to the C calling convention's `...`. Extras at the call site are
|
||||
// passed via the variadic slot with the standard default argument
|
||||
// promotion (s8/s16/bool → s32, f32 → f64) applied implicitly.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
#import c {
|
||||
#source "ffi-foreign-cvariadic.c";
|
||||
};
|
||||
|
||||
sx_ffi_sum_ints :: (n: s32, args: ..s32) -> s64 #foreign;
|
||||
sx_ffi_avg_doubles :: (n: s32, args: ..f64) -> f64 #foreign;
|
||||
sx_ffi_count_args :: (tag: *u8, args: ..*u8) -> s32 #foreign;
|
||||
|
||||
main :: () -> s32 {
|
||||
print("sum_ints(3, 10, 20, 30) = {}\n", sx_ffi_sum_ints(3, 10, 20, 30));
|
||||
print("sum_ints(0) = {}\n", sx_ffi_sum_ints(0));
|
||||
print("avg_doubles(2) = {}\n", sx_ffi_avg_doubles(2, 1.5, 2.5));
|
||||
print("avg_doubles(3) = {}\n", sx_ffi_avg_doubles(3, 1.0, 2.0, 3.0));
|
||||
|
||||
a := "alpha".ptr;
|
||||
b := "beta".ptr;
|
||||
g := "gamma".ptr;
|
||||
sentinel : *u8 = null;
|
||||
print("count_args(3 strs) = {}\n", sx_ffi_count_args("tag".ptr, a, b, g, sentinel));
|
||||
0;
|
||||
}
|
||||
Reference in New Issue
Block a user