[Bug tree-optimization/94357] New: Inline assembly with memory operand is considered nothrow with `-fnon-call-exceptions`
sagebar at web dot de
gcc-bugzilla@gcc.gnu.org
Fri Mar 27 13:36:47 GMT 2020
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94357
Bug ID: 94357
Summary: Inline assembly with memory operand is considered
nothrow with `-fnon-call-exceptions`
Product: gcc
Version: 9.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: sagebar at web dot de
Target Milestone: ---
Created attachment 48130
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=48130&action=edit
Issue demonstration
The documentation of `-fnon-call-exceptions`
(https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fnon-call-exceptions)
states that any instruction with a "memory references" is allowed to throw a
c++ exception (or in other words: do what essentially boils down to performing
a CFI unwind, and calling `__gxx_personality_v0()` without that function
calling `std::terminate()` because the faulting PC isn't allowed to trap)
However, from what I can tell by looking at the GCC sources
(gcc/tree-eh.c:tree_could_trap_p(); case ASM_EXPR), GCC only considers an
`asm()` statement as being able to cause a non-call-exception (i.e. trap) when
written as `asm volatile()`.
Given the fact that "memory references" is listed as one of the possible
reasons for an instruction to be trapable, it stands reason that any inline
assembly statement that uses memory operands (i.e. `asm("..." : "=m" (...))` or
`asm("..." : : "m" (...))`), as well as any assembly statement that specifies
"memory" as part of its clobber list (i.e. `asm("..." : : : "memory")`) should
also be considered as potentially containing instructions that may trap.
Note also that during my investigation I've noticed that the catch(...) block
is fully optimized away in the following case ... (`gcc -S` does contain `/*
Hello */`, but doesn't contain `/* World! */`):
```c
void foo() {
try {
__asm__ __volatile__("/* Hello */");
} catch (...) {
__asm__("/* World! */");
}
}
```
... but isn't optimized away when the first `__asm__ __volatile__` is placed in
an inline function (`gcc -S` does contains both `/* Hello */` and `/* World!
*/`):
```c
inline void bar() {
__asm__ __volatile__("/* Hello */");
}
void foo() {
try {
bar();
} catch (...) {
__asm__("/* World! */");
}
}
```
The attached file shows the different cases where `__asm__` appears in `try ...
catch`, and should be compiled as follows (note that -O* flags don't have any
affect on which catch-statements get deleted; -O0 has the same output as -O3):
$ g++ -S -x c++ -fnon-call-exceptions attaced-file.cc -o - | grep "reference"
The current output is:```
call must_reference_1
```
A consistent output (with the current rules concerning __volatile__) would look
like:```
call must_reference_1
call must_reference_2
call must_reference_3
```
And an output consistent with published documentation would look like:```
call must_reference_1
call must_reference_2
call must_reference_3
call must_reference_4
call must_reference_5
call must_reference_6
```
More information about the Gcc-bugs
mailing list