Suppose that I'm using a modern version of GCC
to compile a C program. Furthermore, consider that my program contain stale branches, but that I'd very much like the dead code in those stale branches to be compiled and present in the final program. Consider the following program:
int main(int argc, char** argv) {
int a = 0;
goto skip;
a = -1;
skip: ;
return a;
}
Clearly, if I use GCC
with default optimization settings, the second assignment will never make it to the final program, as the compiler can easily tell that it'll never be executed. Suppose that I don't want this to happen.
In GCC
, there are a number of flags that dabble with dead code (most notably -fdce
), and I can chose to explicitly deactivate these when invoking GCC accordingly:
-fno-dce
-fno-dse
-fno-tree-dce
-fno-tree-dse
As far as I can tell, this should instruct GCC
not to mess with the second assignment. Yet, the concerned code never seems to make it into my program.
Why does GCC
insist on removing the dead code, and is there a way of instructing GCC not to get rid of the second assignment?
Removing such code has several benefits: it shrinks program size and it allows the running program to avoid executing irrelevant operations, which reduces its running time. It can also enable further optimizations by simplifying program structure. This dead code optimizer also removes code after next or break calls.
Historically, dead-code elimination was performed using information derived from data-flow analysis. An algorithm based on static single-assignment form (SSA) appears in the original journal article on SSA form by Ron Cytron et al.
The -fno-*
options don't work for me either with gcc-4.9.2.
That said, I think the following should be portable for all gcc (4.5+) targets:
__asm__ goto (""::::no_skip);
goto skip;
no_skip:
a = -1;
skip:;
From the manual: "an asm goto statement is always implicitly considered volatile."
Furthermore, with gcc-4.8 and above, you might consider adding an attribute to let the compiler know that this is an 'unlikely' path. This helps prevent branching penalties, etc., that might otherwise occur when taking the 'expected' path:
no_skip: __attribute__ ((cold));
It stands to reason that you could also use:
skip: __attribute__ ((hot));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With