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.

Compiler/TMS320F28335: int -> long cast issue with negative numbers

Part Number: TMS320F28335

Tool/software: TI C/C++ Compiler

I observed a strange behavior in my program which I was able to trace to a int to long cast that doesn't behave as expected with a negative int. 

The code is simply:

typedef         int                             INT16S;
typedef         long                            INT32S;

INT16S var1;
INT32S var2;
.
.
. var2 = (INT32S) var1;

However, when the int variable is negative, somehow the compiler fails to cast it properly to long. 

The disassembly looks like:

761F0338    MOVW         DP, #0x338
8517        MOV          ACC, @0x17
761F02CD    MOVW         DP, #0x2cd
1E28        MOVL         @0x28, ACC

And checking the memory shows that the high word is all zeros whereas I would expect it to be padded with F's. Conversely if I explicitly write

var2 = (INT32S)((INT16S)var1);

The disassembly includes an extra line "SETC SXM" instruction:

3B01        SETC         SXM
761F0338    MOVW         DP, #0x338
8517        MOV          ACC, @0x17
761F02CD    MOVW         DP, #0x2cd
1E28        MOVL         @0x28, ACC

And the result of the cast is padded with F's in the upper word. 

Is this the expected behavior?

I am not sure whether this could be related to using the JTAG debugging probe.

Also, I am compiling with the -O3 flag so maybe this could be due to an optimization?  

I would be very grateful for any hint on this issue.

Best regards,

Laurent Badel

  • I am unable to reproduce the problem. I need a test case which allows me to reproduce it.  For the source file with the problem assignment, please follow the directions in the article How to Submit a Compiler Test Case..  If it is not obvious, mark the problem assignment with a comment like // PROBLEM HERE.

    Thanks and regards,

    -George

  • Hi George and thanks for the quick reply. 

    I will try to produce a running test case. The source file in question is part of a relatively large project and we do use a fairly large number of signed integers; I am sure this would have been noticed much earlier if it were really an issue and probably the compiler is right and my code is wrong.

    I am wondering if the compiler will try to optimize the casts, for example, treat a number as unsigned if there is no need to explicitly represent it as signed (e.g. "-x < -y" yields the same result as "x > y"). If that is the case then it would be easier for me to figure out what the compiler is trying to do with my code. Somehow my program was running fine until yesterday, when I observed a change in behavior as one of the variables changes sign from negative to positive; I guess it must be due to some recent change I made but I can't figure out what could possibly have caused this change in behavior. 

    A few things I forgot to mention is that

    (1) The two variables var1, var2 in the above example are two global variables and they are defined in two different source files. 

    (2) I am using CCS v5.1.1.00031 and TI compiler v6.1.8. 

    I will get back to you if/when I am able to produce a test case.

    Best regards

  • I found the cause of the problem. It was because the int variable was defined as "extern unsigned int" in a header file.  However, the compiler did not complain about it because the file that declared the variable did not include the header file.

    Here is a small example consisting of 4 files to reproduce this behavior

    /*
     * common.h
     */
    
    #ifndef COMMON_H_
    #define COMMON_H_
    
    #ifndef TYPES
    #define TYPES
    typedef         int                             INT16S;
    typedef         unsigned int                    INT16U;
    typedef         long                            INT32S;
    #endif
    
    void initx(void);
    
    #endif /* COMMON_H_ */
    
    
    
    /*
     * nocommon.h
     */
    
    #ifndef NOCOMMON_H_
    #define NOCOMMON_H_
    
    // If x is defined as extern INT16U, the SETC SXM instruction in main.asm disappears
    extern INT16U x;
    //extern INT16S x;
    
    #endif /* NOCOMMON_H_ */
    
    
    
    /*
     * external.c
     */
    
    #include "common.h"
    
    INT16S x;
    
    void initx()
    {
    	x = -100;
    }
    
    
    /*
     * main.c
     */

    #include "common.h"
    #include "nocommon.h"

    INT32S A;

    void main(void) {
    INT16S cnt=0;

    initx();

    A = (INT32S)x;

    while(cnt < 200)
    {
    cnt++;
    if ( (INT32S)x >= A)
    x++;
    }
    }

    By defining x in nocommon.h as either "extern INT16U x;" or "extern INT16S x;", the output main.asm file misses or includes the "SETC SXM" statement:

            SETC      SXM                   ; [CPU_] 
            MOVX      TL,@_x                ; [CPU_] |16| 
            MOVW      DP,#_A                ; [CPU_U] 
            MOVL      @_A,XT                ; [CPU_] |16| 

    becomes:
            MOVU      ACC,@_x               ; [CPU_] |16| 
            MOVW      DP,#_A                ; [CPU_U] 
            MOVL      @_A,ACC               ; [CPU_] |16| 

    I understand that the compiler has no knowledge of the original declaration in external.c and must trust the "extern" statement. 

    I wonder if there may be a way to catch this type of errors, though, as in this case I get no compiler or linker error/warning but the program will not behave as expected!

    (I haven't had a chance to actually test this example - only build and inspect .asm output, but I would expect comparison (INT32S)x > A will return  false when x becomes non-negative (0xffff -> 0x0000) and so the program will continue iterating until x reaches -100 from below again). 

    Best regards,

    Laurent Badel