Optimize integer promotions, CW for HCS12

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

Optimize integer promotions, CW for HCS12

598 Views
Lundin
Senior Contributor IV

My specific case is an old CW3.1, but I suspect the problem is universal for any CW for HCS12.

 

I am trying to optimize down some code in an ISR. This is the code:

 

 

static uint8           indataCount;
static uint8           indataSize;
...
else if(indataCount < indataSize+2)
{
  copy = TRUE;
}      

The integer promotions in C are applied twice in this expression. indataSize is first promoted to an int, then incremented by 2. And then the whole expression is again promoted to an int, which would also have happend if the +2 wasn't there, since the C language can't perform any arithmetics on 8-bit integers.

 

The code translates to the following:

 

 4249:      else if(indataCount < indataSize+2)
  006e 87           CLRA 
  006f b745        TFR   D,X
  0071 f60000     LDAB  indataSize
  0074 c30002     ADDD  #2
  0077 3b           PSHD 
  0078 aeb1        CPX   2,SP+
  007a 2d13        BLT   *+21 ;abs = 008f

 

And I didn't expect any optimization, the C language sort of enforces this to be done on 16 bit.

However, with a little manual tweak, I get much faster code:

 

 4249:      else if(indataCount < (uint8)(indataSize+2))
  0071 b60000      LDAA  indataSize
  0074 8b02         ADDA  #2
  0076 b10000     CMPA  indataCount
  0079 221c         BHI   *+30 ;abs = 0097

Now the compiler has suddenly told the C standard to get lost and skipped the integer promotions  (which is fine with me for this specific case). It seems to me that the compiler assumes that the programmer is clueless about the integer promotions, and decides to abandon the C standard at its own whim, in a non-consistent way.

 

My questions:

1. When will the compiler know where it can skip integer promotions in my code and optimize? Where is this non-standard behavior documented? I can't find anything about it in the compiler docs.

2. Why didn't the compiler not optimize the indataSize+2 subexpression while it did optimize the uint8 < uint8 one?

3. Is there a compiler optimizing setting that toggles this behavior on/off?

Labels (1)
0 Kudos
3 Replies

311 Views
CompilerGuru
NXP Employee
NXP Employee

> 1. When will the compiler know where it can skip integer promotions in my code and optimize?

> Where is this non-standard behavior documented? I can't find anything about it in the compiler docs.

 

The compiler optimizes the comparison when the resulting behavior is absolutely identical, and only then.

In the case of the cast to unsigned char, the high byte of both sides of the comparison are always 0 and the compiler therefore does not bother comparing the high 0 bytes to each other. The behavior is standard compliant.

 

> 2. Why didn't the compiler not optimize the indataSize+2 subexpression while it did optimize the uint8 < uint8 one?

Because for "indataCount < indataSize+2" the behavior is not indistinguishable, when indataSize is 0xFF, indataCount is 7, then the int comparison generates another result than the byte comparison and therefore the compiler cannot just compare the lower 8 bits.

 

> 3. Is there a compiler optimizing setting that toggles this behavior on/off?

 

Not that I know of.

There is a NON ANSI compiler option to suppress the integral promotion (-cni), but often the compiler can see that the comparison is not needed on its own, so I usually do not recommend it as it is non standard compliant.

Also note that ANSI C does conceptually always do integral promotions, and we definitely do not want the compiler to actually do a int comparison for code like (indataCount == 1)....

 

Daniel

 

0 Kudos

311 Views
Lundin
Senior Contributor IV

I wonder if this is true formally. I haven't managed to find where in the standard this is mentioned. As far as I understand it, an uint8 will be implicitly promoted to an int, which is signed. Theoretically that could result in a negative number, but perhaps never on Freescale two's complement implementations.

 

CW does give me 2 as result from sizeof(uint8 < uint8), even though the actual disassembly results in 1 byte. That's why the latter seems to be a non-standard optimization.

 

 

0 Kudos

311 Views
CompilerGuru
NXP Employee
NXP Employee

 

Ansi C does not state that a certain machine code has to read the formal type.

Instead the execution behavior of a program is defined as a set of "side effects"

(from a C89 draft:smileyhappy:

> Accessing a volatile object, modifying an object, modifying a file,

> or calling a function that does any of those operations

 

And those side effects have to occur in between cerain "sequence points".

 

 For the given sample

if(indataCount < indataSize+2){  copy = TRUE;}

 

There is actually only a single side effect in this snippet, the assignment of TRUE to the copy variable.

There are sequencepoints at instruction boundaries, in this case one before the if, one before the copy assignment, one after it and one at after the whole if statement.

The code behaves correct according to ANSI C if the side effect, the assiment, is executed when the if condition evaluates to true.

 

BTW: that "sizeof(uint8 < uint8)" is 2 is irelevant in repect of how the comparision is happening. The sizeof is for the type of the result of the comparison, which is int. It's 2 also for a "sizeof(double < unsigned long)" Smiley Happy.

 

 

 

 

 

0 Kudos