cancel
Showing results for 
Search instead for 
Did you mean: 

Cosmic compiler unexpected result

phorton
Associate II
Posted on February 01, 2013 at 12:05

Hi.

I'm using the Cosmic STM8 compiler (''free'' version, v4.3.9) and it appears to generate unexpected results for the following test :-

static char test(unsigned int x, unsigned int y)

{

   return (int)(x - y) < 0;

}

This function unexpectedly returns 0 when presented with the values x=0x7f80 and y=0x8080.

If I modify the function thus is then returns 1 as expected :-

static char test(unsigned int x, unsigned int y)

{

   x -= y;

   return (int) x < 0;

}

Am I misunderstanding what the result should be ?

P.
18 REPLIES 18
klaasdc
Associate II
Posted on February 06, 2013 at 15:20

Apologies if this a stupid remark, but it is not clear to me why the int cast is only done after the subtraction.

To me, the result cannot be negative because it is an unsigned value, so it is wrapped, and then you cast it to int and because MSB=1 you get a negative value.

If I understand the purpose of the code, I would write

return( ((int) x) - ((int) y) )<0

wolfgang239955_stm1_st
Associate II
Posted on February 08, 2013 at 10:20

Hi,

I think, we all agree, that it is the proper way and good style programming to cast before subtracting.

 

  return ( ( (signed int)x - (signed int)y ) < 0 );

 

BTW: Even an int defined as 32bit or even 64bit word would bring the same result without casting previously to the subtract operation. You only must not mix types as short, long and chars in one operation.

0x00007F80 - 0x00008080 = 0xFFFFFF00 -> cast (signed int) ->

negative

 

There is a file at the STM8S Discovery examples called stm8s_type.h, containing the following typedefs:

  typedef signed long  s32;

 

  typedef signed short s16;

 

  typedef signed char  s8;

 

  typedef unsigned long  u32;

 

  typedef unsigned short u16;

 

  typedef unsigned char  u8;

 

I really like to use this short form and then to write

 

  return( ((s16)x - (s16)y) < 0 );

 

is quite convenient ;o).

WoRo

phorton
Associate II
Posted on February 08, 2013 at 12:36

I don't think we all agree.

Both ''x'' and ''y'' are unsigned quantities, they just happen to wrap at the 16-bit boundary.

If you consider them as values read from a counter for example, they are unsigned values but the difference between two counts can be positive or negative depending on whether one count leads or lags the other.

phorton
Associate II
Posted on February 08, 2013 at 12:39

We don't all agree.

If, for example, ''x'' and ''y'' are values read from a counter timer they are intrinsically unsigned quantities, they just happen to wrap at 16 bits. Though the values are unsigned the difference between two counter timer values can be signed and the result should be correct as long as the values don't differ by more than 15 bits.

phorton
Associate II
Posted on February 08, 2013 at 12:42

I've attached a file which includes generated assembly etc.

Fundamentally the compiler generates different code for these two cases, which is an error as they are functionally identical.

void delta_1(unsigned int x, unsigned int y)

{

return (int)(x - y) < 0;

}

void delta_2(unsigned int x, unsigned int y)

{

x -= y;

return (int) x < 0;

}

________________

Attachments :

details.txt : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HzOJ&d=%2Fa%2F0X0000000bKz%2FxG1xu8aBxSZ7h1tbwsj5x485ST4hk0lubyYVxKhKRwI&asPdf=false
fggnrc2
Associate II
Posted on February 08, 2013 at 14:31

Hello Peter.

The different behaviour between delta_1 and delta_2 is due to the instruction:

 709  80cf 2e05              jrsge    L4

This instruction executes a jump when (N XOR V) = 0, where N and V are respectively the negative flag and the overflow flag.

When x = 0x7F80 and y = 0x8080, both N and V are set, so the jump is taken.

The cast operation is the culprit of this (mis)behaviour, because a signed int can't hold the value of y.

You may wonder if this behaviour is a compiler bug, or else.

I suppose that it's ''implementation defined'', so it's a potential source of errors as all the things that are related to the cast operator.

As regards the subtraction of counter values, which are unsigned quantities by definition, their difference is still the elapsed time, even if y is greater than x.

When x = 0x7F80 and y = 0x8080, their difference is 0xF800 (unsigned) which is exactly the number of counter ticks that elapsed between the ending tick (x) and the starting tick (y).

This result holds only if the counter overflows at most once, otherwise the result must be adjusted with the product of the counter resolution and the number of overflows minus one.

EtaPhi

phorton
Associate II
Posted on February 08, 2013 at 15:47

But the code for delta_1() and delta_2() are the same. Both feature an unsigned subtraction followed by a cast to int and a comparison with 0. The compiler should ideally generate the same code for both cases, failing that it should at least generate the same result.

fggnrc2
Associate II
Posted on February 08, 2013 at 16:36

An ideal compiler would also remove the instructions:

704 80cb 89 pushw x

716 80d7 5b02 addw sp,#2

because they are useless.

The Cosmic compiler does its best to help you, but it sometimes can't translate what you mean because of C language ambiguities whose behaviour is ... implementation defined!

If you want a certain kind of result, you must avoid ambiguities, otherwise you must use the assembler language...

wolfgang239955_stm1_st
Associate II
Posted on February 08, 2013 at 17:29

I tried the different codes with another compiler and there I get the following:

For all the four lines

  { return (int)(x-y) < 0; }

 

  { return ((int)x - (int)y) < 0; }

 

  { x -= y;  return (int)x < 0; }

 

  { int z = x - y;  return z < 0;}

 

the compiler produces absolutely identical codes, similar to what we get with the 3rd line.

While the lines

  { return x < y; }

 

  { return (int)x < (int)y; }

 

will produce code, where the results depend on the signed or unsigned comparison.

I think, Peter you found something very special.

?????

WoRo