Currently, we just hardcode the input and output registers for closures we do partial evaluation on: we tell Cranelift (in lift.rsJit::new) that all functions we compile have the prototype ptr, ptr, int -> int. This means we would miscompile e.g. jit.speedup(|| return (1u64, 2u64) since it wouldn't know that it has to feed the 2 immediate into the output register sink.
We should instead be using mem::size_of<A>() and mem::size_of<O>() to fill out the proper SystemV ABI calling convention for a function that takes and returns arguments of those size. I think this is fairly straightforward - too big arguments/outputs are turned into an argument to a stack buffer to write to, but we should be able to just tell Cranelift that's a ptr afaik since it never optimizes away stores.
Currently, we just hardcode the input and output registers for closures we do partial evaluation on: we tell Cranelift (in
lift.rs
Jit::new
) that all functions we compile have the prototypeptr, ptr, int -> int
. This means we would miscompile e.g.jit.speedup(|| return (1u64, 2u64)
since it wouldn't know that it has to feed the2
immediate into the output register sink.We should instead be using
mem::size_of<A>()
andmem::size_of<O>()
to fill out the proper SystemV ABI calling convention for a function that takes and returns arguments of those size. I think this is fairly straightforward - too big arguments/outputs are turned into an argument to a stack buffer to write to, but we should be able to just tell Cranelift that's a ptr afaik since it never optimizes away stores.