tcastint.nim 8.0 KB

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