{"id":16937282,"url":"https://github.com/copy/lowcaml","last_synced_at":"2025-04-11T19:08:50.548Z","repository":{"id":154477772,"uuid":"623411583","full_name":"copy/lowcaml","owner":"copy","description":"An experimental OCaml-to-C compiler for type-safe accesss to SIMD (unreleased)","archived":false,"fork":false,"pushed_at":"2024-01-25T01:37:09.000Z","size":118,"stargazers_count":16,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-25T15:01:41.429Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/copy.png","metadata":{"files":{"readme":"readme.md","changelog":"changes.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-04T10:15:09.000Z","updated_at":"2024-02-03T10:26:36.000Z","dependencies_parsed_at":"2024-01-25T01:43:41.027Z","dependency_job_id":"371e9781-57b5-421c-b964-3339f151d2bb","html_url":"https://github.com/copy/lowcaml","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/copy%2Flowcaml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/copy%2Flowcaml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/copy%2Flowcaml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/copy%2Flowcaml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/copy","download_url":"https://codeload.github.com/copy/lowcaml/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248465313,"owners_count":21108244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T20:59:13.617Z","updated_at":"2025-04-11T19:08:50.529Z","avatar_url":"https://github.com/copy.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"Lowcaml is an experimental OCaml-to-C compiler. It generates C files as well as\nthe corresponding OCaml bindings. Its primary goal is writing typesafe SIMD\ncode, but it can also be used to accelerate simple OCaml code and create\nbindings to C libraries.\n\nThe following features are supported:\n- built-in OCaml types (`int`, `int32`, `int64`, `unit`, `bool`, `char`, `string`, `bytes` and `Bigarray.Array1.t`)\n- a subset of the OCaml standard library, mostly functions on the above types that don't allocate\n- top-level functions\n- for and while loops\n- if-else expressions\n- let bindings (currently only directly below functions)\n- externals, which call external C functions directly\n- calling other lowcaml functions\n- some libc types\n- stack-allocated `int` (like OCaml's `ref`), currently called `int Mut.t`\n- generating `#include` using `[@@@include \"header\"]`\n\nThe following features are *not* supported, but *may* be supported in the future:\n- C array, struct, enum, union, typedef or bindings to types from external libraries\n- `static` (non-exported) C functions\n- stack-allocated values\n- OCaml variants, records, tuples\n- `ref` and `array` values\n- bytecode stubs\n- bounds checks\n- sub-modules\n- named and optional parameters\n- match expressions\n- top-level constants\n- string literals\n- a pure OCaml implementation of `Lowcaml_stdlib` (for jsoo support)\n\nThe following features are *not* supported, and are out of scope for the project:\n- allocating from lowcaml or calling into the OCaml runtime: All functions generated by lowcaml are marked `[@@noalloc]`\n- closures, partial application, exceptions or effects\n- cross-platform SIMD bindings (but could be implemented as a third-party library)\n- complete libc bindings\n- 32-bit platforms\n- any particular support for shared memory parallelism\n\nA subset of the OCaml stdlib, as well as some libc and SIMD methods are\nexposed. You can browse the interface (wip):\n[`lowcaml_stdlib.mli`](lowcaml_stdlib.mli).\n\nCurrently, only OCaml 5.0 is supported.\n\n\nUsage\n-----\n\nDune users can use this library by vendoring it in their project. opam users\ncan run `dune install` which will install `lowcaml.exe` in their current opam\nswitch.\n\nYou will need a custom rule that invokes `lowcaml.exe` and a library with C\nstubs. In the following, `my_stubs_lowcaml.ml` is the input while `lstubs.ml` and\n`cstubs.c` are generated files. Dune users can use something similar to this:\n\n```\n(rule\n (targets lstubs.ml cstubs.c)\n (deps my_stubs_lowcaml.ml)\n (action (run lowcaml.exe -source my_stubs_lowcaml.ml -o-ml lstubs.ml -o-c cstubs.c)))\n\n(library\n (name lstubs)\n (modules lstubs)\n (foreign_stubs\n  (language c)\n  (names cstubs)\n  (flags\n   :standard\n   -Wall -Wpedantic -Wconversion -Werror\n   -mavx2 ; Note: for SIMD instructions, requires x86_64 with AVX2\n   )))\n```\n\nMerlin is supported by defining a dummy library. Dune users can use the\nfollowing library stanza and run `dune build lowcaml_test_dummy.cma`.\n\n```\n(library\n (name lowcaml_merlin_dummy)\n (modules my_stubs_lowcaml)\n (libraries lowcaml.stdlib)\n (flags :standard -nopervasives -open Lowcaml_stdlib))\n```\n\n\nExamples\n--------\n\nAn implementation of [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes):\n\n```ocaml\nlet sieve b =\n  let len = Bytes.length b in\n  for i = 2 to len - 1 do\n    if Bytes.get_uint8 b i = 0 then (\n      let j = Mut.int (2 * i) in\n      while !j \u003c len do\n        Bytes.set_uint8 b !j 1;\n        j := !j + i;\n      done\n    )\n  done\n```\n\n```c\n// generated by lowcaml\nvoid sieve(const value b)\n{\n    const int64_t len = (int64_t)caml_string_length(b);\n    const int64_t upto = (len-1);\n    for(int64_t i = 2; (i\u003c=upto); (i+=1))\n    {\n        if((*(uint8_t*)\u0026Byte(b, i)==0))\n        {\n            int64_t j = (2*i);\n            while((j\u003clen))\n            {\n                (*(uint8_t*)\u0026Byte(b, j)=(uint8_t)1);\n                (j=(j+i));\n            }\n        }\n    }\n}\n```\n\nA SIMD-based fill32 for `Bytes.t`:\n\n```ocaml\nlet simd_fill32 b x =\n  let i = Mut.int 0 in\n  let len = Bytes.length b in\n  let x = SIMD._mm256_set1_epi32 x in\n  while !i \u003c len do\n    SIMD._mm256_storeu_si256 (Ptr.offset (Ptr.bytes b) !i) x;\n    i := !i + 32;\n  done\n```\n\n```c\n// generated by lowcaml\nvoid simd_fill32(const value b, const int32_t x)\n{\n    int64_t i = 0;\n    const int64_t len = (int64_t)caml_string_length(b);\n    const __m256i x_1 = _mm256_set1_epi32(x);\n    while((i\u003clen))\n    {\n        _mm256_storeu_si256((void*)((uint8_t*)(void*)Bytes_val(b)+i), x_1);\n        (i=(i+32));\n    }\n}\n```\n\nSee also [`tests/test_lowcaml.ml`](tests/test_lowcaml.ml). This section will be\nexpanded.\n\n\nTechnical details\n-----------------\n\nLowcaml generates C code from the typedtree representation in the OCaml\ncompiler. Since typedtree is not a public API and can change significantly\nbetween OCaml versions, we suggest checking the output into your code\nrepository. Lowcaml tries to generate readable C code, preserving variable\nnames and proper indentation.\n\nLowcaml is somewhat more type-safe than writing C code directly:\n- all casts are explicit, thanks to OCaml's stricter type system\n- bindings to the generated C code are generated\n- externals generate a C declaration, which is checked by the C compiler to match the header\n\nLowcaml relies on integer overflow and aliasing being defined behaviour, as\nenabled by the `-fno-strict-aliasing -fwrapv` flags. These flags are\nautomatically included by the OCaml compiler for all C stubs.\n\nOCaml types are mapped to C types in the following places:\n\n- let bindings (as the type that appears in the variable C declaration)\n- parameters and return types of OCaml functions (which become C functions)\n- parameters and return types of OCaml externals (which become C function declarations)\n\nThe mapping is as follows:\n\n| OCaml type                    | C type            | let | arg | ret | ext | Notes                                                                  |\n|-------------------------------|-------------------|-----|-----|-----|-----|------------------------------------------------------------------------|\n| `unit`                        | `value` or `void` |  X  |  X  |  X  |  X  | `value` in arguments of lowcaml functions, `void` otherwise            |\n| `int`                         | `int64_t`         |  X  |  X  |  X  |  X  | note: larger than OCaml's built-in `int`                               |\n| `int64`                       | `int64_t`         |  X  |  X  |  X  |  X  |                                                                        |\n| `int32`                       | `int32_t`         |  X  |  X  |  X  |  X  |                                                                        |\n| `bool`                        | `bool`            |  X  |  X  |  X  |  X  | generates conversion stub if used in param or return                   |\n| `char`                        | `char`            |  X  |  X  |  X  |  X  | generates conversion stub if used in param or return                   |\n| `bytes`                       | `value`           |  X  |  X  |  X  |     |                                                                        |\n| `string`                      | `value`           |  X  |  X  |  X  |     |                                                                        |\n| `Bigarray.Array1.t`           | `value`           |  X  |  X  |  X  |     | only `Bigarray.C_layout`                                               |\n| `int Lowcaml_stdlib.Mut.t`    | `int` or `int*`   |  X  |     |     |     | stack-allocated, memory-safe, not lifetime-safe, similar to `int ref`  |\n| `Lowcaml_stdlib.Ptr.t`        | `void*`           |  X  |     |     |  X  | unsafe, primarily for calling external C functions                     |\n| `Lowcaml_stdlib.Const_ptr.t`  | `const void*`     |  X  |     |     |  X  | unsafe, primarily for calling external C functions                     |\n| `Lowcaml_stdlib.Uint8_t.t`    | `uint8_t`         |  X  |     |     |  X  | primarily for calling external C functions                             |\n| `Lowcaml_stdlib.Uint64_t.t`   | `uint64_t`        |  X  |     |     |  X  | primarily for calling external C functions                             |\n| `Lowcaml_stdlib.SIMD.__m128i` | `__m128i`         |  X  |     |     |  X  | x86 only, will likely be moved out of stdlib                           |\n| `Lowcaml_stdlib.SIMD.__m256i` | `__m256i`         |  X  |     |     |  X  | x86 only, will likely be moved out of stdlib                           |\n\nAll C types, except for `Lowcaml_stdlib.Mut.t`, are marked as `const`.\n\n\nRelated projects\n----------------\n\n- [\"Generating low-level code from a higher-level\n  language\"](https://okmij.org/ftp/meta-programming/tutorial/genc.html),\n  [\"Mutable Variables and Reference Types: L-values demystified and\n  deprecated\"](https://okmij.org/ftp/meta-programming/mutable-var.html), a\n  major inspiration for this project. Lowcaml's `Mut.t` is uses this\n  compilation scheme.\n- [ocaml-ctypes](https://github.com/yallop/ocaml-ctypes), while lowcaml can be\n  used to write some bindings to C libraries, its primary goal is writing SIMD\n  code. ocaml-ctypes is a more complete and stable project for writing\n  bindings.\n- [KaRaMeL](https://github.com/FStarLang/karamel), an F*-to-C compiler. More\n  low-level than lowcaml, with a focus on correctness proofs.\n- [OCaml inline assembly](https://github.com/ocaml/ocaml/pull/162), a\n  (rejected) pull request to the OCaml with support for inline assembly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcopy%2Flowcaml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcopy%2Flowcaml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcopy%2Flowcaml/lists"}