This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

C55x --check_32bit_int_portability switch, enhancement requests

I'm not sure whether to ask this question here or the C5000 forum. Anyway here goes:

The --check_32bit_int_portability switch is very useful for porting code from a standard architecture to the C5000 architecture where chars and ints are both 16 bits. It highlights code that would have worked on a standard architecture but not on the C5000, such as

short s1 = 10000;

short s2 = 600;

long bigNum = s1 * s2; // overflow on C55x

However it throws up many false positives that I think could easily be eliminated. I think the same warning is produced regardless of the binary operator on the last line.I think it should only warn if the operator can increase the number of bits that might be required to produce the result. To me this is just + - << and *, together with their corresponding assignment operators. I'd have to think real hard about it, but depending on the size and signedness of the operands, '-' may not be able to increase the number of bits either.

In other words I don't think it should warn for & | ^ >> / % or the comparison or equality operators. I haven't checked all of these but I know it warns for &, | and >>

I'm using v4.3.9.I've checked 4.4 and it does the same.

Can I put in a request for this enhancement please, or have I got this wrong?

I don't like ignoring warnings, because its easy to miss new ones when code is revised.

The only way to eliminate the warning I have found is to write another assignment expression which does the 16 bit operation, but I don't want to do that for an erroneous warning.

In some cases I can be sure from examining the code that there is no problem. With s1 and s2 as above:

long bignum = s1 + s2;

If I write instead

long bignum = (short)(s1 + s2);

in my view that should inform the compiler that I'm quite sure s1 + s2 won't overflow, and not to produce a warning. However I have to write

short s = s1 + s2

long bignum  = s;

to eliminate the warning, which is overkill just to eliminate a warning.

So here is another request, a cast operator should have the same effect as the separate assignment and eliminate the warning.

  • You came to the right place.  I filed an enhancement request in the SDOWP system.  The id is SDSCM00043246.  Feel free to track it with the SDOWP link below in my signature.

    Thanks and regards,

    -George

  • Be careful here.  While it is obvious that &&, ||, and ! are safe, and slightly less obvious that unary + is safe, some of these are much less obvious, particularly when signedness is mixed.  In fact, some of the things that seem like they should be safe aren't, as the following test case demonstrates.  This gets different results on C6000 and C5500, mostly because of signed integer overflow causing undefined behavior, which is the primary thing --check_32bit_int_portability is trying to warn you about.

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    
    int main()
    {
        /* subtraction is not safe */
        {
            int16_t x = INT16_MIN;
            int16_t y = 1;
            int32_t z = x - y; /* OK on C6000, overflow on C5500 */
            printf("subtraction: %"PRId32"\n", z);
        }
    
        /* unary negation is not safe */
        {
            int16_t x = INT16_MIN;
            int32_t z = -x; /* OK on C6000, overflow on C5500 */
            printf("unary negation: %"PRId32"\n", z);
        }
    
        /* division is not safe (but modulus is!) */
        {
            int16_t x = INT16_MIN;
            int16_t y = -1;
            int32_t z = x / y; /* OK on C6000, overflow on C5500 */
            printf("division: %"PRId32"\n", z);
        }
    
        /* bitwise negation is not safe when the input is unsigned */
        {
            uint16_t x = 0;
            int32_t z = ~x; /* -1 on C6000, 65535 on C5500 */
            printf("bitwise negation: %"PRId32"\n", z);
        }
    
        return 0;
    }
    

    I believe (but have not proven) that the following operations are always safe (with regards to --check_32bit_int_portability only), regardless of the signs of the inputs:

    • logical negation
    • unary plus
    • modulus
    • right shift
    • comparisons
    • bitwise and, xor, or (but not bitwise negation!)
    • logical and (&&) and or (||)
    • assign-ops (*=)

    These are definitely not always safe:

    • bitwise negation
    • unary negation (unary minus)
    • multiplication
    • division
    • addition
    • subtraction
    • left shift



  • John Fisher said:

    long bignum = (short)(s1 + s2);

    Write it like this:

    long bignum = (long)s1 + s2;

    The compiler knows that this is safe (with respect to --check_32bit_int_portability).  Note that the compiler won't necessarily use a 32-bit addition to perform this operation, because it is able to see that the operands are 16-bit operands, so it is possible it could use the cheaper 16-bit addition on C5500.

  • Signed integers are actually quite rare in the code I'm porting. A high proportion of my false positives are & | >> and subtraction of unsigned integers, so this is my main concern with the enhancement request.

  • Unsigned subtraction is not safe, either:

    #include <stdio.h>
    #include <inttypes.h>
    
    int main()
    {
        uint16_t x = 0x0;
        uint16_t y = 0x1;
        uint32_t z = x - y; /* C6000: 4294967295 C5500: 65535 */
        printf("z == %"PRIu32"\n", z);
        return 0;
    }
    
  • John Fisher said:
    I don't like ignoring warnings, because its easy to miss new ones when code is revised.

    Just a note: I believe the intention of this option (when it was added) was that a project would use it once to identify all the possible problems and rewrite those locations using portable syntax, rather than regularly using the option as part of the project.  Then as long as new code was written in the portable syntax there should be no problems going forward.

  • Wolf said:

    I believe the intention of this option (when it was added) was that a project would use it once to identify all the possible problems and rewrite those locations using portable syntax, rather than regularly using the option as part of the project.  Then as long as new code was written in the portable syntax there should be no problems going forward.

    Things don't always work this way. It can take a while to reform habits of those who are used to living in their comfortable worlds of standard architectures, particularly when you have parallel projects moving forward on different architectures for a period of indeterminable length.

  • Archaeologist said:

    Unsigned subtraction is not safe, either:

    My mistake. A long time ago I came across the part of the C standard that says that unsigned computations can't overflow. Later I went looking for it, couldn't find it and decided I'd been imagining it. Anyway I've found it again, so thanks for drawing attention to it. In the code I'm porting the subtractions can't overflow because of immediately preceding tests, but I don't suppose you want to get into the business of static analysis.

  • Archaeologist said:

    long bignum = (short)(s1 + s2);

    Write it like this:

    long bignum = (long)s1 + s2;

    The compiler knows that this is safe (with respect to --check_32bit_int_portability).  Note that the compiler won't necessarily use a 32-bit addition to perform this operation, because it is able to see that the operands are 16-bit operands, so it is possible it could use the cheaper 16-bit addition on C5500.

    [/quote]

    If the compiler can see that it can use a 16-bit addition, even in the absence of a cast, why would it warn?

  • That is a surprisingly difficult question to answer due to the subtle nature of the problem.

    First of all, I made a mistake in my last post; I conflated the idea of an optimization the compiler does for multiplications with the operation of --check_32bit_int_portability.  Given the following expression, the compiler must treat it as a "long" addition:

    long bignum = (long)s1 + s2;

    John Fisher said:
    If the compiler can see that it can use a 16-bit addition, even in the absence of a cast, why would it warn?

    Consider this expression:

    long bignum = s1 + s2;

    In the absence of a cast, the C55x compiler can see that it can use a 16-bit addition because you told it to, by adding two "short" values, which the C standard requires us to treat as "int" for the addition operation.  However, it cannot see that this operation will not overflow.  It can see that the operation might overflow, and that the same operation could not possibly overflow on a target like C6000, so it emits the warning.  With or without the warning, the C55x compiler will use the 16-bit addition.

    If you write this expression:

    long bignum = (long)s1 + s2;

    This is now a 32-bit addition operation, so you don't get the warning.

  • I was already aware that

    long bignum = (long)s1 + s2;

    would avoid the warning by forcing a 32 bit operation. I don't want to do that because I can see a 16-bit op is all that's necessary.

    The suggestion of writing it:

    long bignum = (short)(s1 + s2);

    does look a little weird, but I've reduced real code to an example showing the essentials. It doesn't look so weird if the real code is a larger expression statement involving both 32 bit and 16 bit operations.

    My thinking was that the (short) cast has the effect of isolating the 16 bit part of the expression from the surrounding 32-bit part, assuring the compiler that 16 bits is all that's necessary and so preventing the warning. As I said, I could prevent the warning by declaring a new 16 bit variable and writing separate expression statements, but that does seem like overkill.

  • Could you provide a compilable example for which the 4.3.9 C55x compiler emits the --check_32bit_int_portability warning on that line?  I can't seem to construct one. Here is one attempt:

    long fn(short s1, short s2)
    {
        long bignum = (short)(s1 + s2);
        return bignum;
    }
    
  • It looks like the cast prevents the compiler from emitting the warning. So in fact it does exactly what I thought it should do. I remember testing it, but must have made a mistake somehow. I therefore have only one enhancement request, that it not warn when the operator(s) concerned can't increase the number of bits required. In my case that would eliminate about 100 warnings.

  • The intent of --check_32bit_int_portability is to warn about cases that would have different behavior on C55x versus 32-bit architectures.  Even if we make it do that perfectly (by silencing binary and, etc), it will still warn about cases like "unsigned int" subtraction, as noted above.

  • I understand. Thanks for the help.