[llvm-dev] [RFC][VECLIB] how should we legalize VECLIB calls?

Saito, Hideki via llvm-dev llvm-dev at lists.llvm.org
Thu Jun 28 19:11:05 PDT 2018

Illustrative Example:

clang -fveclib=SVML -O3 svml.c -mavx

#include <math.h>
void foo(double *a, int N){
  int i;
#pragma clang loop vectorize_width(8)
  for (i=0;i<N;i++){
    a[i] = sin(i);

Currently, this results in a call to <8 x double> __svml_sin8(<8 x double>) after the vectorizer.
This is 8-element SVML sin() called with 8-element argument. On the surface, this looks very good.
Later on, standard vector type legalization kicks-in but only the argument and return data are legalized.
        vmovaps %ymm0, %ymm1
        vcvtdq2pd       %xmm1, %ymm0
        vextractf128    $1, %ymm1, %xmm1
        vcvtdq2pd       %xmm1, %ymm1
        callq   __svml_sin8
        vmovups %ymm1, 32(%r15,%r12,8)
        vmovups %ymm0, (%r15,%r12,8)
Unfortunately, __svml_sin8() doesn't use this form of input/output. It takes zmm0 and returns zmm0.
i.e., not legal to use for AVX.

What we need to see instead is two calls to __svml_sin4(), like below.
        vmovaps %ymm0, %ymm1
        vcvtdq2pd       %xmm1, %ymm0
        vextractf128    $1, %ymm1, %xmm1
        vcvtdq2pd       %xmm1, %ymm1
        callq   __svml_sin4
        vmovups %ymm0, 32(%r15,%r12,8)
        vmovups %ymm1, ymm0
        callq   __svml_sin4
        vmovups %ymm0, (%r15,%r12,8)

What would be the most acceptable way to make this happen? Anybody having had a similar need previously?

Easiest workaround is to serialize the call above "type legal" vectorization factor. This can be done with a few lines of code,
plus the code to recognize that the call is "SVML" (which is currently string match against "__svml" prefix in my local workspace).
If higher VF is not forced, cost model will likely favor lower VF. Functionally correct, but obviously not an ideal solution.

Here are a few ideas I thought about:

1)      Standard LegalizeVectorType() in CodeGen/SelectionDAG doesn't seem to work. We could define a generic ISD::VECLIB
and try to split into two or more VECLIB nodes, but at that moment we lost the information about which function to call.
We can't define ISD opcode per function. There will be too many libm entries to deal with. We need a scalable solution.

2)      We could write an IR to IR pass to perform IR level legalization. This is essentially duplicating the functionality of LegalizeVectorType()
but we can make this available for other similar things that can't use ISD level vector type legalization. This looks to be attractive enough
from that perspective.

3)      We have implemented something similar to 2), but legalization code is specialized for SVML legalization. This was much quicker than
trying to generalize the legalization scheme, but I'd imagine community won't like it.

4)      Vectorizer emit legalized VECLIB calls. Since it can emit instructions in scalarized form, adding legalized call functionality is in some sense
similar to that. Vectorizer can't simply choose type legal function name with illegal vector ---- since LegalizeVectorType() will still
end up using one call instead of two.

Anything else?

Also, doing any of this requires reverse mapping from VECLIB name to scalar function name. What's the most recommended way to do so?
Can we use TableGen to create a reverse map?

Your input is greatly appreciated. Is there a real need/desire for 2) outside of VECLIB (or outside of SVML)?

Hideki Saito
Intel Corporation

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20180629/298d24ac/attachment.html>

More information about the llvm-dev mailing list