1: Sample code that reproduces the problem.
_Static_assert(0x10000LL != 0, "high bits");
_Static_assert(0x20000000000000ULL != 0x20000000000001ULL, "distinct values");
_Static_assert(65436U != -100LL, "unsigned value differs from negative value");
2: Exact command used to run SDCC on this sample code.
sdcc -mz80 --std-c11 -S longlong-equality.c
3: SDCC version tested (type "sdcc -v" to find it).
SDCC 4.6.4 #0 (Linux), built from SVN r16960 sources.
4: Copy of the error message or incorrect output, or a clear description of the observed versus expected behavior.
longlong-equality.c:1: warning 215: static assertion failed: "high bits"
longlong-equality.c:2: warning 215: static assertion failed: "distinct values"
longlong-equality.c:3: warning 215: static assertion failed: "unsigned value differs from negative value"
All three assertions are true. The first comparison must account for bit 16. The second compares two distinct integers above the range in which double can represent every integer exactly. In the third, 65436U converts to long long and remains positive, so it differs from -100LL.
valCompare can truncate equality comparisons involving long long constants to unsigned int. Separately, isAstEqual compares literal values after conversion to double, which can round distinct large integers to the same value.
The same failures occur on mcs51 (default, medium, large and stack-auto), ds390, z180, r2k, r4k, sm83, tlcs90, hc08, s08, stm8 and pdk13/14/15. They also occur with Z80 in C23 mode.
GCC 16.2.0 and Clang 23.1.0 accept the example without diagnostics: https://godbolt.org/z/nna4fKed9
While working on [bugs:#3952], I noticed a workaround in
stdckdint.hwhich avoids using_Genericin the way intended by its designer (to select a function before calling it), for performance reasons relating to feature request 880. In turn, that workaround required me to add casts that I would rather not have added because they undermine type safety.My candidate implementation of feature request 880 exposes this bug in checked integer arithmetic, so I believe this bug needs to be fixed first. In any case, it is clearly behaviour that is incompatible with Clang and GCC.
Related
Bugs: #3952
Last edit: Christopher Bazley 1 day ago
Please find a candidate patch to fix this bug attached.
As the comment in valCompare about missing long long support states, there probably is still a problem for relational operators (I guess when precision in the lower bits is lost as a value is converted to floating-point format).
The fix (both yours and my deduplicated variant above) make a test fail:
Last edit: Philipp Klaus Krause 8 hours ago
Hi Philipp, please find a revised candidate patch attached.
It shares
valComparebetween AST and iCode constant folding for all six comparison operators, removing the duplicated equality handling and fixing relational comparisons. This significantly reduces the amount of code in SDCCicode.c.Integer operands undergo integer promotion and common-type conversion before comparison, preserving wide values and signed ordering. The unsigned
> 0simplification now checks the full constant value.The failing
longlong_test_bitassertion exposed incorrect iCode bitwise constant folding. UsingvalBitwisefor&,|and^avoids rounding operands through double or truncating them to 32 bits.The added tests cover wide comparisons, mixed signedness, checked subtraction into a narrower result type, and agreement between constant-folded and runtime bitwise operations.
This fix is a prerequisite for the patch that implements [feature-requests:#880].
Last edit: Christopher Bazley 6 hours ago
Most of this looks good to me. I do have a question on the changes in
isAstEqualthough: the changes clearly fix false positives for long long comparisons, but I think they introduce new false negatives for mixed sign. That might not cause real bugs, since looking at the uses ofisAstEqual, I think false negatives just result in some missed optimizations. Still it feels like the false negatives should either be fixed, or clearly stated in a comment.