Common Code Elimination
cortex-m3 uVision 5.13
I recent had to up the optimization level on my project to level 2 because my code size was too large for my target memory. In doing this I found that it seems to be doing common code elimination where valid routines are not being compiled/linked into the image.
This has caused some routines to be practically wiped out because another is very similar but has some differences. I guess they were common enough for the compiler to decide to get rid of one of them.
I have been Googling and searching everywhere for a way to turn off just the common code elimination but cannot find anything that I can use with uVision.
There is a C51 pragma to change the optimization level to stop this on a file by file basis but the uVision compile causes a error.
There must be a way to turn this off. I understand it is trying to save me space but it is also changing or in some cases eliminating functionality.
Does anyone know of a pragma that will work or something I can do?
Thanks
P.S. of course this happens 2 days before a major delivery on a weekend!!
But what problems do you see?
Common code elimination might add some extra calls or jumps but shouldn't remove functionality - two functions that looks almost identical could be seen as converted into three functions. Two with the differences and one with the common part. You should still get the same side effects.
Do you get too deep call stack? Issues with timing? Something else?
That sounds like a somewhat dubious statement. There is nothing wrong with your original functions being removed so long as the actions of those functions is maintained.
There must be a way to turn this off.
Why?
I understand it is trying to save me space but it is also changing or in some cases eliminating functionality.
You've yet to actually convince anyone that it did eliminate functionality. So far you've only talked about it eliminating code. You don't seem to have bothered checking the difference between those two.
I have to say I would not have posted a question if there was not a problem.
I have two routines. One sets up a actuator and the other a sensor. The set is is basically the same EXECPT I have print statements in this "common looking" code that are different. They would be text strings.
And why I say it is not working is because when I call the routine to set up the sensor it executes for 3 lines which are not unique to the other routine and THEN it exits doing nothing. It does not excute what should now be common code. It does nothing.
I used the ulink debugger which given the optimization is not as reliable as it normally is, to step into the routine and step through those first 3 lines, the remaining ones were not marked as executable (grey box to the left of each line) and it stepped to the return and exited. It did do anything.
I have gotten round this because I have run out of time by changing the sensor routine enough so tha it no longer looks enough like the other one for it to be optimized out.
I see that there are dozens and dozens of other areas that have been optimized as common code but this was a very large block of code compared to those which were only a few lines.
Obviously my system would not run at all of the common block optimization did not work at all. Those smaller optimzed lines of code most be working or the system would fall apart.
It has just been this large block of code that seems to be the problem. It was 20 or 30 lines of code it removed. And like I mentioned they were not exactly the same. There were some text strings that were different that my print statement would output. It obviously did not look that the strings themselves and notice the difference. If it had it would not have optimized it.
I am telling you the truth about what happened. The sensor code which was to send a messge out and print some text strings did not execute at all. It was not until I forced it not to optimized did I get my functionality back.
Its obviously a one off case that I have uncovered. I was/am just afraid of it doing that to some other part of my software and I just haven't stumbled over it yet. That is why I wanted to pay it safe and turn that part of optimization off.
I guess I should post the two routines to technical support so they can research why the optimizer thought these were the same when there were some differences. Not in code executed but in the text strings that the code would output. Smnall but significant differences.
So I'll ask my question again, is there a pragma or switch that I can use to prevent common block optimization?
thanks
Your request to the manual lookup service has found this:
www.keil.com/.../armcc_chr1359124215328.htm - NOTHING APPROPRIATE FOUND
www.keil.com/.../armcc_chr1359124194749.htm - NOTHING APPROPRIATE FOUND
If you think really found a problem, I suggest you attempt to be a tad more precise when passing information to support.
Around the specific routines you do not want optimized
#pragma push // save current pragma state #pragma O0 Your routine that you do not want optimized #pragma pop // restore previous optimization level
It does seem reasonable for the compiler to optimize out redundant code if only the strings are different (even seems like it SHOULD do this at higher optimization levels). It is easy to pass in different strings to the same code. It does seem like the issue may be larger than this but I don't believe the proper fix (on Keil's part) would be to not optimize out the code, but to just make sure the proper strings are used in each case. As people have said it is the functionality that needs to be the same, not the exact code generated.
Also is next to impossible to debug the source code at Optimization level 2 and above (level 1 is not horrible, save switch statements). I find that there is often no way to set break points based on the high level code. Going into the disassembly and setting break points and stepping through at that level can be very helpful. I am not sure if this is the case, but my bet is that when you say that "nothing happens" in the code, if you actually step through the disassembly you will find there is a lot more than nothing going on.
And I have to say you should then have posted the question describing the actual problem. You left out every single important fact of the matter.
The set is is basically the same EXECPT I have print statements in this "common looking" code that are different.
And you're 100% certain that the optimizer cannot possibly have seen through that simple difference and still joined the code correctly, just using two different tables of string constants with the same function, i.e.:
void f1(void) { // code specific to f1 // common code with strings specific to f1 } void f2(void) { // code specific to f2 // common code with strings specific to f2 }
by
char *f1strings[] = { //strings specific to f1 } void f1(void) { // code specific to f1 common(f1strings) } char *f2strings[] = { strings specific to f2 } void f2(void) { // code specific to f2 common(f2strings) } void common(char *strtable[]) { // common code using strings from table }
Stepping through code that has had common code elimination applied may well be impossible, at least that the source code level. You really have to look at machine code to see what actually happens.
And then of course there's always the possibility that the code was eliminated for an entirely different reason than you thought. E.g. the optimizer might have found it to be unreachable, or only reachable if there was undefined behaviour leading up to it.
Hi again
Thank you for your response although some are snippy which is not helpful.
I am sure that there are differences but as I mentioned those are just in the strings being used by a few sprintf statements. The optimizer doesn't seem to take those into account.
All I was asking was is there a way to have this type of optimization not occur.
Obviously I will post all of the details of the two routines to tech support for them to analyze.
yes I had thought about it being eliminated for other reasons such as not being reachable. since it was the same (except for the const strings) as the other routine starting at that point and other one was executable, I didn't see a any reason why it wasn't reachable.
And after I significantly changed it enough for the optimizer to not see it as the same, it reappeared and was executable.
Good idea though
I just think it is because it does not consider const strings are part of its common block block analysis.
I have not seen any other large part of my software like this one eliminated. Just smaller 4 or 5 line sections without const strings.
The system seems to be running ok now that I forced it not to optimize that one routine.