Julia Pragma Macros

Continuing the discussion from Ifelse vs ternary with tuples:

Julia has a few “pragma macros” already and I agree more would be nice. The current collection, such as @inline and @inbounds/@boundscheck, focus on compiler hints/directives, and @nobranch would be a good addition to that.

I’ve seen some issues suggesting that there’s active work on making the compiler more “pluggable” such that this sort of thing could be provided on a package basis.

I’d love to see a collection of these which function as guarantees of behavior, such that they throw compiler errors if the pragma can’t apply. Things like @typestable as a method annotation, @jumptable for a chained if-statement which throws an error if that chain can’t be turned into a switch or computed goto, and an annotation for array/vector types which asserts that they’ll be composed of the data, no pointers (don’t have a great name for this one, @referencefree can probably be improved upon). @allocationlimit 5 throws an error if that number of allocations is exceeded, I think that should be possible to determine during codegen, at least if we define “compiler can’t put a number on allocations” as failing the test.

Getting Julia to exhibit systems-level performance is a bit of an art form, which it kinda has to be, and it’s a strength of the language that it will do what you ask even when it can’t emit optimal machine code. A consequence of this is that tuned-up code is somewhat fragile to any changes. That’s inherent to the language design space Julia occupies, and it would be nice to have more language-level support for turning performance regressions into errors.

Some of what I want here, maybe all of it, would be easier to provide as an ergonomic set of macros intended for the test suite. Not better imho, the best place to assert that a method is type stable is in the definition of that method, but it would do the job just fine, and I could see it avoiding some compile-time knowledge problems to do it that way.

1 Like

You might like GitHub - JuliaLang/AllocCheck.jl: AllocCheck

2 Likes

FWIW, GitHub - JuliaSIMD/LLVMLoopInfo.jl: Pass loop info to LLVM

1 Like

For the ifelse vs branches example, it will be possible to pass !unpredictable hints to LLVM once we upgrade to LLVM 17, at least via llvmcalls, e.g. FindFirstFunctions.jl/src/FindFirstFunctions.jl at 38b267e7ee2300be553830279943cba8eff7ff1d · SciML/FindFirstFunctions.jl · GitHub
Note: I haven’t tested this yet.

2 Likes

Similar to what I had in mind, yes. It looks like everything is there to add the option for the limit to be some other number than zero.

The difference is that this is something you’d annotate with to see if there are no allocations. Wouldn’t want to leave it there because it wraps the function and checks at runtime.

I’m hoping that the work on refining the compiler will allow more cases where the macro inserts some metadata so that codegen can use it. That would allow for a compile-time fail rather than runtime, and more importantly, passing the check would have no impact on the generated code, it would be a static guarantee that allocations don’t happen or stay below a defined boundary.

I didn’t find the issue relating to this, but there’s one that indicates in-progress work on the compiler to enable more of this sort of thing, which is excellent, more ability to affect compiler internals from a package is less things which have to be built in to the language.