I faced a really bizarre behavior of libjit
library.
My task requires using arrays of long double
. I played around with libjit arrays and found myself being not able to make libjit
work with long double arrays. It seems to work fine with int
, float32
, float64
but not with sys_long_double
or nfloat
.
I have the following example. It's pretty straightforward. There is one function that takes an argument x
, puts it into array[0]
and returns array[0]
(that is basically equal to x
).
#include <stdio.h>
#include <jit/jit.h>
// Text replacement float64 -> nfloat, and it doesn't work anymore.
int main(int argc, char **argv)
{
jit_context_t context;
jit_type_t params[1];
jit_type_t signature;
jit_function_t function;
jit_value_t x;
/* Create a context to hold the JIT's primary state */
context = jit_context_create();
/* Lock the context while we build and compile the function */
jit_context_build_start(context);
/* Build the function signature */
params[0] = jit_type_float64;
signature = jit_type_create_signature
(jit_abi_cdecl, jit_type_float64, params, 1, 1);
/* Create the function object */
function = jit_function_create(context, signature);
/* Construct the function body */
x = jit_value_get_param(function, 0);
jit_value_t size = jit_value_create_nint_constant(function, jit_type_int, 256);
jit_value_t res = jit_insn_alloca(function, size);
jit_value_t i = jit_value_create_nint_constant(function, jit_type_int, 0);
jit_insn_store_elem(function, res, i, x);
jit_value_t answer = jit_insn_load_elem(function, res, i, jit_type_float64);
jit_insn_return(function, answer);
/* Compile the function */
jit_function_compile(function);
/* Unlock the context */
jit_context_build_end(context);
/* Execute the function and print the result */
jit_float64 arg1;
void *args[1];
jit_float64 result;
arg1 = 3.0;
args[0] = &arg1;
jit_function_apply(function, args, &result);
printf("answer = %Lf\n", (long double)result);
/* Clean up */
jit_context_destroy(context);
/* Finished */
return 0;
}
My Makefile:
app: app.c
gcc $< -ljit -lpthread -lm -ldl -o $@
The example above works well and produces:
vagrant@jits-host:/vagrant$ make
gcc app.c -ljit -lpthread -lm -ldl -o app
vagrant@jits-host:/vagrant$ ./app
answer = 3.000000
But once I replace float64
with nfloat
or sys_long_double
, it doesn't work anymore. Moreover, it prints some strange debugging stuff.
After replacement:
#include <stdio.h>
#include <jit/jit.h>
int main(int argc, char **argv)
{
jit_context_t context;
jit_type_t params[1];
jit_type_t signature;
jit_function_t function;
jit_value_t x;
/* Create a context to hold the JIT's primary state */
context = jit_context_create();
/* Lock the context while we build and compile the function */
jit_context_build_start(context);
/* Build the function signature */
params[0] = jit_type_nfloat;
signature = jit_type_create_signature
(jit_abi_cdecl, jit_type_nfloat, params, 1, 1);
/* Create the function object */
function = jit_function_create(context, signature);
/* Construct the function body */
x = jit_value_get_param(function, 0);
jit_value_t size = jit_value_create_nint_constant(function, jit_type_int, 256);
jit_value_t res = jit_insn_alloca(function, size);
jit_value_t i = jit_value_create_nint_constant(function, jit_type_int, 0);
jit_insn_store_elem(function, res, i, x);
jit_value_t answer = jit_insn_load_elem(function, res, i, jit_type_nfloat);
jit_insn_return(function, answer);
/* Compile the function */
jit_function_compile(function);
/* Unlock the context */
jit_context_build_end(context);
/* Execute the function and print the result */
jit_nfloat arg1;
void *args[1];
jit_nfloat result;
arg1 = 3.0;
args[0] = &arg1;
jit_function_apply(function, args, &result);
printf("answer = %Lf\n", (long double)result);
/* Clean up */
jit_context_destroy(context);
/* Finished */
return 0;
}
The result:
vagrant@jits-host:/vagrant$ make
gcc app.c -ljit -lpthread -lm -ldl -o app
vagrant@jits-host:/vagrant$ ./app
TODO(19b) at jit-rules-x86-64.c, 3194
answer = 0.000000
What am I missing? Should I compile it in some different way?
One important note: it looks like the types of arg1
and result
are really important. When I use float32
, they must be float
or jit_float32
. When I use float64
, they must be double
or jit_float64
. I expected absolutely the same when using nfloat
or sys_long_double
. Their sizes are 16 bytes. I tried to make arg1
and result
both long double
and jit_nfloat
. But it doesn't work as you could see from the output above.
What is the reason behind it? What do I do wrong?