1b2441318SGreg Kroah-Hartman/* SPDX-License-Identifier: GPL-2.0 */ 2da957e11SThomas Gleixner .file "reg_round.S" 3da957e11SThomas Gleixner/*---------------------------------------------------------------------------+ 4da957e11SThomas Gleixner | reg_round.S | 5da957e11SThomas Gleixner | | 6da957e11SThomas Gleixner | Rounding/truncation/etc for FPU basic arithmetic functions. | 7da957e11SThomas Gleixner | | 8da957e11SThomas Gleixner | Copyright (C) 1993,1995,1997 | 9da957e11SThomas Gleixner | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | 10da957e11SThomas Gleixner | Australia. E-mail billm@suburbia.net | 11da957e11SThomas Gleixner | | 12da957e11SThomas Gleixner | This code has four possible entry points. | 13da957e11SThomas Gleixner | The following must be entered by a jmp instruction: | 14da957e11SThomas Gleixner | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. | 15da957e11SThomas Gleixner | | 16da957e11SThomas Gleixner | The FPU_round entry point is intended to be used by C code. | 17da957e11SThomas Gleixner | From C, call as: | 18da957e11SThomas Gleixner | int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) | 19da957e11SThomas Gleixner | | 20da957e11SThomas Gleixner | Return value is the tag of the answer, or-ed with FPU_Exception if | 21da957e11SThomas Gleixner | one was raised, or -1 on internal error. | 22da957e11SThomas Gleixner | | 23da957e11SThomas Gleixner | For correct "up" and "down" rounding, the argument must have the correct | 24da957e11SThomas Gleixner | sign. | 25da957e11SThomas Gleixner | | 26da957e11SThomas Gleixner +---------------------------------------------------------------------------*/ 27da957e11SThomas Gleixner 28da957e11SThomas Gleixner/*---------------------------------------------------------------------------+ 29da957e11SThomas Gleixner | Four entry points. | 30da957e11SThomas Gleixner | | 31da957e11SThomas Gleixner | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: | 32da957e11SThomas Gleixner | %eax:%ebx 64 bit significand | 33da957e11SThomas Gleixner | %edx 32 bit extension of the significand | 34da957e11SThomas Gleixner | %edi pointer to an FPU_REG for the result to be stored | 35da957e11SThomas Gleixner | stack calling function must have set up a C stack frame and | 36da957e11SThomas Gleixner | pushed %esi, %edi, and %ebx | 37da957e11SThomas Gleixner | | 38da957e11SThomas Gleixner | Needed just for the fpu_reg_round_sqrt entry point: | 39da957e11SThomas Gleixner | %cx A control word in the same format as the FPU control word. | 40da957e11SThomas Gleixner | Otherwise, PARAM4 must give such a value. | 41da957e11SThomas Gleixner | | 42da957e11SThomas Gleixner | | 43da957e11SThomas Gleixner | The significand and its extension are assumed to be exact in the | 44da957e11SThomas Gleixner | following sense: | 45da957e11SThomas Gleixner | If the significand by itself is the exact result then the significand | 46da957e11SThomas Gleixner | extension (%edx) must contain 0, otherwise the significand extension | 47da957e11SThomas Gleixner | must be non-zero. | 48da957e11SThomas Gleixner | If the significand extension is non-zero then the significand is | 49da957e11SThomas Gleixner | smaller than the magnitude of the correct exact result by an amount | 50da957e11SThomas Gleixner | greater than zero and less than one ls bit of the significand. | 51da957e11SThomas Gleixner | The significand extension is only required to have three possible | 52da957e11SThomas Gleixner | non-zero values: | 53da957e11SThomas Gleixner | less than 0x80000000 <=> the significand is less than 1/2 an ls | 54da957e11SThomas Gleixner | bit smaller than the magnitude of the | 55da957e11SThomas Gleixner | true exact result. | 56da957e11SThomas Gleixner | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit | 57da957e11SThomas Gleixner | smaller than the magnitude of the true | 58da957e11SThomas Gleixner | exact result. | 59da957e11SThomas Gleixner | greater than 0x80000000 <=> the significand is more than 1/2 an ls | 60da957e11SThomas Gleixner | bit smaller than the magnitude of the | 61da957e11SThomas Gleixner | true exact result. | 62da957e11SThomas Gleixner | | 63da957e11SThomas Gleixner +---------------------------------------------------------------------------*/ 64da957e11SThomas Gleixner 65da957e11SThomas Gleixner/*---------------------------------------------------------------------------+ 66da957e11SThomas Gleixner | The code in this module has become quite complex, but it should handle | 67da957e11SThomas Gleixner | all of the FPU flags which are set at this stage of the basic arithmetic | 68da957e11SThomas Gleixner | computations. | 69da957e11SThomas Gleixner | There are a few rare cases where the results are not set identically to | 70da957e11SThomas Gleixner | a real FPU. These require a bit more thought because at this stage the | 71da957e11SThomas Gleixner | results of the code here appear to be more consistent... | 72da957e11SThomas Gleixner | This may be changed in a future version. | 73da957e11SThomas Gleixner +---------------------------------------------------------------------------*/ 74da957e11SThomas Gleixner 75da957e11SThomas Gleixner 76da957e11SThomas Gleixner#include "fpu_emu.h" 77da957e11SThomas Gleixner#include "exception.h" 78da957e11SThomas Gleixner#include "control_w.h" 79da957e11SThomas Gleixner 80da957e11SThomas Gleixner/* Flags for FPU_bits_lost */ 81da957e11SThomas Gleixner#define LOST_DOWN $1 82da957e11SThomas Gleixner#define LOST_UP $2 83da957e11SThomas Gleixner 84da957e11SThomas Gleixner/* Flags for FPU_denormal */ 85da957e11SThomas Gleixner#define DENORMAL $1 86da957e11SThomas Gleixner#define UNMASKED_UNDERFLOW $2 87da957e11SThomas Gleixner 88da957e11SThomas Gleixner 89da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU 90da957e11SThomas Gleixner/* Make the code re-entrant by putting 91da957e11SThomas Gleixner local storage on the stack: */ 92da957e11SThomas Gleixner#define FPU_bits_lost (%esp) 93da957e11SThomas Gleixner#define FPU_denormal 1(%esp) 94da957e11SThomas Gleixner 95da957e11SThomas Gleixner#else 96da957e11SThomas Gleixner/* Not re-entrant, so we can gain speed by putting 97da957e11SThomas Gleixner local storage in a static area: */ 98da957e11SThomas Gleixner.data 99da957e11SThomas Gleixner .align 4,0 100da957e11SThomas GleixnerFPU_bits_lost: 101da957e11SThomas Gleixner .byte 0 102da957e11SThomas GleixnerFPU_denormal: 103da957e11SThomas Gleixner .byte 0 104da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */ 105da957e11SThomas Gleixner 106da957e11SThomas Gleixner 107da957e11SThomas Gleixner.text 108da957e11SThomas Gleixner.globl fpu_reg_round 109da957e11SThomas Gleixner.globl fpu_Arith_exit 110da957e11SThomas Gleixner 111da957e11SThomas Gleixner/* Entry point when called from C */ 1126d685e53SJiri SlabySYM_FUNC_START(FPU_round) 113da957e11SThomas Gleixner pushl %ebp 114da957e11SThomas Gleixner movl %esp,%ebp 115da957e11SThomas Gleixner pushl %esi 116da957e11SThomas Gleixner pushl %edi 117da957e11SThomas Gleixner pushl %ebx 118da957e11SThomas Gleixner 119da957e11SThomas Gleixner movl PARAM1,%edi 120da957e11SThomas Gleixner movl SIGH(%edi),%eax 121da957e11SThomas Gleixner movl SIGL(%edi),%ebx 122da957e11SThomas Gleixner movl PARAM2,%edx 123da957e11SThomas Gleixner 124da957e11SThomas Gleixnerfpu_reg_round: /* Normal entry point */ 125da957e11SThomas Gleixner movl PARAM4,%ecx 126da957e11SThomas Gleixner 127da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU 128da957e11SThomas Gleixner pushl %ebx /* adjust the stack pointer */ 129da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */ 130da957e11SThomas Gleixner 131da957e11SThomas Gleixner#ifdef PARANOID 132da957e11SThomas Gleixner/* Cannot use this here yet */ 133da957e11SThomas Gleixner/* orl %eax,%eax */ 134da957e11SThomas Gleixner/* jns L_entry_bugged */ 135da957e11SThomas Gleixner#endif /* PARANOID */ 136da957e11SThomas Gleixner 137da957e11SThomas Gleixner cmpw EXP_UNDER,EXP(%edi) 138da957e11SThomas Gleixner jle L_Make_denorm /* The number is a de-normal */ 139da957e11SThomas Gleixner 140da957e11SThomas Gleixner movb $0,FPU_denormal /* 0 -> not a de-normal */ 141da957e11SThomas Gleixner 142da957e11SThomas GleixnerDenorm_done: 143da957e11SThomas Gleixner movb $0,FPU_bits_lost /* No bits yet lost in rounding */ 144da957e11SThomas Gleixner 145da957e11SThomas Gleixner movl %ecx,%esi 146da957e11SThomas Gleixner andl CW_PC,%ecx 147da957e11SThomas Gleixner cmpl PR_64_BITS,%ecx 148da957e11SThomas Gleixner je LRound_To_64 149da957e11SThomas Gleixner 150da957e11SThomas Gleixner cmpl PR_53_BITS,%ecx 151da957e11SThomas Gleixner je LRound_To_53 152da957e11SThomas Gleixner 153da957e11SThomas Gleixner cmpl PR_24_BITS,%ecx 154da957e11SThomas Gleixner je LRound_To_24 155da957e11SThomas Gleixner 156da957e11SThomas Gleixner#ifdef PECULIAR_486 157da957e11SThomas Gleixner/* With the precision control bits set to 01 "(reserved)", a real 80486 158da957e11SThomas Gleixner behaves as if the precision control bits were set to 11 "64 bits" */ 159da957e11SThomas Gleixner cmpl PR_RESERVED_BITS,%ecx 160da957e11SThomas Gleixner je LRound_To_64 161da957e11SThomas Gleixner#ifdef PARANOID 162da957e11SThomas Gleixner jmp L_bugged_denorm_486 163da957e11SThomas Gleixner#endif /* PARANOID */ 164da957e11SThomas Gleixner#else 165da957e11SThomas Gleixner#ifdef PARANOID 166da957e11SThomas Gleixner jmp L_bugged_denorm /* There is no bug, just a bad control word */ 167da957e11SThomas Gleixner#endif /* PARANOID */ 168da957e11SThomas Gleixner#endif /* PECULIAR_486 */ 169da957e11SThomas Gleixner 170da957e11SThomas Gleixner 171da957e11SThomas Gleixner/* Round etc to 24 bit precision */ 172da957e11SThomas GleixnerLRound_To_24: 173da957e11SThomas Gleixner movl %esi,%ecx 174da957e11SThomas Gleixner andl CW_RC,%ecx 175da957e11SThomas Gleixner cmpl RC_RND,%ecx 176da957e11SThomas Gleixner je LRound_nearest_24 177da957e11SThomas Gleixner 178da957e11SThomas Gleixner cmpl RC_CHOP,%ecx 179da957e11SThomas Gleixner je LCheck_truncate_24 180da957e11SThomas Gleixner 181da957e11SThomas Gleixner cmpl RC_UP,%ecx /* Towards +infinity */ 182da957e11SThomas Gleixner je LUp_24 183da957e11SThomas Gleixner 184da957e11SThomas Gleixner cmpl RC_DOWN,%ecx /* Towards -infinity */ 185da957e11SThomas Gleixner je LDown_24 186da957e11SThomas Gleixner 187da957e11SThomas Gleixner#ifdef PARANOID 188da957e11SThomas Gleixner jmp L_bugged_round24 189da957e11SThomas Gleixner#endif /* PARANOID */ 190da957e11SThomas Gleixner 191da957e11SThomas GleixnerLUp_24: 192da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 193da957e11SThomas Gleixner jne LCheck_truncate_24 /* If negative then up==truncate */ 194da957e11SThomas Gleixner 195da957e11SThomas Gleixner jmp LCheck_24_round_up 196da957e11SThomas Gleixner 197da957e11SThomas GleixnerLDown_24: 198da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 199da957e11SThomas Gleixner je LCheck_truncate_24 /* If positive then down==truncate */ 200da957e11SThomas Gleixner 201da957e11SThomas GleixnerLCheck_24_round_up: 202da957e11SThomas Gleixner movl %eax,%ecx 203da957e11SThomas Gleixner andl $0x000000ff,%ecx 204da957e11SThomas Gleixner orl %ebx,%ecx 205da957e11SThomas Gleixner orl %edx,%ecx 206da957e11SThomas Gleixner jnz LDo_24_round_up 207da957e11SThomas Gleixner jmp L_Re_normalise 208da957e11SThomas Gleixner 209da957e11SThomas GleixnerLRound_nearest_24: 210da957e11SThomas Gleixner /* Do rounding of the 24th bit if needed (nearest or even) */ 211da957e11SThomas Gleixner movl %eax,%ecx 212da957e11SThomas Gleixner andl $0x000000ff,%ecx 213da957e11SThomas Gleixner cmpl $0x00000080,%ecx 214da957e11SThomas Gleixner jc LCheck_truncate_24 /* less than half, no increment needed */ 215da957e11SThomas Gleixner 216da957e11SThomas Gleixner jne LGreater_Half_24 /* greater than half, increment needed */ 217da957e11SThomas Gleixner 218da957e11SThomas Gleixner /* Possibly half, we need to check the ls bits */ 219da957e11SThomas Gleixner orl %ebx,%ebx 220da957e11SThomas Gleixner jnz LGreater_Half_24 /* greater than half, increment needed */ 221da957e11SThomas Gleixner 222da957e11SThomas Gleixner orl %edx,%edx 223da957e11SThomas Gleixner jnz LGreater_Half_24 /* greater than half, increment needed */ 224da957e11SThomas Gleixner 225da957e11SThomas Gleixner /* Exactly half, increment only if 24th bit is 1 (round to even) */ 226da957e11SThomas Gleixner testl $0x00000100,%eax 227da957e11SThomas Gleixner jz LDo_truncate_24 228da957e11SThomas Gleixner 229da957e11SThomas GleixnerLGreater_Half_24: /* Rounding: increment at the 24th bit */ 230da957e11SThomas GleixnerLDo_24_round_up: 231da957e11SThomas Gleixner andl $0xffffff00,%eax /* Truncate to 24 bits */ 232da957e11SThomas Gleixner xorl %ebx,%ebx 233da957e11SThomas Gleixner movb LOST_UP,FPU_bits_lost 234da957e11SThomas Gleixner addl $0x00000100,%eax 235da957e11SThomas Gleixner jmp LCheck_Round_Overflow 236da957e11SThomas Gleixner 237da957e11SThomas GleixnerLCheck_truncate_24: 238da957e11SThomas Gleixner movl %eax,%ecx 239da957e11SThomas Gleixner andl $0x000000ff,%ecx 240da957e11SThomas Gleixner orl %ebx,%ecx 241da957e11SThomas Gleixner orl %edx,%ecx 242da957e11SThomas Gleixner jz L_Re_normalise /* No truncation needed */ 243da957e11SThomas Gleixner 244da957e11SThomas GleixnerLDo_truncate_24: 245da957e11SThomas Gleixner andl $0xffffff00,%eax /* Truncate to 24 bits */ 246da957e11SThomas Gleixner xorl %ebx,%ebx 247da957e11SThomas Gleixner movb LOST_DOWN,FPU_bits_lost 248da957e11SThomas Gleixner jmp L_Re_normalise 249da957e11SThomas Gleixner 250da957e11SThomas Gleixner 251da957e11SThomas Gleixner/* Round etc to 53 bit precision */ 252da957e11SThomas GleixnerLRound_To_53: 253da957e11SThomas Gleixner movl %esi,%ecx 254da957e11SThomas Gleixner andl CW_RC,%ecx 255da957e11SThomas Gleixner cmpl RC_RND,%ecx 256da957e11SThomas Gleixner je LRound_nearest_53 257da957e11SThomas Gleixner 258da957e11SThomas Gleixner cmpl RC_CHOP,%ecx 259da957e11SThomas Gleixner je LCheck_truncate_53 260da957e11SThomas Gleixner 261da957e11SThomas Gleixner cmpl RC_UP,%ecx /* Towards +infinity */ 262da957e11SThomas Gleixner je LUp_53 263da957e11SThomas Gleixner 264da957e11SThomas Gleixner cmpl RC_DOWN,%ecx /* Towards -infinity */ 265da957e11SThomas Gleixner je LDown_53 266da957e11SThomas Gleixner 267da957e11SThomas Gleixner#ifdef PARANOID 268da957e11SThomas Gleixner jmp L_bugged_round53 269da957e11SThomas Gleixner#endif /* PARANOID */ 270da957e11SThomas Gleixner 271da957e11SThomas GleixnerLUp_53: 272da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 273da957e11SThomas Gleixner jne LCheck_truncate_53 /* If negative then up==truncate */ 274da957e11SThomas Gleixner 275da957e11SThomas Gleixner jmp LCheck_53_round_up 276da957e11SThomas Gleixner 277da957e11SThomas GleixnerLDown_53: 278da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 279da957e11SThomas Gleixner je LCheck_truncate_53 /* If positive then down==truncate */ 280da957e11SThomas Gleixner 281da957e11SThomas GleixnerLCheck_53_round_up: 282da957e11SThomas Gleixner movl %ebx,%ecx 283da957e11SThomas Gleixner andl $0x000007ff,%ecx 284da957e11SThomas Gleixner orl %edx,%ecx 285da957e11SThomas Gleixner jnz LDo_53_round_up 286da957e11SThomas Gleixner jmp L_Re_normalise 287da957e11SThomas Gleixner 288da957e11SThomas GleixnerLRound_nearest_53: 289da957e11SThomas Gleixner /* Do rounding of the 53rd bit if needed (nearest or even) */ 290da957e11SThomas Gleixner movl %ebx,%ecx 291da957e11SThomas Gleixner andl $0x000007ff,%ecx 292da957e11SThomas Gleixner cmpl $0x00000400,%ecx 293da957e11SThomas Gleixner jc LCheck_truncate_53 /* less than half, no increment needed */ 294da957e11SThomas Gleixner 295da957e11SThomas Gleixner jnz LGreater_Half_53 /* greater than half, increment needed */ 296da957e11SThomas Gleixner 297da957e11SThomas Gleixner /* Possibly half, we need to check the ls bits */ 298da957e11SThomas Gleixner orl %edx,%edx 299da957e11SThomas Gleixner jnz LGreater_Half_53 /* greater than half, increment needed */ 300da957e11SThomas Gleixner 301da957e11SThomas Gleixner /* Exactly half, increment only if 53rd bit is 1 (round to even) */ 302da957e11SThomas Gleixner testl $0x00000800,%ebx 303da957e11SThomas Gleixner jz LTruncate_53 304da957e11SThomas Gleixner 305da957e11SThomas GleixnerLGreater_Half_53: /* Rounding: increment at the 53rd bit */ 306da957e11SThomas GleixnerLDo_53_round_up: 307da957e11SThomas Gleixner movb LOST_UP,FPU_bits_lost 308da957e11SThomas Gleixner andl $0xfffff800,%ebx /* Truncate to 53 bits */ 309da957e11SThomas Gleixner addl $0x00000800,%ebx 310da957e11SThomas Gleixner adcl $0,%eax 311da957e11SThomas Gleixner jmp LCheck_Round_Overflow 312da957e11SThomas Gleixner 313da957e11SThomas GleixnerLCheck_truncate_53: 314da957e11SThomas Gleixner movl %ebx,%ecx 315da957e11SThomas Gleixner andl $0x000007ff,%ecx 316da957e11SThomas Gleixner orl %edx,%ecx 317da957e11SThomas Gleixner jz L_Re_normalise 318da957e11SThomas Gleixner 319da957e11SThomas GleixnerLTruncate_53: 320da957e11SThomas Gleixner movb LOST_DOWN,FPU_bits_lost 321da957e11SThomas Gleixner andl $0xfffff800,%ebx /* Truncate to 53 bits */ 322da957e11SThomas Gleixner jmp L_Re_normalise 323da957e11SThomas Gleixner 324da957e11SThomas Gleixner 325da957e11SThomas Gleixner/* Round etc to 64 bit precision */ 326da957e11SThomas GleixnerLRound_To_64: 327da957e11SThomas Gleixner movl %esi,%ecx 328da957e11SThomas Gleixner andl CW_RC,%ecx 329da957e11SThomas Gleixner cmpl RC_RND,%ecx 330da957e11SThomas Gleixner je LRound_nearest_64 331da957e11SThomas Gleixner 332da957e11SThomas Gleixner cmpl RC_CHOP,%ecx 333da957e11SThomas Gleixner je LCheck_truncate_64 334da957e11SThomas Gleixner 335da957e11SThomas Gleixner cmpl RC_UP,%ecx /* Towards +infinity */ 336da957e11SThomas Gleixner je LUp_64 337da957e11SThomas Gleixner 338da957e11SThomas Gleixner cmpl RC_DOWN,%ecx /* Towards -infinity */ 339da957e11SThomas Gleixner je LDown_64 340da957e11SThomas Gleixner 341da957e11SThomas Gleixner#ifdef PARANOID 342da957e11SThomas Gleixner jmp L_bugged_round64 343da957e11SThomas Gleixner#endif /* PARANOID */ 344da957e11SThomas Gleixner 345da957e11SThomas GleixnerLUp_64: 346da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 347da957e11SThomas Gleixner jne LCheck_truncate_64 /* If negative then up==truncate */ 348da957e11SThomas Gleixner 349da957e11SThomas Gleixner orl %edx,%edx 350da957e11SThomas Gleixner jnz LDo_64_round_up 351da957e11SThomas Gleixner jmp L_Re_normalise 352da957e11SThomas Gleixner 353da957e11SThomas GleixnerLDown_64: 354da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 355da957e11SThomas Gleixner je LCheck_truncate_64 /* If positive then down==truncate */ 356da957e11SThomas Gleixner 357da957e11SThomas Gleixner orl %edx,%edx 358da957e11SThomas Gleixner jnz LDo_64_round_up 359da957e11SThomas Gleixner jmp L_Re_normalise 360da957e11SThomas Gleixner 361da957e11SThomas GleixnerLRound_nearest_64: 362da957e11SThomas Gleixner cmpl $0x80000000,%edx 363da957e11SThomas Gleixner jc LCheck_truncate_64 364da957e11SThomas Gleixner 365da957e11SThomas Gleixner jne LDo_64_round_up 366da957e11SThomas Gleixner 367da957e11SThomas Gleixner /* Now test for round-to-even */ 368da957e11SThomas Gleixner testb $1,%bl 369da957e11SThomas Gleixner jz LCheck_truncate_64 370da957e11SThomas Gleixner 371da957e11SThomas GleixnerLDo_64_round_up: 372da957e11SThomas Gleixner movb LOST_UP,FPU_bits_lost 373da957e11SThomas Gleixner addl $1,%ebx 374da957e11SThomas Gleixner adcl $0,%eax 375da957e11SThomas Gleixner 376da957e11SThomas GleixnerLCheck_Round_Overflow: 377da957e11SThomas Gleixner jnc L_Re_normalise 378da957e11SThomas Gleixner 379da957e11SThomas Gleixner /* Overflow, adjust the result (significand to 1.0) */ 380da957e11SThomas Gleixner rcrl $1,%eax 381da957e11SThomas Gleixner rcrl $1,%ebx 382da957e11SThomas Gleixner incw EXP(%edi) 383da957e11SThomas Gleixner jmp L_Re_normalise 384da957e11SThomas Gleixner 385da957e11SThomas GleixnerLCheck_truncate_64: 386da957e11SThomas Gleixner orl %edx,%edx 387da957e11SThomas Gleixner jz L_Re_normalise 388da957e11SThomas Gleixner 389da957e11SThomas GleixnerLTruncate_64: 390da957e11SThomas Gleixner movb LOST_DOWN,FPU_bits_lost 391da957e11SThomas Gleixner 392da957e11SThomas GleixnerL_Re_normalise: 393da957e11SThomas Gleixner testb $0xff,FPU_denormal 394da957e11SThomas Gleixner jnz Normalise_result 395da957e11SThomas Gleixner 396da957e11SThomas GleixnerL_Normalised: 397da957e11SThomas Gleixner movl TAG_Valid,%edx 398da957e11SThomas Gleixner 399da957e11SThomas GleixnerL_deNormalised: 400da957e11SThomas Gleixner cmpb LOST_UP,FPU_bits_lost 401da957e11SThomas Gleixner je L_precision_lost_up 402da957e11SThomas Gleixner 403da957e11SThomas Gleixner cmpb LOST_DOWN,FPU_bits_lost 404da957e11SThomas Gleixner je L_precision_lost_down 405da957e11SThomas Gleixner 406da957e11SThomas GleixnerL_no_precision_loss: 407da957e11SThomas Gleixner /* store the result */ 408da957e11SThomas Gleixner 409da957e11SThomas GleixnerL_Store_significand: 410da957e11SThomas Gleixner movl %eax,SIGH(%edi) 411da957e11SThomas Gleixner movl %ebx,SIGL(%edi) 412da957e11SThomas Gleixner 413da957e11SThomas Gleixner cmpw EXP_OVER,EXP(%edi) 414da957e11SThomas Gleixner jge L_overflow 415da957e11SThomas Gleixner 416da957e11SThomas Gleixner movl %edx,%eax 417da957e11SThomas Gleixner 418da957e11SThomas Gleixner /* Convert the exponent to 80x87 form. */ 419da957e11SThomas Gleixner addw EXTENDED_Ebias,EXP(%edi) 420da957e11SThomas Gleixner andw $0x7fff,EXP(%edi) 421da957e11SThomas Gleixner 422da957e11SThomas Gleixnerfpu_reg_round_signed_special_exit: 423da957e11SThomas Gleixner 424da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 425da957e11SThomas Gleixner je fpu_reg_round_special_exit 426da957e11SThomas Gleixner 427da957e11SThomas Gleixner orw $0x8000,EXP(%edi) /* Negative sign for the result. */ 428da957e11SThomas Gleixner 429da957e11SThomas Gleixnerfpu_reg_round_special_exit: 430da957e11SThomas Gleixner 431da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU 432da957e11SThomas Gleixner popl %ebx /* adjust the stack pointer */ 433da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */ 434da957e11SThomas Gleixner 435da957e11SThomas Gleixnerfpu_Arith_exit: 436da957e11SThomas Gleixner popl %ebx 437da957e11SThomas Gleixner popl %edi 438da957e11SThomas Gleixner popl %esi 439da957e11SThomas Gleixner leave 440*f94909ceSPeter Zijlstra RET 441da957e11SThomas Gleixner 442da957e11SThomas Gleixner 443da957e11SThomas Gleixner/* 444da957e11SThomas Gleixner * Set the FPU status flags to represent precision loss due to 445da957e11SThomas Gleixner * round-up. 446da957e11SThomas Gleixner */ 447da957e11SThomas GleixnerL_precision_lost_up: 448da957e11SThomas Gleixner push %edx 449da957e11SThomas Gleixner push %eax 450da957e11SThomas Gleixner call set_precision_flag_up 451da957e11SThomas Gleixner popl %eax 452da957e11SThomas Gleixner popl %edx 453da957e11SThomas Gleixner jmp L_no_precision_loss 454da957e11SThomas Gleixner 455da957e11SThomas Gleixner/* 456da957e11SThomas Gleixner * Set the FPU status flags to represent precision loss due to 457da957e11SThomas Gleixner * truncation. 458da957e11SThomas Gleixner */ 459da957e11SThomas GleixnerL_precision_lost_down: 460da957e11SThomas Gleixner push %edx 461da957e11SThomas Gleixner push %eax 462da957e11SThomas Gleixner call set_precision_flag_down 463da957e11SThomas Gleixner popl %eax 464da957e11SThomas Gleixner popl %edx 465da957e11SThomas Gleixner jmp L_no_precision_loss 466da957e11SThomas Gleixner 467da957e11SThomas Gleixner 468da957e11SThomas Gleixner/* 469da957e11SThomas Gleixner * The number is a denormal (which might get rounded up to a normal) 470da957e11SThomas Gleixner * Shift the number right the required number of bits, which will 471da957e11SThomas Gleixner * have to be undone later... 472da957e11SThomas Gleixner */ 473da957e11SThomas GleixnerL_Make_denorm: 474da957e11SThomas Gleixner /* The action to be taken depends upon whether the underflow 475da957e11SThomas Gleixner exception is masked */ 476da957e11SThomas Gleixner testb CW_Underflow,%cl /* Underflow mask. */ 477da957e11SThomas Gleixner jz Unmasked_underflow /* Do not make a denormal. */ 478da957e11SThomas Gleixner 479da957e11SThomas Gleixner movb DENORMAL,FPU_denormal 480da957e11SThomas Gleixner 481da957e11SThomas Gleixner pushl %ecx /* Save */ 482da957e11SThomas Gleixner movw EXP_UNDER+1,%cx 483da957e11SThomas Gleixner subw EXP(%edi),%cx 484da957e11SThomas Gleixner 485da957e11SThomas Gleixner cmpw $64,%cx /* shrd only works for 0..31 bits */ 486da957e11SThomas Gleixner jnc Denorm_shift_more_than_63 487da957e11SThomas Gleixner 488da957e11SThomas Gleixner cmpw $32,%cx /* shrd only works for 0..31 bits */ 489da957e11SThomas Gleixner jnc Denorm_shift_more_than_32 490da957e11SThomas Gleixner 491da957e11SThomas Gleixner/* 492da957e11SThomas Gleixner * We got here without jumps by assuming that the most common requirement 493da957e11SThomas Gleixner * is for a small de-normalising shift. 494da957e11SThomas Gleixner * Shift by [1..31] bits 495da957e11SThomas Gleixner */ 496da957e11SThomas Gleixner addw %cx,EXP(%edi) 497da957e11SThomas Gleixner orl %edx,%edx /* extension */ 498da957e11SThomas Gleixner setne %ch /* Save whether %edx is non-zero */ 499da957e11SThomas Gleixner xorl %edx,%edx 500da957e11SThomas Gleixner shrd %cl,%ebx,%edx 501da957e11SThomas Gleixner shrd %cl,%eax,%ebx 502da957e11SThomas Gleixner shr %cl,%eax 503da957e11SThomas Gleixner orb %ch,%dl 504da957e11SThomas Gleixner popl %ecx 505da957e11SThomas Gleixner jmp Denorm_done 506da957e11SThomas Gleixner 507da957e11SThomas Gleixner/* Shift by [32..63] bits */ 508da957e11SThomas GleixnerDenorm_shift_more_than_32: 509da957e11SThomas Gleixner addw %cx,EXP(%edi) 510da957e11SThomas Gleixner subb $32,%cl 511da957e11SThomas Gleixner orl %edx,%edx 512da957e11SThomas Gleixner setne %ch 513da957e11SThomas Gleixner orb %ch,%bl 514da957e11SThomas Gleixner xorl %edx,%edx 515da957e11SThomas Gleixner shrd %cl,%ebx,%edx 516da957e11SThomas Gleixner shrd %cl,%eax,%ebx 517da957e11SThomas Gleixner shr %cl,%eax 518da957e11SThomas Gleixner orl %edx,%edx /* test these 32 bits */ 519da957e11SThomas Gleixner setne %cl 520da957e11SThomas Gleixner orb %ch,%bl 521da957e11SThomas Gleixner orb %cl,%bl 522da957e11SThomas Gleixner movl %ebx,%edx 523da957e11SThomas Gleixner movl %eax,%ebx 524da957e11SThomas Gleixner xorl %eax,%eax 525da957e11SThomas Gleixner popl %ecx 526da957e11SThomas Gleixner jmp Denorm_done 527da957e11SThomas Gleixner 528da957e11SThomas Gleixner/* Shift by [64..) bits */ 529da957e11SThomas GleixnerDenorm_shift_more_than_63: 530da957e11SThomas Gleixner cmpw $64,%cx 531da957e11SThomas Gleixner jne Denorm_shift_more_than_64 532da957e11SThomas Gleixner 533da957e11SThomas Gleixner/* Exactly 64 bit shift */ 534da957e11SThomas Gleixner addw %cx,EXP(%edi) 535da957e11SThomas Gleixner xorl %ecx,%ecx 536da957e11SThomas Gleixner orl %edx,%edx 537da957e11SThomas Gleixner setne %cl 538da957e11SThomas Gleixner orl %ebx,%ebx 539da957e11SThomas Gleixner setne %ch 540da957e11SThomas Gleixner orb %ch,%cl 541da957e11SThomas Gleixner orb %cl,%al 542da957e11SThomas Gleixner movl %eax,%edx 543da957e11SThomas Gleixner xorl %eax,%eax 544da957e11SThomas Gleixner xorl %ebx,%ebx 545da957e11SThomas Gleixner popl %ecx 546da957e11SThomas Gleixner jmp Denorm_done 547da957e11SThomas Gleixner 548da957e11SThomas GleixnerDenorm_shift_more_than_64: 549da957e11SThomas Gleixner movw EXP_UNDER+1,EXP(%edi) 550da957e11SThomas Gleixner/* This is easy, %eax must be non-zero, so.. */ 551da957e11SThomas Gleixner movl $1,%edx 552da957e11SThomas Gleixner xorl %eax,%eax 553da957e11SThomas Gleixner xorl %ebx,%ebx 554da957e11SThomas Gleixner popl %ecx 555da957e11SThomas Gleixner jmp Denorm_done 556da957e11SThomas Gleixner 557da957e11SThomas Gleixner 558da957e11SThomas GleixnerUnmasked_underflow: 559da957e11SThomas Gleixner movb UNMASKED_UNDERFLOW,FPU_denormal 560da957e11SThomas Gleixner jmp Denorm_done 561da957e11SThomas Gleixner 562da957e11SThomas Gleixner 563da957e11SThomas Gleixner/* Undo the de-normalisation. */ 564da957e11SThomas GleixnerNormalise_result: 565da957e11SThomas Gleixner cmpb UNMASKED_UNDERFLOW,FPU_denormal 566da957e11SThomas Gleixner je Signal_underflow 567da957e11SThomas Gleixner 568da957e11SThomas Gleixner/* The number must be a denormal if we got here. */ 569da957e11SThomas Gleixner#ifdef PARANOID 570da957e11SThomas Gleixner /* But check it... just in case. */ 571da957e11SThomas Gleixner cmpw EXP_UNDER+1,EXP(%edi) 572da957e11SThomas Gleixner jne L_norm_bugged 573da957e11SThomas Gleixner#endif /* PARANOID */ 574da957e11SThomas Gleixner 575da957e11SThomas Gleixner#ifdef PECULIAR_486 576da957e11SThomas Gleixner /* 577da957e11SThomas Gleixner * This implements a special feature of 80486 behaviour. 578163b0991SIngo Molnar * Underflow will be signaled even if the number is 579da957e11SThomas Gleixner * not a denormal after rounding. 580da957e11SThomas Gleixner * This difference occurs only for masked underflow, and not 581da957e11SThomas Gleixner * in the unmasked case. 582da957e11SThomas Gleixner * Actual 80486 behaviour differs from this in some circumstances. 583da957e11SThomas Gleixner */ 584da957e11SThomas Gleixner orl %eax,%eax /* ms bits */ 585da957e11SThomas Gleixner js LPseudoDenormal /* Will be masked underflow */ 586da957e11SThomas Gleixner#else 587da957e11SThomas Gleixner orl %eax,%eax /* ms bits */ 588da957e11SThomas Gleixner js L_Normalised /* No longer a denormal */ 589da957e11SThomas Gleixner#endif /* PECULIAR_486 */ 590da957e11SThomas Gleixner 591da957e11SThomas Gleixner jnz LDenormal_adj_exponent 592da957e11SThomas Gleixner 593da957e11SThomas Gleixner orl %ebx,%ebx 594da957e11SThomas Gleixner jz L_underflow_to_zero /* The contents are zero */ 595da957e11SThomas Gleixner 596da957e11SThomas GleixnerLDenormal_adj_exponent: 597da957e11SThomas Gleixner decw EXP(%edi) 598da957e11SThomas Gleixner 599da957e11SThomas GleixnerLPseudoDenormal: 600da957e11SThomas Gleixner testb $0xff,FPU_bits_lost /* bits lost == underflow */ 601da957e11SThomas Gleixner movl TAG_Special,%edx 602da957e11SThomas Gleixner jz L_deNormalised 603da957e11SThomas Gleixner 604da957e11SThomas Gleixner /* There must be a masked underflow */ 605da957e11SThomas Gleixner push %eax 606da957e11SThomas Gleixner pushl EX_Underflow 607da957e11SThomas Gleixner call EXCEPTION 608da957e11SThomas Gleixner popl %eax 609da957e11SThomas Gleixner popl %eax 610da957e11SThomas Gleixner movl TAG_Special,%edx 611da957e11SThomas Gleixner jmp L_deNormalised 612da957e11SThomas Gleixner 613da957e11SThomas Gleixner 614da957e11SThomas Gleixner/* 615da957e11SThomas Gleixner * The operations resulted in a number too small to represent. 616da957e11SThomas Gleixner * Masked response. 617da957e11SThomas Gleixner */ 618da957e11SThomas GleixnerL_underflow_to_zero: 619da957e11SThomas Gleixner push %eax 620da957e11SThomas Gleixner call set_precision_flag_down 621da957e11SThomas Gleixner popl %eax 622da957e11SThomas Gleixner 623da957e11SThomas Gleixner push %eax 624da957e11SThomas Gleixner pushl EX_Underflow 625da957e11SThomas Gleixner call EXCEPTION 626da957e11SThomas Gleixner popl %eax 627da957e11SThomas Gleixner popl %eax 628da957e11SThomas Gleixner 629da957e11SThomas Gleixner/* Reduce the exponent to EXP_UNDER */ 630da957e11SThomas Gleixner movw EXP_UNDER,EXP(%edi) 631da957e11SThomas Gleixner movl TAG_Zero,%edx 632da957e11SThomas Gleixner jmp L_Store_significand 633da957e11SThomas Gleixner 634da957e11SThomas Gleixner 635da957e11SThomas Gleixner/* The operations resulted in a number too large to represent. */ 636da957e11SThomas GleixnerL_overflow: 637da957e11SThomas Gleixner addw EXTENDED_Ebias,EXP(%edi) /* Set for unmasked response. */ 638da957e11SThomas Gleixner push %edi 639da957e11SThomas Gleixner call arith_overflow 640da957e11SThomas Gleixner pop %edi 641da957e11SThomas Gleixner jmp fpu_reg_round_signed_special_exit 642da957e11SThomas Gleixner 643da957e11SThomas Gleixner 644da957e11SThomas GleixnerSignal_underflow: 645da957e11SThomas Gleixner /* The number may have been changed to a non-denormal */ 646da957e11SThomas Gleixner /* by the rounding operations. */ 647da957e11SThomas Gleixner cmpw EXP_UNDER,EXP(%edi) 648da957e11SThomas Gleixner jle Do_unmasked_underflow 649da957e11SThomas Gleixner 650da957e11SThomas Gleixner jmp L_Normalised 651da957e11SThomas Gleixner 652da957e11SThomas GleixnerDo_unmasked_underflow: 653da957e11SThomas Gleixner /* Increase the exponent by the magic number */ 654da957e11SThomas Gleixner addw $(3*(1<<13)),EXP(%edi) 655da957e11SThomas Gleixner push %eax 656da957e11SThomas Gleixner pushl EX_Underflow 657da957e11SThomas Gleixner call EXCEPTION 658da957e11SThomas Gleixner popl %eax 659da957e11SThomas Gleixner popl %eax 660da957e11SThomas Gleixner jmp L_Normalised 661da957e11SThomas Gleixner 662da957e11SThomas Gleixner 663da957e11SThomas Gleixner#ifdef PARANOID 664da957e11SThomas Gleixner#ifdef PECULIAR_486 665da957e11SThomas GleixnerL_bugged_denorm_486: 666da957e11SThomas Gleixner pushl EX_INTERNAL|0x236 667da957e11SThomas Gleixner call EXCEPTION 668da957e11SThomas Gleixner popl %ebx 669da957e11SThomas Gleixner jmp L_exception_exit 670da957e11SThomas Gleixner#else 671da957e11SThomas GleixnerL_bugged_denorm: 672da957e11SThomas Gleixner pushl EX_INTERNAL|0x230 673da957e11SThomas Gleixner call EXCEPTION 674da957e11SThomas Gleixner popl %ebx 675da957e11SThomas Gleixner jmp L_exception_exit 676da957e11SThomas Gleixner#endif /* PECULIAR_486 */ 677da957e11SThomas Gleixner 678da957e11SThomas GleixnerL_bugged_round24: 679da957e11SThomas Gleixner pushl EX_INTERNAL|0x231 680da957e11SThomas Gleixner call EXCEPTION 681da957e11SThomas Gleixner popl %ebx 682da957e11SThomas Gleixner jmp L_exception_exit 683da957e11SThomas Gleixner 684da957e11SThomas GleixnerL_bugged_round53: 685da957e11SThomas Gleixner pushl EX_INTERNAL|0x232 686da957e11SThomas Gleixner call EXCEPTION 687da957e11SThomas Gleixner popl %ebx 688da957e11SThomas Gleixner jmp L_exception_exit 689da957e11SThomas Gleixner 690da957e11SThomas GleixnerL_bugged_round64: 691da957e11SThomas Gleixner pushl EX_INTERNAL|0x233 692da957e11SThomas Gleixner call EXCEPTION 693da957e11SThomas Gleixner popl %ebx 694da957e11SThomas Gleixner jmp L_exception_exit 695da957e11SThomas Gleixner 696da957e11SThomas GleixnerL_norm_bugged: 697da957e11SThomas Gleixner pushl EX_INTERNAL|0x234 698da957e11SThomas Gleixner call EXCEPTION 699da957e11SThomas Gleixner popl %ebx 700da957e11SThomas Gleixner jmp L_exception_exit 701da957e11SThomas Gleixner 702da957e11SThomas GleixnerL_entry_bugged: 703da957e11SThomas Gleixner pushl EX_INTERNAL|0x235 704da957e11SThomas Gleixner call EXCEPTION 705da957e11SThomas Gleixner popl %ebx 706da957e11SThomas GleixnerL_exception_exit: 707da957e11SThomas Gleixner mov $-1,%eax 708da957e11SThomas Gleixner jmp fpu_reg_round_special_exit 709da957e11SThomas Gleixner#endif /* PARANOID */ 710bd6be579SJiri Slaby 7116d685e53SJiri SlabySYM_FUNC_END(FPU_round) 712