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.

Literal Not Calculated From Macro As Expected

Other Parts Discussed in Thread: ADS7038

Hello All,

I'm using CCS Version: 10.2.0.00009, C2000 compiler 20.2.2 LTS with COFF output for F2837xD controlCARD.

I want to break out of a loop when a variable >= 2560. When I (try to) calculate the literal 2560d using a macro, the literal value for compare is not as expected when compiled.

The following calculation results in 2560:

(((20,000,000 * 20 * 1) / 2) * 32 * 2) / 5,000,000 = 2560d

But when compiled, the value works out to be 842d or 34Ah so my loop breaks out too early.



The disassembly also confirms the literal 842 (34A) is compiled.

Why does the compiler not arrive at 2560 (A00h) please? I've probably done something daft but can't spot it.

Thank you.

  • My guess is you have an error in your preprocessing statements.  The best way to track down such an error is by building with the compiler option --gen_preprocessor_listing.  This creates a file with same name as the source file, but the extension is changed to .rl.  To learn how to use it, please search the C28x compiler manual for the sub-chapter titled Generating a Raw Listing File.

    If you still cannot find the problem, zip up the .rl file and attach it to your next post.

    Please let me know if this suggestion resolves the problem.

    Thanks and regards,

    -George

  • It could also be that the compiler is using 16bit arithmetic.

    Have you tried doing it in a variable?

  • Please ignore my previous post.  The problem is in the type of the constants. 

    Change the large constants so they have the suffix LL, like this ...

    #define DEVICE_SYSCLK_FREQ 20000000ULL

    That causes the compiler to make the type of those constants long long (64 bits) instead of int (16 bits).  That means the very large intermediate results of the computation of this expression ...

    (((20000000ULL * 20 * 1) / 2) * 32 * 2) / 5000000ULL

    ... are long long as well, and thus do not overflow.

    Thanks and regards,

    -George

  • Looks like you're right Keith.

  • Hi George and Keith,

    Thanks for the tips. Because the DEVICE_SYSCLK_FREQ macro doesn't belong to me as such I just added a cast to my local,  dependent macro. That fixes the issue too:

     #define ADS7038_HAL_SPI_TIMEOUT ( (uint64_t)DEVICE_SYSCLK_FREQ * 32 * 2 / ADS7038_HAL_SPI_CLK_FREQ )

    I confess I don't get really understand the why this is necessary.

    The existing literals (e.g. 20,000,000) already require 32 bit storage so by this logic an L suffix is also mandatory to avoid the same overflow problems and yet L is not present.

    Why then is LL required to for intermediate 64 bit storage please?

  • The evaluation of expressions like ...

    (((20,000,000 * 20 * 1) / 2) * 32 * 2) / 5,000,000

    .... is performed as if it were calculated on the target CPU.  This means the width of the types used (int, long, or long long) are those of the target CPU.  In this case, the target CPU is C28x, where int is 16 bits, long is 32 bits, and long long is 64 bits.  For this particular expression, you have to use the type long long because the result of one part of the expression does not fit in 32 bits.  (((20000000 * 20 * 1) / 2) * 32 * 2) is 12800000000, which does not fit in 32-bits.

    Thanks and regards,

    -George

  • Thank you. However your first explanation gives the reason as being it (the intermediate result) doesn't fit into 16 bits and your second gives the reason it doesn't fit into 32 bits.

    My point is that there's an inconsistency here. The compiler does not require a L suffix to successfully calculate the literal, DEVICE_SYSCLK_FREQ for example, but does require an LL suffix for literals greater than L max value.

  • I have not explained all the nuances.  I think this example better illustrates all the details.

    #define BIG 32767
    #define EXPR (BIG * BIG * BIG)

    The default type of the literal constant 32767 is int (16 bits). When two int values are multiplied, the operation is performed all in int, and is assumed to not overflow.  But these multiplies do overflow, which violates the assumption.  Here is an attempt at a fix ...

    #define BIG 32767L
    #define EXPR (BIG * BIG * BIG)

    The suffix L is added to BIG.  Now the type is long (32 bits).  Thus, the multiply is performed all in long.  But the result of these multiplies exceeds 32 bits, and it still overflows.  So, this is the change which finally fixes the problem ...

    #define BIG 32767LL
    #define EXPR (BIG * BIG * BIG)

    The suffix LL means the type of the constant is long long (64 bits).  Now the multiply is performed in long long, and it does not overflow.

    Thanks and regards,

    -George

  • Thanks George but your explanation based around the native 16 bit int type does not tackle the specific case in point which is concerned with unsigned types.

    I’ll simplify the problem test cases:

     

    If the compiler was consistent I would need an L suffix (e.g. 10000000UL) in line 76 because I absolutely need an LL suffix in line 80. Like I said, the compiler is inconsistent.

    If your explanation for the inconsistency is that my literals, in this case both initial and intermediate values, are greater than the native int/16 bit type then an L suffix must be required in line 76. That is not the case as demonstrated above.

    So I don't think the reason can be to do with the native data type.

  • I think your complaint is that the precise source of the problem, and the solution to the problem, are distant from each other.  

    The source of the problem is that the multiply is assumed to never overflow.  When the #define name is created, it is not known whether it will be an operand to a multiply that may overflow, so it is not obvious at that point whether any suffix is needed.  With that in mind, it may make more sense to apply a solution at the point of the multiply, and not when the #define name is created.  That means applying a cast to at least one of the operands of the multiply.  Like this ...

    #define BIG 32767
    #define EXPR ((uint64_t)BIG * (uint64_t)BIG * (uint64_t)BIG)

    Feel free to use this solution instead.  

    Thanks and regards,

    -George

  • Do the casts work at compiletime to allow for the calculation of the expression?

  • You've made the solution (missing LL) to the original problem clear and I thank you for the advice. However, along the way, I noticed an inconsistency that the compiler rightly requires an LL suffix when the conditions dictate it but does not require an L suffix in a commensurate situation. None of the above explains away that logical discrepancy.

    This open question is perhaps indirectly related to the original question and on reflection I should have raised a new thread. However, it's just not that important so let's just close this thread and thank you for your time.