This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Applying -fno-builtin-xxx / -ffreestanding via pragama GCC / attribute optimize


Hello.

I'm a developer for the open source project LinuxCNC (http://linuxcnc.org).

I hope someone can help me understand the details or limitations of
pragma GCC optimize / attribute optimize as they apply to a specific
case we've encountered, and how to get the results we desire from gcc.

Our project uses FP math in kernel space, and one of the GNU standard
functions we supply an implementation of is sincos(3).  Our
implementation of sincos looks like this:

    void sincos(double x, double *sx, double *cx)
    {
        *sx = sin(x);
        *cx = cos(x);
    }

Unfortunately, on amd64 platforms under most optimization flags, this
compiles into a call to sincos, leading to unbounded recursion at
runtime.  This optimization is only natural, since the form of
the body is *exactly* sincos.  Of course, this optimization is
inappropriate in this specific case, when processing the implementation
of sincos.

Adding -fno-builtin-sin to the commandline inhibits this transformation.
As a result, I expected the following declaration to inhibit the
transformation too:
    __attribute__((optimize("no-builtin-sin")))
    void sincos(double x, double *sx, double *cx);

however, the assembly *still* contains a call to sincos.  This was also
true for any of the following:
    #pragma GCC optimize "no-builtin-sin"
    #pragma GCC optimize "no-builtin-cos"
    #pragma GCC optimize "freestanding"

    __attribute__((optimize("no-builtin-cos")))
    void sincos(double x, double *sx, double *cx);

    __attribute__((optimize("freestanding")))
    void sincos(double x, double *sx, double *cx);
and in a range of gcc versions (4.6, 4.7, 4.8, 4.9 all as packaged by
Debian for the upcoming Jessie release)

I think I don't completely misunderstand how to apply __attribute__
((optimize)) and #pragma GCC, because these alternatives do work:

    #pragma GCC optimize "0"

    __attribute__((optimize("0")))
    void sincos(double x, double *sx, double *cx);

as well as some more exotic trickery such as
    extern double sin_(double) __asm__("sin");
    #define sin sin_
(which of course is not going to work on platforms that prefix extern
identifiers with _, if any such environments exist anymore)

I've prepared a test program and script that should allow you to
recreate my results.  Save ctest.sh and sc.c in the same directory,
customize the top of ctest.sh according to the gcc versions you have
installed, and run it with bash.  The test works by grepping the
assembler output for 'sincos', which is presumably a synthesized call to
that function.

(Possibly because we supply an inline asm implementation of sin/cos as
fsin/fcos on i386 we haven't heard about this problem on i386 systems,
and on arm systems we aren't using the kernel-space model for our
software at all.  so mentioning amd64 specifically may be a red herring
in terms of gcc's behavior)

Thanks for any replies!  I am subscribed to the list but would
appreciate a courtesy copy of responses if it's considered good
etiquette around here.

Jeff

## Cut here for ctest.sh
#!/bin/bash
versions="gcc-4.6 gcc-4.7 gcc-4.8 gcc-4.9"
set -o pipefail
for cc in $versions; do
    for opt in -ffreestanding -fno-builtin-sin -DUSE_PRAGMA_FREESTANDING \
            -DUSE_PRAGMA_NO_BUILTIN -DUSE_PRAGMA_NO_OPTIMIZE \
            -DUSE_ATTRIBUTE_FREESTANDING -DUSE_ATTRIBUTE_NO_BUILTIN \
            -DUSE_ATTRIBUTE_NO_OPTIMIZE -DUSE_ASM_TRICKERY; do
        echo -n $cc - $opt ""
        if $cc -Os -Wall $opt -S -o- sc.c | grep -q sincos; then
            echo "BAD"
        else
            echo "GOOD"
        fi
    done
    echo
done
exit 0

// cut here for sc.c
// (declare sin/cos ourselves to avoid any header cleverness)
extern double sin(double);
extern double cos(double);

#ifdef USE_PRAGMA_FREESTANDING
#pragma GCC optimize "freestanding"
#endif

#ifdef USE_PRAGMA_NO_BUILTIN
#pragma GCC optimize "no-builtin-sin"
#pragma GCC optimize "no-builtin-cos"
#endif

#ifdef USE_PRAGMA_NO_OPTIMIZE
#pragma GCC optimize "0"
#endif

void fn(double x, double *sx, double *cx)
#ifdef USE_ATTRIBUTE_FREESTANDING
__attribute__((optimize("freestanding")))
#endif

#ifdef USE_ATTRIBUTE_NO_BUILTIN
__attribute__((optimize("no-builtin-sin")))
__attribute__((optimize("no-builtin-cos")))
#endif

#ifdef USE_ATTRIBUTE_NO_OPTIMIZE
__attribute__((optimize("0")))
#endif
;

#ifdef USE_ASM_TRICKERY
extern double sin_(double) __asm__("sin");
#define sin sin_
#endif

void fn(double x, double *sx, double *cx) {
    *sx = sin(x);
    *cx = cos(x);
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]