[llvm-commits] [llvm-gcc-4.2] r55796 - /llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp

Duncan Sands baldrick at free.fr
Tue Sep 9 01:07:28 PDT 2008


> > Hi Dale, thinking about this more, I started wondering
> > why you want to produce llvm.pow and friends at all.
> > Does it actually bring any advantage?
> 
> Functionally, no, the point is to get C semantics out of the optimizers.

Well, given that you have several versions of each routine
(eg: pow that writes errno, pow that does not write errno
but uses the rounding mode, pow that does not write errno
and does not use the rounding mode), that makes for a lot
of intrinsics!  Don't forget that SimplifyLibcalls performs
simplifications that apply to all those different pow variants.

That said, I think it is useful to distinguish between
SimplifyLibcalls (SLC) and the rest of the compiler.
The SLC pass is special in that it only exists to muck
around with the standard system library, so it's not
unreasonable that it recognizes standard library functions.
It can always be turned off (llvm-gcc has logic for that).

So, excluding SLC, what about the rest of the compiler?

Well, ConstantFolding.cpp will constant fold a range of
libcalls too.  That's not so great - something should be
done about this (not sure what).  Probably llvm-gcc's
logic should turn this off too, but it currently doesn't...

The other place is codegen:
SelectionDAGBuild.cpp turns several things into SDNodes:
not just pow and cos intrinsics but also functions called
"cos".  Two comments about this: (1) it implies that the
llvm intrinsics must be readnone and not readonly; (2) I
think the recognizing of names like "sin" should be dropped
and only intrinsics used here (this is maybe what you had in
mind). Let me explain (1): why an SDNode shouldn't be generated
unless the function is readnone.  Consider the following
program:

declare double @cos( double ) readonly nounwind
declare void @change_the_rounding_mode() nounwind

define double @f(double %X) readonly nounwind {
  %a = call double @cos( double %X ) readonly nounwind
  call void @change_the_rounding_mode() nounwind
  %b = call double @cos( double %X ) readonly nounwind
  %c = add double %a, %b
  ret double %c
}

Then the bitcode optimizers like GVN (correctly) do not
remove the second call, even though it is the same as the
first, because the change_rounding_mode call may change
the result.  But codegen does!  Here is the result:

f:
        subq    $8, %rsp
        movsd   %xmm0, (%rsp)
        call    change_the_rounding_mode
        movsd   (%rsp), %xmm0
        call    cos
        addsd   %xmm0, %xmm0
        addq    $8, %rsp
        ret

The reason is simple enough: the call to "cos" is turned
into an SDNode, then CSE collapses the two "cos" calls
into one.  This is only correct if "cos" is readnone.

I think things should work like this:
(a) codegen should only turn llvm math intrinsics into SDNodes
(b) llvm math intrinsics should be readnone
(c) llvm-gcc should generate an llvm intrinsic for a gcc builtin
only when the builtin is "const" (= readnone).
(d) maybe SimplifyLibcalls should also automagically turn readnone
calls to "cos" etc into calls to llvm.cos etc.

Ciao,

Duncan.



More information about the llvm-commits mailing list