VM can now cast integer type arbitrarily. (#11459) [feature]
This commit is contained in:
parent
7cf9b522b5
commit
94177f7357
2 changed files with 143 additions and 31 deletions
|
|
@ -813,44 +813,28 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
|
|
||||||
proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
|
const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
|
||||||
var signedIntegers = {tyInt8..tyInt32}
|
var signedIntegers = {tyInt..tyInt64}
|
||||||
var unsignedIntegers = {tyUInt8..tyUInt32, tyChar}
|
var unsignedIntegers = {tyUInt..tyUInt64, tyChar}
|
||||||
let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
|
let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
|
||||||
let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
|
let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
|
||||||
let src_size = getSize(c.config, src)
|
let src_size = getSize(c.config, src)
|
||||||
let dst_size = getSize(c.config, dst)
|
let dst_size = getSize(c.config, dst)
|
||||||
if c.config.target.intSize < 8:
|
if src.kind in allowedIntegers and dst.kind in allowedIntegers:
|
||||||
signedIntegers.incl(tyInt)
|
|
||||||
unsignedIntegers.incl(tyUInt)
|
|
||||||
if src_size == dst_size and src.kind in allowedIntegers and
|
|
||||||
dst.kind in allowedIntegers:
|
|
||||||
let tmp = c.genx(n.sons[1])
|
let tmp = c.genx(n.sons[1])
|
||||||
var tmp2 = c.getTemp(n.sons[1].typ)
|
|
||||||
let tmp3 = c.getTemp(n.sons[1].typ)
|
|
||||||
if dest < 0: dest = c.getTemp(n[0].typ)
|
if dest < 0: dest = c.getTemp(n[0].typ)
|
||||||
proc mkIntLit(ival: int): int =
|
|
||||||
result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(c.graph, n.info, tyInt)))
|
|
||||||
if src.kind in unsignedIntegers and dst.kind in signedIntegers:
|
|
||||||
# cast unsigned to signed integer of same size
|
|
||||||
# signedVal = (unsignedVal xor offset) -% offset
|
|
||||||
let offset = 1 shl (src_size * 8 - 1)
|
|
||||||
c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
|
|
||||||
c.gABC(n, opcBitxorInt, tmp3, tmp, tmp2)
|
|
||||||
c.gABC(n, opcSubInt, dest, tmp3, tmp2)
|
|
||||||
elif src.kind in signedIntegers and dst.kind in unsignedIntegers:
|
|
||||||
# cast signed to unsigned integer of same size
|
|
||||||
# unsignedVal = (offset +% signedVal +% 1) and offset
|
|
||||||
let offset = (1 shl (src_size * 8)) - 1
|
|
||||||
c.gABx(n, opcLdConst, tmp2, mkIntLit(offset))
|
|
||||||
c.gABx(n, opcLdConst, dest, mkIntLit(offset+1))
|
|
||||||
c.gABC(n, opcAddu, tmp3, tmp, dest)
|
|
||||||
c.gABC(n, opcNarrowU, tmp3, TRegister(src_size*8))
|
|
||||||
c.gABC(n, opcBitandInt, dest, tmp3, tmp2)
|
|
||||||
else:
|
|
||||||
c.gABC(n, opcAsgnInt, dest, tmp)
|
c.gABC(n, opcAsgnInt, dest, tmp)
|
||||||
|
if dst_size != sizeof(BiggestInt): # don't do anything on biggest int types
|
||||||
|
if dst.kind in signedIntegers: # we need to do sign extensions
|
||||||
|
if dst_size <= src_size:
|
||||||
|
# Sign extension can be omitted when the size increases.
|
||||||
|
c.gABC(n, opcSignExtend, dest, TRegister(dst_size*8))
|
||||||
|
elif dst.kind in unsignedIntegers:
|
||||||
|
if src.kind in signedIntegers or dst_size < src_size:
|
||||||
|
# Cast from signed to unsigned always needs narrowing. Cast
|
||||||
|
# from unsigned to unsigned only needs narrowing when target
|
||||||
|
# is smaller than source.
|
||||||
|
c.gABC(n, opcNarrowU, dest, TRegister(dst_size*8))
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
c.freeTemp(tmp2)
|
|
||||||
c.freeTemp(tmp3)
|
|
||||||
elif src_size == dst_size and src.kind in allowedIntegers and
|
elif src_size == dst_size and src.kind in allowedIntegers and
|
||||||
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
|
dst.kind in {tyFloat, tyFloat32, tyFloat64}:
|
||||||
let tmp = c.genx(n[1])
|
let tmp = c.genx(n[1])
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ discard """
|
||||||
output: "OK"
|
output: "OK"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import macros
|
||||||
|
|
||||||
type
|
type
|
||||||
Dollar = distinct int
|
Dollar = distinct int
|
||||||
XCoord = distinct int32
|
XCoord = distinct int32
|
||||||
|
|
@ -112,6 +114,130 @@ proc test() =
|
||||||
doAssert(not compiles(cast[uint32](I8)))
|
doAssert(not compiles(cast[uint32](I8)))
|
||||||
doAssert(not compiles(cast[uint64](I8)))
|
doAssert(not compiles(cast[uint64](I8)))
|
||||||
|
|
||||||
|
const prerecordedResults = [
|
||||||
|
# cast to char
|
||||||
|
"\0", "\255",
|
||||||
|
"\0", "\255",
|
||||||
|
"\0", "\255",
|
||||||
|
"\0", "\255",
|
||||||
|
"\0", "\255",
|
||||||
|
"\128", "\127",
|
||||||
|
"\0", "\255",
|
||||||
|
"\0", "\255",
|
||||||
|
"\0", "\255",
|
||||||
|
# cast to uint8
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"128", "127",
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
# cast to uint16
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "65535",
|
||||||
|
"0", "65535",
|
||||||
|
"0", "65535",
|
||||||
|
"65408", "127",
|
||||||
|
"32768", "32767",
|
||||||
|
"0", "65535",
|
||||||
|
"0", "65535",
|
||||||
|
# cast to uint32
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "65535",
|
||||||
|
"0", "4294967295",
|
||||||
|
"0", "4294967295",
|
||||||
|
"4294967168", "127",
|
||||||
|
"4294934528", "32767",
|
||||||
|
"2147483648", "2147483647",
|
||||||
|
"0", "4294967295",
|
||||||
|
# cast to uint64
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "65535",
|
||||||
|
"0", "4294967295",
|
||||||
|
"0", "18446744073709551615",
|
||||||
|
"18446744073709551488", "127",
|
||||||
|
"18446744073709518848", "32767",
|
||||||
|
"18446744071562067968", "2147483647",
|
||||||
|
"9223372036854775808", "9223372036854775807",
|
||||||
|
# cast to int8
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
"-128", "127",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
# cast to int16
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
"-128", "127",
|
||||||
|
"-32768", "32767",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
# cast to int32
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "65535",
|
||||||
|
"0", "-1",
|
||||||
|
"0", "-1",
|
||||||
|
"-128", "127",
|
||||||
|
"-32768", "32767",
|
||||||
|
"-2147483648", "2147483647",
|
||||||
|
"0", "-1",
|
||||||
|
# cast to int64
|
||||||
|
"0", "255",
|
||||||
|
"0", "255",
|
||||||
|
"0", "65535",
|
||||||
|
"0", "4294967295",
|
||||||
|
"0", "-1",
|
||||||
|
"-128", "127",
|
||||||
|
"-32768", "32767",
|
||||||
|
"-2147483648", "2147483647",
|
||||||
|
"-9223372036854775808", "9223372036854775807",
|
||||||
|
]
|
||||||
|
|
||||||
|
proc free_integer_casting() =
|
||||||
|
# cast from every integer type to every type and ensure same
|
||||||
|
# behavior in vm and execution time.
|
||||||
|
macro bar(arg: untyped) =
|
||||||
|
result = newStmtList()
|
||||||
|
var i = 0
|
||||||
|
for it1 in arg:
|
||||||
|
let typA = it1[0]
|
||||||
|
for it2 in arg:
|
||||||
|
let lowB = it2[1]
|
||||||
|
let highB = it2[2]
|
||||||
|
let castExpr1 = nnkCast.newTree(typA, lowB)
|
||||||
|
let castExpr2 = nnkCast.newTree(typA, highB)
|
||||||
|
let lit1 = newLit(prerecordedResults[i*2])
|
||||||
|
let lit2 = newLit(prerecordedResults[i*2+1])
|
||||||
|
result.add quote do:
|
||||||
|
doAssert($(`castExpr1`) == `lit1`)
|
||||||
|
doAssert($(`castExpr2`) == `lit2`)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
bar([
|
||||||
|
(char, '\0', '\255'),
|
||||||
|
(uint8, 0'u8, 0xff'u8),
|
||||||
|
(uint16, 0'u16, 0xffff'u16),
|
||||||
|
(uint32, 0'u32, 0xffffffff'u32),
|
||||||
|
(uint64, 0'u64, 0xffffffffffffffff'u64),
|
||||||
|
(int8, 0x80'i8, 0x7f'i8),
|
||||||
|
(int16, 0x8000'i16, 0x7fff'i16),
|
||||||
|
(int32, 0x80000000'i32, 0x7fffffff'i32),
|
||||||
|
(int64, 0x8000000000000000'i64, 0x7fffffffffffffff'i64)
|
||||||
|
])
|
||||||
|
|
||||||
proc test_float_cast =
|
proc test_float_cast =
|
||||||
|
|
||||||
|
|
@ -158,9 +284,11 @@ proc test_float32_cast =
|
||||||
test()
|
test()
|
||||||
test_float_cast()
|
test_float_cast()
|
||||||
test_float32_cast()
|
test_float32_cast()
|
||||||
|
free_integer_casting()
|
||||||
static:
|
static:
|
||||||
test()
|
test()
|
||||||
test_float_cast()
|
test_float_cast()
|
||||||
test_float32_cast()
|
test_float32_cast()
|
||||||
|
free_integer_casting()
|
||||||
|
|
||||||
echo "OK"
|
echo "OK"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue