Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/arch/x86/math-emu/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 10 kB image not shown  

Quelle  reg_compare.c   Sprache: 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);

}

/* 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;
}

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;
}

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;
}

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;
}

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;
}

/*---------------------------------------------------------------------------*/

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

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

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

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

}

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

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

/* P6+ compare-to-EFLAGS ops */

void fcomi_(void)
{
 /* fcomi st(i) */
 compare_i_st_st(FPU_rm);
}

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

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

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

Messung V0.5
C=90 H=95 G=92

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.