libjit
 
LibJIT is a fairly straightforward, lightweight library for runtime compilation with a simple and stable ABI.

Website: https://www.gnu.org/software/libjit/
Platforms supported: Windows, Linux
Headers to include: jit.bi
Header version: git a8293e141b79c28734a3633a81a43f92f29fc2d7

Native ABI configuration
Use jit_int and jit_uint for C-style 32-bit integer arguments and return storage. jit_nint, jit_nuint and jit_size_t follow the native pointer width. FreeBASIC Integer is not a substitute for jit_int on a 64-bit target.

The native library and binding must agree on jit_nfloat. Windows builds normally use Double. For a library configured with --disable-long-double on another target, define JIT_NFLOAT_IS_DOUBLE before including jit.bi, or compile with -d JIT_NFLOAT_IS_DOUBLE. Match this choice to the installed library's generated C headers, not just its filename.

FreeBASIC's CLongDouble is opaque byte storage. It does not implement C long-double arithmetic or by-value calls, and cannot reproduce a 16-byte-aligned C union in jit_constant_t. Use libjit's double configuration for native-float calls and constant structures on such targets. Changing this configuration requires rebuilding the native library as well as the application.

The upstream x86-64 apply implementation in revision 942c988db170d98061a9e934fb3d7b618b7d5137 uses the System V calling convention. Its Windows 64-bit build fails in the native apply-rules generator. A Win32 library belongs to a Win32 application; it cannot be linked into a Win64 executable.

The same revision has been built and checked natively on Linux amd64 with --disable-long-double and JIT_NFLOAT_IS_DOUBLE. Independent C layouts agree with both FreeBASIC backends; native checks cover signed results, a callback, native-float calls, constant structures and the original multiplication/addition and GCD examples. This is an actual System V build of the upstream JIT.

These examples check context creation, instruction building, compilation and application. A created function keeps its own signature reference, so the caller releases its reference with jit_type_free. Every build-start call is paired with build-end before destroying the context. The GCD example's subtraction algorithm requires positive inputs.

Example

'' examples/manual/libraries/jit/mul_add.bas
''
'' Example extracted from the FreeBASIC Manual
'' from topic 'libjit'
'' Purpose: Compile and call a C-style integer multiply/add function.
'' Responsibilities: Typed arguments, build locking and owned context cleanup.
'' This example contains no persistent machine code or native-float ABI calls.
''
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ExtLibJit
'' --------

'' Simple mul/add example

#include "jit.bi"

' The caller owns the build lock and releases the context on failure.
Function emit_mul_add(ByVal mul_add As jit_function_t) As Integer
    ' build function (result = (x*y)+z)
    Dim As jit_value_t x, y, z, temp1, temp2
    x = jit_value_get_param(mul_add, 0)
    y = jit_value_get_param(mul_add, 1)
    z = jit_value_get_param(mul_add, 2)
    If x = 0 OrElse y = 0 OrElse z = 0 Then Return 0
    temp1 = jit_insn_mul(mul_add, x, y)
    If temp1 = 0 Then Return 0
    temp2 = jit_insn_add(mul_add, temp1, z)
    If temp2 = 0 Then Return 0
    If jit_insn_return(mul_add, temp2) = 0 Then Return 0

    ' compile function
    Return jit_function_compile(mul_add)
End Function

' initialize libjit
Dim context As jit_context_t = jit_context_create()
If context = 0 Then End 1
jit_context_build_start(context)

' define function mul_add(x, y, z)
Dim params(0 To 2) As jit_type_t = {jit_type_int, jit_type_int, jit_type_int}
Dim signature As jit_type_t = jit_type_create_signature( _
    jit_abi_cdecl,  _ ' C-style function
    jit_type_int,   _ ' Return type
    @params(0),     _ ' Parameter array
    3,              _ ' Number of components
    1               _ ' Count references?
)
If signature = 0 Then
    jit_context_build_end(context)
    jit_context_destroy(context)
    End 1
End If
Dim mul_add As jit_function_t = jit_function_create(context, signature)
'' The function retains its own signature reference.
jit_type_free(signature)
If mul_add = 0 Then
    jit_context_build_end(context)
    jit_context_destroy(context)
    End 1
End If

Dim As Integer build_ok = emit_mul_add(mul_add)
jit_context_build_end(context)
If build_ok = 0 Then
    jit_context_destroy(context)
    End 1
End If

' call function
'' jit_type_int is a C int, even when FreeBASIC Integer is 64 bits.
Dim As jit_int a = 3
Dim As jit_int b = 5
Dim As jit_int c = 2
Dim As jit_int result
Dim args(0 To 2) As jit_int Ptr = {@a, @b, @c}
If jit_function_apply(mul_add, @args(0), @result) = 0 Then
    jit_context_destroy(context)
    End 1
End If
Print Using "mul__add(&, &, &) = &"; a; b; c; result

' clean up libjit
jit_context_destroy(context)
'' end of mul_add.bas


'' examples/manual/libraries/jit/gcd.bas
''
'' Example extracted from the FreeBASIC Manual
'' from topic 'libjit'
'' Purpose: Compile a recursive greatest-common-divisor function.
'' Responsibilities: Positive unsigned inputs, build locking and context cleanup.
'' This example contains no arbitrary-input parser or native-float ABI calls.
''
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ExtLibJit
'' --------

'' GCD calculation example

#include "jit.bi"

' The caller owns the build lock and releases the context on failure.
Function emit_gcd(ByVal gcd As jit_function_t) As Integer
    ' build function
    ' check x = y
    Dim As jit_value_t x, y, x_eq_y
    x = jit_value_get_param(gcd, 0)
    y = jit_value_get_param(gcd, 1)
    If x = 0 OrElse y = 0 Then Return 0
    x_eq_y = jit_insn_eq(gcd, x, y)
    If x_eq_y = 0 Then Return 0

    ' if x = y, return x
    Dim label_x_ne_y As jit_label_t = jit_label_undefined
    If jit_insn_branch_if_not(gcd, x_eq_y, @label_x_ne_y) = 0 Then Return 0
    If jit_insn_return(gcd, x) = 0 Then Return 0

    ' else if...
    If jit_insn_label(gcd, @label_x_ne_y) = 0 Then Return 0

    ' check x < y
    Dim As jit_value_t x_lt_y
    Dim label_x_gte_y As jit_label_t = jit_label_undefined
    x_lt_y = jit_insn_lt(gcd, x, y)
    If x_lt_y = 0 Then Return 0
    If jit_insn_branch_if_not(gcd, x_lt_y, @label_x_gte_y) = 0 Then Return 0

    ' if x < y, return gcd(x, y-x)
    Dim As jit_value_t gcd_args(0 To 1), gcd_result
    gcd_args(0) = x
    gcd_args(1) = jit_insn_sub(gcd, y, x)
    If gcd_args(1) = 0 Then Return 0
    gcd_result = jit_insn_call( _
        gcd,          _ ' where we are calling from
        "gcd",        _ ' function name
        gcd,          _ ' function reference
        0,            _ ' signature = auto
        @gcd_args(0), _ ' arguments
        2,            _ ' argument count
        0             _ ' flags = nothing special
    )
    If gcd_result = 0 Then Return 0
    If jit_insn_return(gcd, gcd_result) = 0 Then Return 0

    ' else...
    If jit_insn_label(gcd, @label_x_gte_y) = 0 Then Return 0

    ' return gcd(x-y, y)
    gcd_args(0) = jit_insn_sub(gcd, x, y)
    If gcd_args(0) = 0 Then Return 0
    gcd_args(1) = y
    gcd_result = jit_insn_call( _
        gcd,          _ ' where we are calling from
        "gcd",        _ ' function name
        gcd,          _ ' function reference
        0,            _ ' signature = auto
        @gcd_args(0), _ ' arguments
        2,            _ ' argument count
        0             _ ' flags = nothing special
    )
    If gcd_result = 0 Then Return 0
    If jit_insn_return(gcd, gcd_result) = 0 Then Return 0

    ' compile function
    Return jit_function_compile(gcd)
End Function

' initialize libjit
Dim context As jit_context_t = jit_context_create()
If context = 0 Then End 1
jit_context_build_start(context)

' define function gcd(x as jit_uint, y as jit_uint) as jit_uint
Dim params(0 To 1) As jit_type_t = {jit_type_uint, jit_type_uint}
Dim signature As jit_type_t = jit_type_create_signature( _
    jit_abi_cdecl,  _ ' C-style function
    jit_type_uint,  _ ' Return type
    @params(0),     _ ' Parameter array
    2,              _ ' Number of components
    1               _ ' Count references?
)
If signature = 0 Then
    jit_context_build_end(context)
    jit_context_destroy(context)
    End 1
End If
Dim gcd As jit_function_t = jit_function_create(context, signature)
'' The function retains its own signature reference.
jit_type_free(signature)
If gcd = 0 Then
    jit_context_build_end(context)
    jit_context_destroy(context)
    End 1
End If

Dim As Integer build_ok = emit_gcd(gcd)
jit_context_build_end(context)
If build_ok = 0 Then
    jit_context_destroy(context)
    End 1
End If

' call function
Dim As jit_uint a = 21
Dim As jit_uint b = 14
Dim As jit_uint result
Dim As jit_uint Ptr args(0 To 1) = {@a, @b}
'' The subtraction algorithm needs positive inputs to make progress.
If a = 0 OrElse b = 0 Then
    jit_context_destroy(context)
    End 1
End If
If jit_function_apply(gcd, @args(0), @result) = 0 Then
    jit_context_destroy(context)
    End 1
End If
Print Using "gcd(&, &) = &"; a; b; result

' clean up libjit
jit_context_destroy(context)
'' end of gcd.bas