sparc unordered compares

Richard Henderson rth@cygnus.com
Tue Jan 25 04:43:00 GMT 2000


        * sparc-protos.h (select_cc_mode): Declare.
        * sparc.c (select_cc_mode): New.  Handle unordered compares.
        (output_cbranch): Always reverse via code change.  Handle
        unordered compares.  Factor tests and string updates.
        * sparc.h (SELECT_CC_MODE): Split out to select_cc_mode.
        (REVERSIBLE_CC_MODE): Also exclude CCFPmode.
        * sparc.md (bunordered, bordered): New.
        (bungt, bunlt, buneq, bunge, bunle): New.

Index: sparc-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sparc/sparc-protos.h,v
retrieving revision 1.6
diff -c -p -d -r1.6 sparc-protos.h
*** sparc-protos.h	2000/01/04 08:09:06	1.6
--- sparc-protos.h	2000/01/25 12:35:17
*************** extern void sparc_flat_save_restore PARA
*** 77,82 ****
--- 77,83 ----
  					     const char *, unsigned long));
  
  #ifdef RTX_CODE
+ extern enum machine_mode select_cc_mode PARAMS ((enum rtx_code, rtx, rtx));
  /* Define the function that build the compare insn for scc and bcc.  */
  extern rtx gen_compare_reg PARAMS ((enum rtx_code code, rtx, rtx));
  extern void sparc_emit_float_lib_cmp PARAMS ((rtx, rtx, enum rtx_code));
Index: sparc.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sparc/sparc.c,v
retrieving revision 1.105
diff -c -p -d -r1.105 sparc.c
*** sparc.c	2000/01/18 23:44:36	1.105
--- sparc.c	2000/01/25 12:35:18
*************** sparc_emit_set_const64 (op0, op1)
*** 2072,2077 ****
--- 2072,2132 ----
    sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
  }
  
+ /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
+    return the mode to be used for the comparison.  For floating-point,
+    CCFP[E]mode is used.  CC_NOOVmode should be used when the first operand
+    is a PLUS, MINUS, NEG, or ASHIFT.  CCmode should be used when no special
+    processing is needed.  */
+ 
+ enum machine_mode
+ select_cc_mode (op, x, y)
+      enum rtx_code op;
+      rtx x;
+      rtx y ATTRIBUTE_UNUSED;
+ {
+   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+     {
+       switch (op)
+ 	{
+ 	case EQ:
+ 	case NE:
+ 	case UNORDERED:
+ 	case ORDERED:
+ 	case UNLT:
+ 	case UNLE:
+ 	case UNGT:
+ 	case UNGE:
+ 	case UNEQ:
+ 	case UNNE:
+ 	  return CCFPmode;
+ 
+ 	case LT:
+ 	case LE:
+ 	case GT:
+ 	case GE:
+ 	  return CCFPEmode;
+ 
+ 	default:
+ 	  abort ();
+ 	}
+     }
+   else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
+ 	   || GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
+     {
+       if (TARGET_ARCH64 && GET_MODE (x) == DImode)
+ 	return CCX_NOOVmode;
+       else
+ 	return CC_NOOVmode;
+     }
+   else
+     {
+       if (TARGET_ARCH64 && GET_MODE (x) == DImode)
+ 	return CCXmode;
+       else
+ 	return CCmode;
+     }
+ }
+ 
  /* X and Y are two things to compare using CODE.  Emit the compare insn and
     return the rtx for the cc reg in the proper mode.  */
  
*************** output_cbranch (op, label, reversed, ann
*** 4583,4588 ****
--- 4638,4644 ----
    static char v9_xcc_labelno[] = "%%xcc, %lX";
    static char v9_fcc_labelno[] = "%%fccX, %lY";
    char *labelno;
+   const char *branch;
    int labeloff, spaces = 8;
  
    /* ??? !v9: FP branches cannot be preceded by another floating point insn.
*************** output_cbranch (op, label, reversed, ann
*** 4593,4740 ****
      strcpy (string, "nop\n\t");
    else
      string[0] = '\0';
- 
-   /* If not floating-point or if EQ or NE, we can just reverse the code.  */
-   if (reversed
-       && ((mode != CCFPmode && mode != CCFPEmode) || code == EQ || code == NE))
-     code = reverse_condition (code), reversed = 0;
  
!   /* Start by writing the branch condition.  */
!   switch (code)
      {
!     case NE:
!       if (mode == CCFPmode || mode == CCFPEmode)
! 	{
! 	  strcat (string, "fbne");
! 	  spaces -= 4;
! 	}
!       else
! 	{
! 	  strcpy (string, "bne");
! 	  spaces -= 3;
! 	}
!       break;
! 
!     case EQ:
!       if (mode == CCFPmode || mode == CCFPEmode)
! 	{
! 	  strcat (string, "fbe");
! 	  spaces -= 3;
! 	}
!       else
! 	{
! 	  strcpy (string, "be");
! 	  spaces -= 2;
! 	}
!       break;
! 
!     case GE:
!       if (mode == CCFPmode || mode == CCFPEmode)
! 	{
! 	  if (reversed)
! 	    strcat (string, "fbul");
! 	  else
! 	    strcat (string, "fbge");
! 	  spaces -= 4;
! 	}
!       else if (mode == CC_NOOVmode)
! 	{
! 	  strcpy (string, "bpos");
! 	  spaces -= 4;
! 	}
!       else
! 	{
! 	  strcpy (string, "bge");
! 	  spaces -= 3;
! 	}
!       break;
! 
!     case GT:
        if (mode == CCFPmode || mode == CCFPEmode)
  	{
! 	  if (reversed)
! 	    {
! 	      strcat (string, "fbule");
! 	      spaces -= 5;
! 	    }
! 	  else
  	    {
! 	      strcat (string, "fbg");
! 	      spaces -= 3;
! 	    }
! 	}
!       else
! 	{
! 	  strcpy (string, "bg");
! 	  spaces -= 2;
! 	}
!       break;
! 
!     case LE:
!       if (mode == CCFPmode || mode == CCFPEmode)
! 	{
! 	  if (reversed)
! 	    strcat (string, "fbug");
! 	  else
! 	    strcat (string, "fble");
! 	  spaces -= 4;
! 	}
!       else
! 	{
! 	  strcpy (string, "ble");
! 	  spaces -= 3;
! 	}
!       break;
  
!     case LT:
!       if (mode == CCFPmode || mode == CCFPEmode)
! 	{
! 	  if (reversed)
! 	    {
! 	      strcat (string, "fbuge");
! 	      spaces -= 5;
! 	    }
! 	  else
! 	    {
! 	      strcat (string, "fbl");
! 	      spaces -= 3;
  	    }
  	}
-       else if (mode == CC_NOOVmode)
- 	{
- 	  strcpy (string, "bneg");
- 	  spaces -= 4;
- 	}
        else
! 	{
! 	  strcpy (string, "bl");
! 	  spaces -= 2;
! 	}
!       break;
! 
!     case GEU:
!       strcpy (string, "bgeu");
!       spaces -= 4;
!       break;
! 
!     case GTU:
!       strcpy (string, "bgu");
!       spaces -= 3;
!       break;
  
!     case LEU:
!       strcpy (string, "bleu");
!       spaces -= 4;
!       break;
  
!     case LTU:
!       strcpy (string, "blu");
!       spaces -= 3;
!       break;
  
!     default:
!       abort ();
!     }
  
    /* Now add the annulling, the label, and a possible noop.  */
    if (annul)
--- 4649,4807 ----
      strcpy (string, "nop\n\t");
    else
      string[0] = '\0';
  
!   if (reversed)
      {
!       /* Reversal of FP compares takes care -- an ordered compare
! 	 becomes an unordered compare and vice versa.  */
        if (mode == CCFPmode || mode == CCFPEmode)
  	{
! 	  switch (code)
  	    {
! 	    case EQ:
! 	      code = NE;
! 	      break;
! 	    case NE:
! 	      code = EQ;
! 	      break;
! 	    case GE:
! 	      code = UNLT;
! 	      break;
! 	    case GT:
! 	      code = UNLE;
! 	      break;
! 	    case LE:
! 	      code = UNGT;
! 	      break;
! 	    case LT:
! 	      code = UNGE;
! 	      break;
! 	    case UNORDERED:
! 	      code = ORDERED;
! 	      break;
! 	    case ORDERED:
! 	      code = UNORDERED;
! 	      break;
! 	    case UNGT:
! 	      code = LE;
! 	      break;
! 	    case UNLT:
! 	      code = GE;
! 	      break;
! 	    case UNEQ:
! 	      /* ??? We don't have a "less or greater" rtx code.  */
! 	      code = UNKNOWN;
! 	      break;
! 	    case UNGE:
! 	      code = LT;
! 	      break;
! 	    case UNLE:
! 	      code = GT;
! 	      break;
  
! 	    default:
! 	      abort ();
  	    }
  	}
        else
! 	code = reverse_condition (code);
!     }
  
!   /* Start by writing the branch condition.  */
!   if (mode == CCFPmode || mode == CCFPEmode)
!     switch (code)
!       {
!       case NE:
! 	branch = "fbne";
! 	break;
!       case EQ:
! 	branch = "fbe";
! 	break;
!       case GE:
! 	branch = "fbge";
! 	break;
!       case GT:
! 	branch = "fbg";
! 	break;
!       case LE:
! 	branch = "fble";
! 	break;
!       case LT:
! 	branch = "fbl";
! 	break;
!       case UNORDERED:
! 	branch = "fbu";
! 	break;
!       case ORDERED:
! 	branch = "fbo";
! 	break;
!       case UNGT:
! 	branch = "fbug";
! 	break;
!       case UNLT:
! 	branch = "fbul";
! 	break;
!       case UNEQ:
! 	branch = "fbue";
! 	break;
!       case UNGE:
! 	branch = "fbuge";
! 	break;
!       case UNLE:
! 	branch = "fbule";
! 	break;
!       case UNKNOWN:
! 	branch = "fblg";
! 	break;
  
!       default:
! 	abort ();
!       }
!   else
!     switch (code)
!       {
!       case NE:
! 	branch = "bne";
! 	break;
!       case EQ:
! 	branch = "be";
! 	break;
!       case GE:
! 	if (mode == CC_NOOVmode)
! 	  branch = "bpos";
! 	else
! 	  branch = "bge";
! 	break;
!       case GT:
! 	branch = "bg";
! 	break;
!       case LE:
! 	branch = "ble";
! 	break;
!       case LT:
! 	if (mode == CC_NOOVmode)
! 	  branch = "bneg";
! 	else
! 	  branch = "bl";
! 	break;
!       case GEU:
! 	branch = "bgeu";
! 	break;
!       case GTU:
! 	branch = "bgu";
! 	break;
!       case LEU:
! 	branch = "bleu";
! 	break;
!       case LTU:
! 	branch = "blu";
! 	break;
  
!       default:
! 	abort ();
!       }
!   strcpy (string, branch);
!   spaces -= strlen (branch);
  
    /* Now add the annulling, the label, and a possible noop.  */
    if (annul)
Index: sparc.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sparc/sparc.h,v
retrieving revision 1.97
diff -c -p -d -r1.97 sparc.h
*** sparc.h	1999/12/17 15:49:32	1.97
--- sparc.h	2000/01/25 12:35:18
*************** do {                                    
*** 2672,2689 ****
     CCFP[E]mode is used.  CC_NOOVmode should be used when the first operand is a
     PLUS, MINUS, NEG, or ASHIFT.  CCmode should be used when no special
     processing is needed.  */
! #define SELECT_CC_MODE(OP,X,Y) \
!   (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT				\
!    ? ((OP == EQ || OP == NE) ? CCFPmode : CCFPEmode)			\
!    : ((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS			\
!        || GET_CODE (X) == NEG || GET_CODE (X) == ASHIFT)		\
!       ? (TARGET_ARCH64 && GET_MODE (X) == DImode ? CCX_NOOVmode : CC_NOOVmode) \
!       : ((TARGET_ARCH64 || TARGET_V8PLUS) && GET_MODE (X) == DImode ? CCXmode : CCmode)))
  
  /* Return non-zero if SELECT_CC_MODE will never return MODE for a
     floating point inequality comparison.  */
  
! #define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode)
  
  /* A function address in a call instruction
     is a byte address (for indexing purposes)
--- 2672,2683 ----
     CCFP[E]mode is used.  CC_NOOVmode should be used when the first operand is a
     PLUS, MINUS, NEG, or ASHIFT.  CCmode should be used when no special
     processing is needed.  */
! #define SELECT_CC_MODE(OP,X,Y)  select_cc_mode ((OP), (X), (Y))
  
  /* Return non-zero if SELECT_CC_MODE will never return MODE for a
     floating point inequality comparison.  */
  
! #define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode && (MODE) != CCFPmode)
  
  /* A function address in a call instruction
     is a byte address (for indexing purposes)
Index: sparc.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sparc/sparc.md,v
retrieving revision 1.96
diff -c -p -d -r1.96 sparc.md
*** sparc.md	2000/01/21 20:49:33	1.96
--- sparc.md	2000/01/25 12:35:18
***************
*** 1794,1799 ****
--- 1794,1928 ----
    "
  { operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);
  }")
+ 
+ (define_expand "bunordered"
+   [(set (pc)
+ 	(if_then_else (unordered (match_dup 1) (const_int 0))
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   ""
+   "
+ {
+   if (GET_MODE (sparc_compare_op0) == TFmode
+       && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+     {
+       sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1,
+ 				UNORDERED);
+       emit_jump_insn (gen_bne (operands[0]));
+       DONE;
+     }
+   operands[1] = gen_compare_reg (UNORDERED, sparc_compare_op0,
+ 				 sparc_compare_op1);
+ }")
+ 
+ (define_expand "bordered"
+   [(set (pc)
+ 	(if_then_else (ordered (match_dup 1) (const_int 0))
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   ""
+   "
+ {
+   if (GET_MODE (sparc_compare_op0) == TFmode
+       && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+     {
+       sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, ORDERED);
+       emit_jump_insn (gen_bne (operands[0]));
+       DONE;
+     }
+   operands[1] = gen_compare_reg (ORDERED, sparc_compare_op0,
+ 				 sparc_compare_op1);
+ }")
+ 
+ (define_expand "bungt"
+   [(set (pc)
+ 	(if_then_else (ungt (match_dup 1) (const_int 0))
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   ""
+   "
+ {
+   if (GET_MODE (sparc_compare_op0) == TFmode
+       && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+     {
+       sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNGT);
+       emit_jump_insn (gen_bne (operands[0]));
+       DONE;
+     }
+   operands[1] = gen_compare_reg (UNGT, sparc_compare_op0, sparc_compare_op1);
+ }")
+ 
+ (define_expand "bunlt"
+   [(set (pc)
+ 	(if_then_else (unlt (match_dup 1) (const_int 0))
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   ""
+   "
+ {
+   if (GET_MODE (sparc_compare_op0) == TFmode
+       && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+     {
+       sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNLT);
+       emit_jump_insn (gen_bne (operands[0]));
+       DONE;
+     }
+   operands[1] = gen_compare_reg (UNLT, sparc_compare_op0, sparc_compare_op1);
+ }")
+ 
+ (define_expand "buneq"
+   [(set (pc)
+ 	(if_then_else (uneq (match_dup 1) (const_int 0))
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   ""
+   "
+ {
+   if (GET_MODE (sparc_compare_op0) == TFmode
+       && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+     {
+       sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNEQ);
+       emit_jump_insn (gen_bne (operands[0]));
+       DONE;
+     }
+   operands[1] = gen_compare_reg (UNEQ, sparc_compare_op0, sparc_compare_op1);
+ }")
+ 
+ (define_expand "bunge"
+   [(set (pc)
+ 	(if_then_else (unge (match_dup 1) (const_int 0))
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   ""
+   "
+ {
+   if (GET_MODE (sparc_compare_op0) == TFmode
+       && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+     {
+       sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNGE);
+       emit_jump_insn (gen_bne (operands[0]));
+       DONE;
+     }
+   operands[1] = gen_compare_reg (UNGE, sparc_compare_op0, sparc_compare_op1);
+ }")
+ 
+ (define_expand "bunle"
+   [(set (pc)
+ 	(if_then_else (unle (match_dup 1) (const_int 0))
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   ""
+   "
+ {
+   if (GET_MODE (sparc_compare_op0) == TFmode
+       && TARGET_ARCH64 && ! TARGET_HARD_QUAD)
+     {
+       sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, UNLE);
+       emit_jump_insn (gen_bne (operands[0]));
+       DONE;
+     }
+   operands[1] = gen_compare_reg (UNLE, sparc_compare_op0, sparc_compare_op1);
+ }")
  
  ;; Now match both normal and inverted jump.
  


More information about the Gcc-patches mailing list