Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/iic.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ def mk_script(args, output_directory):
if args.O0:
script = []
script.append(":filter_unlisted_functions imports")
script.append(":xform_monomorphize")
script.append(":filter_reachable_from --no-keep-builtins exports")
if args.Obounded: script.append(":xform_bounded")
if args.transform_foreign: script.append(":xform_foreign")
Expand Down
9 changes: 3 additions & 6 deletions bin/iii.ml
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,9 @@ let read_foreign_idents (export : bool) (ds : AST.declaration list) :
Ident.t list =
List.filter_map (fun d ->
match d with
| Decl_FunFFI (nm, is_export, f, [], loc) when is_export = export -> Some f
| Decl_FunFFI (nm, is_export, f, ps, loc) when is_export = export ->
let name = Ident.name_with_tag f in
raise (Utils.InternalError
(loc, Format.asprintf "No specialized function '%s' created" name,
(fun fmt -> FMT.declaration fmt d), __LOC__ ))
| Decl_FunFFI (nm, is_export, f, _, loc) when is_export = export -> Some f
| Decl_VarFFI (nm, is_export, f, loc) when is_export = export -> Some f
| Decl_TypeFFI (nm, is_export, f, loc) when is_export = export -> Some f
| _ -> None
) ds

Expand Down
114 changes: 63 additions & 51 deletions libISA/backend_c.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1552,7 +1552,7 @@ let mk_ffi_conversion (loc : Loc.t) (indirect : bool) (c_name : Ident.t) (asl_na
when Ident.equal f cvt_sintN_int
-> mk_ffi_convert_large_bits (Z.to_int n.v)
| _ ->
let msg = PP.asprintf "Type '%a' cannot be used in functions that are imported or exported between ASL and C"
let msg = PP.asprintf "Type '%a' cannot be used in functions that are imported from or exported to C"
FMT.ty asl_type
in
raise (Error.TypeError (loc, msg))
Expand Down Expand Up @@ -1892,26 +1892,63 @@ let mk_ffi_import_wrapper

(pp_proto, pp_wrapper)

(* Make list of foreign import/export pairs based either on old-style config files
* or new-style foreign import/export declarations.
*)
let get_ffi (get_exports : bool) (decls : AST.declaration list) : (string * Ident.t) list =
(* old-style imports/exports are specified via a configuration json file *)
let key = if get_exports then "exports" else "imports" in
let raw_exports = if !new_ffi then Configuration.get_strings key else [] in
let old_exports = List.filter_map (fun d ->
( match d with
| AST.Decl_Record (x, _, _, _)
| AST.Decl_Enum (x, _, _)
| AST.Decl_Var (x, _, _)
| AST.Decl_Config (x, _, _, _)
| AST.Decl_Const (x, _, _, _)
| AST.Decl_FunType (x, _, _)
when List.mem (Ident.name x) raw_exports
-> Some (Ident.name x, x)
| _
-> None
))
decls
in

(* new-style imports/exports are specified using foreign import/export declarations *)
let new_exports = List.filter_map (fun d ->
( match d with
| AST.Decl_FunFFI (nm, is_export, x, _, _)
| AST.Decl_VarFFI (nm, is_export, x, _)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decl_VarFFI should be ignored here - it is handled in xform_foreign.ml

Suggested change
| AST.Decl_VarFFI (nm, is_export, x, _)

| AST.Decl_TypeFFI (nm, is_export, x, _)
when is_export == get_exports

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
when is_export == get_exports
when is_export = get_exports

Not a bug. But = is better by default (unless you optimize the comparison)

-> Some (nm, x)
| _
-> None
)) decls
in
old_exports @ new_exports


let mk_ffi_infos (is_import : bool) (decl_map : AST.declaration list Bindings.t)
(c_names : string list) :
(xs : (string * Ident.t) list) :
(Ident.t * Ident.t * AST.function_type * Loc.t) list =
let missing : string list ref = ref [] in
let infos = List.filter_map (fun c_name ->
let asl_ident = Ident.mk_fident c_name in
let infos = List.filter_map (fun (c_name, isa_ident) ->
let c_ident = Ident.mk_ident c_name in
let info = ( match Bindings.find_opt asl_ident decl_map with
let info = ( match Bindings.find_opt isa_ident decl_map with
| Some ds ->
( match List.find_opt (function AST.Decl_FunType _ -> true | _ -> false) ds with
| Some (AST.Decl_FunType (_, fty, loc)) -> Some (c_ident, asl_ident, fty, loc)
| Some (AST.Decl_FunType (_, fty, loc)) -> Some (c_ident, isa_ident, fty, loc)
| _ -> None
)
| _ -> None
) in
if Option.is_none info && not (is_enumerated_type c_ident) then begin
if Option.is_none info && not (is_enumerated_type isa_ident) then begin
missing := c_name :: !missing
end;
info
) c_names
) xs
in
if not (Utils.is_empty !missing) then begin
let direction = if is_import then "Import" else "Export" in
Expand All @@ -1920,32 +1957,6 @@ let mk_ffi_infos (is_import : bool) (decl_map : AST.declaration list Bindings.t)
end;
infos

let mk_new_ffi_infos (is_import : bool)
(decl_map : AST.declaration list Bindings.t) (ds : AST.declaration list) :
(Ident.t * Ident.t * AST.function_type * Loc.t) list =
List.filter_map (fun x ->
match x with
| AST.Decl_FunFFI (nm, is_export, f, ps, loc) when is_export = not is_import ->
let c_ident = Ident.mk_ident nm in
let info = ( match Bindings.find_opt f decl_map with
| Some ds ->
( match List.find_opt (function AST.Decl_FunType _ -> true | _ -> false) ds with
| Some (AST.Decl_FunType (_, fty, loc)) -> Some (c_ident, f, fty, loc)
| _ -> None
)
| _ -> None
) in
if Option.is_none info then begin
let direction = if is_import then "Import" else "Export" in
let pp fmt = FMT.declaration fmt x in
let fname = Ident.name_with_tag f in
raise (InternalError
(loc, PP.asprintf "%sed function '%s' is not defined" direction fname, pp, __LOC__))
end;
info
| _ -> None)
ds

(* Build ffi wrapper functions *)
let mk_ffi_wrappers (is_import : bool)
(infos : (Ident.t * Ident.t * AST.function_type * Loc.t) list) :
Expand All @@ -1971,12 +1982,16 @@ let mk_ffi_wrappers (is_import : bool)
let pp_defns fmt : unit = List.iter (fun f -> f fmt) mk_defns in
(pp_protos, pp_defns)

let ffi_track_enums (decl_map : (AST.declaration list) Bindings.t) (exports : string list) : unit =
List.iter (fun c_name ->
let c_ident = Ident.mk_ident c_name in
( match Bindings.find_opt c_ident decl_map with
| Some (Decl_Enum (tc, es, loc) :: _) ->
add_enumerated_type tc es
let ffi_track_enums (decl_map : (AST.declaration list) Bindings.t) (exports : (string * Ident.t) list) : unit =
List.iter (fun (c_name, isa_ident) ->
( match Bindings.find_opt isa_ident decl_map with
| Some ds ->
List.iter (fun d ->
( match d with
| AST.Decl_Enum (tc, es, loc) -> add_enumerated_type tc es
| _ -> ()
))
ds
| _ ->
()
))
Expand All @@ -2003,7 +2018,7 @@ let config_getter_prefix = "ASL_get_config_"
(* Generate ASL functions for reading/writing configuration variables.
* These will then be exported so that C code can read/write the variables.
*)
let mk_ffi_config (decls : AST.declaration list) : (string list * AST.declaration list) =
let mk_ffi_config (decls : AST.declaration list) : ((string * Ident.t) list * AST.declaration list) =
let configs = List.filter_map (fun x ->
( match x with
| AST.Decl_Config (v, ty, i, loc) -> Some (v, ty, loc)
Expand All @@ -2012,7 +2027,7 @@ let mk_ffi_config (decls : AST.declaration list) : (string list * AST.declaratio
decls
in

let mk_functions ((v, ty, loc) : (Ident.t * AST.ty * Loc.t)) : (string list * AST.declaration list) =
let mk_functions ((v, ty, loc) : (Ident.t * AST.ty * Loc.t)) : ((string * Ident.t) list * AST.declaration list) =
let getter_name = config_getter_prefix ^ Ident.name v in
let getter_id = Ident.mk_fident getter_name in
let getter_fty : AST.function_type = {
Expand Down Expand Up @@ -2048,7 +2063,7 @@ let mk_ffi_config (decls : AST.declaration list) : (string list * AST.declaratio
let setter_defn = AST.Decl_FunDefn (setter_id, setter_fty, setter_body, loc) in
let setter_type = AST.Decl_FunType (setter_id, setter_fty, loc) in

([getter_name; setter_name], [getter_defn; getter_type; setter_defn; setter_type])
([(getter_name, getter_id); (setter_name, setter_id)], [getter_defn; getter_type; setter_defn; setter_type])
in

let (names, decls) = List.map mk_functions configs |> List.split in
Expand Down Expand Up @@ -2259,22 +2274,19 @@ let _ =
let (cfg_exports, cfg_funs) = mk_ffi_config decls in
let decls' = decls @ cfg_funs in
let decl_map = Isa_utils.decls_map_of decls' in
let imports = if !new_ffi then Configuration.get_strings "imports" else [] in
let exports = if !new_ffi then Configuration.get_strings "exports" else [] in

let imports = get_ffi false decls' in
let exports = get_ffi true decls' in

ffi_track_enums decl_map exports;
ffi_track_return_types decls';

let ffi_import_infos = mk_ffi_infos true decl_map imports in
let new_ffi_import_infos = mk_new_ffi_infos true decl_map decls' in
let (ffi_import_protos, ffi_import_defns) =
mk_ffi_wrappers true (ffi_import_infos @ new_ffi_import_infos)
let (ffi_import_protos, ffi_import_defns) = mk_ffi_wrappers true ffi_import_infos
in

let ffi_export_infos = mk_ffi_infos false decl_map (cfg_exports @ exports) in
let new_ffi_export_infos = mk_new_ffi_infos false decl_map decls' in
let (ffi_export_protos, ffi_export_defns) =
mk_ffi_wrappers false (ffi_export_infos @ new_ffi_export_infos)
let (ffi_export_protos, ffi_export_defns) = mk_ffi_wrappers false ffi_export_infos
in

let ffi_protos (fmt : PP.formatter) : unit =
Expand Down
2 changes: 1 addition & 1 deletion libISA/isa_ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ declaration =
| Decl_FunInstance of Ident.t * (Ident.t * Value.value option) list * Loc.t
| Decl_FunFFI of string * bool * Ident.t * (Ident.t * Value.value) list * Loc.t
| Decl_VarFFI of string * bool * Ident.t * Loc.t
| Decl_TypeFFI of string * bool * ty * Loc.t
| Decl_TypeFFI of string * bool * Ident.t * Loc.t
| Decl_Operator1 of unop * Ident.t list * Loc.t
| Decl_Operator2 of binop * Ident.t list * Loc.t
| Decl_Config of Ident.t * ty * expr * Loc.t
Expand Down
2 changes: 1 addition & 1 deletion libISA/isa_fmt.ml
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,7 @@ let declaration ?(short=false) (fmt : PP.formatter) (x : AST.declaration) : unit
ffi_direction is_export
kw_type
nm
ty t
tycon t
| Decl_Operator1 (op, fs, loc) ->
kw_underscore_operator1 fmt;
nbsp fmt;
Expand Down
2 changes: 1 addition & 1 deletion libISA/isa_parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ let ffi_definition :=
"var"; nm=STRINGLIT; "="; v=path; ";";
{ Decl_VarFFI(nm, is_export, v, Range($symbolstartpos, $endpos)) }
| "foreign"; is_export=ffi_direction;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if I do foreign import type "E" = E; (import instead of export) by mistake, will it be simply ignored for now?

"type"; nm=STRINGLIT; "="; t=ty; ";";
"type"; nm=STRINGLIT; "="; t=path; ";";
{ Decl_TypeFFI(nm, is_export, t, Range($symbolstartpos, $endpos)) }

let ffi_parameter_value :=
Expand Down
2 changes: 1 addition & 1 deletion libISA/isa_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ let decl_name (x : declaration) : Ident.t option =
| Decl_FunInstance (f, _, loc) -> Some f
| Decl_FunFFI (nm, is_export, f, _, loc) -> Some f
| Decl_VarFFI (nm, is_export, v, loc) -> Some v
| Decl_TypeFFI (nm, is_export, t, loc) -> None
| Decl_TypeFFI (nm, is_export, t, loc) -> Some t
| Decl_Operator1 (op, vs, loc) -> None
| Decl_Operator2 (op, vs, loc) -> None
| Decl_Config (v, ty, e, loc) -> Some v
Expand Down
6 changes: 3 additions & 3 deletions libISA/isa_visitor.ml
Original file line number Diff line number Diff line change
Expand Up @@ -655,9 +655,9 @@ let visit_decl (vis : isaVisitor) (x : declaration) : declaration =
| Decl_VarFFI (nm, is_export, v, loc) ->
let v' = visit_var vis Definition v in
if v == v' then x else Decl_VarFFI (nm, is_export, v', loc)
| Decl_TypeFFI (nm, is_export, t, loc) ->
let t' = visit_type vis t in
if t == t' then x else Decl_TypeFFI (nm, is_export, t', loc)
| Decl_TypeFFI (nm, is_export, tc, loc) ->
let tc' = visit_var vis Definition tc in
if tc == tc' then x else Decl_TypeFFI (nm, is_export, tc', loc)
| Decl_Operator1 (op, vs, loc) ->
let vs' = mapNoCopy (visit_var vis Definition) vs in
if vs == vs' then x else Decl_Operator1 (op, vs', loc)
Expand Down
12 changes: 9 additions & 3 deletions libISA/tcheck.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3271,9 +3271,13 @@ let tc_declaration (env : GlobalEnv.t) (d : AST.declaration) :
| Decl_VarFFI (nm, is_export, v, loc) ->
let v' = get_var (Env.mkEnv env) loc v in
[ Decl_VarFFI (nm, is_export, v'.name, loc) ]
| Decl_TypeFFI (nm, is_export, t, loc) ->
let t' = tc_type (Env.mkEnv env) loc t in
[ Decl_TypeFFI (nm, is_export, t', loc) ]
| Decl_TypeFFI (nm, is_export, tc, loc) ->
let tc' = GlobalEnv.renameType env tc in
if (tc' = Builtin_idents.sintN) || (GlobalEnv.isTycon env tc') then (
[ Decl_TypeFFI (nm, is_export, tc', loc) ]
) else (
raise (IsNotA (loc, "type constructor", Ident.to_string tc))
)
| Decl_Operator1 (op, funs, loc) ->
let funs' =
List.concat
Expand Down Expand Up @@ -3332,6 +3336,8 @@ let genPrototypes (ds : AST.declaration list) :
| Decl_FunDefn (qid, fty, _, loc) ->
post := d :: !post;
pre := Decl_FunType (qid, fty, loc) :: !pre
| Decl_FunFFI (_, _, _, _, _) ->
post := d :: !post;
| _ -> pre := d :: !pre)
ds;
(List.rev !pre, List.rev !post)
Expand Down
5 changes: 4 additions & 1 deletion tests/backends/ffi_export_00.isa
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// RUN: %aslrun %s --import=FFI_Call128 --export=FFI_Extract128_32 --extra-c=%S/ffi_export_00.c | filecheck %s
// RUN: %aslrun %s --extra-c=%S/ffi_export_00.c | filecheck %s
// Copyright (C) 2025-2026 Intel Corporation

// UNSUPPORTED: interpreter

foreign import function "FFI_Call128" = FFI_Call128 with {};
foreign export function "FFI_Extract128_32" = FFI_Extract128_32 with {};

// Function imported from C
function FFI_Call128(x : Bits(128)) -> Bits(32);

Expand Down
21 changes: 20 additions & 1 deletion tests/backends/ffi_export_01.isa
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
// RUN: %aslrun %s --configuration=%S/ffi_export_01.json --extra-c=%S/ffi_export_01.c | filecheck %s
// RUN: %aslrun %s --extra-c=%S/ffi_export_01.c | filecheck %s
// Copyright (C) 2025-2026 Intel Corporation

// UNSUPPORTED: interpreter

foreign export type "E" = E;
foreign export function "FFI_bits8" = FFI_bits8 with {};
foreign export function "FFI_bits16" = FFI_bits16 with {};
foreign export function "FFI_bits32" = FFI_bits32 with {};
foreign export function "FFI_bits64" = FFI_bits64 with {};
foreign export function "FFI_bits2" = FFI_bits2 with {};
foreign export function "FFI_bits17" = FFI_bits17 with {};
foreign export function "FFI_bits65" = FFI_bits65 with {};
foreign export function "FFI_bits127" = FFI_bits127 with {};
foreign export function "FFI_bits128" = FFI_bits128 with {};
foreign export function "FFI_string" = FFI_string with {};
foreign export function "FFI_E" = FFI_E with {};
foreign export function "FFI_Boolean" = FFI_Boolean with {};
foreign export function "FFI_integer" = FFI_integer with {};
foreign export function "FFI_sint17" = FFI_sint17 with {};
foreign export function "FFI_int_bool" = FFI_int_bool with {};

foreign import function "FFI_test_exports" = FFI_test_exports with {};

enumeration E = { A, B, C };

// to be exported
Expand Down
26 changes: 0 additions & 26 deletions tests/backends/ffi_export_01.json

This file was deleted.

19 changes: 7 additions & 12 deletions tests/backends/ffi_import_00.isa
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
// RUN: %aslrun %s --import=FFI_Invert32 --import=FFI_Invert128 --extra-c=%S/ffi_import_00.c | filecheck %s
// RUN: %aslrun %s --extra-c=%S/ffi_import_00.c | filecheck %s
// Copyright (C) 2025-2026 Intel Corporation

// UNSUPPORTED: interpreter

foreign import function "FFI_Invert32" = FFI_Invert with { size => 32 };
foreign import function "FFI_Invert128" = FFI_Invert with { size => 128 };

// The following functions will be replaced by
// a version that is defined externally.
// Normally, the internal and external version have
// similar behaviour but, for testing purposes, the
// internal version is the identity function
// and the external version inverts its argument.
function FFI_Invert32(x : Bits(32)) -> Bits(32)
begin
return x;
end

function FFI_Invert128(x : Bits(128)) -> Bits(128)
begin
return x;
end
function FFI_Invert(implicit size : {0..}, x : Bits(size)) -> Bits(size);

function main() -> Builtin::Foreign::CInt
begin
Std::Print::Bits::Hex(FFI_Invert32(32'x3)); Print("\n");
Std::Print::Bits::Hex(FFI_Invert(32'x3)); Print("\n");
// CHECK: 32'xfffffffc

Std::Print::Bits::Hex(FFI_Invert128(128'x3)); Print("\n");
Std::Print::Bits::Hex(FFI_Invert(128'x3)); Print("\n");
// CHECK: 128'xfffffffffffffffffffffffffffffffc

return Builtin::Foreign::CInt::From_Integer(0);
Expand Down
Loading