Removing Dead Code & pragma instruction

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Removing Dead Code & pragma instruction

2,858 Views
nostradamux
Contributor I

Hi.

 

I'm using CodeWarrior 6.2 to program Dz128. In my code there are senteces like for (i=0;i<200; i++); to make active waitings. When I compile it, I check that appears warnigs likeC5560: Removed dead code, and I don't want that. If I use pragma instruction #pragma opt_dead_code off  in my code, I received this warnig: C4201: pragma opt_dead_code was not handled.

 

Anyone knows how could I avoid this removing?

 

Thanks a lot.

Labels (1)
0 Kudos
Reply
19 Replies

1,959 Views
Lundin
Senior Contributor IV

No matter the compiler, that loop will likely be optimized away. To solve this for any C compiler in the world, declare "i" as volatile. Never use compiler-specific #pragmas when the C standard already provides a solution.

 

0 Kudos
Reply

1,959 Views
tonyp
Senior Contributor II

Although I'm not a CW user, I think you could 'fool' the compiler if you simply added some code to the loop (like a NOP instruction).  But I'm not the right person to offer a suggestion, as I'm not that familiar with the tool.

 

My response is mainly because I think there is a misinterpretation (by the compiler [writers]) of what 'dead code' actually is.  Any code that has to run, by definition, isn't dead.  'Dead code' means code that NEVER runs (or at least doesn't affect the run), like functions that never get called, or redundant variable assignments.  So, in my view, it should not be a question of how to disable the warning but a question of not giving a wrong warning in the first place.  I could possibly understand removal of this code only if speed optimization is turned on, but certainly not as dead code.

0 Kudos
Reply

1,959 Views
nostradamux
Contributor I

I agree with you. I understand this code is not dead code, because it has a function: waiting time. I think is an error of compiler interpretation.

 

Dead code, perphaps, is: if (0) checkADC();, useful to debugging.

 

But, do you know why my compiler doesn't hadle my pragma instruction?

 

Thanks!!

0 Kudos
Reply

1,959 Views
Lundin
Senior Contributor IV

That argument is the same thing as if I had written code like

 

int x = (int) func;

rather than int x = (int) func();

 

and then said that the compiler is dumb because it didn't understand that I wanted the result of the function and not a function pointer. Even though the behavior of the compiler is well-defined by the C standard in this case.

 

How on earth do you expect the compiler to understand what your code is a dead waiting loop? It doesn't know your application, so it interprets the code as it is required to do by the C language, that's all it can do.

 

0 Kudos
Reply

1,959 Views
CompilerGuru
NXP Employee
NXP Employee

> I agree with you. I understand this code is not dead code, because it has a function: waiting time.

>  I think is an error of compiler interpretation.

 

Dead code for a compiler typically means never executed, apparently here it means more no side effect.

If you want to make sure the compiler does generate code for such things, add a side effect. There are numerous ways to archive this many already suggested previously. I would follow the advice to make the counter variable volatile. Maybe move the delay handling into its own function (with a volatile counter in there).

 

> But, do you know why my compiler doesn't hadle my pragma instruction?

 

Wrong compiler. The pragma you tried works for the coldfire (or eppc) compiler, it is not supported by the S08 compiler. I don't think the S08 compiler has an pragma with that particular effect.

 

Daniel

 

BTW: I thought the S08 compiler would intentionally not throw such delay loops away, but I did not check. Would not be too surprising if it would and I consider it legal as long as the there are no side effects as volatile accesses.

0 Kudos
Reply

1,959 Views
bigmac
Specialist III

Hello,

 

I seem to recall that I had no S08 compiler optimisation problems when creating a function to cause a short delay, at least not with the default compiler settings.  The required delay value was passed to the function.

 

void delay( word n){   for ( ; n; n--};}or alternativelyvoid delay( word n){   while (n) n--;}

 Regards,

Mac

 

0 Kudos
Reply

1,959 Views
Lundin
Senior Contributor IV

Calling a function is a side-effect, just like having a volatile loop iterator. So the compiler can't optimize it away, unless you explicitly inline the function.

 

0 Kudos
Reply

1,959 Views
Lundin
Senior Contributor IV

The compiler optimizes away that loop correctly. The loop contains only one side effect: i is set to 200. So the whole loop can be replaced by i=200; and that is perfectly legal C code. Had "i" been declared volatile, every access to the variable had produced a side-effect, and thus the loop couldn't be optimized away, again as defined by the C standard.

 

There are no misinterpretions by the compiler. Nobody had told the compiler that the code needed to run, so the compiler is free to remove it, in fact you should expect it to be removed. As a professional C programmer you need to know the C language.

 

0 Kudos
Reply

1,959 Views
tonyp
Senior Contributor II

"Nobody had told the compiler that the code needed to run, so the compiler is free to remove it,"

 

Well, the (professional C) programmer has told the compiler that s/he wants the code to be there.  That should  be enough of a clue (unless a compiler is ALWAYS making the assumption the programmer is the dumber of the two).  So, if any delay-generating code is to be automatically considered 'dead code', wouldn't it be impossible to write any delays using the C language (as the compiler should remove it as dead code)?  And if not, what is the 'deciding' factor?

 

Anyway, no need to start a debate.  Anyone is entitled to an opinion.  I stated mine.

 

"As a professional C programmer you need to know the C language."

I don't think dead code optimization is part of the C language specification, is it?  This is a compiler issue, not a language definition issue.

0 Kudos
Reply

1,959 Views
Lundin
Senior Contributor IV

Code is considered dead when it has no effect. That's pretty logical to me at least. This is not a compiler issue, it is all part of the C language, and well-defined by the C standard. I believe the C90 and C99 standards are identical in this case, this is from ISO 9899:1999:

 

 

"5.1.2.3 Program execution

/--/

"2 Accessing a volatile object, modifying an object, modifying a file, or calling a function
that does any of those operations are all side effects,11) which are changes in the state of
the execution environment. Evaluation of an expression may produce side effects. At
certain specified points in the execution sequence called sequence points, all side effects
of previous evaluations shall be complete and no side effects of subsequent evaluations
shall have taken place. (A summary of the sequence points is given in annex C.)"

 

The above is pretty self-explaining. Between certain places in the code, all modifications of variables, volatile access, function calls etc must be done and evaluated. I.e, evaluation takes place at certain sequence points in the program flow.

 

"3 In the abstract machine, all expressions are evaluated as specified by the semantics. An
actual implementation need not evaluate part of an expression if it can deduce that its
value is not used and that no needed side effects are produced (including any caused by
calling a function or accessing a volatile object)."


Here you have it black on white in the C standard. The compiler is free to optimize away code where the values aren't used and which doesn't contain side-effects. Like it or not, that's how the C language is defined. There are countless of far more monsterous things allowed by C, this part of the language is actually fairly logical.

 

As already pointed out by me in earlier posts, the solution is to make the iterator variable volatile.

0 Kudos
Reply

1,959 Views
tonyp
Senior Contributor II

Although I was hoping this wouldn't escalate this much, I'm afraid I can't but answer some of the latest remarks:

 

"3 In the abstract machine, all expressions are evaluated as specified by the semantics. An
actual implementation need
not evaluate part of an expression if it can deduce that its
value is not used and that no needed side effects are produced
(including any caused by
calling a function or accessing a volatile object)."

 

This talks about expressions.  A FOR loop is NOT an expression.  The expressions are used to control the FOR loop.  So, the expressions are indeed used by the FOR loop, and as such they can't be eliminated.  The fact the FOR loop has no block of statements is irrelevant.  Besides, the grammar of the language wouldn't allow a FOR loop (and other similar constructs) without at least one statement in it, if the intent was for an empty FOR loop to act as nothing more than a comment.

 

And in this case, besides the expressions being used by the FOR loop (so it can loop), we also have a needed side effect, the delay effect itself.  So, on both counts there is nothing to suggest the FOR should be completely eliminated.

 

"Accessing a volatile object, modifying an object, modifying a file, or calling a function
that does any of those operations
are all side effects"

 

(The above does not imply this: "Calling a function is a side-effect, just like having a volatile loop iterator. So the compiler can't optimize it away, unless you explicitly inline the function.")

 

According to the above, calling a function by itself isn't enough to be a side effect.  So, a function can contain no statements, or only a single statement, the same FOR loop (of the OP), which should be (according to some) eliminated as dead code, leaving the function empty.  Basically, that would translate to no more than a JSR/BSR to a single RTS, and at this point, I, too, would be very happy if that got optimized away, as well.

 

"The compiler is free to optimize away code where the values aren't used and which doesn't contain side-effects."

 

(Again, the expressions are used to control the loop, so they need to stay.)  To some people, delay = no-effect.  If we accept this, then yes, the compiler is correct in that regard only.  To me, however, delay = work, so it can't get removed.

 

"How on earth do you expect the compiler to understand what your code is a dead waiting loop? It doesn't know your application, so it interprets the code as it is required to do by the C language, that's all it can do."

 

No, I do NOT expect the compiler to understand the programmer's intentions.  Quite the opposite, don't even try to.  A compiler is only allowed to optimize what it knows for sure has no side effect (as the standard so wisely says).  Anytime the compiler can't be certain, it should leave the code alone.  It is, afterall, the responsibility of the programmer to write meaningful code, but certainly not the job of a compiler to decide what is or isn't meaningful, whenever that decision could go either way, as in this case.

 

I still think it's a mistake to eliminate such FOR loops as dead code, because they simply aren't dead (yet).  Unless a universal decree comes out that says "software delays aren't allowed anymore."

0 Kudos
Reply

1,959 Views
Lundin
Senior Contributor IV

> "This talks about expressions. A FOR loop is NOT an expression. The expressions are used to control the FOR loop. So, the expressions are indeed used by the FOR loop, and as such they can't be eliminated. "

 

By this flawed logic, the same would also be true for

 

if(0)

 

The 0 is used by the if statment, so the compiler can't be allowed to optimize it away. By the same flawed logic, nothing in the C language can be optimized, as all statements will always "use" expressions.

You must realize that a compiler/optimizer can only care about values, the program flow needed to get the desired values is completely irrelevant. If the program flow was not allowed to be optimized because it uses expressions, then what code would there be left to optimize?

 

If you are writing programs that depend on the program flow, you are writing programs that depend on a certain compiler, which is always a bad thing.

 

 

>> "Accessing a volatile object, modifying an object, modifying a file, or calling a function
that does any of those operations are all side effects"
> "(The above does not imply this: "Calling a function is a side-effect, just like having a volatile loop iterator. So the compiler can't optimize it away, unless you explicitly inline the function.")"

 

Oh I suppose I should have written "calling a function that modifies an object".


> "Unless a universal decree comes out that says "software delays aren't allowed anymore." "

Honestly, wouldn't that be nice? If we disregard this whole optimizing debate above, software delay loops that do get executed are terribly inefficient. They occupy the CPU 100%, making it consume 100% current, while doing nothing. And there exists no case where you must use one. They are only used because the programmer wants a quick & dirty delay, without care for program efficiency. The two alternatives, using a "Sleep()" function in the OS or using hardware timers, are much better options.

0 Kudos
Reply

1,959 Views
tonyp
Senior Contributor II

"By this flawed logic, the same would also be true for

 

if(0)

 

The 0 is used by the if statement, so the compiler can't be allowed to optimize it away. By the same flawed logic, nothing in the C language can be optimized, as all statements will always "use" expressions."

 

Again, the zero is a constant, not an expression (or even the result of a constant expression that is evaluated at compilation time, not at run time), so it's different situation.  Remember, how I said the compiler is free to optimize when it is certain for the result.  There is no possibility for your IF example statement to be interpreted in more than one way.

 

Anyway, I find it pointless to take this any further.  You can stick to your understanding of the world, and I can stick to mine (even if it appears flawed to you).  I guess the only final argument I could make is "reality always wins" no matter what each of us may think that should be.  In other words, if a program doesn't behave as it should based on the specific instructions given by the programmer, then the programmer's logic isn't flawed, it's the compiler's interpretation that's flawed.

0 Kudos
Reply

1,959 Views
Lundin
Senior Contributor IV

No, by your logic it cannot optimize away if(0) because maybe the programmer had calculated that this would turn into a BNE instruction that would take a certain number of CPU ticks. This instruction was "given by the programmer", and if the compiler optimizes it away, it is flawed.

A better example:

 

char str [] = /* 10000 byte long string */

 

for(i=0; i<strlen(str); i++)

{

  do_something();

}

 

By your logic: since the for loop is "using" the 2nd expression, the compiler isn't allowed to optimize it. strlen must go through 10000 bytes at each time in the loop, because maybe the programmer wrote the program in hope that this painfully slow iteration will take place. In other words: optimizations aren't allowed to take place because the programmer might have ulterior motives with every code line they write.

 

If reality wins, then deal with the fact that most compilers on the market will optimize away the loop in the original post.

 

0 Kudos
Reply

1,959 Views
tonyp
Senior Contributor II

"No, by your logic it cannot optimize away if(0) because maybe the programmer had calculated that this would turn into a BNE instruction that would take a certain number of CPU ticks."

 

[Actually, that would be a BRN (a BNE would require a previous comparison to bring the CCR in the expected state).  And, I would be OK either way, whether it left the BRN in there or not.  if (0) is an unconditional non-jump.]

 

No, a programmer interested in calculating cycles would necessarily use assembly (at least for that particular segment of code), you know that.

 

Even the best optimizer imaginable would reduce a FOR loop to the absolute minimum of cycles required to initialize the loop, test the termination condition, and change the control variable(s).  But that can never amount to zero because these steps have to occur if you want to call this a loop.  So, by changing the loop termination value you can always affect how much time the loop will take, irrespective of how many cycles are actually used by a particular compiler's optimization efforts.  With no loop there at all, it simply isn't possible.  I'm sure this is flawed logic to you, so just ignore it for now.  But, what if I put it in non-computer terms?  Would it make more sense to you?  For example, starting from home take a walk for a half-hour returning back home.  While outside, do nothing (other than walk).  Would that be the same to you as not taking the walk at all?  Would you optimize it out and stay in the whole time?  There are no side effects, other than spending a half-hour (walking).  But the two have different outcome for how your day went.

 

"A better example:

 

char str [] = /* 10000 byte long string */

 

for(i=0; i<strlen(str); i++)

{

  do_something();

}

"

 

If str size isn't altered by do_something(), then it can optimize it by calling it once and then compare that same strlen() result every time through the loop.  But, if str may be altered (in size), shouldn't strlen() be called each time?

 

"If reality wins, then deal with the fact that most compilers on the market will optimize away the loop in the original post."

 

Most? But, if it's the expected behavior, why not all?  Why would anyone buy one of those compilers that do not remove the loop?  (They must be all be flawed like me.)  But, what you're really saying is "the majority wins."  That's a reality, too (in many situations.)

 

By "reality wins", I mean (and I thought it was pretty clear last time I wrote) you can't (no one can) deny the fact that no matter what should or shouldn't be optimized, the result should be equivalent and correct according to the instructions given.  If not, the flaw is with the compiler,  So, the same source fed into two different compilers must produce the same functional result, or else one of the two has issues.  Now, it may be that one code is smaller or faster than the other (due to the better code generation), but the application has to appear to behave the same (even if at different absolute speeds), or else one of the compilers is flawed.  I hope you can agree to this much.

 

Out of curiosity, would you also accept this kind of optimization:

Programmer writes: a = a * 2 / 2

Compiler => a = a * 1

Compiler => a = a

Compiler => nothing

 

0 Kudos
Reply

1,959 Views
Lundin
Senior Contributor IV

"If str size isn't altered by do_something(), then it can optimize it by calling it once and then compare that same strlen() result every time through the loop. But, if str may be altered (in size), shouldn't strlen() be called each time?"

 

By your logic it can't be altered either way, because the programmer may have expected the function to be executed and thereby cause a delay.

 

 

> >"If reality wins, then deal with the fact that most compilers on the market will optimize away the loop in the original post."

 > Most? But, if it's the expected behavior, why not all? Why would anyone buy one of those compilers that do not remove the loop? (They must be all be flawed like me.) But, what you're really saying is "the majority wins." That's a reality, too (in many situations.)

In this sentence I'm not saying whether they are right or wrong in doing so, but merely stating that's how the cold harsh reality looks like.

 

Anyway, the arguments are turning ridiculous. I already cited the C standard. If you don't agree with me, kindly cite the C standard in return to prove me wrong. Your personal opinions of how the C language should have been designed aren't particularly relevant.

0 Kudos
Reply

1,959 Views
J2MEJediMaster
Specialist I

This discussion was interesting, up to a point. However, the current trend of the discussion does not look favorable, and somebody will be mentioning the Nazis next. Then I'll have to invoke Godwin's Law. Therefore, I have locked this thread.

 

---Tom

0 Kudos
Reply

1,959 Views
CompilerGuru
NXP Employee
NXP Employee

I'm not really sure where this discussion is heading, but C compilers are typically defined against a ANSI C standard.

 

And as far as the ANSI C standard is concerned my understanding is clearly that delay loops can be removed.

Using a volatile counter is the simple and working solution as the ANSI C mandates that volatile accesses have to be performed.

Not necessarily as loop, the compiler could unroll the loop, but all reads or writes have to happen.

 

Optimizing "a = a * 2 / 2" is BTW a bit tricky as the operation is defined as a = (a * 2) / 2, so the *2/2 may have the effect of clearing the most significant bit, so a compiler will typically not remove the operation. Still even though most compilers wont optimize it, they could actually because ANSI C does not define any particular result if the intermediate value a*2 overflows, the bit clearing only takes place for undefined cases, so the compiler could throw the assignment away, well as I said I doubt many do though.

 

Daniel

0 Kudos
Reply

1,959 Views
tonyp
Senior Contributor II

Oops!  Our discussion was just optimized out, even though it had the side-effect of increasing our posting message counters :smileyhappy:

Nice talking with you, though.

0 Kudos
Reply