Products > Programming

GCC ARM32 compiler too clever, or not clever enough?

<< < (19/24) > >>

peter-h:
Another Q on compiler "optimisation":

What are the rules for removing code, after a construct like

while (true)
{
 some code
}

which will obviously never execute.

Some of it can be quite subtle, and removal of one thing can lead to removal of everything it calls, and so on. The compiler must build a tree of all related code and work up that tree and if it finds a branch gone it then goes back down and removes all the others that are affected.

But it doesn't always seem to happen. A colleague is working on the same Cube IDE (32F417) project but on a linux machine (I use win7-64) and he's just had half his code go missing, just by commenting out one FreeRTOS task :) Presumably we have different compiler options somewhere...

brucehoult:
Certainly the compiler can (and should!) remove unreachable code. And variables that are used only by unreachable code. And variables that are read but never set, or set but never read.

If a compiler removes code that surprises you, and the compiler is a current version of gcc or llvm, then there is a 99.999% chance that it is you that doesn't understand your program, not the compiler.

SiliconWizard:

--- Quote from: peter-h on June 20, 2022, 08:57:12 am ---Another Q on compiler "optimisation":

What are the rules for removing code, after a construct like

while (true)
{
 some code
}

which will obviously never execute.
--- End quote ---

Are you sure? ;D


--- Quote from: peter-h on June 20, 2022, 08:57:12 am ---Some of it can be quite subtle, and removal of one thing can lead to removal of everything it calls, and so on. The compiler must build a tree of all related code and work up that tree and if it finds a branch gone it then goes back down and removes all the others that are affected.

--- End quote ---

Any code that is statically analyzed as unreachable during compilation will just not yield emitted code from the compiler. That usually happens even at the first level of optimization.

Now for any function call that would be unreachable, the function call itself will not be emitted, but the code of the function itself may still remain, even if it's never called anywhere, as long as said function has external linkage (in other words, if it's not a static function - static-qualified functions that are not called in their compilation unit will get pruned, but compilers usually give you a warning about those anyway.)

As we already talked about, the code of functions that have external linkage and that are never called anywhere will get removed, not by the compiler, but by the linker, and *only* if you have set the corresponding options (which consist of instructing the compiler to put each function in a separate section, and instructing the linker to prune unused sections.) Otherwise, it'll remain in the final object code as dead beef.

OTOH, code removed by a compiler while it should NOT get removed (meaning it is called or there is an execution path that should execute it) should never happen. If it does, this is a compiler bug, and then just open a ticket.

peter-h:
OK; the key word is "statically", which is what got me into trouble last time, creating a function located by the linker at a given address and then creating a jump to that address, but the compiler obviously didn't realise what was going on, and on a static analysis the function was not called by anything. So I had to do some hacks to stop that function being removed. In the end all it took was a
dw function-name
statement in an assembler file, to prevent the removal. Doing it from C was difficult because the referring C code was also not called by anything so the whole lot was still getting removed ;) But assembler code is not removed.

How does one implement function tables (not sure of the right word) where you use an index to jump to one of a list of functions? I have never done this in C and normally use a case statement, but if you had lots of cases then a table makes sense. I used to do this extensively in assembler. Obvously the index needs to be range checked :)

SiliconWizard:
There are a number of ways of doing that.
If you just want to access functions through an index, declare an array of function pointers. Of course, that means that all functions you want to access this way should have the same prototype. Otherwise, I don't see the point or the feasability.

Then it can be something like: (assuming your functions have the prototype defined below, adapt to your use case:)

--- Code: ---typedef int (*myFunctions_t)(int n, char *s);

int foo1(int n, char *) { (...) }
int foo2(int n, char *) { (...) }
(...)

myFunctions_t myFunctionTable[] = {
    foo1,
    foo2,
   (...)
};

--- End code ---
And calling one of those:

--- Code: ---int ret = myFunctionTable[index](n, s);

--- End code ---

Navigation

[0] Message Index

[#] Next page

[*] Previous page

There was an error while thanking
Thanking...
Go to full version