This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[m32c] fix reload bug with conditional set/move insns


If we have to reload a conditional set or move, the new insns get
inserted between the compare and the conditional, and clobber the
flags.  So, we have to keep compares and conditionals together until
after reload, then split them.

No regressions (some progressions) for both C and C++.  Applied.

2006-09-01  DJ Delorie  <dj@redhat.com>

	* config/m32c/cond.md (cbranch<mode>4): Defer splitting until after reload.
	(stzx_16): Likewise.
	("stzx_24_<mode>"): Likewise.
	("stzx_reversed_<mode>"): Likewise, and make mode-specific.
	("cmp<mode>_op"): New.
	(cmp<mode>): Change to expander; just save operands.
	(b<code>_op): New.
	(b<code>): Change to expander, emit compare here.
	(s<code>_op): Change to use split and expander.
	(s<code>_24_op): Likewise.
	(s<code>_<mode>): New.
	(s<code>_<mode>_24): New.
	(movqicc_<code>_<mode): New.
	(movhicc_<code>_<mode>): New.
	(s<code>): New.
	(s<code>_24): New.
	* config/m32c/m32c.c (compare_op0, compare_op1): New.
	(m32c_pend_compare): New.
	(m32c_unpend_compare): New.
	(m32c_expand_scc): New.
	(m32c_expand_movcc): Emit the compare also.
	* config/m32c/predicates.md (mra_nopp_operand): New.


Index: config/m32c/predicates.md
===================================================================
--- config/m32c/predicates.md	(revision 116652)
+++ config/m32c/predicates.md	(working copy)
@@ -141,6 +141,17 @@
   (and (match_operand 0 "nonimmediate_operand" "")
        (not (match_operand 1 "cr_operand" ""))))
 
+; As above, but no push/pop operations
+(define_predicate "mra_nopp_operand"
+  (match_operand 0 "mra_operand" "")
+{
+  if (GET_CODE (op) == MEM
+      && (GET_CODE (XEXP (op, 0)) == PRE_DEC
+	  || (GET_CODE (XEXP (op, 0)) == POST_INC)))
+    return 0;
+  return 1;
+})
+
 ; TRUE for memory, r0..r3, a0..a1, or immediates.
 (define_predicate "mrai_operand"
   (and (and (match_operand 0 "m32c_any_operand" "")
Index: config/m32c/cond.md
===================================================================
--- config/m32c/cond.md	(revision 116652)
+++ config/m32c/cond.md	(working copy)
@@ -22,6 +22,20 @@
 
 ; conditionals - cmp, jcc, setcc, etc.
 
+; Special note about conditional instructions: GCC always emits the
+; compare right before the insn, which is good, because m32c's mov
+; insns modify the flags.  However, this means that any conditional
+; insn that may require reloading must be kept with its compare until
+; after reload finishes, else the reload insns might clobber the
+; flags.  Thus, these rules:
+;
+; * the cmp* expanders just save the operands in compare_op0 and
+;   compare_op1 via m32c_pend_compare.
+; * conditional insns that won't need reload can call
+;   m32c_unpend_compare before their expansion.
+; * other insns must expand to include the compare operands within,
+;   then split after reload to a separate compare and conditional.
+
 ; Until support for relaxing is supported in gas, we must assume that
 ; short labels won't reach, so we must use long labels.
 ; Unfortunately, there aren't any conditional jumps with long labels,
@@ -41,7 +55,7 @@
 	      (pc)))]
   ""
   "#"
-  ""
+  "reload_completed"
   [(set (reg:CC FLG_REGNO)
 	(compare (match_dup 1)
 		 (match_dup 2)))
@@ -56,7 +70,7 @@
 	(if_then_else:QI (eq (reg:CC FLG_REGNO) (const_int 0))
 			 (match_operand:QI 1 "const_int_operand" "i,i,0")
 			 (match_operand:QI 2 "const_int_operand" "i,0,i")))]
-  "TARGET_A16"
+  "TARGET_A16 && reload_completed"
   "@
    stzx\t%1,%2,%0
    stz\t%1,%0
@@ -69,30 +83,30 @@
 	(if_then_else:QHI (eq (reg:CC FLG_REGNO) (const_int 0))
 			 (match_operand:QHI 1 "const_int_operand" "i,i,0")
 			 (match_operand:QHI 2 "const_int_operand" "i,0,i")))]
-  "TARGET_A24"
+  "TARGET_A24 && reload_completed"
   "@
    stzx.<bwl>\t%1,%2,%0
    stz.<bwl>\t%1,%0
    stnz.<bwl>\t%2,%0"
   [(set_attr "flags" "n,n,n")])
 
-(define_insn_and_split "stzx_reversed"
-  [(set (match_operand 0 "m32c_r0_operand" "")
-	(if_then_else (ne (reg:CC FLG_REGNO) (const_int 0))
-			 (match_operand 1 "const_int_operand" "")
-			 (match_operand 2 "const_int_operand" "")))]
-  "TARGET_A24 || GET_MODE (operands[0]) == QImode"
+(define_insn_and_split "stzx_reversed_<mode>"
+  [(set (match_operand:QHI 0 "m32c_r0_operand" "")
+	(if_then_else:QHI (ne (reg:CC FLG_REGNO) (const_int 0))
+			 (match_operand:QHI 1 "const_int_operand" "")
+			 (match_operand:QHI 2 "const_int_operand" "")))]
+  "(TARGET_A24 || GET_MODE (operands[0]) == QImode) && reload_completed"
   "#"
   ""
   [(set (match_dup 0)
-	(if_then_else (eq (reg:CC FLG_REGNO) (const_int 0))
+	(if_then_else:QHI (eq (reg:CC FLG_REGNO) (const_int 0))
 		      (match_dup 2)
 		      (match_dup 1)))]
   ""
   )
 
 
-(define_insn "cmp<mode>"
+(define_insn "cmp<mode>_op"
   [(set (reg:CC FLG_REGNO)
 	(compare (match_operand:QHPSI 0 "mra_operand" "RraSd")
 		 (match_operand:QHPSI 1 "mrai_operand" "RraSdi")))]
@@ -100,7 +114,14 @@
   "* return m32c_output_compare(insn, operands); "
   [(set_attr "flags" "oszc")])
 
-(define_insn "b<code>"
+(define_expand "cmp<mode>"
+  [(set (reg:CC FLG_REGNO)
+	(compare (match_operand:QHPSI 0 "mra_operand" "RraSd")
+		 (match_operand:QHPSI 1 "mrai_operand" "RraSdi")))]
+  ""
+  "m32c_pend_compare (operands); DONE;")
+
+(define_insn "b<code>_op"
   [(set (pc)
         (if_then_else (any_cond (reg:CC FLG_REGNO)
 				(const_int 0))
@@ -111,23 +132,131 @@
   [(set_attr "flags" "n")]
 )
 
+(define_expand "b<code>"
+  [(set (pc)
+        (if_then_else (any_cond (reg:CC FLG_REGNO)
+				(const_int 0))
+                      (label_ref (match_operand 0 ""))
+                      (pc)))]
+  ""
+  "m32c_unpend_compare ();"
+)
+
 ;; m32c_conditional_register_usage changes the setcc_gen_code array to
 ;; point to the _24 variants if needed.
 
-(define_insn "s<code>"
+;; We need to keep the compare and conditional sets together through
+;; reload, because reload might need to add address reloads to the
+;; set, which would clobber the flags.  By keeping them together, the
+;; reloads get put before the compare, thus preserving the flags.
+
+;; These are the post-split patterns for the conditional sets.
+
+(define_insn "s<code>_op"
   [(set (match_operand:QI 0 "register_operand" "=Rqi")
 	(any_cond:QI (reg:CC FLG_REGNO) (const_int 0)))]
-  "TARGET_A16"
+  "TARGET_A16 && reload_completed"
   "* return m32c_scc_pattern(operands, <CODE>);")
 
-(define_insn "s<code>_24"
+(define_insn "s<code>_24_op"
   [(set (match_operand:HI 0 "mra_operand" "=RhiSd")
 	(any_cond:HI (reg:CC FLG_REGNO) (const_int 0)))]
-  "TARGET_A24"
+  "TARGET_A24 && reload_completed"
   "sc<code>\t%0"
   [(set_attr "flags" "n")]
 )
 
+;; These are the pre-split patterns for the conditional sets.  Yes,
+;; there are a lot of permutations.
+
+(define_insn_and_split "s<code>_<mode>"
+  [(set (match_operand:QI 0 "register_operand" "=Rqi")
+	(any_cond:QI (match_operand:QHPSI 1 "mra_operand" "RraSd")
+		     (match_operand:QHPSI 2 "mrai_operand" "RraSdi")))]
+  "TARGET_A16"
+  "#"
+  "reload_completed"
+  [(set (reg:CC FLG_REGNO)
+	(compare (match_dup 1)
+		 (match_dup 2)))
+   (set (match_dup 0)
+	(any_cond:QI (reg:CC FLG_REGNO) (const_int 0)))]
+  ""
+  [(set_attr "flags" "x")]
+)
+
+(define_insn_and_split "s<code>_<mode>_24"
+  [(set (match_operand:HI 0 "mra_nopp_operand" "=RhiSd")
+	(any_cond:HI (match_operand:QHPSI 1 "mra_operand" "RraSd")
+		     (match_operand:QHPSI 2 "mrai_operand" "RraSdi")))]
+  "TARGET_A24"
+  "#"
+  "reload_completed"
+  [(set (reg:CC FLG_REGNO)
+	(compare (match_dup 1)
+		 (match_dup 2)))
+   (set (match_dup 0)
+	(any_cond:HI (reg:CC FLG_REGNO) (const_int 0)))]
+  ""
+  [(set_attr "flags" "x")]
+)
+
+(define_insn_and_split "movqicc_<code>_<mode>"
+  [(set (match_operand:QI 0 "register_operand" "")
+        (if_then_else:QI (eqne_cond:QI (match_operand:QHPSI 1 "mra_operand" "RraSd")
+				       (match_operand:QHPSI 2 "mrai_operand" "RraSdi"))
+			  (match_operand:QI 3 "const_int_operand" "")
+			  (match_operand:QI 4 "const_int_operand" "")))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (reg:CC FLG_REGNO)
+	(compare (match_dup 1)
+		 (match_dup 2)))
+   (set (match_dup 0)
+        (if_then_else:QI (eqne_cond:QI (reg:CC FLG_REGNO) (const_int 0))
+			 (match_dup 3)
+			 (match_dup 4)))]
+  ""
+  [(set_attr "flags" "x")]
+  )
+
+(define_insn_and_split "movhicc_<code>_<mode>"
+  [(set (match_operand:HI 0 "register_operand" "")
+        (if_then_else:HI (eqne_cond:HI (match_operand:QHPSI 1 "mra_operand" "RraSd")
+				       (match_operand:QHPSI 2 "mrai_operand" "RraSdi"))
+			  (match_operand:QI 3 "const_int_operand" "")
+			  (match_operand:QI 4 "const_int_operand" "")))]
+  "TARGET_A24"
+  "#"
+  "reload_completed"
+  [(set (reg:CC FLG_REGNO)
+	(compare (match_dup 1)
+		 (match_dup 2)))
+   (set (match_dup 0)
+        (if_then_else:HI (eqne_cond:HI (reg:CC FLG_REGNO) (const_int 0))
+			 (match_dup 3)
+			 (match_dup 4)))]
+  ""
+  [(set_attr "flags" "x")]
+  )
+
+;; And these are the expanders, which read the pending compare
+;; operands to build a combined insn.
+
+(define_expand "s<code>"
+  [(set (match_operand:QI 0 "register_operand" "=Rqi")
+	(any_cond:QI (reg:CC FLG_REGNO) (const_int 0)))]
+  "TARGET_A16"
+  "m32c_expand_scc (<CODE>, operands); DONE;")
+
+(define_expand "s<code>_24"
+  [(set (match_operand:HI 0 "mra_nopp_operand" "=RhiSd")
+	(any_cond:HI (reg:CC FLG_REGNO) (const_int 0)))]
+  "TARGET_A24"
+  "m32c_expand_scc (<CODE>, operands); DONE;")
+
+
 (define_expand "movqicc"
   [(set (match_operand:QI 0 "register_operand" "")
         (if_then_else:QI (match_operand 1 "m32c_eqne_operator" "")
Index: config/m32c/m32c.c
===================================================================
--- config/m32c/m32c.c	(revision 116652)
+++ config/m32c/m32c.c	(working copy)
@@ -3488,6 +3488,42 @@ m32c_expand_neg_mulpsi3 (rtx * operands)
   emit_insn (gen_truncsipsi2 (operands[0], temp2));
 }
 
+static rtx compare_op0, compare_op1;
+
+void
+m32c_pend_compare (rtx *operands)
+{
+  compare_op0 = operands[0];
+  compare_op1 = operands[1];
+}
+
+void
+m32c_unpend_compare (void)
+{
+  switch (GET_MODE (compare_op0))
+    {
+    case QImode:
+      emit_insn (gen_cmpqi_op (compare_op0, compare_op1));
+    case HImode:
+      emit_insn (gen_cmphi_op (compare_op0, compare_op1));
+    case PSImode:
+      emit_insn (gen_cmppsi_op (compare_op0, compare_op1));
+    }
+}
+
+void
+m32c_expand_scc (int code, rtx *operands)
+{
+  enum machine_mode mode = TARGET_A16 ? QImode : HImode;
+
+  emit_insn (gen_rtx_SET (mode,
+			  operands[0],
+			  gen_rtx_fmt_ee (code,
+					  mode,
+					  compare_op0,
+					  compare_op1)));
+}
+
 /* Pattern Output Functions */
 
 /* Returns a (OP (reg:CC FLG_REGNO) (const_int 0)) from some other
@@ -3505,6 +3541,8 @@ int
 m32c_expand_movcc (rtx *operands)
 {
   rtx rel = operands[1];
+  rtx cmp;
+
   if (GET_CODE (rel) != EQ && GET_CODE (rel) != NE)
     return 1;
   if (GET_CODE (operands[2]) != CONST_INT
@@ -3517,12 +3555,17 @@ m32c_expand_movcc (rtx *operands)
       operands[2] = operands[3];
       operands[3] = tmp;
     }
-  if (TARGET_A16)
-    emit_insn (gen_stzx_16 (operands[0], operands[2], operands[3]));
-  else if (GET_MODE (operands[0]) == QImode)
-    emit_insn (gen_stzx_24_qi (operands[0], operands[2], operands[3]));
-  else
-    emit_insn (gen_stzx_24_hi (operands[0], operands[2], operands[3]));
+
+  cmp = gen_rtx_fmt_ee (GET_CODE (rel),
+			GET_MODE (rel),
+			compare_op0,
+			compare_op1);
+
+  emit_move_insn (operands[0],
+		  gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+					cmp,
+					operands[2],
+					operands[3]));
   return 0;
 }
 
Index: config/m32c/m32c-protos.h
===================================================================
--- config/m32c/m32c-protos.h	(revision 116652)
+++ config/m32c/m32c-protos.h	(working copy)
@@ -46,6 +46,7 @@ void m32c_register_pragmas (void);
 int  m32c_regno_ok_for_base_p (int);
 int  m32c_trampoline_alignment (void);
 int  m32c_trampoline_size (void);
+void m32c_unpend_compare (void);
 
 #if defined(RTX_CODE) && defined(TREE_CODE)
 
@@ -68,6 +69,7 @@ int  m32c_expand_movmemhi (rtx *);
 int  m32c_expand_movstr (rtx *);
 void m32c_expand_neg_mulpsi3 (rtx *);
 int  m32c_expand_setmemhi (rtx *);
+void m32c_expand_scc (int, rtx *);
 int  m32c_extra_constraint_p (rtx, char, const char *);
 int  m32c_extra_constraint_p2 (rtx, char, const char *);
 int  m32c_hard_regno_nregs (int, MM);
@@ -86,6 +88,7 @@ int  m32c_mode_dependent_address (rtx);
 int  m32c_modes_tieable_p (MM, MM);
 bool m32c_mov_ok (rtx *, MM);
 char * m32c_output_compare (rtx, rtx *);
+void m32c_pend_compare (rtx *);
 int  m32c_preferred_output_reload_class (rtx, int);
 int  m32c_preferred_reload_class (rtx, int);
 int  m32c_prepare_move (rtx *, MM);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]