diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index de314a552b..035ab25cdd 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -813,28 +813,44 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) = proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) = const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar} - var signedIntegers = {tyInt..tyInt64} - var unsignedIntegers = {tyUInt..tyUInt64, tyChar} + var signedIntegers = {tyInt8..tyInt32} + var unsignedIntegers = {tyUInt8..tyUInt32, tyChar} let src = n.sons[1].typ.skipTypes(abstractRange)#.kind let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind let src_size = getSize(c.config, src) let dst_size = getSize(c.config, dst) - if src.kind in allowedIntegers and dst.kind in allowedIntegers: + if c.config.target.intSize < 8: + 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]) + 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) - 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)) + 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.freeTemp(tmp) + c.freeTemp(tmp2) + c.freeTemp(tmp3) elif src_size == dst_size and src.kind in allowedIntegers and dst.kind in {tyFloat, tyFloat32, tyFloat64}: let tmp = c.genx(n[1]) diff --git a/tests/vm/tcastint.nim b/tests/vm/tcastint.nim index c64dbc666e..437342a74b 100644 --- a/tests/vm/tcastint.nim +++ b/tests/vm/tcastint.nim @@ -2,8 +2,6 @@ discard """ output: "OK" """ -import macros - type Dollar = distinct int XCoord = distinct int32 @@ -114,130 +112,6 @@ proc test() = doAssert(not compiles(cast[uint32](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 = @@ -284,11 +158,9 @@ proc test_float32_cast = test() test_float_cast() test_float32_cast() -free_integer_casting() static: test() test_float_cast() test_float32_cast() - free_integer_casting() echo "OK"