Add standalone JIT expression compiler [DO NOT MERGE] - #3047
Add standalone JIT expression compiler [DO NOT MERGE]#3047fulmicoton-dd wants to merge 6 commits into
Conversation
| // SAFETY: Same input contract as above. The fixed arena never reallocates, | ||
| // and its new output range starts after any arena-backed input range. | ||
| let input = | ||
| unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(input_ptr, input_len)) }; |
There was a problem hiding this comment.
this code is really dumb...
aba7127 to
4910fad
Compare
| let variable_types: HashMap<&str, VarType> = | ||
| std::iter::once(("my_col", VarType::F64)).collect(); | ||
|
|
||
| let compiled_fn: Arc<CompiledFn> = compile(&untyped_expr, &variable_types)?; |
There was a problem hiding this comment.
I'm missing the point of returning separately a CompiledFnCtx and CompiledFn. In this example the actual .call happens on compiled_fn_ctx and not on compiled_fn. Can CompiledFn be used without being passed to CompiledFnCtx?
There was a problem hiding this comment.
Make function compilation cachable.
It takes a few ms to compile but generally the compilation applies to all splits. (rather we can generate/cache one version per set of column types)
| Literal::I64(value) => InferredTypeSet { | ||
| i64: true, | ||
| u64: *value >= 0, | ||
| f64: (*value as f64) as i128 == *value as i128, |
There was a problem hiding this comment.
I don't really understand this magic of casting a f64 to i128 :)
There was a problem hiding this comment.
I will try to add comments and wrangel the code into something that makes sense.
There was a problem hiding this comment.
with furhter thoughts we don't want that behavior and we want to always accept f64.
Explaining the presence of i128 though.
The question this was trying to answer is given a u64, when can it be translated into f64 in a loss less manner.
By lossless, we do not just mean:
u64 -> f64 -> u64 brings us back to the same value,
we also want to make sure that the f64 value was indeed representing the original u64 value so that
we do not have strange side effect if we did arithmetic in the f64 world.
u64::MAX does NOT map to its value in f64 world, but remaps correctly to u64::MAX due to saturation.
Using u128 make it possible to rule out u64::MAX as having a f64 representation.
There was a problem hiding this comment.
Thanks for the explanation!
There was a problem hiding this comment.
This file is used only in bin/jitexpr-asm, it's not used anywhere else to parse user input.
There was a problem hiding this comment.
good point i will try to isolate it.
There was a problem hiding this comment.
After investigation, the benefit might not be as large as the gain.
(either via feature flag or via creation of a project).
Let's do the separate project if we end up adding some binary specific dependency. Right now this is not the case.
There was a problem hiding this comment.
(right now it has the benefit of offering a good looking Debug/Display. Deserialization is pretty useless though)
| )))] | ||
| compile_error!( | ||
| "the direct VariableValue JIT return ABI is only implemented for x86-64 System V and AArch64" | ||
| ); |
There was a problem hiding this comment.
This #[cfg] does not exclude aarch64-pc-windows-*, I didn't test but I'm expecting it to fail as well.
There was a problem hiding this comment.
yes it is not supported because the ABI does not support returning more than a single word via register. I commented along these lines. If we want to support windows the natural fix would be to change that to passing a destination value pointer as arg.
71cd5a3 to
0f3f25f
Compare
0f3f25f to
10aa21a
Compare
JitExpr is an expression JIT compiler for tantivy.
The goal here is to be able to evaluate dynamically defined predicate over columns.
The compilation goes through different representations:
Function specific logic is isolated in a FnCall trait that offers rails for AI / humans to extend the system
safely and in a uniform manner.
Input and output variable are 16 bytes VariableValue object that are Copy.
Primitive types are using 8 bytes for the value and 8bytes for the bool (alignement)
String are also supposed as Option<&str> and also take 16 bytes.
strings are not manipulated by the cranelift program itself. Instead the program calls native function and
treats them as opaque objects.
Function that return reference to an input string or a literal just return a reference over one or the other.
Function that build string use a string arena as their scratch pad to write their bytes and return a &str
pointing to it.
As a result the return type has a lifetime limited to &self (literal + string arena) and the input lifetime (regex extract for instance).
Use of AI
Most of the function themselves (all but ADD, REGEXP_EXTRACT, LOWER), the unit tests, the serialization format code is isolated and has been coded by LLM with very little review.