⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 reg_compare.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/*---------------------------------------------------------------------------+ |  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);}/* 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;#ifdef PARANOID      default:	EXCEPTION(EX_INTERNAL|0x121);	f = SW_C3 | SW_C2 | SW_C0;	break;#endif PARANOID      }  setcc(f);  if (c & COMP_Denormal)    {      return denormal_operand() < 0;    }  return 0;}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;#ifdef PARANOID      default:	EXCEPTION(EX_INTERNAL|0x122);	f = SW_C3 | SW_C2 | SW_C0;	break;#endif PARANOID      }  setcc(f);  if (c & COMP_Denormal)    {      return denormal_operand() < 0;    }  return 0;}static int compare_u_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);      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;}/*---------------------------------------------------------------------------*/void fcom_st(){  /* fcom st(i) */  compare_st_st(FPU_rm);}void fcompst(){  /* fcomp st(i) */  if ( !compare_st_st(FPU_rm) )    FPU_pop();}void fcompp(){  /* fcompp */  if (FPU_rm != 1)    {      FPU_illegal();      return;    }  if ( !compare_st_st(1) )      poppop();}void fucom_(){  /* fucom st(i) */  compare_u_st_st(FPU_rm);}void fucomp(){  /* fucomp st(i) */  if ( !compare_u_st_st(FPU_rm) )    FPU_pop();}void fucompp(){  /* fucompp */  if (FPU_rm == 1)    {      if ( !compare_u_st_st(1) )	poppop();    }  else    FPU_illegal();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -