tcastint.nim 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. import macros
  2. from stdtest/testutils import disableVM
  3. type
  4. Dollar = distinct int
  5. XCoord = distinct int32
  6. Digit = range[-9..0]
  7. # those are necessary for comparisons below.
  8. proc `==`(x, y: Dollar): bool {.borrow.}
  9. proc `==`(x, y: XCoord): bool {.borrow.}
  10. proc dummy[T](x: T): T = x
  11. template roundTrip(a, T) =
  12. let a2 = a # sideeffect safe
  13. let b = cast[T](a2)
  14. let c = cast[type(a2)](b)
  15. doAssert c == a2
  16. proc test() =
  17. let U8 = 0b1011_0010'u8
  18. let I8 = 0b1011_0010'i8
  19. let C8 = 0b1011_0010'u8.char
  20. let C8_1 = 0b1011_0011'u8.char
  21. let U16 = 0b10100111_00101000'u16
  22. let I16 = 0b10100111_00101000'i16
  23. let U32 = 0b11010101_10011100_11011010_01010000'u32
  24. let I32 = 0b11010101_10011100_11011010_01010000'i32
  25. let U64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64
  26. let I64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64
  27. let U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64
  28. let I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64
  29. when sizeof(int) == 8:
  30. let UX = U64A.uint
  31. let IX = I64A.int
  32. elif sizeof(int) == 4:
  33. let UX = U32.uint
  34. let IX = I32.int
  35. elif sizeof(int) == 2:
  36. let UX = U16.uint
  37. let IX = I16.int
  38. else:
  39. let UX = U8.uint
  40. let IX = I8.int
  41. doAssert(cast[char](I8) == C8)
  42. doAssert(cast[uint8](I8) == U8)
  43. doAssert(cast[uint16](I16) == U16)
  44. doAssert(cast[uint32](I32) == U32)
  45. doAssert(cast[uint64](I64A) == U64A)
  46. doAssert(cast[uint64](I64B) == U64B)
  47. doAssert(cast[int8](U8) == I8)
  48. doAssert(cast[int16](U16) == I16)
  49. doAssert(cast[int32](U32) == I32)
  50. doAssert(cast[int64](U64A) == I64A)
  51. doAssert(cast[int64](U64B) == I64B)
  52. doAssert(cast[uint](IX) == UX)
  53. doAssert(cast[int](UX) == IX)
  54. doAssert(cast[char](I8 + 1) == C8_1)
  55. doAssert(cast[uint8](I8 + 1) == U8 + 1)
  56. doAssert(cast[uint16](I16 + 1) == U16 + 1)
  57. doAssert(cast[uint32](I32 + 1) == U32 + 1)
  58. doAssert(cast[uint64](I64A + 1) == U64A + 1)
  59. doAssert(cast[uint64](I64B + 1) == U64B + 1)
  60. doAssert(cast[int8](U8 + 1) == I8 + 1)
  61. doAssert(cast[int16](U16 + 1) == I16 + 1)
  62. doAssert(cast[int32](U32 + 1) == I32 + 1)
  63. doAssert(cast[int64](U64A + 1) == I64A + 1)
  64. doAssert(cast[int64](U64B + 1) == I64B + 1)
  65. doAssert(cast[uint](IX + 1) == UX + 1)
  66. doAssert(cast[int](UX + 1) == IX + 1)
  67. doAssert(cast[char](I8.dummy) == C8.dummy)
  68. doAssert(cast[uint8](I8.dummy) == U8.dummy)
  69. doAssert(cast[uint16](I16.dummy) == U16.dummy)
  70. doAssert(cast[uint32](I32.dummy) == U32.dummy)
  71. doAssert(cast[uint64](I64A.dummy) == U64A.dummy)
  72. doAssert(cast[uint64](I64B.dummy) == U64B.dummy)
  73. doAssert(cast[int8](U8.dummy) == I8.dummy)
  74. doAssert(cast[int16](U16.dummy) == I16.dummy)
  75. doAssert(cast[int32](U32.dummy) == I32.dummy)
  76. doAssert(cast[int64](U64A.dummy) == I64A.dummy)
  77. doAssert(cast[int64](U64B.dummy) == I64B.dummy)
  78. doAssert(cast[uint](IX.dummy) == UX.dummy)
  79. doAssert(cast[int](UX.dummy) == IX.dummy)
  80. doAssert(cast[int64](if false: U64B else: 0'u64) == (if false: I64B else: 0'i64))
  81. block:
  82. let raw = 3
  83. let money = Dollar(raw) # this must be a variable, is otherwise constant folded.
  84. doAssert(cast[int](money) == raw)
  85. doAssert(cast[Dollar](raw) == money)
  86. block:
  87. let raw = 150'i32
  88. let position = XCoord(raw) # this must be a variable, is otherwise constant folded.
  89. doAssert(cast[int32](position) == raw)
  90. doAssert(cast[XCoord](raw) == position)
  91. block:
  92. let raw = -2
  93. let digit = Digit(raw)
  94. doAssert(cast[int](digit) == raw)
  95. doAssert(cast[Digit](raw) == digit)
  96. block:
  97. roundTrip(I64A, float)
  98. roundTrip(I8, uint16)
  99. roundTrip(I8, uint32)
  100. roundTrip(I8, uint64)
  101. doAssert cast[uint16](I8) == 65458'u16
  102. doAssert cast[uint32](I8) == 4294967218'u32
  103. doAssert cast[uint64](I8) == 18446744073709551538'u64
  104. doAssert cast[uint32](I64A) == 2571663889'u32
  105. doAssert cast[uint16](I64A) == 31249
  106. doAssert cast[char](I64A).ord == 17
  107. doAssert compiles(cast[float32](I64A))
  108. disableVM: # xxx Error: VM does not support 'cast' from tyInt64 to tyFloat32
  109. doAssert cast[uint32](cast[float32](I64A)) == 2571663889'u32
  110. const prerecordedResults = [
  111. # cast to char
  112. "\0", "\255",
  113. "\0", "\255",
  114. "\0", "\255",
  115. "\0", "\255",
  116. "\0", "\255",
  117. "\128", "\127",
  118. "\0", "\255",
  119. "\0", "\255",
  120. "\0", "\255",
  121. # cast to uint8
  122. "0", "255",
  123. "0", "255",
  124. "0", "255",
  125. "0", "255",
  126. "0", "255",
  127. "128", "127",
  128. "0", "255",
  129. "0", "255",
  130. "0", "255",
  131. # cast to uint16
  132. "0", "255",
  133. "0", "255",
  134. "0", "65535",
  135. "0", "65535",
  136. "0", "65535",
  137. "65408", "127",
  138. "32768", "32767",
  139. "0", "65535",
  140. "0", "65535",
  141. # cast to uint32
  142. "0", "255",
  143. "0", "255",
  144. "0", "65535",
  145. "0", "4294967295",
  146. "0", "4294967295",
  147. "4294967168", "127",
  148. "4294934528", "32767",
  149. "2147483648", "2147483647",
  150. "0", "4294967295",
  151. # cast to uint64
  152. "0", "255",
  153. "0", "255",
  154. "0", "65535",
  155. "0", "4294967295",
  156. "0", "18446744073709551615",
  157. "18446744073709551488", "127",
  158. "18446744073709518848", "32767",
  159. "18446744071562067968", "2147483647",
  160. "9223372036854775808", "9223372036854775807",
  161. # cast to int8
  162. "0", "-1",
  163. "0", "-1",
  164. "0", "-1",
  165. "0", "-1",
  166. "0", "-1",
  167. "-128", "127",
  168. "0", "-1",
  169. "0", "-1",
  170. "0", "-1",
  171. # cast to int16
  172. "0", "255",
  173. "0", "255",
  174. "0", "-1",
  175. "0", "-1",
  176. "0", "-1",
  177. "-128", "127",
  178. "-32768", "32767",
  179. "0", "-1",
  180. "0", "-1",
  181. # cast to int32
  182. "0", "255",
  183. "0", "255",
  184. "0", "65535",
  185. "0", "-1",
  186. "0", "-1",
  187. "-128", "127",
  188. "-32768", "32767",
  189. "-2147483648", "2147483647",
  190. "0", "-1",
  191. # cast to int64
  192. "0", "255",
  193. "0", "255",
  194. "0", "65535",
  195. "0", "4294967295",
  196. "0", "-1",
  197. "-128", "127",
  198. "-32768", "32767",
  199. "-2147483648", "2147483647",
  200. "-9223372036854775808", "9223372036854775807",
  201. ]
  202. proc free_integer_casting() =
  203. # cast from every integer type to every type and ensure same
  204. # behavior in vm and execution time.
  205. macro bar(arg: untyped) =
  206. result = newStmtList()
  207. var i = 0
  208. for it1 in arg:
  209. let typA = it1[0]
  210. for it2 in arg:
  211. let lowB = it2[1]
  212. let highB = it2[2]
  213. let castExpr1 = nnkCast.newTree(typA, lowB)
  214. let castExpr2 = nnkCast.newTree(typA, highB)
  215. let lit1 = newLit(prerecordedResults[i*2])
  216. let lit2 = newLit(prerecordedResults[i*2+1])
  217. result.add quote do:
  218. doAssert($(`castExpr1`) == `lit1`)
  219. doAssert($(`castExpr2`) == `lit2`)
  220. i += 1
  221. bar([
  222. (char, '\0', '\255'),
  223. (uint8, 0'u8, 0xff'u8),
  224. (uint16, 0'u16, 0xffff'u16),
  225. (uint32, 0'u32, 0xffffffff'u32),
  226. (uint64, 0'u64, 0xffffffffffffffff'u64),
  227. (int8, 0x80'i8, 0x7f'i8),
  228. (int16, 0x8000'i16, 0x7fff'i16),
  229. (int32, 0x80000000'i32, 0x7fffffff'i32),
  230. (int64, 0x8000000000000000'i64, 0x7fffffffffffffff'i64)
  231. ])
  232. proc test_float_cast =
  233. const
  234. exp_bias = 1023'i64
  235. exp_shift = 52
  236. exp_mask = 0x7ff'i64 shl exp_shift
  237. mantissa_mask = 0xfffffffffffff'i64
  238. let f = 8.0
  239. let fx = cast[int64](f)
  240. let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias
  241. let mantissa = fx and mantissa_mask
  242. doAssert(exponent == 3, $exponent)
  243. doAssert(mantissa == 0, $mantissa)
  244. # construct 2^N float, where N is integer
  245. let x = -2'i64
  246. let xx = (x + exp_bias) shl exp_shift
  247. let xf = cast[float](xx)
  248. doAssert(xf == 0.25, $xf)
  249. proc test_float32_cast =
  250. const
  251. exp_bias = 127'i32
  252. exp_shift = 23
  253. exp_mask = 0x7f800000'i32
  254. mantissa_mask = 0x007ffff'i32
  255. let f = -0.5'f32
  256. let fx = cast[int32](f)
  257. let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias
  258. let mantissa = fx and mantissa_mask
  259. doAssert(exponent == -1, $exponent)
  260. doAssert(mantissa == 0, $mantissa)
  261. # construct 2^N float32 where N is integer
  262. let x = 4'i32
  263. let xx = (x + exp_bias) shl exp_shift
  264. let xf = cast[float32](xx)
  265. doAssert(xf == 16.0'f32, $xf)
  266. proc test_float32_castB() =
  267. let a: float32 = -123.125
  268. let b = cast[int32](a)
  269. let c = cast[uint32](a)
  270. doAssert b == -1024049152
  271. doAssert cast[uint64](b) == 18446744072685502464'u64
  272. doAssert c == 3270918144'u32
  273. # ensure the unused bits in the internal representation don't have
  274. # any surprising content.
  275. doAssert cast[uint64](c) == 3270918144'u64
  276. template main() =
  277. test()
  278. test_float_cast()
  279. test_float32_cast()
  280. free_integer_casting()
  281. test_float32_castB()
  282. static: main()
  283. main()