Access to libmvec from MLIR

Hi,

is there currently a way to access functions from libmvec (GLIBC vector math library) from MLIR?

Concretely, I have some uses of std.exp and std.log operating on vectors (e.g. vector<4xf64>) in MLIR, which get lowered to the intrinsic @llvm.exp.v4f64 when converting the MLIR module to LLVM IR. However, the generated assembly seems to not use vectorized implementations of these functions, but extracts each element from the vector, calls exp on it and inserts the element back into the vector.

LLVM recently gained support for libmvec (https://reviews.llvm.org/D88154). Is there any option to automatically lower the std.exp operating on 1D-vectors to the equivalent function from libmvec during the lowering to LLVM dialect or LLVM IR (e.g. through some option)?

Alternatively, is there any pass that would replace the call to the LLVM intrinsic with calls to libmvec in LLVM IR? The combination of -inject-tli-mappings -loop-vectorize mentioned in https://reviews.llvm.org/D88154 only inserts the attributes, but does not touch the existing LLVM intrinsics.

Thanks in advance!

Lukas

MLIR will convert std ops to llvm dialect ops according to its conversion patterns. For the two ops in question, it will convert them to the llvm dialect ops that correspond to LLVM IR intrinsics. How LLVM choses to handle those intrinsics is out of MLIR’s control, you’ll likely get a better answer on llvm-dev.

That being said, we can consider converting relevant std ops to std.call targeting library functions directly in MLIR. This will require a new pass, and potentially some additional plumbing to give functions the same amount of optimization-related metadata as LLVM.

Hi @ftynse,

thanks for your feedback & help!

Would it also be an option to add the insertion of calls to libmvec (and similar libraries, e.g. Intel SVML) into the translation between LLVM dialect and the actual LLVM IR? The ops from the LLVM dialect, that correspond to the intrinsics and match one of the functions of libmvec (vector-size etc.) would then be translated into the libmvec calls instead of calls to the “generic” LLVM intrincis.

Which of the two implementations (pass on MLIR std/llvm dialect vs. part of the translation to LLVM IR) would you consider preferable?

Thanks,
Lukas

I am quite opposed to doing non-trivial transformations in the LLVM dialect to LLVM IR translation. It is complicated enough because it needs to handle the fundamental differences between two IRs (nested modules, phi values, globals, thread safety), and adding complexity to the level that produces LLVM IR sounds contrary to one of the core ideas of MLIR – progressive lowering.

The way you describe it, I would suggest this transformation to be performed on LLVM IR proper, as a pass that transforms intrinsic function calls into library function calls. Pipelines coming from MLIR will be able to use it and so will be other pipelines that don’t use MLIR.

Building it as an std to std dialect transformation pass would I think be a modular way to do this as @ftynse suggests above – slightly better than implementing this as an MLIR LLVM dialect pass as those library calls are really not connected to LLVM.

1 Like

@ftynse, @bondhugula thanks for your feedback!

I’ve asked on the llvm-dev mailing list if there’s already such as pass (doesn’t seem to be the case) and if it would be interesting to have such a pass.

@bondhugula: I see your point that having this as an std to std transform would make it reusable for other targets and you’re right, libmvec (and others, such as Intel SVML) are not bound directly to LLVM. Did you have a specific target in mind that could also use this pass? AFAIK, libmvec is limited to CPU right now (correct me if I’m wrong here).

Implementing it as an LLVM IR pass on the other would allow to reuse the existing TargetLibraryInfo infrastructure for the pass.

None in my mind, but there are likely others.