Skip to content

Support Direct Linking #324

@stmonty

Description

@stmonty

Direct Linking

We want to support direct linking Jank modules for more efficient function invocation. In Jank, function's are called through their vars, but with direct linking this indirection will be removed for the module that was compiled with the direct linking optimization.

The removal of this indirection will increase the efficiency of the compiled module. Compiling Jank's clojure.core will be a good example of a module that can gain speed improvements through direct linking.

Drawback

The main drawback of direct linking is that it limits the dynamic nature of Jank as redefining a var won't automatically change all the call-sites to use the new var. This can be mitigated by marking a var with ^:dynamic or ^:redef but this use case won't be supported for now.

Implementation Plan

The plan is to add a new compilation flag -fdirect-linking that when set would change the IR generation.

The main IR functions that are currently used are jank_deref for derefing the var to get the function ptr and then performing jank_call with the function pointer and arguments.

How it looks now:

define ptr @clojure_core_add_7604_2(ptr %a, ptr %b) {
entry:
  %0 = load ptr, ptr @var_clojure.core_SLASH__PLUS_, align 8
  %1 = call ptr @jank_deref(ptr %0)
  %2 = call ptr @jank_call2(ptr %1, ptr %a, ptr %b)
  ret ptr %2
}

The idea would be to simplify this by not requiring the loading of the var and the need to dereference it. Instead we would still have a global var and a single dereference to get the function pointer and use the function pointer directly in the call. This will be the first pass.

The IR would then look like this, with @0 representing the global derefed function pointer:

define ptr @clojure_core_add_7604_2(ptr %a, ptr %b) {
entry:
  %0 = call ptr @jank_call2(ptr @0, ptr %a, ptr %b)
  ret ptr %0
}

For non-variadic functions, at compile time, all the call-sites for a function will be replaced with the static call to the function pointer. The var will still exist in the global namespace map. Variadic functions will still use a call to jank_call<n>.

For non-variadic functions, the IR would then look like this at the function call site:

define ptr @clojure_core_add_7604_2(ptr %a, ptr %b) {
entry:
  %0 = call ptr @clojure_core__PLUS__1234_2(ptr %a, ptr %b)
  ret ptr %0
}

Metadata

Metadata

Assignees

Labels

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions