Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

712 lines
22 KiB

  1. subttl emround.asm - Rounding and Precision Control and FRNDINT
  2. page
  3. ;*******************************************************************************
  4. ;emround.asm - Rounding and Precision Control
  5. ;
  6. ; Microsoft Confidential
  7. ;
  8. ; Copyright (c) Microsoft Corporation 1991
  9. ; All Rights Reserved
  10. ;
  11. ;Purpose:
  12. ; Rounding and precision control. The correct routine is jumped
  13. ; to through the [RoundMode] vector.
  14. ;
  15. ;Revision History:
  16. ;
  17. ; [] 09/05/91 TP Initial 32-bit version.
  18. ; 02/28/92 JWM Minor bug fix in NotNearLow
  19. ;
  20. ;*******************************************************************************
  21. RndIntSpcl:
  22. cmp cl,bTAG_INF
  23. jz RndIntX ;Leave infinity unchanged
  24. cmp cl,bTAG_DEN
  25. jnz SpclDestNotDen ;Handle NAN & empty - in emarith.asm
  26. ;Handle denormal
  27. mov EMSEG:[CURerr],Denormal
  28. test EMSEG:[CWmask],Denormal ;Is it masked?
  29. jnz NormRndInt ;If so, ignore denormalization
  30. RndIntX:
  31. ret
  32. ;********
  33. EM_ENTRY eFRNDINT
  34. eFRNDINT:
  35. ;********
  36. ;edi points to top of stack
  37. mov ecx,EMSEG:[edi].ExpSgn
  38. cmp cl,bTAG_ZERO
  39. .erre bTAG_VALID lt bTAG_ZERO
  40. .erre bTAG_SNGL lt bTAG_ZERO
  41. jz RndIntX
  42. ja RndIntSpcl
  43. cmp ecx,63 shl 16 ;Is it already integer?
  44. jge RndIntX
  45. NormRndInt:
  46. mov ebx,EMSEG:[edi].lManHi
  47. mov esi,EMSEG:[edi].lManLo
  48. mov EMSEG:[Result],edi ;Save result pointer
  49. xor eax,eax ;Extend mantissa
  50. push offset SaveResult
  51. jmp RoundToBit
  52. ;*******************************************************************************
  53. ResultOverflow:
  54. ;mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl.
  55. ;We were all ready to save the rounded result, but the exponent turned out
  56. ;to be too large.
  57. or EMSEG:[CURerr],Overflow
  58. sub ecx,UnderBias shl 16 ;Unmasked response
  59. test EMSEG:[CWmask],Overflow ;Is exception unmasked?
  60. jz SaveResult ;If so, we're ready
  61. ;Produce masked overflow response
  62. mov ebx,1 shl 31 ;Assume infinity
  63. xor esi,esi
  64. mov cl,bTAG_INF
  65. mov al,EMSEG:[CWcntl] ;Get rounding control
  66. mov ah,al
  67. and ah,RCchop ;Rounding control only
  68. ;Return max value if RCup bit = 1 and -, or RCdown bit = 1 and +
  69. ;i.e., RCup & sign OR RCdown & not sign
  70. .erre RCchop eq RCup + RCdown ;Always return max value
  71. .erre RCnear eq 0 ;Never return max value
  72. sar ch,7 ;Expand sign through whole byte
  73. .erre (RCdown and bSign) eq 0 ;Don't want to change real sign
  74. xor ch,RCdown ;Flip sign for RCdown bit
  75. and ah,ch ;RCup & sign OR RCdown & not sign
  76. jnz SaveMax
  77. and ecx,0FFFFH
  78. or ecx,TexpMax shl 16
  79. jmp SaveResult ;Save Infinity
  80. SaveMax:
  81. ;Get max value for current precision
  82. mov ebx,0FFFFFF00H ;Max value for 24 bits
  83. and ecx,bSign shl 8 ;Preserve only sign
  84. or ecx,(IexpMax-IexpBias-1) shl 16 + bTAG_VALID ;Set up max value
  85. and al,PrecisionControl
  86. .erre PC24 eq 0
  87. jz SaveResult ;Save 24-bit max value
  88. dec esi ;esi == -1
  89. mov ebx,esi
  90. cmp al,PC53
  91. jnz SaveResult ;Save 64-bit max value
  92. mov esi,0FFFFF800H
  93. jmp SaveResult ;Save 53-bit max value
  94. ;*******************************************************************************
  95. ;
  96. ;64-bit rounding routines
  97. ;
  98. ;***********
  99. Round64down:
  100. ;***********
  101. cmp ecx,(IexpMin-IexpBias+1) shl 16 ;Test for Underflow
  102. jl RndDenorm64
  103. or eax,eax ;Exact result?
  104. jz SaveValidResult
  105. or EMSEG:[CURerr],Precision ;Set flag on inexact result
  106. ;Chop if positive, increase mantissa if negative
  107. test ch,bSign
  108. jz SaveValidResult ;Positive, so chop
  109. jmp RoundUp64 ;Round up if negative
  110. RndDenorm64:
  111. test EMSEG:[CWmask],Underflow ;Is exception unmasked?
  112. jz RndSetUnder
  113. Denormalize:
  114. ;We don't really store in denormalized format, but we need the number
  115. ;to be rounded as if we do. If the exponent were -IexpBias, we would
  116. ;lose 1 bit of precision; as it gets more negative, we lose more bits.
  117. ;We'll do this by adjusting the exponent so that the bits we want to
  118. ;keep look like integer bits, and performing round-to-integer.
  119. add ecx,(IexpBias+62) shl 16 ;Adjust exponent so we're integer
  120. call RoundToBit
  121. ;Set underflow exception if precision exception is set
  122. mov al,EMSEG:[CURerr]
  123. and al,Precision
  124. ror al,Precision-Underflow ;Move Precision bit to Underflow pos.
  125. or EMSEG:[CURerr],al ;Signal Underflow if inexact
  126. cmp cl,bTAG_ZERO
  127. jz SaveResult
  128. sub ecx,(IexpBias+62) shl 16;Restore unbiased exponent
  129. cmp ecx,TexpMin shl 16 ;Did we round out of denorm?
  130. jae SaveResult
  131. mov cl,bTAG_DEN
  132. jmp SaveResult
  133. RndSetUnder:
  134. ;Underflow exception not masked. Adjust exponent and try again.
  135. or EMSEG:[CURerr],Underflow
  136. add ecx,UnderBias shl 16
  137. jmp EMSEG:[RoundMode] ;Try again with revised exponent
  138. ;***********
  139. Round64near:
  140. ;***********
  141. ;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
  142. cmp ecx,TexpMin shl 16 ;Test for Underflow
  143. jl RndDenorm64
  144. or eax,eax ;Exact result?
  145. jz short SaveValidResult
  146. or EMSEG:[CURerr],Precision ;Set flag on inexact result
  147. ;To perform "round even" when the round bit is set and the sticky bits
  148. ;are zero, we treat the LSB as if it were a sticky bit. Thus if the LSB
  149. ;is set, that will always force a round up (to even) if the round bit is
  150. ;set. If the LSB is zero, then the sticky bits remain zero and we always
  151. ;round down. This rounding rule is implemented by adding RoundBit-1
  152. ;(7F..FFH), setting CY if round up.
  153. bt esi,0 ;Is mantissa even or odd? (set CY)
  154. adc eax,(1 shl 31)-1 ;Sum LSB & sticky bits--CY if round up
  155. jnc SaveValidResult
  156. RoundUp64:
  157. mov EMSEG:[SWcc],RoundUp
  158. add esi,1
  159. adc ebx,0
  160. jc BumpExponent ;Overflowed, increment exponent
  161. SaveValidResult: ;A jump to here requires 9 clocks
  162. or esi,esi ;Any bits in low half?
  163. .erre bTAG_VALID eq 1
  164. .erre bTAG_SNGL eq 0
  165. setnz cl ;if low half==0 then cl=0 else cl=1
  166. cmp ecx,TexpMax shl 16 ;Test for overflow
  167. jge ResultOverflow
  168. SaveResult: ;A jump to here requires 10 clocks
  169. ;mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
  170. mov edi,EMSEG:[Result]
  171. SaveResultEdi:
  172. mov EMSEG:[edi].lManLo,esi
  173. mov EMSEG:[edi].lManHi,ebx
  174. SaveExpSgn:
  175. mov EMSEG:[edi].ExpSgn,ecx
  176. ret
  177. ;***********
  178. Round64up:
  179. ;***********
  180. cmp ecx,TexpMin shl 16 ;Test for Underflow
  181. jl RndDenorm64
  182. or eax,eax ;Exact result?
  183. jz short SaveValidResult
  184. or EMSEG:[CURerr],Precision;Set flag on inexact result
  185. ;Chop if negative, increase mantissa if positive
  186. cmp ch,bSign ;No CY iff sign bit is set
  187. jc RoundUp64 ;Round up if positive
  188. jmp short SaveValidResult
  189. ;***********
  190. Round64chop:
  191. ;***********
  192. cmp ecx,TexpMin shl 16 ;Test for Underflow
  193. jl RndDenorm64
  194. or eax,eax ;Exact result?
  195. jz short SaveValidResult
  196. or EMSEG:[CURerr],Precision;Set flag on inexact result
  197. jmp short SaveValidResult
  198. ;*******************************************************************************
  199. ;
  200. ;53-bit rounding routines
  201. ;
  202. ;***********
  203. Round53down:
  204. ;***********
  205. cmp ecx,TexpMin shl 16 ;Test for Underflow
  206. jl RndDenorm53
  207. mov edx,esi ;Get low bits
  208. and edx,(1 shl 11) - 1 ;Mask to last 11 bits
  209. or edx,eax ;Throwing away any bits?
  210. jz SaveValidResult
  211. or EMSEG:[CURerr],Precision;Set flag on inexact result
  212. ;Chop if positive, increase mantissa if negative
  213. and esi,not ((1 shl 11)-1) ;Mask off low 11 bits
  214. test ch,bSign
  215. jz SaveValidResult ;Positive, go chop
  216. jmp RoundUp53
  217. RndDenorm53:
  218. test EMSEG:[CWmask],Underflow;Is exception unmasked?
  219. jz RndSetUnder
  220. ;We don't really store in denormalized format, but we need the number
  221. ;to be rounded as if we do. If the exponent were -IexpBias, we would
  222. ;lose 1 bit of precision; as it gets more negative, we lose more bits.
  223. ;We'll do this by adjusting the exponent so that the bits we want to
  224. ;keep look like integer bits, and performing round-to-integer.
  225. add ecx,(IexpBias+51) shl 16 ;Adjust exponent so we're integer
  226. call RoundToBit
  227. ;Set underflow exception if precision exception is set
  228. mov al,EMSEG:[CURerr]
  229. and al,Precision
  230. ror al,Precision-Underflow ;Move Precision bit to Underflow pos.
  231. or EMSEG:[CURerr],al ;Signal Underflow if inexact
  232. cmp cl,bTAG_ZERO
  233. jz SaveResult
  234. sub ecx,(IexpBias+51) shl 16;Restore unbiased exponent
  235. cmp ecx,(IexpMin-IexpBias+1) shl 16 ;Did we round out of denorm?
  236. jae SaveResult
  237. mov cl,bTAG_DEN
  238. jmp SaveResult
  239. ;***********
  240. Round53near:
  241. ;***********
  242. ;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
  243. cmp ecx,TexpMin shl 16 ;Test for Underflow
  244. jl RndDenorm53
  245. mov edx,esi ;Get low bits
  246. and edx,(1 shl 11) - 1 ;Mask to last 11 bits
  247. or edx,eax ;Throwing away any bits?
  248. jz SaveValidResult
  249. or EMSEG:[CURerr],Precision;Set flag on inexact result
  250. ;To perform "round even" when the round bit is set and the sticky bits
  251. ;are zero, we treat the LSB as if it were a sticky bit. Thus if the LSB
  252. ;is set, that will always force a round up (to even) if the round bit is
  253. ;set. If the LSB is zero, then the sticky bits remain zero and we always
  254. ;round down.
  255. mov edx,esi
  256. and esi,not ((1 shl 11)-1) ;Mask off low 11 bits
  257. test edx,1 shl 10 ;Is round bit set?
  258. jz SaveValidResult
  259. and edx,(3 shl 10)-1 ;Keep only sticky bits and LSB
  260. or eax,edx ;Combine with other sticky bits
  261. jz SaveValidResult
  262. RoundUp53:
  263. mov EMSEG:[SWcc],RoundUp
  264. add esi,1 shl 11 ;Round
  265. adc ebx,0
  266. jnc SaveValidResult
  267. BumpExponent:
  268. add ecx,1 shl 16 ;Mantissa overflowed, bump exponent
  269. or ebx,1 shl 31 ;Set MSB
  270. jmp SaveValidResult
  271. ;***********
  272. Round53up:
  273. ;***********
  274. cmp ecx,TexpMin shl 16 ;Test for Underflow
  275. jl RndDenorm53
  276. mov edx,esi ;Get low bits
  277. and edx,(1 shl 11) - 1 ;Mask to last 11 bits
  278. or edx,eax ;Throwing away any bits?
  279. jz SaveValidResult
  280. or EMSEG:[CURerr],Precision;Set flag on inexact result
  281. ;Chop if negative, increase mantissa if positive
  282. and esi,not ((1 shl 11)-1) ;Mask off low 11 bits
  283. test ch,bSign
  284. jz RoundUp53 ;Round up if positive
  285. jmp SaveValidResult
  286. ;***********
  287. Round53chop:
  288. ;***********
  289. cmp ecx,TexpMin shl 16 ;Test for Underflow
  290. jl RndDenorm53
  291. mov edx,esi ;Get low bits
  292. and edx,(1 shl 11) - 1 ;Mask to last 11 bits
  293. or edx,eax ;Throwing away any bits?
  294. jz SaveValidResult
  295. or EMSEG:[CURerr],Precision;Set flag on inexact result
  296. and esi,not ((1 shl 11)-1) ;Mask off low 11 bits
  297. jmp SaveValidResult
  298. ;*******************************************************************************
  299. ;
  300. ;24-bit rounding routines
  301. ;
  302. ;***********
  303. Round24down:
  304. ;***********
  305. cmp ecx,TexpMin shl 16 ;Test for Underflow
  306. jl RndDenorm24
  307. or eax,esi ;Low dword is just sticky bits
  308. mov edx,ebx ;Get low bits
  309. and edx,(1 shl 8) - 1 ;Mask to last 8 bits
  310. or edx,eax ;Throwing away any bits?
  311. jz SaveValidResult
  312. or EMSEG:[CURerr],Precision;Set flag on inexact result
  313. ;Chop if positive, increase mantissa if negative
  314. xor esi,esi
  315. and ebx,not ((1 shl 8)-1) ;Mask off low 8 bits
  316. test ch,bSign
  317. jz SaveValidResult ;Chop if positive
  318. jmp RoundUp24
  319. RndDenorm24:
  320. test EMSEG:[CWmask],Underflow;Is exception unmasked?
  321. jz RndSetUnder
  322. ;We don't really store in denormalized format, but we need the number
  323. ;to be rounded as if we do. If the exponent were -IexpBias, we would
  324. ;lose 1 bit of precision; as it gets more negative, we lose more bits.
  325. ;We'll do this by adjusting the exponent so that the bits we want to
  326. ;keep look like integer bits, and performing round-to-integer.
  327. add ecx,(IexpBias+22) shl 16 ;Adjust exponent so we're integer
  328. call RoundToBit
  329. ;Set underflow exception if precision exception is set
  330. mov al,EMSEG:[CURerr]
  331. and al,Precision
  332. ror al,Precision-Underflow ;Move Precision bit to Underflow pos.
  333. or EMSEG:[CURerr],al ;Signal Underflow if inexact
  334. cmp cl,bTAG_ZERO
  335. jz SaveResult
  336. sub ecx,(IexpBias+22) shl 16;Restore unbiased exponent
  337. cmp ecx,(IexpMin-IexpBias+1) shl 16 ;Did we round out of denorm?
  338. jae SaveResult
  339. mov cl,bTAG_DEN
  340. jmp SaveResult
  341. ;***********
  342. Round24near:
  343. ;***********
  344. ;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
  345. cmp ecx,TexpMin shl 16 ;Test for Underflow
  346. jl RndDenorm24
  347. or eax,esi ;Low dword is just sticky bits
  348. mov edx,ebx ;Get low bits
  349. and edx,(1 shl 8) - 1 ;Mask to last 8 bits
  350. or edx,eax ;Throwing away any bits?
  351. jz SaveValidResult
  352. or EMSEG:[CURerr],Precision;Set flag on inexact result
  353. xor esi,esi
  354. ;To perform "round even" when the round bit is set and the sticky bits
  355. ;are zero, we treat the LSB as if it were a sticky bit. Thus if the LSB
  356. ;is set, that will always force a round up (to even) if the round bit is
  357. ;set. If the LSB is zero, then the sticky bits remain zero and we always
  358. ;round down.
  359. mov edx,ebx
  360. and ebx,not ((1 shl 8)-1) ;Mask off low 8 bits
  361. test dl,1 shl 7 ;Round bit set?
  362. jz SaveValidResult
  363. and edx,(3 shl 7)-1 ;Mask to LSB and sticky bits
  364. or eax,edx ;Combine all sticky bits
  365. jz SaveValidResult
  366. RoundUp24:
  367. mov EMSEG:[SWcc],RoundUp
  368. add ebx,1 shl 8
  369. jnc SaveValidResult
  370. jmp BumpExponent ;Overflowed, increment exponent
  371. ;***********
  372. Round24up:
  373. ;***********
  374. cmp ecx,TexpMin shl 16 ;Test for Underflow
  375. jl RndDenorm24
  376. or eax,esi ;Low dword is just sticky bits
  377. mov edx,ebx ;Get low bits
  378. and edx,(1 shl 8) - 1 ;Mask to last 8 bits
  379. or edx,eax ;Throwing away any bits?
  380. jz SaveValidResult
  381. or EMSEG:[CURerr],Precision;Set flag on inexact result
  382. ;Chop if negative, increase mantissa if positive
  383. xor esi,esi
  384. and ebx,not ((1 shl 8)-1) ;Mask off low 8 bits
  385. test ch,bSign
  386. jz RoundUp24 ;Round up if positive
  387. jmp SaveValidResult
  388. ;***********
  389. Round24chop:
  390. ;***********
  391. cmp ecx,TexpMin shl 16 ;Test for Underflow
  392. jl RndDenorm24
  393. or eax,esi ;Low dword is just sticky bits
  394. mov edx,ebx ;Get low bits
  395. and edx,(1 shl 8) - 1 ;Mask to last 8 bits
  396. or edx,eax ;Throwing away any bits?
  397. jz SaveValidResult
  398. or EMSEG:[CURerr],Precision;Set flag on inexact result
  399. xor esi,esi
  400. and ebx,not ((1 shl 8)-1) ;Mask off low 8 bits
  401. jmp SaveValidResult
  402. ;*******************************************************************************
  403. ;*** RoundToInteger
  404. ;
  405. ;This routine is used by FISTP Int64 and BSTP. Unlike RoundToBit, this
  406. ;unnormalizes the number into a 64-bit integer.
  407. ;
  408. ;Inputs:
  409. ; edi = pointer to number to round in stack
  410. ;Outputs:
  411. ; CY set if invalid operation
  412. ; ebx:edi = rounded integer if CY clear
  413. ; ch = sign if CY clear
  414. ;Note:
  415. ; FIST/FISTP/BSTP exception rules are used: If the number is too big,
  416. ; Invalid Operation occurs. Denormals are ignored.
  417. ;
  418. ;esi preserved
  419. RoundSpcl64Int:
  420. cmp cl,bTAG_DEN
  421. jz NormRound64Int ;Ignore denormal
  422. cmp cl,bTAG_EMPTY
  423. jnz RoundInvalid ;All other specials are invalid
  424. mov EMSEG:[CURerr],StackFlag+Invalid
  425. stc ;Flag exception to caller
  426. ret
  427. RoundInvalid:
  428. ;Overflow on integer store is invalid according to IEEE
  429. mov EMSEG:[CURerr],Invalid
  430. stc ;Flag exception to caller
  431. ret
  432. RoundToInteger:
  433. mov ebx,EMSEG:[edi].lManHi
  434. mov ecx,EMSEG:[edi].ExpSgn
  435. mov edi,EMSEG:[edi].lManLo
  436. ;mantissa in ebx:edi, exponent in high ecx, sign in ch bit 7, tag in cl
  437. mov al,ch ;Save sign bit
  438. cmp cl,bTAG_ZERO
  439. .erre bTAG_VALID lt bTAG_ZERO
  440. .erre bTAG_SNGL lt bTAG_ZERO
  441. jz RoundIntX ;Just return zero
  442. ja RoundSpcl64Int
  443. NormRound64Int:
  444. xor edx,edx
  445. sar ecx,16 ;Bring exponent down
  446. cmp ecx,-1 ;Is it less than 1?
  447. jle Under64Int
  448. cmp ecx,63
  449. jg RoundInvalid
  450. sub ecx,63
  451. neg ecx ;cl = amount to shift right
  452. mov ch,al ;Get sign out of al
  453. xor eax,eax
  454. cmp cl,32 ;Too big for one shift?
  455. jl ShortShft64
  456. ;32-bit shift right
  457. xchg edx,edi
  458. xchg ebx,edi ;ebx=0 now
  459. shrd eax,edx,cl
  460. ;Max total shift is 63 bits, so we know that the LSB of eax is still zero.
  461. ;We can rotate this zero to the MSB so the sticky bits in eax can be combined
  462. ;with those in edx without affecting the rounding bit in the MSB of edx.
  463. ror eax,1 ;MSB is now zero
  464. ShortShft64:
  465. ;Shift count in cl is modulo-32
  466. shrd edx,edi,cl
  467. shrd edi,ebx,cl
  468. shr ebx,cl
  469. or edx,eax ;Collapse sticky bits into one dword
  470. jz RoundIntX ;No sticky or round bits, so don't round
  471. ;Result will not be exact--check rounding mode
  472. Round64Int:
  473. mov EMSEG:[CURerr],Precision;Set flag on inexact result
  474. test EMSEG:[CWcntl],RoundControl ;Check rounding control bits
  475. .erre RCnear eq 0
  476. jnz NotNearest64Int ;Not just round-to-nearest
  477. ;To perform "round even" when the round bit is set and the sticky bits
  478. ;are zero, we treat the LSB as if it were a sticky bit. Thus if the LSB
  479. ;is set, that will always force a round up (to even) if the round bit is
  480. ;set. If the LSB is zero, then the sticky bits remain zero and we always
  481. ;round down.
  482. bt edi,0 ;Look at LSB (for round even)
  483. adc edx,(1 shl 31)-1 ;CY set if round up
  484. jnc RoundIntX
  485. mov EMSEG:[SWcc],RoundUp
  486. add edi,1 ;Round
  487. adc ebx,0
  488. jc RoundInvalid
  489. RoundIntX:
  490. ret ;CY clear, no Invalid exception
  491. Shift64Round:
  492. or edi,edi
  493. setnz dl ;Set sticky bit in edx
  494. xor edi,edi ;Mantissa is all zero
  495. jmp Round64Int
  496. Under64Int:
  497. ;ZF set if exponent is -1
  498. xchg ebx,edx ;64-bit right shift
  499. mov ch,al ;Restore sign to ch
  500. jz Shift64Round ;Exp. is -1, could need to round up
  501. xor edi,edi ;Mantissa is all zero
  502. mov EMSEG:[CURerr],Precision;Set flag on inexact result
  503. NotNearest64Int:
  504. ;We want to increase the magnitude if RCup and +, or RCdown and -
  505. mov al,EMSEG:[CWcntl] ;Get rounding control
  506. .erre (not RCup and RoundControl) eq RCdown
  507. sar ch,7 ;Expand sign through whole byte
  508. xor al,ch ;Flip round mode if -
  509. and al,RoundControl
  510. cmp al,RCup ;Rounding up?
  511. jnz RoundIntOk ;No, chop it
  512. mov EMSEG:[SWcc],RoundUp
  513. add edi,1
  514. adc ebx,0
  515. jc RoundInvalid
  516. RoundIntOk:
  517. clc
  518. ret
  519. ;*******************************************************************************
  520. ;*** RoundToBit
  521. ;
  522. ;This is a relatively low performance routine used by FRNDINT and to
  523. ;generate internal-format denormals. It can round to any bit position.
  524. ;
  525. ;Inputs:
  526. ; mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
  527. ;Purpose:
  528. ; Round number to integer. Zero exponent means number is in the
  529. ; range [1,2), so only the MSB will survive (MSB-1 is round bit).
  530. ; Larger exponents keep more bits; 63 would mean no rounding.
  531. ;Outputs:
  532. ; mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
  533. ;
  534. ;Does NOT detect overflow.
  535. NoSigBits:
  536. ;Exponent was negative: no integer part
  537. and ecx,bSign shl 8 ;Zero exponent, preserve sign
  538. mov cl,bTAG_ZERO
  539. or EMSEG:[CURerr],Precision;Set flag on inexact result
  540. test EMSEG:[CWcntl],RoundControl ;Check rounding control bits
  541. .erre RCnear eq 0
  542. jnz NotNearNoSig ;Not just round-to-nearest
  543. cmp edx,-1 ;Exponent of -1 ==> range [.5,1)
  544. je HalfBitRound
  545. RndIntToZero:
  546. xor ebx,ebx
  547. mov esi,ebx ;Just return zero
  548. ret
  549. NotNearNoSig:
  550. ;We want to increase the magnitude if RCup and +, or RCdown and -
  551. mov al,EMSEG:[CWcntl] ;Get rounding control
  552. sar ch,7 ;Expand sign through whole byte
  553. xor al,ch ;Flip rounding bits if negative
  554. and al,RoundControl
  555. cmp al,RCup ;Rounding up?
  556. jnz RndIntToZero ;No, chop it
  557. RndIntToOne:
  558. mov ebx,1 shl 31
  559. xor esi,esi
  560. mov cl,bTAG_SNGL
  561. mov EMSEG:[SWcc],RoundUp
  562. ret
  563. HalfBitRound:
  564. add ebx,ebx ;Shift off MSB (round bit)
  565. or ebx,esi
  566. or ebx,eax
  567. jnz RndIntToOne
  568. ret ;Return zero
  569. ;**********
  570. RoundToBit:
  571. ;**********
  572. mov edx,ecx ;Make copy of exponent
  573. sar edx,16 ;Bring rounding exponent down
  574. jl NoSigBits
  575. mov cl,dl
  576. cmp cl,32 ;Rounding in low word?
  577. jae RoundLow
  578. ;When cl = 31, the RoundBit is in the low half while the LSB is in the
  579. ;high half. We must preserve the RoundBit when we move it to eax.
  580. xchg eax,esi ;Low half becomes sticky bits
  581. or ah,al ;Preserve lowest bits in ah
  582. add esi,-1 ;Set CY if any original sticky bits
  583. sbb al,al ;Put original sticky bits in al
  584. mov esi,ebx
  585. xor ebx,ebx ;Shift mantissa right 32 bits
  586. RoundLow:
  587. mov edx,(1 shl 31) - 1
  588. shr edx,cl ;Make mask
  589. ;Note in the case of cl = 31, edx is now zero.
  590. mov edi,esi
  591. and edi,edx
  592. or edi,eax ;Any bits being lost?
  593. jz RndSetTag ;All done
  594. inc edx ;Mask for LSB
  595. or EMSEG:[CURerr],Precision;Set flag on inexact result
  596. test EMSEG:[CWcntl],RoundControl ;Check rounding control bits
  597. .erre RCnear eq 0
  598. jnz NotNearLow ;Not just round-to-nearest
  599. mov edi,edx ;Save LSB mask
  600. shr edi,1 ;Mask for round bit
  601. jc SplitRound ;Round bit in eax?
  602. test esi,edi ;Round bit set?
  603. jz MaskOffLow
  604. dec edi ;Mask for sticky bits
  605. or edi,edx ;Sticky bits + LSB
  606. and edi,esi
  607. or edi,eax ;Any sticky bits set?
  608. jz MaskOffLow
  609. RoundUpThenMask:
  610. mov EMSEG:[SWcc],RoundUp
  611. add esi,edx ;Round up
  612. adc ebx,0
  613. jc RoundBumpExp
  614. MaskOffLow:
  615. dec edx ;Mask for round & sticky bits
  616. not edx
  617. and esi,edx ;Zero out low bits
  618. RndSetTag:
  619. or ebx,ebx ;Is it normalized?
  620. jns RoundedHighHalf
  621. or esi,esi ;Any bits in low half?
  622. .erre bTAG_VALID eq 1
  623. .erre bTAG_SNGL eq 0
  624. setnz cl ;if low half==0 then cl=0 else cl=1
  625. ret
  626. SplitRound:
  627. ;Rounding high half in esi on rounding bit in eax
  628. bt esi,0 ;Look at LSB
  629. adc eax,(1 shl 31) - 1 ;Set CY if round up
  630. jc RoundUpThenMask
  631. or ebx,ebx ;Will set ZF for jnz below
  632. RoundedHighHalf:
  633. ;Rounding occured in high half, which had been moved low.
  634. ;Move it back up high.
  635. ;
  636. ;ZF set here on content of ebx. If not zero, rounding high half in esi
  637. ;rippled forward into zero in ebx.
  638. mov cl,bTAG_SNGL
  639. jnz RndIntNorm ;Present high half should be zero
  640. xchg ebx,esi ;Shift left 32 bits
  641. ret
  642. RndIntNorm:
  643. ;Rounded up high half of mantissa, which rolled over to 0.
  644. add ecx,1 shl 16 ;Increase exponent
  645. mov ebx,1 shl 31 ;Restore MSB
  646. ret ;Tag already set to SNGL
  647. RoundBumpExp:
  648. ;Mantissa was FFFFF... and rolled over to 0 when we rounded
  649. add ecx,1 shl 16 ;Increase exponent
  650. mov ebx,1 shl 31 ;Restore MSB
  651. jmp MaskOffLow
  652. NotNearLow:
  653. ;We want to increase the magnitude if RCup and +, or RCdown and -
  654. mov al,EMSEG:[CWcntl] ;Get rounding control
  655. sar ch,7 ;Expand sign through whole byte
  656. .erre (not RCup and RoundControl) eq RCdown
  657. xor al,ch ;Flip rounding bits if negative
  658. and al,RoundControl
  659. cmp al,RCup ;Rounding up?
  660. jz RoundUpThenMask ;yes
  661. jmp MaskOffLow ;No, chop it