|
8 | 8 | #ifndef _ASM_COMPILER_H
|
9 | 9 | #define _ASM_COMPILER_H
|
10 | 10 |
|
| 11 | +/* |
| 12 | + * With GCC 4.5 onwards we can use __builtin_unreachable to indicate to the |
| 13 | + * compiler that a particular code path will never be hit. This allows it to be |
| 14 | + * optimised out of the generated binary. |
| 15 | + * |
| 16 | + * Unfortunately at least GCC 4.6.3 through 7.3.0 inclusive suffer from a bug |
| 17 | + * that can lead to instructions from beyond an unreachable statement being |
| 18 | + * incorrectly reordered into earlier delay slots if the unreachable statement |
| 19 | + * is the only content of a case in a switch statement. This can lead to |
| 20 | + * seemingly random behaviour, such as invalid memory accesses from incorrectly |
| 21 | + * reordered loads or stores. See this potential GCC fix for details: |
| 22 | + * |
| 23 | + * https://gcc.gnu.org/ml/gcc-patches/2015-09/msg00360.html |
| 24 | + * |
| 25 | + * It is unclear whether GCC 8 onwards suffer from the same issue - nothing |
| 26 | + * relevant is mentioned in GCC 8 release notes and nothing obviously relevant |
| 27 | + * stands out in GCC commit logs, but these newer GCC versions generate very |
| 28 | + * different code for the testcase which doesn't exhibit the bug. |
| 29 | + * |
| 30 | + * GCC also handles stack allocation suboptimally when calling noreturn |
| 31 | + * functions or calling __builtin_unreachable(): |
| 32 | + * |
| 33 | + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365 |
| 34 | + * |
| 35 | + * We work around both of these issues by placing a volatile asm statement, |
| 36 | + * which GCC is prevented from reordering past, prior to __builtin_unreachable |
| 37 | + * calls. |
| 38 | + * |
| 39 | + * The .insn statement is required to ensure that any branches to the |
| 40 | + * statement, which sadly must be kept due to the asm statement, are known to |
| 41 | + * be branches to code and satisfy linker requirements for microMIPS kernels. |
| 42 | + */ |
| 43 | +#undef barrier_before_unreachable |
| 44 | +#define barrier_before_unreachable() asm volatile(".insn") |
| 45 | + |
11 | 46 | #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
12 | 47 | #define GCC_IMM_ASM() "n"
|
13 | 48 | #define GCC_REG_ACCUM "$0"
|
|
0 commit comments