cregit-Linux how code gets into the kernel

Release 4.14 arch/x86/math-emu/reg_compare.c

// SPDX-License-Identifier: GPL-2.0
/*---------------------------------------------------------------------------+
 |  reg_compare.c                                                            |
 |                                                                           |
 | Compare two floating point registers                                      |
 |                                                                           |
 | Copyright (C) 1992,1993,1994,1997                                         |
 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
 |                  E-mail   billm@suburbia.net                              |
 |                                                                           |
 |                                                                           |
 +---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------+
 | compare() is the core FPU_REG comparison function                         |
 +---------------------------------------------------------------------------*/

#include "fpu_system.h"
#include "exception.h"
#include "fpu_emu.h"
#include "control_w.h"
#include "status_w.h"


static int compare(FPU_REG const *b, int tagb) { int diff, exp0, expb; u_char st0_tag; FPU_REG *st0_ptr; FPU_REG x, y; u_char st0_sign, signb = getsign(b); st0_ptr = &st(0); st0_tag = FPU_gettag0(); st0_sign = getsign(st0_ptr); if (tagb == TAG_Special) tagb = FPU_Special(b); if (st0_tag == TAG_Special) st0_tag = FPU_Special(st0_ptr); if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal)) || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) { if (st0_tag == TAG_Zero) { if (tagb == TAG_Zero) return COMP_A_eq_B; if (tagb == TAG_Valid) return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B); if (tagb == TW_Denormal) return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) | COMP_Denormal; } else if (tagb == TAG_Zero) { if (st0_tag == TAG_Valid) return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); if (st0_tag == TW_Denormal) return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) | COMP_Denormal; } if (st0_tag == TW_Infinity) { if ((tagb == TAG_Valid) || (tagb == TAG_Zero)) return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); else if (tagb == TW_Denormal) return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) | COMP_Denormal; else if (tagb == TW_Infinity) { /* The 80486 book says that infinities can be equal! */ return (st0_sign == signb) ? COMP_A_eq_B : ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); } /* Fall through to the NaN code */ } else if (tagb == TW_Infinity) { if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero)) return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B); if (st0_tag == TW_Denormal) return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) | COMP_Denormal; /* Fall through to the NaN code */ } /* The only possibility now should be that one of the arguments is a NaN */ if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) { int signalling = 0, unsupported = 0; if (st0_tag == TW_NaN) { signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000; unsupported = !((exponent(st0_ptr) == EXP_OVER) && (st0_ptr-> sigh & 0x80000000)); } if (tagb == TW_NaN) { signalling |= (b->sigh & 0xc0000000) == 0x80000000; unsupported |= !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)); } if (signalling || unsupported) return COMP_No_Comp | COMP_SNaN | COMP_NaN; else /* Neither is a signaling NaN */ return COMP_No_Comp | COMP_NaN; } EXCEPTION(EX_Invalid); } if (st0_sign != signb) { return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? COMP_Denormal : 0); } if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) { FPU_to_exp16(st0_ptr, &x); FPU_to_exp16(b, &y); st0_ptr = &x; b = &y; exp0 = exponent16(st0_ptr); expb = exponent16(b); } else { exp0 = exponent(st0_ptr); expb = exponent(b); } #ifdef PARANOID if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid); #endif /* PARANOID */ diff = exp0 - expb; if (diff == 0) { diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are identical */ if (diff == 0) { diff = st0_ptr->sigl > b->sigl; if (diff == 0) diff = -(st0_ptr->sigl < b->sigl); } } if (diff > 0) { return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? COMP_Denormal : 0); } if (diff < 0) { return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? COMP_Denormal : 0); } return COMP_A_eq_B | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ? COMP_Denormal : 0); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)82599.64%880.00%
Ingo Molnar20.24%110.00%
Linus Torvalds10.12%110.00%
Total828100.00%10100.00%

/* This function requires that st(0) is not empty */
int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) { int f, c; c = compare(loaded_data, loaded_tag); if (c & COMP_NaN) { EXCEPTION(EX_Invalid); f = SW_C3 | SW_C2 | SW_C0; } else switch (c & 7) { case COMP_A_lt_B: f = SW_C0; break; case COMP_A_eq_B: f = SW_C3; break; case COMP_A_gt_B: f = 0; break; case COMP_No_Comp: f = SW_C3 | SW_C2 | SW_C0; break; default: #ifdef PARANOID EXCEPTION(EX_INTERNAL | 0x121); #endif /* PARANOID */ f = SW_C3 | SW_C2 | SW_C0; break; } setcc(f); if (c & COMP_Denormal) { return denormal_operand() < 0; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13497.10%583.33%
Arnd Bergmann42.90%116.67%
Total138100.00%6100.00%


static int compare_st_st(int nr) { int f, c; FPU_REG *st_ptr; if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { setcc(SW_C3 | SW_C2 | SW_C0); /* Stack fault */ EXCEPTION(EX_StackUnder); return !(control_word & CW_Invalid); } st_ptr = &st(nr); c = compare(st_ptr, FPU_gettagi(nr)); if (c & COMP_NaN) { setcc(SW_C3 | SW_C2 | SW_C0); EXCEPTION(EX_Invalid); return !(control_word & CW_Invalid); } else switch (c & 7) { case COMP_A_lt_B: f = SW_C0; break; case COMP_A_eq_B: f = SW_C3; break; case COMP_A_gt_B: f = 0; break; case COMP_No_Comp: f = SW_C3 | SW_C2 | SW_C0; break; default: #ifdef PARANOID EXCEPTION(EX_INTERNAL | 0x122); #endif /* PARANOID */ f = SW_C3 | SW_C2 | SW_C0; break; } setcc(f); if (c & COMP_Denormal) { return denormal_operand() < 0; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)19397.97%583.33%
Arnd Bergmann42.03%116.67%
Total197100.00%6100.00%


static int compare_i_st_st(int nr) { int f, c; FPU_REG *st_ptr; if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF); /* Stack fault */ EXCEPTION(EX_StackUnder); return !(control_word & CW_Invalid); } partial_status &= ~SW_C0; st_ptr = &st(nr); c = compare(st_ptr, FPU_gettagi(nr)); if (c & COMP_NaN) { FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF); EXCEPTION(EX_Invalid); return !(control_word & CW_Invalid); } switch (c & 7) { case COMP_A_lt_B: f = X86_EFLAGS_CF; break; case COMP_A_eq_B: f = X86_EFLAGS_ZF; break; case COMP_A_gt_B: f = 0; break; case COMP_No_Comp: f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF; break; default: #ifdef PARANOID EXCEPTION(EX_INTERNAL | 0x122); #endif /* PARANOID */ f = 0; break; } FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f; if (c & COMP_Denormal) { return denormal_operand() < 0; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko20798.10%150.00%
Arnd Bergmann41.90%150.00%
Total211100.00%2100.00%


static int compare_u_st_st(int nr) { int f = 0, c; FPU_REG *st_ptr; if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { setcc(SW_C3 | SW_C2 | SW_C0); /* Stack fault */ EXCEPTION(EX_StackUnder); return !(control_word & CW_Invalid); } st_ptr = &st(nr); c = compare(st_ptr, FPU_gettagi(nr)); if (c & COMP_NaN) { setcc(SW_C3 | SW_C2 | SW_C0); if (c & COMP_SNaN) { /* This is the only difference between un-ordered and ordinary comparisons */ EXCEPTION(EX_Invalid); return !(control_word & CW_Invalid); } return 0; } else switch (c & 7) { case COMP_A_lt_B: f = SW_C0; break; case COMP_A_eq_B: f = SW_C3; break; case COMP_A_gt_B: f = 0; break; case COMP_No_Comp: f = SW_C3 | SW_C2 | SW_C0; break; #ifdef PARANOID default: EXCEPTION(EX_INTERNAL | 0x123); f = SW_C3 | SW_C2 | SW_C0; break; #endif /* PARANOID */ } setcc(f); if (c & COMP_Denormal) { return denormal_operand() < 0; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)20798.10%562.50%
Dave Jones20.95%112.50%
Linus Torvalds10.47%112.50%
Ingo Molnar10.47%112.50%
Total211100.00%8100.00%


static int compare_ui_st_st(int nr) { int f = 0, c; FPU_REG *st_ptr; if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) { FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF); /* Stack fault */ EXCEPTION(EX_StackUnder); return !(control_word & CW_Invalid); } partial_status &= ~SW_C0; st_ptr = &st(nr); c = compare(st_ptr, FPU_gettagi(nr)); if (c & COMP_NaN) { FPU_EFLAGS |= (X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF); if (c & COMP_SNaN) { /* This is the only difference between un-ordered and ordinary comparisons */ EXCEPTION(EX_Invalid); return !(control_word & CW_Invalid); } return 0; } switch (c & 7) { case COMP_A_lt_B: f = X86_EFLAGS_CF; break; case COMP_A_eq_B: f = X86_EFLAGS_ZF; break; case COMP_A_gt_B: f = 0; break; case COMP_No_Comp: f = X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF; break; #ifdef PARANOID default: EXCEPTION(EX_INTERNAL | 0x123); f = 0; break; #endif /* PARANOID */ } FPU_EFLAGS = (FPU_EFLAGS & ~(X86_EFLAGS_ZF | X86_EFLAGS_PF | X86_EFLAGS_CF)) | f; if (c & COMP_Denormal) { return denormal_operand() < 0; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko225100.00%1100.00%
Total225100.00%1100.00%

/*---------------------------------------------------------------------------*/
void fcom_st(void) { /* fcom st(i) */ compare_st_st(FPU_rm); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1076.92%150.00%
Al Viro323.08%150.00%
Total13100.00%2100.00%


void fcompst(void) { /* fcomp st(i) */ if (!compare_st_st(FPU_rm)) FPU_pop(); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1684.21%480.00%
Al Viro315.79%120.00%
Total19100.00%5100.00%


void fcompp(void) { /* fcompp */ if (FPU_rm != 1) { FPU_illegal(); return; } if (!compare_st_st(1)) poppop(); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2890.32%685.71%
Al Viro39.68%114.29%
Total31100.00%7100.00%


void fucom_(void) { /* fucom st(i) */ compare_u_st_st(FPU_rm); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1076.92%150.00%
Al Viro323.08%150.00%
Total13100.00%2100.00%


void fucomp(void) { /* fucomp st(i) */ if (!compare_u_st_st(FPU_rm)) FPU_pop(); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1684.21%480.00%
Al Viro315.79%120.00%
Total19100.00%5100.00%


void fucompp(void) { /* fucompp */ if (FPU_rm == 1) { if (!compare_u_st_st(1)) poppop(); } else FPU_illegal(); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2890.32%583.33%
Al Viro39.68%116.67%
Total31100.00%6100.00%

/* P6+ compare-to-EFLAGS ops */
void fcomi_(void) { /* fcomi st(i) */ compare_i_st_st(FPU_rm); }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko13100.00%1100.00%
Total13100.00%1100.00%


void fcomip(void) { /* fcomip st(i) */ if (!compare_i_st_st(FPU_rm)) FPU_pop(); }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko19100.00%1100.00%
Total19100.00%1100.00%


void fucomi_(void) { /* fucomi st(i) */ compare_ui_st_st(FPU_rm); }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko13100.00%1100.00%
Total13100.00%1100.00%


void fucomip(void) { /* fucomip st(i) */ if (!compare_ui_st_st(FPU_rm)) FPU_pop(); }

Contributors

PersonTokensPropCommitsCommitProp
Denys Vlasenko19100.00%1100.00%
Total19100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)148673.53%1058.82%
Denys Vlasenko49724.59%15.88%
Al Viro180.89%15.88%
Arnd Bergmann120.59%15.88%
Ingo Molnar30.15%15.88%
Linus Torvalds20.10%15.88%
Dave Jones20.10%15.88%
Greg Kroah-Hartman10.05%15.88%
Total2021100.00%17100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.