Why is usage of llvmcall so restricted?

Evaluation of millions of different mathematical expressions that are generated at runtime. There are various approaches, one constraint I care about is writing the output of every node in the expression to a vector. In polish notation, the output of the expression [*, squared, x, y] could be [16, 4, 2, 4] for instance. Here you would do for loops, which is nice and fast, but you lose some type information (and therefore speed) by needing abstract type Function. Things can be made fully static using approaches like [ANN] New package: CallableExpressions v1.0.0, where all of the expression goes into the type parameters of your structs. Super-fast to evaluate, but very slow to compile, ~100ms for a medium size one, which makes millions of expressions untenable. Not to mention exploding method tables. These math expressions are unlikely to be used again so I’d love to know how to avoid them being stored in the method table.

So, the LLVM IR for the individual functions is easy. And I thought to just squish it together to make different expressions possible, thereby getting the good performance but hopefully avoiding some compile time. I got it to work, but hit the problem in my original post. Runtime generated functions avoid the dynamic problem, but seem to add more compile overhead.

That just means llvmcall is the wrong approach, but the general gist is that in the chain julia code -> lowered -> typed -> llvm -> native, we could maybe avoid some compile overhead if we attack later in the chain. You’re right about the string parsing, there is probably another object (CodeInfo?) that is less intensive to get LLVM IR out of.