arithm.nim 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # simple integer arithmetic with overflow checking
  10. proc raiseOverflow {.compilerproc, noinline.} =
  11. # a single proc to reduce code size to a minimum
  12. sysFatal(OverflowDefect, "over- or underflow")
  13. proc raiseDivByZero {.compilerproc, noinline.} =
  14. sysFatal(DivByZeroDefect, "division by zero")
  15. when defined(builtinOverflow):
  16. # Builtin compiler functions for improved performance
  17. when sizeof(clong) == 8:
  18. proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
  19. importc: "__builtin_saddl_overflow", nodecl, nosideeffect.}
  20. proc subInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
  21. importc: "__builtin_ssubl_overflow", nodecl, nosideeffect.}
  22. proc mulInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
  23. importc: "__builtin_smull_overflow", nodecl, nosideeffect.}
  24. elif sizeof(clonglong) == 8:
  25. proc addInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
  26. importc: "__builtin_saddll_overflow", nodecl, nosideeffect.}
  27. proc subInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
  28. importc: "__builtin_ssubll_overflow", nodecl, nosideeffect.}
  29. proc mulInt64Overflow[T: int64|int](a, b: T, c: var T): bool {.
  30. importc: "__builtin_smulll_overflow", nodecl, nosideeffect.}
  31. when sizeof(int) == 8:
  32. proc addIntOverflow(a, b: int, c: var int): bool {.inline.} =
  33. addInt64Overflow(a, b, c)
  34. proc subIntOverflow(a, b: int, c: var int): bool {.inline.} =
  35. subInt64Overflow(a, b, c)
  36. proc mulIntOverflow(a, b: int, c: var int): bool {.inline.} =
  37. mulInt64Overflow(a, b, c)
  38. elif sizeof(int) == 4 and sizeof(cint) == 4:
  39. proc addIntOverflow(a, b: int, c: var int): bool {.
  40. importc: "__builtin_sadd_overflow", nodecl, nosideeffect.}
  41. proc subIntOverflow(a, b: int, c: var int): bool {.
  42. importc: "__builtin_ssub_overflow", nodecl, nosideeffect.}
  43. proc mulIntOverflow(a, b: int, c: var int): bool {.
  44. importc: "__builtin_smul_overflow", nodecl, nosideeffect.}
  45. proc addInt64(a, b: int64): int64 {.compilerproc, inline.} =
  46. if addInt64Overflow(a, b, result):
  47. raiseOverflow()
  48. proc subInt64(a, b: int64): int64 {.compilerproc, inline.} =
  49. if subInt64Overflow(a, b, result):
  50. raiseOverflow()
  51. proc mulInt64(a, b: int64): int64 {.compilerproc, inline.} =
  52. if mulInt64Overflow(a, b, result):
  53. raiseOverflow()
  54. else:
  55. proc addInt64(a, b: int64): int64 {.compilerproc, inline.} =
  56. result = a +% b
  57. if (result xor a) >= int64(0) or (result xor b) >= int64(0):
  58. return result
  59. raiseOverflow()
  60. proc subInt64(a, b: int64): int64 {.compilerproc, inline.} =
  61. result = a -% b
  62. if (result xor a) >= int64(0) or (result xor not b) >= int64(0):
  63. return result
  64. raiseOverflow()
  65. #
  66. # This code has been inspired by Python's source code.
  67. # The native int product x*y is either exactly right or *way* off, being
  68. # just the last n bits of the true product, where n is the number of bits
  69. # in an int (the delivered product is the true product plus i*2**n for
  70. # some integer i).
  71. #
  72. # The native float64 product x*y is subject to three
  73. # rounding errors: on a sizeof(int)==8 box, each cast to double can lose
  74. # info, and even on a sizeof(int)==4 box, the multiplication can lose info.
  75. # But, unlike the native int product, it's not in *range* trouble: even
  76. # if sizeof(int)==32 (256-bit ints), the product easily fits in the
  77. # dynamic range of a float64. So the leading 50 (or so) bits of the float64
  78. # product are correct.
  79. #
  80. # We check these two ways against each other, and declare victory if they're
  81. # approximately the same. Else, because the native int product is the only
  82. # one that can lose catastrophic amounts of information, it's the native int
  83. # product that must have overflowed.
  84. #
  85. proc mulInt64(a, b: int64): int64 {.compilerproc.} =
  86. var
  87. resAsFloat, floatProd: float64
  88. result = a *% b
  89. floatProd = toBiggestFloat(a) # conversion
  90. floatProd = floatProd * toBiggestFloat(b)
  91. resAsFloat = toBiggestFloat(result)
  92. # Fast path for normal case: small multiplicands, and no info
  93. # is lost in either method.
  94. if resAsFloat == floatProd: return result
  95. # Somebody somewhere lost info. Close enough, or way off? Note
  96. # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
  97. # The difference either is or isn't significant compared to the
  98. # true value (of which floatProd is a good approximation).
  99. # abs(diff)/abs(prod) <= 1/32 iff
  100. # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
  101. if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
  102. return result
  103. raiseOverflow()
  104. proc negInt64(a: int64): int64 {.compilerproc, inline.} =
  105. if a != low(int64): return -a
  106. raiseOverflow()
  107. proc absInt64(a: int64): int64 {.compilerproc, inline.} =
  108. if a != low(int64):
  109. if a >= 0: return a
  110. else: return -a
  111. raiseOverflow()
  112. proc divInt64(a, b: int64): int64 {.compilerproc, inline.} =
  113. if b == int64(0):
  114. raiseDivByZero()
  115. if a == low(int64) and b == int64(-1):
  116. raiseOverflow()
  117. return a div b
  118. proc modInt64(a, b: int64): int64 {.compilerproc, inline.} =
  119. if b == int64(0):
  120. raiseDivByZero()
  121. return a mod b
  122. proc absInt(a: int): int {.compilerproc, inline.} =
  123. if a != low(int):
  124. if a >= 0: return a
  125. else: return -a
  126. raiseOverflow()
  127. const
  128. asmVersion = defined(i386) and (defined(vcc) or defined(wcc) or
  129. defined(dmc) or defined(gcc) or defined(llvm_gcc))
  130. # my Version of Borland C++Builder does not have
  131. # tasm32, which is needed for assembler blocks
  132. # this is why Borland is not included in the 'when'
  133. when asmVersion and not defined(gcc) and not defined(llvm_gcc):
  134. # assembler optimized versions for compilers that
  135. # have an intel syntax assembler:
  136. proc addInt(a, b: int): int {.compilerproc, asmNoStackFrame.} =
  137. # a in eax, and b in edx
  138. asm """
  139. mov eax, ecx
  140. add eax, edx
  141. jno theEnd
  142. call `raiseOverflow`
  143. theEnd:
  144. ret
  145. """
  146. proc subInt(a, b: int): int {.compilerproc, asmNoStackFrame.} =
  147. asm """
  148. mov eax, ecx
  149. sub eax, edx
  150. jno theEnd
  151. call `raiseOverflow`
  152. theEnd:
  153. ret
  154. """
  155. proc negInt(a: int): int {.compilerproc, asmNoStackFrame.} =
  156. asm """
  157. mov eax, ecx
  158. neg eax
  159. jno theEnd
  160. call `raiseOverflow`
  161. theEnd:
  162. ret
  163. """
  164. proc divInt(a, b: int): int {.compilerproc, asmNoStackFrame.} =
  165. asm """
  166. test edx, edx
  167. jne L_NOT_ZERO
  168. call `raiseDivByZero`
  169. L_NOT_ZERO:
  170. cmp ecx, 0x80000000
  171. jne L_DO_DIV
  172. cmp edx, -1
  173. jne L_DO_DIV
  174. call `raiseOverflow`
  175. L_DO_DIV:
  176. mov eax, ecx
  177. mov ecx, edx
  178. cdq
  179. idiv ecx
  180. ret
  181. """
  182. proc modInt(a, b: int): int {.compilerproc, asmNoStackFrame.} =
  183. asm """
  184. test edx, edx
  185. jne L_NOT_ZERO
  186. call `raiseDivByZero`
  187. L_NOT_ZERO:
  188. cmp ecx, 0x80000000
  189. jne L_DO_DIV
  190. cmp edx, -1
  191. jne L_DO_DIV
  192. call `raiseOverflow`
  193. L_DO_DIV:
  194. mov eax, ecx
  195. mov ecx, edx
  196. cdq
  197. idiv ecx
  198. mov eax, edx
  199. ret
  200. """
  201. proc mulInt(a, b: int): int {.compilerproc, asmNoStackFrame.} =
  202. asm """
  203. mov eax, ecx
  204. mov ecx, edx
  205. xor edx, edx
  206. imul ecx
  207. jno theEnd
  208. call `raiseOverflow`
  209. theEnd:
  210. ret
  211. """
  212. elif false: # asmVersion and (defined(gcc) or defined(llvm_gcc)):
  213. proc addInt(a, b: int): int {.compilerproc, inline.} =
  214. # don't use a pure proc here!
  215. asm """
  216. "addl %%ecx, %%eax\n"
  217. "jno 1\n"
  218. "call _raiseOverflow\n"
  219. "1: \n"
  220. :"=a"(`result`)
  221. :"a"(`a`), "c"(`b`)
  222. """
  223. #".intel_syntax noprefix"
  224. #/* Intel syntax here */
  225. #".att_syntax"
  226. proc subInt(a, b: int): int {.compilerproc, inline.} =
  227. asm """ "subl %%ecx,%%eax\n"
  228. "jno 1\n"
  229. "call _raiseOverflow\n"
  230. "1: \n"
  231. :"=a"(`result`)
  232. :"a"(`a`), "c"(`b`)
  233. """
  234. proc mulInt(a, b: int): int {.compilerproc, inline.} =
  235. asm """ "xorl %%edx, %%edx\n"
  236. "imull %%ecx\n"
  237. "jno 1\n"
  238. "call _raiseOverflow\n"
  239. "1: \n"
  240. :"=a"(`result`)
  241. :"a"(`a`), "c"(`b`)
  242. :"%edx"
  243. """
  244. proc negInt(a: int): int {.compilerproc, inline.} =
  245. asm """ "negl %%eax\n"
  246. "jno 1\n"
  247. "call _raiseOverflow\n"
  248. "1: \n"
  249. :"=a"(`result`)
  250. :"a"(`a`)
  251. """
  252. proc divInt(a, b: int): int {.compilerproc, inline.} =
  253. asm """ "xorl %%edx, %%edx\n"
  254. "idivl %%ecx\n"
  255. "jno 1\n"
  256. "call _raiseOverflow\n"
  257. "1: \n"
  258. :"=a"(`result`)
  259. :"a"(`a`), "c"(`b`)
  260. :"%edx"
  261. """
  262. proc modInt(a, b: int): int {.compilerproc, inline.} =
  263. asm """ "xorl %%edx, %%edx\n"
  264. "idivl %%ecx\n"
  265. "jno 1\n"
  266. "call _raiseOverflow\n"
  267. "1: \n"
  268. "movl %%edx, %%eax"
  269. :"=a"(`result`)
  270. :"a"(`a`), "c"(`b`)
  271. :"%edx"
  272. """
  273. when not declared(addInt) and defined(builtinOverflow):
  274. proc addInt(a, b: int): int {.compilerproc, inline.} =
  275. if addIntOverflow(a, b, result):
  276. raiseOverflow()
  277. when not declared(subInt) and defined(builtinOverflow):
  278. proc subInt(a, b: int): int {.compilerproc, inline.} =
  279. if subIntOverflow(a, b, result):
  280. raiseOverflow()
  281. when not declared(mulInt) and defined(builtinOverflow):
  282. proc mulInt(a, b: int): int {.compilerproc, inline.} =
  283. if mulIntOverflow(a, b, result):
  284. raiseOverflow()
  285. # Platform independent versions of the above (slower!)
  286. when not declared(addInt):
  287. proc addInt(a, b: int): int {.compilerproc, inline.} =
  288. result = a +% b
  289. if (result xor a) >= 0 or (result xor b) >= 0:
  290. return result
  291. raiseOverflow()
  292. when not declared(subInt):
  293. proc subInt(a, b: int): int {.compilerproc, inline.} =
  294. result = a -% b
  295. if (result xor a) >= 0 or (result xor not b) >= 0:
  296. return result
  297. raiseOverflow()
  298. when not declared(negInt):
  299. proc negInt(a: int): int {.compilerproc, inline.} =
  300. if a != low(int): return -a
  301. raiseOverflow()
  302. when not declared(divInt):
  303. proc divInt(a, b: int): int {.compilerproc, inline.} =
  304. if b == 0:
  305. raiseDivByZero()
  306. if a == low(int) and b == -1:
  307. raiseOverflow()
  308. return a div b
  309. when not declared(modInt):
  310. proc modInt(a, b: int): int {.compilerproc, inline.} =
  311. if b == 0:
  312. raiseDivByZero()
  313. return a mod b
  314. when not declared(mulInt):
  315. #
  316. # This code has been inspired by Python's source code.
  317. # The native int product x*y is either exactly right or *way* off, being
  318. # just the last n bits of the true product, where n is the number of bits
  319. # in an int (the delivered product is the true product plus i*2**n for
  320. # some integer i).
  321. #
  322. # The native float64 product x*y is subject to three
  323. # rounding errors: on a sizeof(int)==8 box, each cast to double can lose
  324. # info, and even on a sizeof(int)==4 box, the multiplication can lose info.
  325. # But, unlike the native int product, it's not in *range* trouble: even
  326. # if sizeof(int)==32 (256-bit ints), the product easily fits in the
  327. # dynamic range of a float64. So the leading 50 (or so) bits of the float64
  328. # product are correct.
  329. #
  330. # We check these two ways against each other, and declare victory if
  331. # they're approximately the same. Else, because the native int product is
  332. # the only one that can lose catastrophic amounts of information, it's the
  333. # native int product that must have overflowed.
  334. #
  335. proc mulInt(a, b: int): int {.compilerproc.} =
  336. var
  337. resAsFloat, floatProd: float
  338. result = a *% b
  339. floatProd = toFloat(a) * toFloat(b)
  340. resAsFloat = toFloat(result)
  341. # Fast path for normal case: small multiplicands, and no info
  342. # is lost in either method.
  343. if resAsFloat == floatProd: return result
  344. # Somebody somewhere lost info. Close enough, or way off? Note
  345. # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
  346. # The difference either is or isn't significant compared to the
  347. # true value (of which floatProd is a good approximation).
  348. # abs(diff)/abs(prod) <= 1/32 iff
  349. # 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
  350. if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
  351. return result
  352. raiseOverflow()
  353. # We avoid setting the FPU control word here for compatibility with libraries
  354. # written in other languages.
  355. proc raiseFloatInvalidOp {.compilerproc, noinline.} =
  356. sysFatal(FloatInvalidOpDefect, "FPU operation caused a NaN result")
  357. proc nanCheck(x: float64) {.compilerproc, inline.} =
  358. if x != x: raiseFloatInvalidOp()
  359. proc raiseFloatOverflow(x: float64) {.compilerproc, noinline.} =
  360. if x > 0.0:
  361. sysFatal(FloatOverflowDefect, "FPU operation caused an overflow")
  362. else:
  363. sysFatal(FloatUnderflowDefect, "FPU operations caused an underflow")
  364. proc infCheck(x: float64) {.compilerproc, inline.} =
  365. if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x)