From d5a149f487d1005e1a4cac36a36366f5bfa59f68 Mon Sep 17 00:00:00 2001 From: Alastair Reid Date: Wed, 27 May 2026 07:30:04 -0700 Subject: [PATCH 1/2] FFI: fix return of large bitvectors For FFI imported functions that return more than 64 bits, like this function F() -> (Bits(512), Boolean); We need to generate an FFI wrapper that includes a line like this uint64_t c_r0[8]; bool c_r1; F(c_r0, &c_r1); Note that c_r1 requires '&' to pass a pointer while c_r0 must not have '&' because C/C++ compilers will promote the array to a pointer. --- libISA/backend_c.ml | 22 +++++++++++++------ tests/backends/ffi_import_03.c | 16 ++++++++++++++ tests/backends/ffi_import_03.isa | 36 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 tests/backends/ffi_import_03.c create mode 100644 tests/backends/ffi_import_03.isa diff --git a/libISA/backend_c.ml b/libISA/backend_c.ml index 8194f3e2..a181af65 100644 --- a/libISA/backend_c.ml +++ b/libISA/backend_c.ml @@ -1401,10 +1401,12 @@ let fun_decls (xs : AST.declaration list) : AST.declaration list = (**************************************************************** * The core of this process is data conversion for which we * generate the following from the ASL variable name and type - * - A C variable name - * - The corresponding C type - * - Code to convert the ASL type to the C type - * - Code to convert the C type to the ASL type + * - c_name: A C variable name + * - pp_c_type: Code to generate the corresponding C type + * - pp_c_decl: Code to generate a declaration for the C variable + * - pp_c_ref: Code to pass the argument by reference (either x (for arrays) or &x) + * - pp_asl_to_c: Code to convert the ASL type to the C type + * - pp_c_to_asl: Code to convert the C type to the ASL type * The type and conversion code are Format functions. * Optionally, the C variable can be a pointer to a value. * For convenience, the ASL variable and type are also part of the @@ -1417,6 +1419,7 @@ type ffi_conversion = { c_name : Ident.t; pp_c_type : (PP.formatter -> unit) option; pp_c_decl : PP.formatter -> unit; + pp_c_ref : (PP.formatter -> unit); pp_asl_to_c : PP.formatter -> unit; pp_c_to_asl : PP.formatter -> unit; } @@ -1434,6 +1437,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na pp_c_type = Some (fun fmt -> PP.fprintf fmt "uint%d_t" n_fixed); pp_c_decl = (fun fmt -> PP.fprintf fmt "uint%d_t %a%a" n_fixed ptr () ident c_name); + pp_c_ref = (fun fmt -> PP.fprintf fmt "&%a" ident c_name); pp_asl_to_c = (fun fmt -> PP.fprintf fmt "%a%a = %a;" ptr () @@ -1455,6 +1459,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na PP.fprintf fmt "uint64_t %a[%d]" ident c_name chunks); + pp_c_ref = (fun fmt -> PP.fprintf fmt "%a" ident c_name); (* no & required *) pp_asl_to_c = (fun fmt -> Runtime.ffi_asl2c_bits_large fmt n pp_c_name pp_asl_name); pp_c_to_asl = (fun fmt -> @@ -1469,6 +1474,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na c_name = c_name; pp_c_type = Some (fun fmt -> PP.fprintf fmt "bool%a" ptr ()); pp_c_decl = (fun fmt -> PP.fprintf fmt "bool %a%a" ptr () ident c_name); + pp_c_ref = (fun fmt -> PP.fprintf fmt "&%a" ident c_name); pp_asl_to_c = (fun fmt -> PP.fprintf fmt "%a%a = %a;" ptr () ident c_name ident asl_name); pp_c_to_asl = (fun fmt -> PP.fprintf fmt "bool %a = %a%a;" ident asl_name ptr () ident c_name); } @@ -1483,6 +1489,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na c_name = c_name; pp_c_type = Some (fun fmt -> PP.fprintf fmt "const char*%a" ptr ()); pp_c_decl = (fun fmt -> PP.fprintf fmt "const char *%a%a" ptr () ident c_name); + pp_c_ref = (fun fmt -> PP.fprintf fmt "&%a" ident c_name); pp_asl_to_c = (fun fmt -> PP.fprintf fmt "%a%a = %a;" ptr () ident c_name ident asl_name); pp_c_to_asl = (fun fmt -> PP.fprintf fmt "const char *%a = %a%a;" ident asl_name ptr () ident c_name); } @@ -1493,6 +1500,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na c_name = c_name; pp_c_type = Some (fun fmt -> PP.fprintf fmt "enum %a%a" ident tc ptr ()); pp_c_decl = (fun fmt -> PP.fprintf fmt "enum %a %a%a" ident tc ptr () ident c_name); + pp_c_ref = (fun fmt -> PP.fprintf fmt "&%a" ident c_name); pp_asl_to_c = (fun fmt -> PP.fprintf fmt "%a%a = %a;" ptr () ident c_name ident asl_name); pp_c_to_asl = (fun fmt -> PP.fprintf fmt "%a %a = %a%a;" ident tc ident asl_name ptr () ident c_name); } @@ -1502,6 +1510,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na c_name = c_name; pp_c_type = Some (fun fmt -> PP.fprintf fmt "int%a" ptr ()); pp_c_decl = (fun fmt -> PP.fprintf fmt "int %a%a" ptr () ident c_name); + pp_c_ref = (fun fmt -> PP.fprintf fmt "&%a" ident c_name); pp_asl_to_c = (fun fmt -> PP.fprintf fmt "%a%a = %a;" ptr () ident c_name ident asl_name); pp_c_to_asl = (fun fmt -> PP.fprintf fmt "%a %a = %a%a;" ident tc ident asl_name ptr () ident c_name); } @@ -1511,6 +1520,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na c_name = c_name; pp_c_type = Some (fun fmt -> PP.fprintf fmt "%s%a" !ffi_integer ptr ()); pp_c_decl = (fun fmt -> PP.fprintf fmt "%s %a%a" !ffi_integer ptr () ident c_name); + pp_c_ref = (fun fmt -> PP.fprintf fmt "&%a" ident c_name); pp_asl_to_c = (fun fmt -> PP.fprintf fmt "%a%a = %a;" ptr () @@ -1530,6 +1540,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na c_name = c_name; pp_c_type = Some (fun fmt -> PP.fprintf fmt "int%a" ptr ()); pp_c_decl = (fun fmt -> PP.fprintf fmt "int %a%a" ptr () ident c_name); + pp_c_ref = (fun fmt -> PP.fprintf fmt "&%a" ident c_name); pp_asl_to_c = (fun fmt -> PP.fprintf fmt "%a%a = %a;" ptr () @@ -1807,8 +1818,7 @@ let mk_ffi_import_wrapper Ident.pp asl_field_name Ident.pp asl_name in - let pp_c_arg fmt = PP.fprintf fmt "&%a" Ident.pp field.c_name in - (pp_insert, field_indirect.pp_c_decl, field.pp_c_decl, pp_c_arg, field.pp_c_to_asl) + (pp_insert, field_indirect.pp_c_decl, field.pp_c_decl, field.pp_c_ref, field.pp_c_to_asl) ) |> Utils.split5 in diff --git a/tests/backends/ffi_import_03.c b/tests/backends/ffi_import_03.c new file mode 100644 index 00000000..1206a27e --- /dev/null +++ b/tests/backends/ffi_import_03.c @@ -0,0 +1,16 @@ +// FFI testing support functions to be imported into ASL test programs +// Copyright (C) 2025-2026 Intel Corporation +#include +#include "isa_ffi.h" + +// Wide bitvectors are represented as arrays of uint64_t +// If returning a wide bitvector, an extra array argument is +// added as the last argument + +void FFI_bits_bool(int64_t x, uint64_t r0[2], bool *r1) +{ + for(int i = 0; i < 2; ++i) { + r0[i] = (uint64_t)x; + } + *r1 = true; +} diff --git a/tests/backends/ffi_import_03.isa b/tests/backends/ffi_import_03.isa new file mode 100644 index 00000000..a820186c --- /dev/null +++ b/tests/backends/ffi_import_03.isa @@ -0,0 +1,36 @@ +// RUN: %aslrun %s --transform-foreign --extra-c=%S/ffi_import_03.c | filecheck %s +// Copyright (C) 2025-2026 Intel Corporation + +// UNSUPPORTED: interpreter + +// Check that returning a tuple containing a large bitvector works +// (Fixes a bug caused by the generated C containing "&v1" +// when v1 is the array the result should be placed in. +// This is incorrect because C automatically promotes arrays to pointers +// by implicitly adding the "&" for us.) +// +// Note that this test does not invoke the :xform_tuples transform so +// we manually apply the effect of :xform_tuples by introducing the +// __Return_FFI_bits_bool tuple. + +record __Return_FFI_bits_bool = { + r0 : Bits(128), + r1 : Boolean +}; + +function FFI_bits_bool(x : Integer) -> __Return_FFI_bits_bool; + +foreign import function "FFI_bits_bool" = FFI_bits_bool with {}; + +function main() -> Builtin::Foreign::CInt +begin + let ret1 := FFI_bits_bool(3); + + Std::Print::Bits::Hex(ret1.r0); Print("\n"); + // CHECK: 128'x30000000000000003 + + Std::Print::Boolean(ret1.r1); Print("\n"); + // CHECK: True + + return Builtin::Foreign::CInt::From_Integer(0); +end From 3e85ef3d028b7de6ad1ea27d4b574de609c83e7c Mon Sep 17 00:00:00 2001 From: Alastair Reid Date: Mon, 22 Jun 2026 12:39:23 +0100 Subject: [PATCH 2/2] Update tests/backends/ffi_import_03.c Co-authored-by: Nikolay Kosarev Signed-off-by: Alastair Reid --- tests/backends/ffi_import_03.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/backends/ffi_import_03.c b/tests/backends/ffi_import_03.c index 1206a27e..beb08c50 100644 --- a/tests/backends/ffi_import_03.c +++ b/tests/backends/ffi_import_03.c @@ -1,4 +1,4 @@ -// FFI testing support functions to be imported into ASL test programs +// FFI testing support functions to be imported into ISA test programs // Copyright (C) 2025-2026 Intel Corporation #include #include "isa_ffi.h"