Discussion:
bug in type conversion?
Cosmin Apreutesei
2014-08-11 14:16:17 UTC
Permalink
Hi,

The following code fails with jit on, but works with jit off (luajit
2.0.3 and 2.1, 32bit and 64bit).


local ffi = require'ffi'

local buf = ffi.new'uint32_t[1]'
local p = ffi.cast('uint32_t*', buf)

local c = -0x80000000
for i = 1,1000 do --wait for the jit to kick in
p[0] = c
end

print(string.format('0x%x', p[0])) --should be 0x8000 0000 but it's 0


PS: Probably not related, but in 64bit mode, string.format('0x%x',
bit.lshift(128, 24)) prints 0xffff ffff 8000 0000 although
print(bit.lshift(128, 24)) shows -2147483648.


Thanks.
Mike Lynch
2014-08-11 14:34:32 UTC
Permalink
Post by Cosmin Apreutesei
local ffi = require'ffi'
local buf = ffi.new'uint32_t[1]'
local p = ffi.cast('uint32_t*', buf)
local c = -0x80000000
for i = 1,1000 do --wait for the jit to kick in
p[0] = c
end
print(string.format('0x%x', p[0])) --should be 0x8000 0000 but it's 0
Works for me with v2.1 branch built for PPC with or without the '-' on
'local c = -0x80000000'.
Mike Pall
2014-08-11 14:45:32 UTC
Permalink
Post by Cosmin Apreutesei
local ffi = require'ffi'
local buf = ffi.new'uint32_t[1]'
local p = ffi.cast('uint32_t*', buf)
local c = -0x80000000
for i = 1,1000 do --wait for the jit to kick in
p[0] = c
end
print(string.format('0x%x', p[0])) --should be 0x8000 0000 but it's 0
Nope, the result is undefined. -0x80000000 is a *negative*
floating-point number. As such, any conversion to an *unsigned*
integer is undefined.

You probably wanted to convert 0x80000000, which is a positive
number (and that works fine).
Post by Cosmin Apreutesei
PS: Probably not related, but in 64bit mode, string.format('0x%x',
bit.lshift(128, 24)) prints 0xffff ffff 8000 0000 although
print(bit.lshift(128, 24)) shows -2147483648.
bit.* always returns signed numbers in the range of 32 bit
integers (*). The result of bit.lshift(128, 24) is negative.

(*) The rules are different if you pass 64 bit cdata numbers to
bit.* (2.1 feature).

The behavior of string.format("%x") wrt. negative numbers is
ill-defined in Lua 5.1 and LuaJIT 2.0. The conversion was
undefined and/or 32/64 bit versions returned different results.

Starting with LuaJIT 2.1, string.format("%x") accepts input in the
combined range of int64_t and uint64_t and converts it to hex as
if it was an uint64_t. This means you'll get "ffffffff80000000"
as a result.

If you need to convert a number to a hex string in a defined way
for all versions, use bit.tohex().

--Mike
Cosmin Apreutesei
2014-08-11 17:26:30 UTC
Permalink
Hi Mike, thanks for answering.
Post by Mike Pall
bit.* always returns signed numbers in the range of 32 bit
integers (*). The result of bit.lshift(128, 24) is negative.
What would be a good way to do bit-shuffling and then pass the results
to uint32 cdata without the sign getting in the way?

I think I need something like the opposite of bit.tobit().
Mike Pall
2014-08-11 17:32:45 UTC
Permalink
Post by Cosmin Apreutesei
What would be a good way to do bit-shuffling and then pass the results
to uint32 cdata without the sign getting in the way?
Use int32_t cdata. The JIT compiler likes it much better, anyway.

You can pretty much ignore the signedness everywhere, except for
ordered comparisons. If necessary, lie to the C side.

--Mike
Cosmin Apreutesei
2014-08-11 18:20:03 UTC
Permalink
Got it, I'll embrace signed types. I revisited bitop's rationale page
so I can chill about bitop signed results :)

Btw, these tech pages that you write are so good. Ever thought about
writing The LuaJIT Book? It would probably be the size of Atlas
Shrugged, but hopefully wouldn't take that many years to write :-)
Loading...