Skip to content

Inconsistent treatment of signedness of Cmm literals

Consider these Cmm programs:

testA() { return (       0x8000000000000000::bits64    ); }
testB() { return (      -0x8000000000000000::bits64    ); }
testC() { return (%quot( 0x8000000000000000::bits64, 2)); }
testD() { return (%quot(-0x8000000000000000::bits64, 2)); }

In general, one wouldn't expect that 0x8000000000000000::bits64 and -0x8000000000000000::bits64 differ semantically, given that we assume a two's complement sign representation.

In the case of testA and testB GHC respects this expectation. However, in the case of testC and testD there is a surprising difference:

Program          Value emitted in assembler
-----------      ---------------------------
`testA`          `-9223372036854775808`
`testB`          `-9223372036854775808`
`testC`          ` 4611686018427387904`
`testD`          `-4611686018427387904`

That is, while we produce the correct result in testD, in testC we silently drop the sign bit. Given that this same behavior is not observed in testA and testB, I can only assume that this is some constant folding going awry.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information