3 ms·
A Case for a Native Runtime Compilation Language
- PhilipVinc 5y agoIsn’t this roughly what Julia does?
- brrrrrm 5y agoyes! Julia does compile this way. Julia emphasizes JIT compilation based on runtime types rather than runtime values. I couldn't get runtime captures to work, e.g. a = 2 function f(n) return n * a end println(f(4)) @code_llvm f(4) @code_native f(4)
- eigenspace 5y agoThat's because defining `a = 2` at the top level is a global constant, which can be changed at any time. Hence, the compiler can't optimize it out. If you tell the compiler it's a `const` though, it'll indeed do the optimization you were hoping for const a = 2 f(n) = n * a julia> @code_llvm f(4) ; @ REPL[2]:1 within `f' define i64 @julia_f_290(i64 signext %0) { top: ; @ REPL[2]:2 within `f' ; ┌ @ int.jl:88 within `*' %1 = shl i64 %0, 1 ; └ ret i64 %1 } julia> @code_native f(4) .text ; ┌ @ REPL[2]:2 within `f' ; │┌ @ int.jl:88 within `*' leaq (%rdi,%rdi), %rax ; │└ retq nopw %cs:(%rax,%rax) ; └
- eigenspace 5y agoJulia does this. The only caveat is that if you write function foo(a, xs) function bar(b) b * a end res = 0 for x in xs res += bar(x) end res end what the author desires (the lifting of a to a compile time constant) won't happen automatically because compiling a new bar for every value of a is going to be a bad idea unless the loop over xs takes longer than compiling a function. Hence, we make people 'opt-in' to this by lifting a from a runtime variable to a type parameter (julia types are parametric and their parameters can contain values). Hence, one way to do this would be to write foo(a, xs) = foo(Val{a}, xs) function foo(::Type{Val{a}}, xs) where {a} function bar(b) b * a end res = 0 for x in xs res += bar(x) end res end Now, when you run foo(2, v) (where v is some iterable), this will turn into foo(Val{2}, v) which then gets specialized on the type parameter {2}, and then can compile a new bar function that's aware of the value of a. Here's an example at the repl where we can inspect the generated code more easily: julia> f(a) = f(Val{a}) f (generic function with 1 method) julia> function f(::Type{Val{a}}) where {a} function g(b) b * a end end f (generic function with 2 methods) julia> g1 = f(1) (::var"#g#4"{1}) (generic function with 1 method) julia> @code_llvm debuginfo=:none g1(4) define i64 @julia_g_442(i64 signext %0) { top: ret i64 %0 } julia> g2 = f(2) (::var"#g#4"{2}) (generic function with 1 method) julia> @code_llvm debuginfo=:none g2(4) define i64 @julia_g_444(i64 signext %0) { top: %1 = shl i64 %0, 1 ret i64 %1 } Notice that g1 and g2 have different optimizations applied that depend on the different runtime values of a.
- daly 5y agoLisp?