From b5c82fa1381f4c1610f8137ede5ea6789fa90c8a Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <bonzini@gnu.org>
Date: Mon, 3 Apr 2006 11:20:07 +0000
Subject: [PATCH] re PR target/19653 (x87 reg allocated for constants for
 -mfpmath=sse)

2005-08-08  Paolo Bonzini  <bonzini@gnu.org>
	    Dale Johannesen  <dalej@apple.com>

	PR target/19653
	* regclass.c (struct reg_pref): Update documentation.
	(regclass): Set prefclass to NO_REGS if memory is the best option.
	(record_reg_classes): Cope with a prefclass set to NO_REGS.
	* reload.c (find_reloads): Take PREFERRED_OUTPUT_RELOAD_CLASS
	into account.  For non-registers, equate an empty preferred
	reload class to a `!' in the constraint; move the if clause to
	do so after those that reject the insn.
	(push_reload): Allow PREFERRED_*_RELOAD_CLASS to liberally
	return NO_REGS.
	(find_dummy_reload): Likewise.
	* doc/tm.texi (Register Classes): Document what it means
	if PREFERRED_*_RELOAD_CLASS return NO_REGS.
	* config/i386/i386.c (ix86_preferred_reload_class): Force
	using SSE registers (and return NO_REGS for floating-point
	constants) if math is done with SSE.
	(ix86_preferred_output_reload_class): New.
	* config/i386/i386-protos.h (ix86_preferred_output_reload_class): New.
	* config/i386/i386.h (PREFERRED_OUTPUT_RELOAD_CLASS): New.
	* config/i386/i386.md: Remove # register preferences.


Co-Authored-By: Dale Johannesen <dalej@apple.com>

From-SVN: r112637
---
 gcc/ChangeLog                 |  24 ++++++++
 gcc/config/i386/i386-protos.h |   1 +
 gcc/config/i386/i386.c        |  48 ++++++++++++---
 gcc/config/i386/i386.h        |  10 +++-
 gcc/config/i386/i386.md       | 110 +++++++++++++++++-----------------
 gcc/doc/tm.texi               |  10 ++++
 gcc/regclass.c                |  14 +++--
 gcc/reload.c                  |  59 ++++++++++++------
 8 files changed, 191 insertions(+), 85 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 97507f1f55ff..ebf0227b0db5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,27 @@
+2005-08-08  Paolo Bonzini  <bonzini@gnu.org>
+	    Dale Johannesen  <dalej@apple.com>
+
+	PR target/19653
+	* regclass.c (struct reg_pref): Update documentation.
+	(regclass): Set prefclass to NO_REGS if memory is the best option.
+	(record_reg_classes): Cope with a prefclass set to NO_REGS.
+	* reload.c (find_reloads): Take PREFERRED_OUTPUT_RELOAD_CLASS
+	into account.  For non-registers, equate an empty preferred
+	reload class to a `!' in the constraint; move the if clause to
+	do so after those that reject the insn.
+	(push_reload): Allow PREFERRED_*_RELOAD_CLASS to liberally
+	return NO_REGS.
+	(find_dummy_reload): Likewise.
+	* doc/tm.texi (Register Classes): Document what it means
+	if PREFERRED_*_RELOAD_CLASS return NO_REGS.
+	* config/i386/i386.c (ix86_preferred_reload_class): Force
+	using SSE registers (and return NO_REGS for floating-point
+	constants) if math is done with SSE.
+	(ix86_preferred_output_reload_class): New.
+	* config/i386/i386-protos.h (ix86_preferred_output_reload_class): New.
+	* config/i386/i386.h (PREFERRED_OUTPUT_RELOAD_CLASS): New.
+	* config/i386/i386.md: Remove # register preferences.
+
 2006-04-02  Sebastian Pop  <pop@cri.ensmp.fr>
 
 	PR bootstrap/26992
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index ed9d4f3d62e7..315487e8fd47 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -142,6 +142,7 @@ extern int ix86_secondary_memory_needed (enum reg_class, enum reg_class,
 extern bool ix86_cannot_change_mode_class (enum machine_mode,
 					   enum machine_mode, enum reg_class);
 extern enum reg_class ix86_preferred_reload_class (rtx, enum reg_class);
+extern enum reg_class ix86_preferred_output_reload_class (rtx, enum reg_class);
 extern int ix86_memory_move_cost (enum machine_mode, enum reg_class, int);
 extern int ix86_mode_needed (int, rtx);
 extern void emit_i387_cw_initialization (int);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index da4b1350a0fd..84b19b9dac2b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -16361,15 +16361,28 @@ ix86_free_from_memory (enum machine_mode mode)
 enum reg_class
 ix86_preferred_reload_class (rtx x, enum reg_class class)
 {
+  enum machine_mode mode = GET_MODE (x);
+
   /* We're only allowed to return a subclass of CLASS.  Many of the 
      following checks fail for NO_REGS, so eliminate that early.  */
   if (class == NO_REGS)
     return NO_REGS;
 
   /* All classes can load zeros.  */
-  if (x == CONST0_RTX (GET_MODE (x)))
+  if (x == CONST0_RTX (mode))
     return class;
 
+  /* Force constants into memory if we are loading a (non-zero) constant into
+     an MMX or SSE register.  This is because there are no MMX/SSE instructions
+     to load from a constant.  */
+  if (CONSTANT_P (x)
+      && (MAYBE_MMX_CLASS_P (class) || MAYBE_SSE_CLASS_P (class)))
+    return NO_REGS;
+
+  /* Prefer SSE regs only, if we can use them for math.  */
+  if (TARGET_SSE_MATH && !TARGET_MIX_SSE_I387 && SSE_FLOAT_MODE_P (mode))
+    return SSE_CLASS_P (class) ? class : NO_REGS;
+
   /* Floating-point constants need more complex checks.  */
   if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
     {
@@ -16381,8 +16394,6 @@ ix86_preferred_reload_class (rtx x, enum reg_class class)
 	 zero above.  We only want to wind up preferring 80387 registers if
 	 we plan on doing computation with them.  */
       if (TARGET_80387
-	  && (TARGET_MIX_SSE_I387 
-	      || !(TARGET_SSE_MATH && SSE_FLOAT_MODE_P (GET_MODE (x))))
 	  && standard_80387_constant_p (x))
 	{
 	  /* Limit class to non-sse.  */
@@ -16398,10 +16409,6 @@ ix86_preferred_reload_class (rtx x, enum reg_class class)
 
       return NO_REGS;
     }
-  if (MAYBE_MMX_CLASS_P (class) && CONSTANT_P (x))
-    return NO_REGS;
-  if (MAYBE_SSE_CLASS_P (class) && CONSTANT_P (x))
-    return NO_REGS;
 
   /* Generally when we see PLUS here, it's the function invariant
      (plus soft-fp const_int).  Which can only be computed into general
@@ -16423,6 +16430,33 @@ ix86_preferred_reload_class (rtx x, enum reg_class class)
   return class;
 }
 
+/* Discourage putting floating-point values in SSE registers unless
+   SSE math is being used, and likewise for the 387 registers.  */
+enum reg_class
+ix86_preferred_output_reload_class (rtx x, enum reg_class class)
+{
+  enum machine_mode mode = GET_MODE (x);
+
+  /* Restrict the output reload class to the register bank that we are doing
+     math on.  If we would like not to return a subset of CLASS, reject this
+     alternative: if reload cannot do this, it will still use its choice.  */
+  mode = GET_MODE (x);
+  if (TARGET_SSE_MATH && SSE_FLOAT_MODE_P (mode))
+    return MAYBE_SSE_CLASS_P (class) ? SSE_REGS : NO_REGS;
+
+  if (TARGET_80387 && SCALAR_FLOAT_MODE_P (mode))
+    {
+      if (class == FP_TOP_SSE_REGS)
+	return FP_TOP_REG;
+      else if (class == FP_SECOND_SSE_REGS)
+	return FP_SECOND_REG;
+      else
+	return FLOAT_CLASS_P (class) ? class : NO_REGS;
+    }
+
+  return class;
+}
+
 /* If we are copying between general and FP registers, we need a memory
    location. The same is true for SSE and MMX registers.
 
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index fc8f62661b58..b7839138065d 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -669,7 +669,9 @@ extern int x86_prefetch_sse;
 
 #define STACK_REGS
 #define IS_STACK_MODE(MODE)					\
-  ((MODE) == DFmode || (MODE) == SFmode || (MODE) == XFmode)	\
+  (((MODE) == SFmode && (!TARGET_SSE || !TARGET_SSE_MATH))	\
+   || ((MODE) == DFmode && (!TARGET_SSE2 || !TARGET_SSE_MATH))  \
+   || (MODE) == XFmode)
 
 /* Number of actual hardware registers.
    The hardware registers are assigned numbers for the compiler
@@ -1222,6 +1224,12 @@ enum reg_class
 #define PREFERRED_RELOAD_CLASS(X, CLASS) \
    ix86_preferred_reload_class ((X), (CLASS))
 
+/* Discourage putting floating-point values in SSE registers unless
+   SSE math is being used, and likewise for the 387 registers.  */
+
+#define PREFERRED_OUTPUT_RELOAD_CLASS(X, CLASS) \
+   ix86_preferred_output_reload_class ((X), (CLASS))
+
 /* If we are copying between general and FP registers, we need a memory
    location. The same is true for SSE and MMX registers.  */
 #define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 827bf4e4da1d..ef3f36b69641 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -968,8 +968,8 @@
 
 (define_insn "*cmpfp_i_mixed"
   [(set (reg:CCFP FLAGS_REG)
-	(compare:CCFP (match_operand 0 "register_operand" "f#x,x#f")
-		      (match_operand 1 "nonimmediate_operand" "f#x,xm#f")))]
+	(compare:CCFP (match_operand 0 "register_operand" "f,x")
+		      (match_operand 1 "nonimmediate_operand" "f,xm")))]
   "TARGET_MIX_SSE_I387
    && SSE_FLOAT_MODE_P (GET_MODE (operands[0]))
    && GET_MODE (operands[0]) == GET_MODE (operands[1])"
@@ -1017,8 +1017,8 @@
 
 (define_insn "*cmpfp_iu_mixed"
   [(set (reg:CCFPU FLAGS_REG)
-	(compare:CCFPU (match_operand 0 "register_operand" "f#x,x#f")
-		       (match_operand 1 "nonimmediate_operand" "f#x,xm#f")))]
+	(compare:CCFPU (match_operand 0 "register_operand" "f,x")
+		       (match_operand 1 "nonimmediate_operand" "f,xm")))]
   "TARGET_MIX_SSE_I387
    && SSE_FLOAT_MODE_P (GET_MODE (operands[0]))
    && GET_MODE (operands[0]) == GET_MODE (operands[1])"
@@ -2222,7 +2222,7 @@
 
 (define_insn "*pushsf"
   [(set (match_operand:SF 0 "push_operand" "=<,<,<")
-	(match_operand:SF 1 "general_no_elim_operand" "f#rx,rFm#fx,x#rf"))]
+	(match_operand:SF 1 "general_no_elim_operand" "f,rFm,x"))]
   "!TARGET_64BIT"
 {
   /* Anything else should be already split before reg-stack.  */
@@ -2235,7 +2235,7 @@
 
 (define_insn "*pushsf_rex64"
   [(set (match_operand:SF 0 "push_operand" "=X,X,X")
-	(match_operand:SF 1 "nonmemory_no_elim_operand" "f#rx,rF#fx,x#rf"))]
+	(match_operand:SF 1 "nonmemory_no_elim_operand" "f,rF,x"))]
   "TARGET_64BIT"
 {
   /* Anything else should be already split before reg-stack.  */
@@ -2274,9 +2274,9 @@
 
 (define_insn "*movsf_1"
   [(set (match_operand:SF 0 "nonimmediate_operand"
-	  "=f#xr,m   ,f#xr,r#xf  ,m    ,x#rf,x#rf,x#rf ,m   ,!*y,!rm,!*y")
+	  "=f,m   ,f,r,m    ,x,x,x,m   ,!*y,!rm,!*y")
 	(match_operand:SF 1 "general_operand"
-	  "fm#rx,f#rx,G   ,rmF#fx,Fr#fx,C   ,x   ,xm#rf,x#rf,rm ,*y ,*y"))]
+	  "fm,f,G   ,rmF,Fr,C   ,x   ,xm,x,rm ,*y ,*y"))]
   "!(MEM_P (operands[0]) && MEM_P (operands[1]))
    && (reload_in_progress || reload_completed
        || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
@@ -2389,7 +2389,7 @@
 
 (define_insn "*pushdf_nointeger"
   [(set (match_operand:DF 0 "push_operand" "=<,<,<,<")
-	(match_operand:DF 1 "general_no_elim_operand" "f#Y,Fo#fY,*r#fY,Y#f"))]
+	(match_operand:DF 1 "general_no_elim_operand" "f,Fo,*r,Y"))]
   "!TARGET_64BIT && !TARGET_INTEGER_DFMODE_MOVES"
 {
   /* This insn should be already split before reg-stack.  */
@@ -2401,7 +2401,7 @@
 
 (define_insn "*pushdf_integer"
   [(set (match_operand:DF 0 "push_operand" "=<,<,<")
-	(match_operand:DF 1 "general_no_elim_operand" "f#rY,rFo#fY,Y#rf"))]
+	(match_operand:DF 1 "general_no_elim_operand" "f,rFo,Y"))]
   "TARGET_64BIT || TARGET_INTEGER_DFMODE_MOVES"
 {
   /* This insn should be already split before reg-stack.  */
@@ -2441,9 +2441,9 @@
 
 (define_insn "*movdf_nointeger"
   [(set (match_operand:DF 0 "nonimmediate_operand"
-			"=f#Y,m  ,f#Y,*r  ,o  ,Y*x#f,Y*x#f,Y*x#f ,m    ")
+			"=f,m  ,f,*r  ,o  ,Y*x,Y*x,Y*x,m    ")
 	(match_operand:DF 1 "general_operand"
-			"fm#Y,f#Y,G  ,*roF,F*r,C    ,Y*x#f,mY*x#f,Y*x#f"))]
+			"fm,f,G  ,*roF,F*r,C    ,Y*x,mY*x,Y*x"))]
   "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
    && ((optimize_size || !TARGET_INTEGER_DFMODE_MOVES) && !TARGET_64BIT)
    && (reload_in_progress || reload_completed
@@ -2561,9 +2561,9 @@
 
 (define_insn "*movdf_integer"
   [(set (match_operand:DF 0 "nonimmediate_operand"
-		"=f#Yr,m   ,f#Yr,r#Yf  ,o    ,Y*x#rf,Y*x#rf,Y*x#rf,m")
+		"=f,m   ,f,r,o    ,Y*x,Y*x,Y*x,m")
 	(match_operand:DF 1 "general_operand"
-		"fm#Yr,f#Yr,G   ,roF#Yf,Fr#Yf,C     ,Y*x#rf,m     ,Y*x#rf"))]
+		"fm,f,G   ,roF,Fr,C     ,Y*x,m     ,Y*x"))]
   "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
    && ((!optimize_size && TARGET_INTEGER_DFMODE_MOVES) || TARGET_64BIT)
    && (reload_in_progress || reload_completed
@@ -2736,7 +2736,7 @@
 
 (define_insn "*pushxf_integer"
   [(set (match_operand:XF 0 "push_operand" "=<,<")
-	(match_operand:XF 1 "general_no_elim_operand" "f#r,ro#f"))]
+	(match_operand:XF 1 "general_no_elim_operand" "f,ro"))]
   "!optimize_size"
 {
   /* This insn should be already split before reg-stack.  */
@@ -2808,8 +2808,8 @@
    (set_attr "mode" "XF,XF,XF,SI,SI")])
 
 (define_insn "*movxf_integer"
-  [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o")
-	(match_operand:XF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))]
+  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,r,o")
+	(match_operand:XF 1 "general_operand" "fm,f,G,roF,Fr"))]
   "!optimize_size
    && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
    && (reload_in_progress || reload_completed
@@ -3538,8 +3538,8 @@
 })
 
 (define_insn "*extendsfdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Y,m#fY,Y#f")
-        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm#Y,f#Y,mY#f")))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,Y")
+        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f,mY")))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387
    && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
 {
@@ -3872,7 +3872,7 @@
 })
 
 (define_insn "*truncxfsf2_mixed"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#rx,?r#fx,?x#rf")
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f,?r,?x")
 	(float_truncate:SF
 	 (match_operand:XF 1 "register_operand" "f,f,f,f")))
    (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m"))]
@@ -3899,7 +3899,7 @@
    (set_attr "mode" "SF")])
 
 (define_insn "*truncxfsf2_i387"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#r,?r#f")
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f,?r")
 	(float_truncate:SF
 	 (match_operand:XF 1 "register_operand" "f,f,f")))
    (clobber (match_operand:SF 2 "memory_operand" "=X,m,m"))]
@@ -3970,7 +3970,7 @@
 })
 
 (define_insn "*truncxfdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f#rY,?r#fY,?Y#rf")
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f,?r,?Y")
 	(float_truncate:DF
 	 (match_operand:XF 1 "register_operand" "f,f,f,f")))
    (clobber (match_operand:DF 2 "memory_operand" "=X,m,m,m"))]
@@ -3997,7 +3997,7 @@
    (set_attr "mode" "DF")])
 
 (define_insn "*truncxfdf2_i387"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f#r,?r#f")
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f,?r")
 	(float_truncate:DF
 	 (match_operand:XF 1 "register_operand" "f,f,f")))
    (clobber (match_operand:DF 2 "memory_operand" "=X,m,m"))]
@@ -4471,7 +4471,7 @@
   "")
 
 (define_insn "*floatsisf2_mixed"
-  [(set (match_operand:SF 0 "register_operand" "=f#x,?f#x,x#f,x#f")
+  [(set (match_operand:SF 0 "register_operand" "=f,?f,x,x")
 	(float:SF (match_operand:SI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_MIX_SSE_I387"
   "@
@@ -4514,7 +4514,7 @@
   "")
 
 (define_insn "*floatdisf2_mixed"
-  [(set (match_operand:SF 0 "register_operand" "=f#x,?f#x,x#f,x#f")
+  [(set (match_operand:SF 0 "register_operand" "=f,?f,x,x")
 	(float:SF (match_operand:DI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_64BIT && TARGET_MIX_SSE_I387"
   "@
@@ -4582,7 +4582,7 @@
   "")
 
 (define_insn "*floatsidf2_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,?f#Y,Y#f,Y#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,?f,Y,Y")
 	(float:DF (match_operand:SI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387"
   "@
@@ -4625,7 +4625,7 @@
   "")
 
 (define_insn "*floatdidf2_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,?f#Y,Y#f,Y#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,?f,Y,Y")
 	(float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_64BIT && TARGET_SSE2 && TARGET_MIX_SSE_I387"
   "@
@@ -9545,9 +9545,9 @@
   "ix86_expand_fp_absneg_operator (ABS, SFmode, operands); DONE;")
 
 (define_insn "*absnegsf2_mixed"
-  [(set (match_operand:SF 0 "nonimmediate_operand"    "=x#f,x#f,f#x,rm")
+  [(set (match_operand:SF 0 "nonimmediate_operand"    "=x,x,f,rm")
 	(match_operator:SF 3 "absneg_operator"
-	  [(match_operand:SF 1 "nonimmediate_operand" "0   ,x#f,0  ,0")]))
+	  [(match_operand:SF 1 "nonimmediate_operand" "0   ,x,0  ,0")]))
    (use (match_operand:V4SF 2 "nonimmediate_operand"  "xm  ,0  ,X  ,X"))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_SSE_MATH && TARGET_MIX_SSE_I387
@@ -9641,9 +9641,9 @@
   "ix86_expand_fp_absneg_operator (ABS, DFmode, operands); DONE;")
 
 (define_insn "*absnegdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand"    "=Y#f,Y#f,f#Y,rm")
+  [(set (match_operand:DF 0 "nonimmediate_operand"    "=Y,Y,f,rm")
 	(match_operator:DF 3 "absneg_operator"
-	  [(match_operand:DF 1 "nonimmediate_operand" "0   ,Y#f,0  ,0")]))
+	  [(match_operand:DF 1 "nonimmediate_operand" "0   ,Y,0  ,0")]))
    (use (match_operand:V2DF 2 "nonimmediate_operand"  "Ym  ,0  ,X  ,X"))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387
@@ -13170,8 +13170,8 @@
 (define_insn "*fp_jcc_1_mixed"
   [(set (pc)
 	(if_then_else (match_operator 0 "comparison_operator"
-			[(match_operand 1 "register_operand" "f#x,x#f")
-			 (match_operand 2 "nonimmediate_operand" "f#x,xm#f")])
+			[(match_operand 1 "register_operand" "f,x")
+			 (match_operand 2 "nonimmediate_operand" "f,xm")])
 	  (label_ref (match_operand 3 "" ""))
 	  (pc)))
    (clobber (reg:CCFP FPSR_REG))
@@ -13215,8 +13215,8 @@
 (define_insn "*fp_jcc_2_mixed"
   [(set (pc)
 	(if_then_else (match_operator 0 "comparison_operator"
-			[(match_operand 1 "register_operand" "f#x,x#f")
-			 (match_operand 2 "nonimmediate_operand" "f#x,xm#f")])
+			[(match_operand 1 "register_operand" "f,x")
+			 (match_operand 2 "nonimmediate_operand" "f,xm")])
 	  (pc)
 	  (label_ref (match_operand 3 "" ""))))
    (clobber (reg:CCFP FPSR_REG))
@@ -14535,10 +14535,10 @@
 ;; so use special patterns for add and mull.
 
 (define_insn "*fop_sf_comm_mixed"
-  [(set (match_operand:SF 0 "register_operand" "=f#x,x#f")
+  [(set (match_operand:SF 0 "register_operand" "=f,x")
 	(match_operator:SF 3 "binary_fp_operator"
 			[(match_operand:SF 1 "nonimmediate_operand" "%0,0")
-			 (match_operand:SF 2 "nonimmediate_operand" "fm#x,xm#f")]))]
+			 (match_operand:SF 2 "nonimmediate_operand" "fm,xm")]))]
   "TARGET_MIX_SSE_I387
    && COMMUTATIVE_ARITH_P (operands[3])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
@@ -14587,7 +14587,7 @@
   [(set (match_operand:SF 0 "register_operand" "=f,f,x")
 	(match_operator:SF 3 "binary_fp_operator"
 			[(match_operand:SF 1 "nonimmediate_operand" "0,fm,0")
-			 (match_operand:SF 2 "nonimmediate_operand" "fm,0,xm#f")]))]
+			 (match_operand:SF 2 "nonimmediate_operand" "fm,0,xm")]))]
   "TARGET_MIX_SSE_I387
    && !COMMUTATIVE_ARITH_P (operands[3])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
@@ -14681,10 +14681,10 @@
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*fop_df_comm_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,Y#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,Y")
 	(match_operator:DF 3 "binary_fp_operator"
 			[(match_operand:DF 1 "nonimmediate_operand" "%0,0")
-			 (match_operand:DF 2 "nonimmediate_operand" "fm#Y,Ym#f")]))]
+			 (match_operand:DF 2 "nonimmediate_operand" "fm,Ym")]))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387
    && COMMUTATIVE_ARITH_P (operands[3])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
@@ -14730,10 +14730,10 @@
    (set_attr "mode" "DF")])
 
 (define_insn "*fop_df_1_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,f#Y,Y#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,f,Y")
 	(match_operator:DF 3 "binary_fp_operator"
 			[(match_operand:DF 1 "nonimmediate_operand" "0,fm,0")
-			 (match_operand:DF 2 "nonimmediate_operand" "fm,0,Ym#f")]))]
+			 (match_operand:DF 2 "nonimmediate_operand" "fm,0,Ym")]))]
   "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387
    && !COMMUTATIVE_ARITH_P (operands[3])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
@@ -15048,8 +15048,8 @@
 })
 
 (define_insn "*sqrtsf2_mixed"
-  [(set (match_operand:SF 0 "register_operand" "=f#x,x#f")
-	(sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "0#x,xm#f")))]
+  [(set (match_operand:SF 0 "register_operand" "=f,x")
+	(sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "0,xm")))]
   "TARGET_USE_FANCY_MATH_387 && TARGET_MIX_SSE_I387"
   "@
    fsqrt
@@ -15086,8 +15086,8 @@
 })
 
 (define_insn "*sqrtdf2_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,Y#f")
-	(sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "0#Y,Ym#f")))]
+  [(set (match_operand:DF 0 "register_operand" "=f,Y")
+	(sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "0,Ym")))]
   "TARGET_USE_FANCY_MATH_387 && TARGET_SSE2 && TARGET_MIX_SSE_I387"
   "@
    fsqrt
@@ -18584,11 +18584,11 @@
   "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
 
 (define_insn "*movsfcc_1_387"
-  [(set (match_operand:SF 0 "register_operand" "=f#r,f#r,r#f,r#f")
+  [(set (match_operand:SF 0 "register_operand" "=f,f,r,r")
 	(if_then_else:SF (match_operator 1 "fcmov_comparison_operator" 
 				[(reg FLAGS_REG) (const_int 0)])
-		      (match_operand:SF 2 "nonimmediate_operand" "f#r,0,rm#f,0")
-		      (match_operand:SF 3 "nonimmediate_operand" "0,f#r,0,rm#f")))]
+		      (match_operand:SF 2 "nonimmediate_operand" "f,0,rm,0")
+		      (match_operand:SF 3 "nonimmediate_operand" "0,f,0,rm")))]
   "TARGET_80387 && TARGET_CMOVE
    && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
   "@
@@ -18608,11 +18608,11 @@
   "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
 
 (define_insn "*movdfcc_1"
-  [(set (match_operand:DF 0 "register_operand" "=f#r,f#r,&r#f,&r#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,f,&r,&r")
 	(if_then_else:DF (match_operator 1 "fcmov_comparison_operator" 
 				[(reg FLAGS_REG) (const_int 0)])
-		      (match_operand:DF 2 "nonimmediate_operand" "f#r,0,rm#f,0")
-		      (match_operand:DF 3 "nonimmediate_operand" "0,f#r,0,rm#f")))]
+		      (match_operand:DF 2 "nonimmediate_operand" "f,0,rm,0")
+		      (match_operand:DF 3 "nonimmediate_operand" "0,f,0,rm")))]
   "!TARGET_64BIT && TARGET_80387 && TARGET_CMOVE
    && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
   "@
@@ -18624,11 +18624,11 @@
    (set_attr "mode" "DF")])
 
 (define_insn "*movdfcc_1_rex64"
-  [(set (match_operand:DF 0 "register_operand" "=f#r,f#r,r#f,r#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,f,r,r")
 	(if_then_else:DF (match_operator 1 "fcmov_comparison_operator" 
 				[(reg FLAGS_REG) (const_int 0)])
-		      (match_operand:DF 2 "nonimmediate_operand" "f#r,0#r,rm#f,0#f")
-		      (match_operand:DF 3 "nonimmediate_operand" "0#r,f#r,0#f,rm#f")))]
+		      (match_operand:DF 2 "nonimmediate_operand" "f,0,rm,0")
+		      (match_operand:DF 3 "nonimmediate_operand" "0,f,0,rm")))]
   "TARGET_64BIT && TARGET_80387 && TARGET_CMOVE
    && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
   "@
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index b1dae1151a50..2e7632e5a3a6 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2404,12 +2404,22 @@ register, so @code{PREFERRED_RELOAD_CLASS} returns @code{NO_REGS} when
 into any kind of register, code generation will be better if
 @code{LEGITIMATE_CONSTANT_P} makes the constant illegitimate instead
 of using @code{PREFERRED_RELOAD_CLASS}.
+
+If an insn has pseudos in it after register allocation, reload will go
+through the alternatives and call repeatedly @code{PREFERRED_RELOAD_CLASS}
+to find the best one.  Returning @code{NO_REGS}, in this case, makes
+reload add a @code{!} in front of the constraint: the x86 back-end uses
+this feature to discourage usage of 387 registers when math is done in
+the SSE registers (and vice versa).
 @end defmac
 
 @defmac PREFERRED_OUTPUT_RELOAD_CLASS (@var{x}, @var{class})
 Like @code{PREFERRED_RELOAD_CLASS}, but for output reloads instead of
 input reloads.  If you don't define this macro, the default is to use
 @var{class}, unchanged.
+
+You can also use @code{PREFERRED_OUTPUT_RELOAD_CLASS} to discourage
+reload from using some alternatives, like @code{PREFERRED_RELOAD_CLASS}.
 @end defmac
 
 @defmac LIMIT_RELOAD_CLASS (@var{mode}, @var{class})
diff --git a/gcc/regclass.c b/gcc/regclass.c
index f76fdcd77cfa..1f1e6c24166d 100644
--- a/gcc/regclass.c
+++ b/gcc/regclass.c
@@ -811,7 +811,8 @@ struct costs
 /* Structure used to record preferences of given pseudo.  */
 struct reg_pref
 {
-  /* (enum reg_class) prefclass is the preferred class.  */
+  /* (enum reg_class) prefclass is the preferred class.  May be
+     NO_REGS if no class is better than memory.  */
   char prefclass;
 
   /* altclass is a register class that we should use for allocating
@@ -1314,6 +1315,10 @@ regclass (rtx f, int nregs)
 		best = reg_class_subunion[(int) best][class];
 	    }
 
+	  /* If no register class is better than memory, use memory. */
+	  if (p->mem_cost < best_cost)
+	    best = NO_REGS;
+
 	  /* Record the alternate register class; i.e., a class for which
 	     every register in it is better than using memory.  If adding a
 	     class would make a smaller class (i.e., no union of just those
@@ -1524,7 +1529,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 		     to what we would add if this register were not in the
 		     appropriate class.  */
 
-		  if (reg_pref)
+		  if (reg_pref && reg_pref[REGNO (op)].prefclass != NO_REGS)
 		    alt_cost
 		      += (may_move_in_cost[mode]
 			  [(unsigned char) reg_pref[REGNO (op)].prefclass]
@@ -1750,7 +1755,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 		     to what we would add if this register were not in the
 		     appropriate class.  */
 
-		  if (reg_pref)
+		  if (reg_pref && reg_pref[REGNO (op)].prefclass != NO_REGS)
 		    alt_cost
 		      += (may_move_in_cost[mode]
 			  [(unsigned char) reg_pref[REGNO (op)].prefclass]
@@ -1836,7 +1841,8 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 	  int class;
 	  unsigned int nr;
 
-	  if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0)
+	  if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0
+	      && reg_pref[regno].prefclass != NO_REGS)
 	    {
 	      enum reg_class pref = reg_pref[regno].prefclass;
 
diff --git a/gcc/reload.c b/gcc/reload.c
index 9bfb74854cae..f3023ae78b48 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -1184,15 +1184,24 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
 
   /* Narrow down the class of register wanted if that is
      desirable on this machine for efficiency.  */
-  if (in != 0)
-    class = PREFERRED_RELOAD_CLASS (in, class);
+  {
+    enum reg_class preferred_class = class;
+
+    if (in != 0)
+      preferred_class = PREFERRED_RELOAD_CLASS (in, class);
 
   /* Output reloads may need analogous treatment, different in detail.  */
 #ifdef PREFERRED_OUTPUT_RELOAD_CLASS
-  if (out != 0)
-    class = PREFERRED_OUTPUT_RELOAD_CLASS (out, class);
+    if (out != 0)
+      preferred_class = PREFERRED_OUTPUT_RELOAD_CLASS (out, preferred_class);
 #endif
 
+    /* Discard what the target said if we cannot do it.  */
+    if (preferred_class != NO_REGS
+	|| (optional && type == RELOAD_FOR_OUTPUT))
+      class = preferred_class;
+  }
+
   /* Make sure we use a class that can handle the actual pseudo
      inside any subreg.  For example, on the 386, QImode regs
      can appear within SImode subregs.  Although GENERAL_REGS
@@ -1885,7 +1894,11 @@ find_dummy_reload (rtx real_in, rtx real_out, rtx *inloc, rtx *outloc,
 
   /* Narrow down the reg class, the same way push_reload will;
      otherwise we might find a dummy now, but push_reload won't.  */
-  class = PREFERRED_RELOAD_CLASS (in, class);
+  {
+    enum reg_class preferred_class = PREFERRED_RELOAD_CLASS (in, class);
+    if (class != NO_REGS)
+      class = preferred_class;
+  }
 
   /* See if OUT will do.  */
   if (REG_P (out)
@@ -3401,22 +3414,10 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 		    losers++;
 		}
 
-	      /* If we can't reload this value at all, reject this
-		 alternative.  Note that we could also lose due to
-		 LIMIT_RELOAD_RELOAD_CLASS, but we don't check that
-		 here.  */
-
-	      if (! CONSTANT_P (operand)
-		  && (enum reg_class) this_alternative[i] != NO_REGS
-		  && (PREFERRED_RELOAD_CLASS (operand,
-					      (enum reg_class) this_alternative[i])
-		      == NO_REGS))
-		bad = 1;
-
 	      /* Alternative loses if it requires a type of reload not
 		 permitted for this insn.  We can always reload SCRATCH
 		 and objects with a REG_UNUSED note.  */
-	      else if (GET_CODE (operand) != SCRATCH
+	      if (GET_CODE (operand) != SCRATCH
 		       && modified[i] != RELOAD_READ && no_output_reloads
 		       && ! find_reg_note (insn, REG_UNUSED, operand))
 		bad = 1;
@@ -3424,6 +3425,28 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
 		       && ! const_to_mem)
 		bad = 1;
 
+	      /* If we can't reload this value at all, reject this
+		 alternative.  Note that we could also lose due to
+		 LIMIT_RELOAD_CLASS, but we don't check that
+		 here.  */
+
+	      if (! CONSTANT_P (operand)
+		  && (enum reg_class) this_alternative[i] != NO_REGS)
+		{
+		  if (PREFERRED_RELOAD_CLASS
+			(operand, (enum reg_class) this_alternative[i])
+		      == NO_REGS)
+		    reject = 600;
+
+#ifdef PREFERRED_OUTPUT_RELOAD_CLASS
+		  if (operand_type[i] == RELOAD_FOR_OUTPUT
+		      && PREFERRED_OUTPUT_RELOAD_CLASS
+			   (operand, (enum reg_class) this_alternative[i])
+		         == NO_REGS)
+		    reject = 600;
+#endif
+		}
+
 	      /* We prefer to reload pseudos over reloading other things,
 		 since such reloads may be able to be eliminated later.
 		 If we are reloading a SCRATCH, we won't be generating any
-- 
GitLab