This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Integer promotion bug

I think there is a bug in the C51 and CX51 compilers
regarding integer promotion. I have not deselected
integer promotion and thus expect proper C semantics
without adding casts. The bug seems to be appearing
in different cases but working in others, like with
the "?" operator versus the if-statement.

Se code below with comments on actual and expected results.

typedef unsigned char uint8_t;
typedef   signed char int8_t;
typedef   signed int  int16_t;

volatile int x;

void foo(void)
{
    int8_t b1 = -128, b2 = 0;

    x = -b1; // OK: x = 128
    x = b1 > 0 ?
          0 :
          -b1;   // ERR: x = -128

    if (b1 > 0)
       x = 0;
    else
       x = -b1;     // OK: x = +128

    x = -(b1-b2);   // OK: x = 128
    x = (b1-b2) > 0 ?
          0 :
          -(b1-b2);    //ERR: x = -128

    if ((b1-b2) > 0)
       x = 0;
    else
       x = -(b1-b2);     // OK: x = +128
}

void fie(void)
{
    uint8_t b1 = 10, b2 = 20;

    x = (b1-b2) > 0 ?
          0 : // ERR: This branch is executed -> x = 0
          -(b1-b2);

    if ((b1-b2) > 0)
       x = 0;  // ERR: This branch is executed -> x = 0
    else
       x = -(b1-b2);
}

#define ABS(a) ((a) > 0 ? (a) : (-(a)))
#define ABS_FIX(a) ((int16_t)(a) > 0 ? (a) : ((int16_t)-(a)))

void fum(void)
{
   int8_t b1 = -128;
   uint8_t b2 = 10, b3 = 20;

   x = ABS(b1); // ERR: x = -128
   x = ABS_FIX(b1); // OK: x = +128

   x = ABS(b2-b3); // ERR: x = 246
   x = ABS_FIX(b2-b3); // OK: x = 10
}

int main(void)
{
   foo();
   fie();
   fum();
   return 0;
}

  • You've omitted some detail.

    Like:

    The version of the compiler you're using.

    What optimizations, and whether the results change when you change optimizations.

  • Here is the missing info;

    The problem is the same in optimize level 0 and 8.

    Tool Version Numbers:
    Toolchain: PK51 Prof. Developers Kit Version: 8.18
    Toolchain Path: C:\Keil\C51\BIN\
    C Compiler: C51.Exe V8.18
    Assembler: A51.Exe V8.01
    Linker/Locator: BL51.Exe V6.20
    Librarian: LIB51.Exe V4.24
    Hex Converter: OH51.Exe V2.6
    CPU DLL: S8051.DLL V3.65
    Dialog DLL: DP51.DLL V2.54

  • Always put parentheses around what you are evaluating, it's surprising what the results will be if you don't. And no it's not a bug in the compiler just your code.

    Stephen

  • Why isn't this a bug? Is C51 a special kind of compiler that is supposed to produce different results than any other C-compiler?

  • Put parentheses around the evaluation like you would (and did) in if then else statements and it will work. That's not a bug it's a matter of operator precedence and evaluation of the expression.

    Essentially your expressions when using the ? operator are ALWAYS evaluating to zero for the '?' operator and that means the expression past the ':' is always the result.

    This is a common mistake and Lint would have picked it up immediately.

    Stephen

  • Sorry but you are wrong. This is not a operator precedence bug, maybe in C51, so I tested adding
    parentheses around all expressions. The result is
    exactly the same.

    The code with extra parentheses follows.

    
    typedef unsigned char uint8_t;
    typedef   signed char int8_t;
    typedef   signed int  int16_t;
    
    volatile int x;
    
    void foo(void)
    {
        int8_t b1 = -128, b2 = 0;
    
        x = -b1; // OK: x = 128
        x = ((b1) > 0) ?
              (0) :
              (-b1);   // ERR: x = -128
    
        if (((b1) > 0))
           x = 0;
        else
           x = -b1;     // OK: x = +128
    
            x = -(b1-b2);   // OK: x = 128
        x = ((b1)-(b2)) > 0 ?
              0 :
              (-(b1-b2));    //ERR: x = -128
    
        if (((b1)-(b2)) > 0)
           x = 0;
        else
           x = -(b1-b2);     // OK: x = +128
    }
    
    void fie(void)
    {
        uint8_t b1 = 10, b2 = 20;
    
        x = ((b1)-(b2)) > 0 ?
              0 : // ERR: This branch is executed -> x = 0
              (-((b1)-(b2)));
    
        if (((b1)-(b2)) > 0)
           x = 0;  // ERR: This branch is executed -> x = 0
        else
           x = -(b1-b2);
    }
    
    #define ABS(a) (((a) > 0) ? (a) : (-(a)))
    #define ABS_FIX(a) (((int16_t)(a) > 0) ? (a) : ((int16_t)-(a)))
    
    void fum(void)
    {
       int8_t b1 = -128;
       uint8_t b2 = 10, b3 = 20;
    
       x = ABS(b1); // ERR: x = -128
       x = ABS_FIX(b1); // OK: x = +128
    
       x = ABS((b2-b3)); // ERR: x = 246
       x = ABS_FIX((b2-b3)); // OK: x = 10
    }
    
    int main(void)
    {
        foo();
            fie();
            fum();
            return 0;
    }
    

  • I don't agree that this is a problem with precedence.

    This is the part I concentrated on:

        x = b1 > 0 ?
              0 :
              -b1;   // ERR: x = -128
    

    I ran it through the Keil ARM compiler and got the answer you (and I) expected.

    I would take it up with Keil support.

  • Looks like I am wrong indeed. The parser appears to be evaluating the second value in the comparison operator expression and using that as the resultant of the expression. This of course means it's a constant false and anything post the : token is considered the resultant. If it's optimizing hmmm this could be a bug in the optimizer, have you tried the same code with no optimization? Of course that won't help you with your problem any. (sigh)

    Sorry hopefully keil support will be a lot more helpful than I.

    Stephen

  • Sorry hopefully keil support will be a lot more helpful than I.
    they won't unless you tell them. Keil support do not (regulrily) watch the forum

    Erik