I would personally try cranelift for this. Its goals are around producing executable code quickly rather than optimally, which is pretty much the opposite of llvm. There are lots of things out there that use llvm for jit, but even its jit library layer is pretty heavy and you’ll probably spend more time generating code than you’d like.

That said, cranelift is still experimental.

I haven't used it, but cranelift is also my first thought for this.

If you want a stable interface though, I might use wasm on top of it via wasmtime. I'm not sure how stable the API for wasmtime is, but at least the IR (wasm) is, and there's an ecosystem of tools around it.

https://github.com/bytecodealliance/wasmtime