Math instructions

Hello,

I'm currently adding the floating point math instructions (fabs, fsin, fcos ...) to the x86 instruction set. I'm a bit unsure how to make the back end actually generate these instructions, though. My current plan is to add llvm intrinsics for these instructions but I've noticed that llvm already handles C math library functions to some extent. It feels a bit strange to add code for example to constant fold these intrinsics when there is already code to constant fold a calls to libmath functions -- but the libmath functions have certain semantics regarding how errno is set which I don't really want to deal with.

Other compilers have options to enable the direct use of fp instructions for math operations (gcc has -fno-math-errno, -funsafe-math-optimizations and -fno-trapping-math), this could be useful also for LLVM. Assuming there is such an option, should I modify the visitCallInst function to generate machine instructions directly for calls to math functions or is it better to include a pass which converts the calls into intrinsics? An advantage of the second solution is that it makes it easier for other front ends (like ours) which don't have the semantics of libmath to generate code...

Awaiting feedback,

m.

I'm currently adding the floating point math instructions (fabs, fsin, fcos ...) to the x86 instruction set.

Cool!

I'm a bit unsure how to make the back end actually generate these instructions, though. My current plan is to add llvm intrinsics for these instructions but I've noticed that llvm already handles C math library functions to some extent. It feels a bit strange to add code for example to constant fold these intrinsics when there is already code to constant fold a calls to libmath functions -- but the libmath functions have certain semantics regarding how errno is set which I don't really want to deal with.

The way to deal with this is to add LLVM intrinsics, but only for functions that set errno. For example, you could add llvm.sqrt, which is just undefined on a negative value other than -0.0. For your uses, you just emit llvm.sqrt, the C frontend will make use of it and wrap errno handling around it as required.

For functions like sin/cos/etc, which do not set errno, you should be able to recognize an external function with that name and generate code for it.

Other compilers have options to enable the direct use of fp instructions for math operations (gcc has -fno-math-errno, -funsafe-math-optimizations and -fno-trapping-math), this could be useful also for LLVM.

Yes, but this is really a separate issue, at least initially.

Assuming there is such an option, should I modify the visitCallInst function to generate machine instructions directly for calls to math functions or is it better to include a pass which converts the calls into intrinsics? An advantage of the second solution is that it makes it easier for other front ends (like ours) which don't have the semantics of libmath to generate code...

The X86 visitCall should just handle any functions like sin/cos that can be directly codegen'd into machine code. For intrinsics you add, like llvm.sqrt, we should have code in the LowerIntrinsics code to lower it to a call to sqrt (for code generators that do not support it), but the X86 backend and many others could support it natively.

Finally, for fabs, we should just be able to recognize the setcc/select pair and generate that instruction.

-Chris

Chris Lattner wrote:

The way to deal with this is to add LLVM intrinsics, but only for functions that set errno. For example, you could add llvm.sqrt, which is just undefined on a negative value other than -0.0. For your uses, you just emit llvm.sqrt, the C frontend will make use of it and wrap errno handling around it as required.

For functions like sin/cos/etc, which do not set errno, you should be able to recognize an external function with that name and generate code for it.

Is this really safe? If you don't include math.h and don't link with the math library you're free to define sin/cos/etc any way you like, aren't you?

Finally, for fabs, we should just be able to recognize the setcc/select pair and generate that instruction.

the C math library has abs and absf, so it's easier to recognize the function calls. Of course the previous comment also applies to this...

- for now I've just implemented all of them as llvm.xxx intrinsics, but I'm a bit unsure how to lower these if the target does not support them and the program does not link with libmath... Maybe I worry too much :wink:

m.

Chris Lattner wrote:

The way to deal with this is to add LLVM intrinsics, but only for functions that set errno. For example, you could add llvm.sqrt, which is just undefined on a negative value other than -0.0. For your uses, you just emit llvm.sqrt, the C frontend will make use of it and wrap errno handling around it as required.

For functions like sin/cos/etc, which do not set errno, you should be able to recognize an external function with that name and generate code for it.

Is this really safe? If you don't include math.h and don't link with the math library you're free to define sin/cos/etc any way you like, aren't you?

No, not for C programs at least. In C, all standard C and math library function names are reserved.

Finally, for fabs, we should just be able to recognize the setcc/select pair and generate that instruction.

the C math library has abs and absf, so it's easier to recognize the function calls. Of course the previous comment also applies to this...

The problem there is that these functions are inline functions that expand to the select/setcc pair. For this testcase:

#include <math.h>
double test1(double X) { return fabs(X); }
float test2(float X) { return fabsf(X); }

llvm-gcc compiles it to:

double %test1(double %X) {
         %comp = setge double %X, 0.000000e+00
         %abs.pos = sub double 0.000000e+00, %X
         %abs.1 = select bool %comp, double %X, double %abs.pos
         ret double %abs.1
}

float %test2(float %X) {
         %comp = setge float %X, 0.000000e+00
         %abs.pos = sub float 0.000000e+00, %X
         %abs.1 = select bool %comp, float %X, float %abs.pos
         ret float %abs.1
}

... so i won't help the C front-end at least. If you want to add support for fabs and fabsf as calls, I can implement the pattern matching for the forms above someday.

- for now I've just implemented all of them as llvm.xxx intrinsics, but I'm a bit unsure how to lower these if the target does not support them and the program does not link with libmath... Maybe I worry too much :wink:

Yeah, I would worry about this one too much for now.

-Chris