[llvm-dev] LLVM v3.9.0 and math built-ins
Hubert Tong via llvm-dev
llvm-dev at lists.llvm.org
Tue Sep 20 06:53:44 PDT 2016
Hi Martin,
I believe Mehdi was referring to C11 subclause 7.12.1 paragraph 7:
If no such error occurs, errno shall be left unmodified regardless of the
setting of math_errhandling.
Thus we are left with a question as to why a call with the constant is
needs to be preserved when errno is specified not to change by C11.
-- HT
On Tue, Sep 20, 2016 at 7:12 AM, Martin J. O'Riordan via llvm-dev <
llvm-dev at lists.llvm.org> wrote:
> Hi Mehdi,
>
>
>
> The ISO C specification does permit the math functions to modify ‘errno’,
> but I thought that the ‘-fno-math-errno’ option was to tell the
> optimiser to assume that ‘errno’ is not modified by the math functions.
> Explicitly providing ‘-fno-math-errno’ is not restoring the elision
> optimisation that was performed by LLVM v3.8, and this is really only a
> driver option, with ‘-fmath-errno’ passed onto CC1 if ‘MathErrno’ is
> true, and omitted if false.
>
>
>
> I certainly agree that if ‘MathErrno’ is true, then the compiler should
> not elide the call as it has to assume that there are memory write
> side-effects. It already models the math functions as built-ins and
> determine the expected answer when the arguments are constants, and elides
> the tests in the simple example below - all this is good, and when I use ‘
> -fno-builtin’ it stops correctly disabled this optimisation.
>
>
>
> I modified my sources to force ‘readnone’ and even tried ‘
> setDoesNotAccessMemory()’ on the math functions, but this still results
> in one call occurring and the code generated is effectively:
>
>
>
> (void)exp(1.0);
>
> return 0;
>
>
>
> This is better, but still not as optimal as it was in v3.8. With this
> change, compiling with ‘-fmath-errno’ reverts to inserting two calls.
>
>
>
> While calling these functions with constants is not terribly common in C
> code (mostly contrived test cases), it is a lot more common in real C++
> code via template expansions and inlining. With ‘-O3 -S -emit-llvm
> -fno-math-errno’ plus my change to call ‘setDoesNotAccessMemory()’, the
> IR generated is as follows:
>
>
>
> ; ModuleID = 'src/mathElisions.c'
>
> source_filename = "src/mathElisions.c"
>
> target datalayout = "e-m:e-p:32:32-f64:64-i64:64-
> v128:64-v64:64-v32:32-v16:16-n8:16:32-S64"
>
> target triple = "shave"
>
>
>
> ; Function Attrs: nounwind readnone
>
> define i32 @useMathName() local_unnamed_addr #0 {
>
> %1 = tail call float @exp(float 1.000000e+00)
>
> ret i32 0
>
> }
>
>
>
> ; Function Attrs: readnone
>
> declare float @exp(float) local_unnamed_addr #1
>
>
>
> ; Function Attrs: nounwind
>
> define i32 @useOtherName() local_unnamed_addr #2 {
>
> %1 = tail call float @foo(float 1.000000e+00) #4
>
> %2 = fcmp olt float %1, 0x4005AE1480000000
>
> br i1 %2, label %7, label %3
>
>
>
> ; <label>:3: ; preds = %0
>
> %4 = tail call float @foo(float 1.000000e+00) #4
>
> %5 = fcmp ogt float %4, 0x4005C28F60000000
>
> br i1 %5, label %7, label %6
>
>
>
> ; <label>:6: ; preds = %3
>
> br label %7
>
>
>
> ; <label>:7: ; preds = %0, %3, %6
>
> %8 = phi i32 [ 0, %6 ], [ -1, %3 ], [ -1, %0 ]
>
> ret i32 %8
>
> }
>
>
>
> declare float @foo(float) local_unnamed_addr #3
>
>
>
> attributes #0 = { nounwind readnone "disable-tail-calls"="false"
> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
> "no-jump-tables"="false" "no-nans-fp-math"="false"
> "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8"
> "target-cpu"="myriad2.2" "unsafe-fp-math"="false" "use-soft-float"="false" }
>
> attributes #1 = { readnone "disable-tail-calls"="false"
> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
> "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false"
> "stack-protector-buffer-size"="8" "target-cpu"="myriad2.2"
> "unsafe-fp-math"="false" "use-soft-float"="false" }
>
> attributes #2 = { nounwind "disable-tail-calls"="false"
> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
> "no-jump-tables"="false" "no-nans-fp-math"="false"
> "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8"
> "target-cpu"="myriad2.2" "unsafe-fp-math"="false" "use-soft-float"="false" }
>
> attributes #3 = { "disable-tail-calls"="false"
> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
> "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false"
> "stack-protector-buffer-size"="8" "target-cpu"="myriad2.2"
> "unsafe-fp-math"="false" "use-soft-float"="false" }
>
> attributes #4 = { nounwind }
>
>
>
> Our implementation has C ‘float’ and ‘double’ as 32-bit IEEE
> Single-Precision and ‘long double’ as 64-bit IEEE Double-Precision.
>
>
>
> Thanks,
>
>
>
> MartinO
>
>
>
> *From:* mehdi.amini at apple.com [mailto:mehdi.amini at apple.com
> <mehdi.amini at apple.com>]
> *Sent:* 16 September 2016 21:16
>
>
>
> On Sep 16, 2016, at 1:30 AM, Martin J. O'Riordan via llvm-dev <
> llvm-dev at lists.llvm.org> wrote:
>
>
>
> A little while ago I asked a question on CFE-Dev about a change in the
> behaviour of programs using the ISO C math functions, although that
> question should have been put to LLVM-Dev. But I got excellent
> clarification of the problem anyway. However, since then I have been
> trying to adapt our out-of-tree implementation to get the previous
> behaviour. The problem is that something like:
>
>
>
> #include <math.h>
>
>
>
> extern double foo(double);
>
>
>
> int useMathName() {
>
> if ((exp(1.0) < 2.71) || (exp(1.0) > 2.72))
>
> return -1;
>
> return 0;
>
> }
>
>
>
> int useOtherName() {
>
> if ((foo(1.0) < 2.71) || (foo(1.0) > 2.72))
>
> return -1;
>
> return 0;
>
> }
>
>
>
> With v3.8.0 the compiler elided both the calls to ‘exp’ and the tests, so
> the function ‘useMathName’ reduced to simply:
>
>
>
> return 0;
>
>
>
> But this was not correct as it ignored the possibility that the math
> functions could have the side-effect of changing ‘errno’, and this was
> fixed in v3.9.0, and the calls are no longer elided, though using the
> “as-if” rule, the tests are still eliminated and ‘useMathName’ becomes:
>
>
>
> (void)exp(1.0);
>
> (void)exp(1.0);
>
>
>
> o me: isn’t the spec saying that errno shall be set on underflow and
> overflow. The constant folding should be able to detect this and fold if it
> does not happen?
>
>
>
> Also, because we don’t really model errno, we don’t constant fold these
> call anymore :(
>
>
>
> return 0;
>
>
>
> So I changed our implementation so that ‘-fno-math-errno’ is the default
> for the tool-chain, and the ‘-fmath-errno’ option is not passed on to the
> CC1 phase. I expected that this would allow the compiler to elide the
> calls, but it is not doing so. I don’t want to use ‘-ffast-math’ as this
> has lots of FP issues, and I don’t want to make it the default.
>
>
>
> Any idea why the math functions are not elided? I am using ‘-O3’ and
> implying ‘-fno-math-errno’. I have verified that our Toolchain
> implements ‘IsMathErrnoDefault’ and returns ‘false’, and that the option ‘
> -fmath-errno’ is not being passed to the CC1 stage. Since our math
> function implementation does not in fact change ‘errno’, it is very
> desirable that this elision occurs in an FP safe way.
>
>
>
> You can check that clang when emitting the IR is adding the attribute
> "readnone” on the declaration of exp(). If it does not then it assumes
> errno.
>
>
>
> As a starting point, have you tried to pass -fno-math-errno?
>
>
>
> —
>
> Mehdi
>
>
>
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160920/7ebf011e/attachment-0001.html>
More information about the llvm-dev
mailing list