[PATCH]: Improvement for HC12 code generation

Stephane Carrez Stephane.Carrez@worldnet.fr
Fri May 4 11:23:00 GMT 2001


Hi!

The HC12 has several instructions that can be generated:

 - 'sex' for the sign-extension of a register to another
 - 'tbeq'/'tbne' for the test and branch
 - 'min'/'max' for min/max assignments

The patch below introduces several patterns that handle the above
instructions (conditionalized by TARGET_M6812).  Tested on 2.95 mostly.

I've committed this patch on the mainline and the 3_0-branch.

	Stephane

2001-05-04  Stephane Carrez  <Stephane.Carrez@worldnet.fr>

	* config/m68hc11/m68hc11.md (*tbne, *tbeq): New patterns for 68HC12.
	(extendqisi2, extendqihi2, extendhisi2): Use sex for 68HC12.
	(uminqi3, umaxqi3, uminhi3, umaxhi3): New pattern for 68HC12.
Index: config/m68hc11/m68hc11.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/m68hc11/m68hc11.md,v
retrieving revision 1.5
diff -u -p -r1.5 m68hc11.md
--- m68hc11.md	2001/05/03 21:09:28	1.5
+++ m68hc11.md	2001/05/04 18:05:25
@@ -1273,6 +1273,20 @@
   rtx ops[3];
   int need_tst = 0;
 
+  /* The 68HC12 has a sign-extension instruction.  Use it when the
+     destination is the register (X,D).  First sign-extend the low
+     part and fill X with the sign-extension of the high part.  */
+  if (TARGET_M6812 && X_REG_P (operands[0]))
+    {
+      if (!D_REG_P (operands[1]))
+        {
+	  ops[0] = gen_rtx (REG, QImode, HARD_D_REGNUM);
+	  ops[1] = operands[1];
+	  m68hc11_gen_movqi (insn, ops);
+	}
+      return \"sex\\tb,d\\n\\tsex\\ta,x\";
+    }
+
   ops[2] = gen_label_rtx ();
 
   if (X_REG_P (operands[1]))
@@ -1368,6 +1382,16 @@
   ops[0] = gen_label_rtx ();
   if (D_REG_P (operands[0]))
     {
+      if (TARGET_M6812)
+	{
+	  if (!D_REG_P (operands[1]))
+	    {
+	      ops[0] = gen_rtx (REG, QImode, HARD_D_REGNUM);
+	      ops[1] = operands[1];
+	      m68hc11_gen_movqi (insn, ops);
+	    }
+	  return \"sex\\tb,d\";
+	}
       output_asm_insn (\"clra\", operands);
       if (H_REG_P (operands[1]))
         {
@@ -1426,14 +1450,12 @@
   "*
 {
   extern rtx ix_reg;
-  rtx ops[1];
+  rtx ops[2];
   int x_reg_used;
 
   if (Y_REG_P (operands[1]))
     return \"#\";
 
-  ops[0] = gen_label_rtx ();
-
   if (X_REG_P (operands[1]))
     {
       output_asm_insn (\"xgdx\", operands);
@@ -1446,9 +1468,29 @@
       x_reg_used = reg_mentioned_p (ix_reg, operands[1]);
       if (x_reg_used)
         {
-          output_asm_insn (\"ldd\\t%1\", operands);
+	  ops[0] = gen_rtx (REG, HImode, HARD_D_REGNUM);
+	  ops[1] = operands[1];
+	  m68hc11_gen_movhi (insn, ops);
         }
     }
+
+  CC_STATUS_INIT;
+  if (TARGET_M6812 && 0)
+    {
+      /* This sequence of code is larger than the one for 68HC11.
+         Don't use it; keep it for documentation.  */
+      if (!D_REG_P (operands[1]) && !x_reg_used)
+        {
+          ops[0] = gen_rtx (REG, HImode, HARD_D_REGNUM);
+          ops[1] = operands[1];
+          m68hc11_gen_movhi (insn, ops);
+        }
+      output_asm_insn (\"sex\\ta,x\", operands);
+      output_asm_insn (\"xgdx\", operands);
+      output_asm_insn (\"sex\\ta,d\", operands);
+      return \"xgdx\";
+    }
+
   output_asm_insn (\"ldx\\t#0\", operands);
   if (D_REG_P (operands[1]) || x_reg_used)
     {
@@ -1456,18 +1498,107 @@
     }
   else
     {
-      output_asm_insn (\"ldd\\t%1\", operands);
+      ops[0] = gen_rtx (REG, HImode, HARD_D_REGNUM);
+      ops[1] = operands[1];
+      m68hc11_gen_movhi (insn, ops);
     }
+
+  ops[0] = gen_label_rtx ();
   output_asm_insn (\"bpl\\t%l0\", ops);
   output_asm_insn (\"dex\", operands);
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (ops[0]));
 
-  CC_STATUS_INIT;
   return \"\";
 }")
 
 
 ;;--------------------------------------------------------------------
+;;- Min and Max instructions (68HC12).
+;;--------------------------------------------------------------------
+(define_insn "uminqi3"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m")
+	(umin:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+		 (match_operand:QI 2 "general_operand" "m,d")))]
+  "TARGET_M6812"
+  "*
+{
+  /* Flags are set according to (sub:QI (operand 1) (operand2)).
+     The mina/minm use A as the source or destination.  This is the
+     high part of D.  There is no way to express that in the pattern
+     so we must use 'exg a,b' to put the operand in the good register.  */
+  CC_STATUS_INIT;
+  if (D_REG_P (operands[0]))
+    {
+      return \"exg\\ta,b\\n\\tmina\\t%2\\n\\texg\\ta,b\";
+    }
+  else
+    {
+      return \"exg\\ta,b\\n\\tminm\\t%0\\n\\texg\\ta,b\";
+    }
+}")
+
+(define_insn "umaxqi3"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,m")
+	(umax:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+		 (match_operand:QI 2 "general_operand" "m,d")))]
+  "TARGET_M6812"
+  "*
+{
+  /* Flags are set according to (sub:QI (operand 1) (operand2)).
+     The maxa/maxm use A as the source or destination.  This is the
+     high part of D.  There is no way to express that in the pattern
+     so we must use 'exg a,b' to put the operand in the good register.  */
+  CC_STATUS_INIT;
+  if (D_REG_P (operands[0]))
+    {
+      return \"exg\\ta,b\\n\\tmaxa\\t%2\\n\\texg\\ta,b\";
+    }
+  else
+    {
+      return \"exg\\ta,b\\n\\tmaxm\\t%0\\n\\texg\\ta,b\";
+    }
+}")
+
+(define_insn "uminhi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,m")
+	(umin:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+		 (match_operand:HI 2 "general_operand" "m,d")))]
+  "TARGET_M6812"
+  "*
+{
+  /* Flags are set according to (sub:HI (operand 1) (operand2)).  */
+  CC_STATUS_INIT;
+  if (D_REG_P (operands[0]))
+    {
+      return \"emind\\t%2\";
+    }
+  else
+    {
+      return \"eminm\\t%0\";
+    }
+}")
+
+(define_insn "umaxhi3"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,m")
+	(umax:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+		 (match_operand:HI 2 "general_operand" "m,d")))]
+  "TARGET_M6812"
+  "*
+{
+  /* Flags are set according to (sub:HI (operand 1) (operand2)).  */
+  CC_STATUS_INIT;
+  if (D_REG_P (operands[0]))
+    {
+      return \"emaxd\\t%2\";
+    }
+  else
+    {
+      return \"emaxm\\t%0\";
+    }
+}")
+
+
+;;--------------------------------------------------------------------
 ;;- Add instructions.
 ;;--------------------------------------------------------------------
 ;; 64-bit: Use a library call because what GCC generates is huge.
@@ -5216,6 +5347,78 @@
 				     m68hc11_compare_op1, 
 				     operands[0]);
   DONE;
+}")
+
+;;
+;; Test and branch instructions for 68HC12 for EQ and NE.
+;; 'z' must not appear in the constraints because the z replacement 
+;; pass does not know how to restore the replacement register.
+;;
+(define_insn "*tbeq"
+  [(set (pc)
+	(if_then_else (eq (match_operand:HI 0 "register_operand" "dxy")
+			  (const_int 0))
+		      (label_ref (match_operand 1 "" ""))
+		      (pc)))]
+  "TARGET_M6812"
+  "*
+{
+   /* If the flags are already set correctly, use 'bne/beq' which are
+      smaller and a little bit faster.  This happens quite often due
+      to reloading of operands[0].  In that case, flags are set correctly
+      due to the load instruction.  */
+  if (cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0]))
+    return \"beq\\t%l1\";
+  else
+    return \"tbeq\\t%0,%l1\";
+}")
+
+(define_insn "*tbne"
+  [(set (pc)
+	(if_then_else (ne (match_operand:HI 0 "register_operand" "dxy")
+			  (const_int 0))
+		      (label_ref (match_operand 1 "" ""))
+		      (pc)))]
+  "TARGET_M6812"
+  "*
+{
+   if (cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0]))
+     return \"bne\\t%l1\";
+   else
+     return \"tbne\\t%0,%l1\";
+}")
+
+;;
+;; Test and branch with 8-bit register.  Register must be B (or A).
+;;
+(define_insn "*tbeq8"
+  [(set (pc)
+	(if_then_else (eq (match_operand:QI 0 "register_operand" "d")
+			  (const_int 0))
+		      (label_ref (match_operand 1 "" ""))
+		      (pc)))]
+  "TARGET_M6812"
+  "*
+{
+   if (cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0]))
+     return \"beq\\t%l1\";
+   else
+     return \"tbeq\\tb,%l1\";
+}")
+
+(define_insn "*tbne8"
+  [(set (pc)
+	(if_then_else (ne (match_operand:QI 0 "register_operand" "d")
+			  (const_int 0))
+		      (label_ref (match_operand 1 "" ""))
+		      (pc)))]
+  "TARGET_M6812"
+  "*
+{
+   if (cc_status.value1 && rtx_equal_p (cc_status.value1, operands[0]))
+     return \"bne\\t%l1\";
+   else
+     return \"tbne\\tb,%l1\";
 }")
 
 (define_insn "*beq"


More information about the Gcc-patches mailing list