Odin
Odin copied to clipboard
Constant signed big endian negative values are incorrect
Expected Behavior
Steps to Reproduce
package main
import "core:fmt"
main :: proc()
{
{
v := i16be(-1) //Assign with constant big endian literal
fmt.printf("{}\n", v)
w := i16(-1)
v = auto_cast w //Assign big endian variable with -1, but do the cast at runtime
fmt.printf("{}\n", v)
fmt.printf("----\n")
}
{
v := i32be(-1)
fmt.printf("{}\n", v)
w := i32(-1)
v = auto_cast w
fmt.printf("{}\n", v)
fmt.printf("----\n")
}
{
v := i64be(-1)
fmt.printf("{}\n", v)
w := i64(-1)
v = auto_cast w
fmt.printf("{}\n", v)
fmt.printf("----\n")
}
{
v := i128be(-1)
fmt.printf("{}\n", v)
w := i128(-1)
v = auto_cast w
fmt.printf("{}\n", v)
fmt.printf("----\n")
}
fmt.printf("{}\n", i64be(-1))
fmt.printf("{}\n", i64be(-2))
fmt.printf("{}\n", i64be(-3))
fmt.printf("{}\n", i64be(-1<<8))
fmt.printf("{}\n", i64be(-1<<16))
fmt.printf("{}\n", i64be(-1<<32))
fmt.printf("{}\n", i64be(123_456_789_000))
}
This prints:
255
-1
----
255
-1
----
255
-1
----
255
-1
----
255
254
253
65535
16777215
1099511627775
123456789000
Casting native int into a big endian one at runtime works fine. Last value was correctly casted since it was positive.
Context
Odin: dev-2022-08:c82d7d3d
OS: Windows 10 Professional (version: 21H2), build 19044.1889
CPU: Intel(R) Core(TM) i5-8600K CPU @ 3.60GHz
RAM: 16330 MiB
I think I might have found a reason why this happens.
In function lb_big_int_to_llvm
in llvm_backend_const.cpp
we get our constant in big int which stores the absolute value and a sign. For example, let's take i64be(-32)
. We first unpack it into 20 00 00 00 00 00 00 00
(little endian).
Since if (!is_type_endian_little(original_type))
is true we swap bytes to get 00 00 00 00 00 00 00 20
.
Because if (big_int_is_neg(a))
is true we negate this, however it seems that LLVMConstNeg
assumes it's little endian, so we get 00 00 00 00 00 00 00 E0
. E0 is 224 in decimal.
fmt.println(mem.any_to_bytes(i64be(-32)), mem.any_to_bytes(i64be(32)))
prints: [0, 0, 0, 0, 0, 0, 0, 224] [0, 0, 0, 0, 0, 0, 0, 32]
fmt.println(mem.any_to_bytes(i64be(-1<<16)), mem.any_to_bytes(i64be(1<<16)))
prints: [0, 0, 0, 0, 0, 255, 255, 255] [0, 0, 0, 0, 0, 1, 0, 0]