This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TDA4AP-Q1: TDA4AP-Q1: How to trap floating point exceptions on linux?

Part Number: TDA4AP-Q1


Tool/software:

Hi,

how can you trap floating point exceptions on linux?

We tried to use feenableexcept() but it failed for every exception bit.
We looked into the ARM A72 doc, but it says, it is not supported. Is there any way to stop execution in case of FPE?
Can this be enabled via the NEON coprocessor?

Thanks

  • Hello,

    The question seems like one for a forum which is supporting the libc version in use.  Are you using GLIBC or something else.  

    A generic search shows a few pointers on stackoverflow, however, a fuller discussion of standard library usage shows up on an apple forum here:
    https://forums.developer.apple.com/forums/thread/689159

    I would suggest reviewing the above post and then asking the question to a glibc forum.  If you provide more information as to what you are trying to do with an example here we can review but the answer is likely with glibc folks (or perhaps with ARM where the base tool chain likely came from).

    Regards,
    Richard W.
  • Do not dwell on the libc usage. Setting the regisisters directly does also not work.

  • Hello,

    You need to give more details for me to follow exactly what you have tried. From my perspective the first issue point is at the library usage, then library implementation level.  After that, there can be kernel level implementation issues, then finally hardware level issues. If what is being tried is uncommon, all levels could have issues to work through.

    Regards,
    Richard W.
  • Alright, I have some code for you:

    #include <cstdint> // uintxx_t
    #include <fenv.h> // feenableexcept
    #include <csignal>
    #include <iostream>

    static void setFPRegValue(uint32_t value)
    {
    #if defined(__i386__) || defined(__x86_64__)
    // Write 'value' to x86 mxcsr register.
    asm volatile("ldmxcsr %0" : : "m"(value));
    #elif defined(__aarch64__)
    // Write 'value' to AArch32 FPCR register.
    asm volatile("MSR FPCR, %0 " : : "r"(value));
    #endif
    }

    static uint32_t getFPRegValue()
    {
    uint32_t result;
    #if defined(__i386__) || defined(__x86_64__)
    // Load value of the x86 mxcsr register into the variable 'result'.
    asm volatile("stmxcsr %0" : "=m"(result));
    #elif defined(__aarch64__)
    // Load value of AArch32 FPCR register into the variable 'result'.
    asm volatile("MRS %0, FPCR " : "=r"(result));
    #endif
    return result;
    }

    static bool enableAllExceptions()
    {
    #if defined(__i386__) || defined(__x86_64__)
    if(-1 == feenableexcept(FE_DIVBYZERO)) return false;
    #elif defined(__aarch64__)
    uint32_t currentValue = getFPRegValue();
    // Bit 9 is the division-by-zero exception enable bit on AR
    uint32_t enabledDivByZero = currentValue | (1 << 9);
    setFPRegValue(enabledDivByZero);
    #endif
    printf("Enabled: %d\n", getFPRegValue());
    return true;
    }

    [[noreturn]] void fpeSignalHandler(int signum)
    {
    printf("Catched an FPE: %d\n", signum);
    exit(signum);
    }

    int main(int argc, char **argv)
    {
    signal(SIGFPE, fpeSignalHandler);

    if (!enableAllExceptions()) return -1;
    float a = 1;
    float b = 0;
    float result = a / b;

    return 0;
    }

    This code compiles for Intel (aka my laptop) and arm64 (aka Jacinto).

    On my laptop the signal is sent and caught:

    ~ $ ./fpeIntel
    Enabled: 7552
    Catched an FPE: 8

    Without catching it, the process would terminate.

    On Jacinto, the signal is nor sent not caught, nor does the process terminate:

    ~ $ ./fpeArm         
    Enabled: 0


    Note that we do not use libc to set the registers in the ARM code path! So either, the linux kernel does not send out the signal, or the hardware does not support catching floating point exceptions.

  • Hello,

    This code makes it very clear on what you want and have tried. After checking the run time in the debugger and looking at specifications it does appear that the Cortex-A72 does not support trapping. The FPSCR.DZE (bit9) as used in your code is undefined. The ARMv8 architecture specification does specify traps for DZE, however, it does have the caveat that its implementation dependent.  The Cortex-A72 TRM is clear in that it does not support the feature and it shows bit 9 as reserved.

    As a side note, when I fiddled with your test on my Linux PC, I noted the default response for c = a/b (1/0) is c = inf not a terminating trap (if no handler is installed).  Searching on the topic using precise key words, I see different approaches for dealing with division by zero recommended, some assert its result is well defined in IEEE 754 and 0 can be returned or infinity, or, ... and many algorithms work fine with this behavior.  However, I can see where that does not cover all cases and other checks of the denominator + throws or using using isfinite() and isinf() may be needed.

    Regards,
    Richard W.
  • Thanks you. I am glad that you can reproduce and confirm our research.