C5906: Subtraction with zero

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

C5906: Subtraction with zero

4,134 Views
Lundin
Senior Contributor IV
Using CW3.1 for HCS12 DG128.

I get a strange warning "C5906: Subtraction with zero" which I don't understand where it comes from. I have the following code:


(Gah, it is hopeless to post any kind of source code on this site, please check attached file instead.)


The code seems to work, but I like to know where that warning came from. According to the helpfile you may get it from the tree optimizer:

"This message may be generated during tree optimizations (Option -Ont to switch it off)."

So I disabled that one and the warning disappeared. I still don't understand why I got it, there seems to be nothing wrong with the code and if I look at the asm code, no subtraction with zero is taking place. Everything looks ok even though the subraction is done inside the if-condition rather than at the line where the value is assigned:

07ba ec8f LDD 15,SP
07bc 830300 SUBD #768
07bf 8c001f CPD #31
07c2 226a BHI *+108 ;abs = 082e


Any ideas?
Labels (1)
Tags (1)
0 Kudos
Reply
11 Replies

1,123 Views
Alban
Senior Contributor II
Hello,
 
How to post code easily is explained in the following thread.
 

There has never been any problem reported with this procedure I use daily to correct code un-correctly posted.

 is in the editor toolbar.

Regards,
Alban.

0 Kudos
Reply

1,123 Views
Lundin
Senior Contributor IV
I've read that and tried it. No use. I'm using Opera, so that might have something to do with it. The forum assumes that you use IE.
0 Kudos
Reply

1,123 Views
kef
Specialist I
You have
 
 #define DCAN_MSG_FEEDBACK0  0x0300
and
 
 dsip_id = (uint8)(id - DCAN_MSG_FEEDBACK0); /* WARNING C5906 */
 
 
This ^^ expression may be rewritten as
 
 dsip_id = (uint8)id - (uint8)0x300;
 
 
(uint8)0x300 == 0
0 Kudos
Reply

1,123 Views
Lundin
Senior Contributor IV
No, it may not be rewritten as that, the parenthesis takes precedence. The subtraction is done first and since both operands are 16 bit, that means that the result will be 16 bit. Then it is casted to 8 bit, since I know that the result will be less than 256.


EDIT: From Codewarriors own help file:

Order of Operand Evaluation

"Operators Associativity

() [] -> . left to right
! ~ ++ -- + - * & (type) sizeof right to left"


It is a bit tricky to cite ANSI C since they don't have a summary of the operator priorities, the priority is set by the chapter order. See chaper 6.5 in ISO/IEC 9899:1999.

Message Edited by Lundin on 2007-02-1401:15 PM

0 Kudos
Reply

1,123 Views
kef
Specialist I
I agree that according to C rules subtraction must be done first in your code. But optimizer is absolutely right that always
 
(uint8)(uint16 - uint16) == (uint8)uint16 - (uint8)uint16
 
I'm not sure about warning, maybe it shouldn't appear since you didn't really - 0, you did - 0x300. But since you are choping upper 8 bits of difference, it's same as if you subtracted 0...
0 Kudos
Reply

1,123 Views
Lundin
Senior Contributor IV
The thing is, the optimizer was the one who decided to remove 0x300 from the id variable and store the result in acc D. Then further down, it decides to use

D - 0 which is indeed equal to id - 0x300.

And then it complains subraction with zero.

Creepy, unexpected warnings like this make me nervous and make me suspect that the "tree optimizer" isn't tested properly. Creepier still, setting all variables involved to volatile doesn't help. To be on the safe side, I think I'll disable this optimizer option for all my projects.

---

How much easier things would have been if Metrowerks/Freescale didn't force us to debug optimized code. As I have said countless of times: CW is the only compiler out there that has optimization enabled by default and no simple way to turn it off.

Last time I went in and tried to disable all the optimizer options, I accidently removed one option too much and the code started to behave in unexpected, non-standard ways. The Metrowerks support was clueless, they obviously didn't know about this particular compiler option. Neither did I, so I yelled at them about compiler bugs and then one month later or so I found the compiler option by experimenting on my own.

It can't be awfully hard for the person who knows the details about all 555 optimizer options to write another option "disable optimizer". As things are now, all users who don't like to debug optimized code must read in detail about 555 optimizer options they don't intend to use, or else their programs might behave in weird or random ways when they disable them.
0 Kudos
Reply

1,123 Views
kef
Specialist I


Lundin wrote:
The thing is, the optimizer was the one who decided to remove 0x300 from the id variable and store the result in acc D. Then further down, it decides to use

D - 0 which is indeed equal to id - 0x300.

And then it complains subraction with zero.

Creepy, unexpected warnings like this make me nervous and make me suspect that the "tree optimizer" isn't tested properly. Creepier still, setting all variables involved to volatile doesn't help. To be on the safe side, I think I'll disable this optimizer option for all my projects.

---

Optimizer removed 0x300 not in the line you are getting warning from.
 
 
v4.5 disassembly
   80:  if(id >= DCAN_MSG_FEEDBACK0  &&  0002 830300       [2]     SUBD  #768  0005 8c001f       [2]     CPD   #31  0008 2204         [3/1]   BHI   *+6 ;abs = 000e   81:     id < (DCAN_MSG_FEEDBACK0+FEEDBACK_MSG_N))   82:  {   83:     84:    dsip_id = (unsigned char)(id - DCAN_MSG_FEEDBACK0); /* WARNING C5906 */  000a e681         [3]     LDAB  1,SP  000c 6b82         [2]     STAB  2,SP   85:  }

 
Optimizer removed 0x300 while checking if uint16 id is in the range FEEDBACK0 to FEEDBACK0+N. Nice optimization indeed.
 
C5906 warning comes from line 84:. Subtraction -0 is removed completely, only LDAB id  and STAB dsip_id are here.
I understand your frustration but sometimes we need to be more objective.
0 Kudos
Reply

1,123 Views
Lundin
Senior Contributor IV
Still I wonder why I get the warning when changing all variables to volatile. If I make variable "id" volatile, it is still placed in acc D and said optimization occurs later on, when the variable is used a second time. CW decides to optimize volatile variables, despite ANSI C.


ISO 9899:1999 5.1.2.3.5

"The least requirements on a conforming implementation are:

— At sequence points, volatile objects are stable in the sense that previous accesses are complete and subsequent accesses have not yet occurred."

I can't find any documentation about the tree optimizer where it is stated that keeping it enabled will stop the code from being ANSI/ISO compilant.
0 Kudos
Reply

1,123 Views
kef
Specialist I
OK, id is volatile now. Say me what's not ANSI here
Code:
   81:  if(id >= DCAN_MSG_FEEDBACK0  &&  0001 fc0000       [3]     LDD   id  0004 8c0300       [2]     CPD   #768  0007 250d         [3/1]   BCS   *+15 ;abs = 0016   82:     id < (DCAN_MSG_FEEDBACK0+FEEDBACK_MSG_N))  0009 fc0000       [3]     LDD   id  000c 8c0320       [2]     CPD   #800  000f 2405         [3/1]   BCC   *+7 ;abs = 0016   83:  {   84:     85:    dsip_id = (unsigned char)(id - DCAN_MSG_FEEDBACK0); /* WARNING C5906 */  0011 f60000       [3]     LDAB  id:1  0014 6b80         [2]     STAB  0,SP

 
id is reloaded as many times as id is mentioned in the code. But volatile doesn't and shouldn't prevent optimization on line 85:.
0 Kudos
Reply

1,123 Views
Lundin
Senior Contributor IV
Hmm. It seems I confused the disassebly with volatile for the one without it. If LDAB is performed on "volatile id" later on, yeah then it behaves correctly.

(Assuming a 8-bit access and a 16-bit access gives the same result. I can't remember if there is some case on the HCS12 where it doesn't, but when it comes to timer registers and similar, I'm not so sure.)

So I guess I just do #pragma MESSAGE DISABLE C5906 on this function and pretend I never saw that warning.
0 Kudos
Reply

1,123 Views
kef
Specialist I


Lundin wrote:
(Assuming a 8-bit access and a 16-bit access gives the same result. I can't remember if there is some case on the HCS12 where it doesn't, but when it comes to timer registers and similar, I'm not so sure.)

Yes, in this case 8-bit access and 16-bit access gives the same result.
TCNT is special in that it's free running and 16-bit access is not the same as reading upper and lower bytes and combining them into single 16-bit value. Of course it takes longer to do two 8-bit accesses, but problem is not the +- a couple of timer ticks error, but +- multiplies of 256 timer ticks. Suppose lower part of TCNT is close to 8-bit overflow, for example TCNT is 0x04FD. Reading TCNT high byte first can give you something like 0x0403, reading it low byte first can give you something like 0x05FE. But if you are interested only in lower 8bits of TCNT, then it's OK to access just 8-bits of it.
 
Regarding C5906, yes, I would just #pragma MESSAGE DISABLE it. But I agree with you that it would be nice if we wouldn't need to guess the matter of these weird warnings. If such a warning from the middle/end of optimization appears, then it should be shown how did optimizer transform my code. Probably it's not so easy to implement. If so then these warnings should be disabled by default.
0 Kudos
Reply