m32c.c (m32c_prepare_shift): Add code to deal with the 16 bit shift limit of the...
authorDJ Delorie <dj@redhat.com>
Thu, 19 Jan 2006 23:18:57 +0000 (18:18 -0500)
committerDJ Delorie <dj@gcc.gnu.org>
Thu, 19 Jan 2006 23:18:57 +0000 (18:18 -0500)
* config/m32c/m32c.c (m32c_prepare_shift): Add code to deal with
the 16 bit shift limit of the m16c.

From-SVN: r109987

gcc/ChangeLog
gcc/config/m32c/m32c.c

index 927251a..7ed92c2 100644 (file)
@@ -1,3 +1,8 @@
+2006-01-19  DJ Delorie  <dj@redhat.com>
+
+       * config/m32c/m32c.c (m32c_prepare_shift): Add code to deal with
+       the 16 bit shift limit of the m16c.
+
 2006-01-19  Andrew Pinski  <pinskia@physics.uc.edu>
 
        PR target/22099
index 24b7fff..73d75d6 100644 (file)
@@ -2891,13 +2891,73 @@ m32c_prepare_shift (rtx * operands, int scale, int shift_code)
       emit_insn (func (operands[0], operands[1], GEN_INT (count)));
       return 1;
     }
+
+  temp = gen_reg_rtx (QImode);
   if (scale < 0)
-    {
-      temp = gen_reg_rtx (QImode);
-      emit_move_insn (temp, gen_rtx_NEG (QImode, operands[2]));
-    }
+    /* The pattern has a NEG that corresponds to this. */
+    emit_move_insn (temp, gen_rtx_NEG (QImode, operands[2]));
+  else if (TARGET_A16 && mode == SImode)
+    /* We do this because the code below may modify this, we don't
+       want to modify the origin of this value.  */
+    emit_move_insn (temp, operands[2]);
   else
+    /* We'll only use it for the shift, no point emitting a move.  */
     temp = operands[2];
+    
+
+  if (TARGET_A16 && mode == SImode)
+    {
+      /* The m16c has a limit of -16..16 for SI shifts, even when the
+        shift count is in a register.  Since there are so many targets
+        of these shifts, it's better to expand the RTL here than to
+        call a helper function.
+
+        The resulting code looks something like this:
+
+               cmp.b   r1h,-16
+               jge.b   1f
+               shl.l   -16,dest
+               add.b   r1h,16
+       1f:     cmp.b   r1h,16
+               jle.b   1f
+               shl.l   16,dest
+               sub.b   r1h,16
+       1f:     shl.l   r1h,dest
+
+        We take advantage of the fact that "negative" shifts are
+        undefined to skip one of the comparisons.  */
+
+      rtx count;
+      rtx label, lref, insn;
+
+      count = temp;
+      label = gen_label_rtx ();
+      lref = gen_rtx_LABEL_REF (VOIDmode, label);
+      LABEL_NUSES (label) ++;
+
+      if (shift_code == ASHIFT)
+       {
+         /* This is a left shift.  We only need check positive counts.  */
+         emit_jump_insn (gen_cbranchqi4 (gen_rtx_LE (VOIDmode, 0, 0),
+                                         count, GEN_INT (16), label));
+         emit_insn (func (operands[1], operands[1], GEN_INT (8)));
+         emit_insn (func (operands[1], operands[1], GEN_INT (8)));
+         insn = emit_insn (gen_addqi3 (count, count, GEN_INT (-16)));
+         emit_label_after (label, insn);
+       }
+      else
+       {
+         /* This is a right shift.  We only need check negative counts.  */
+         emit_jump_insn (gen_cbranchqi4 (gen_rtx_GE (VOIDmode, 0, 0),
+                                         count, GEN_INT (-16), label));
+         emit_insn (func (operands[1], operands[1], GEN_INT (-8)));
+         emit_insn (func (operands[1], operands[1], GEN_INT (-8)));
+         insn = emit_insn (gen_addqi3 (count, count, GEN_INT (16)));
+         emit_label_after (label, insn);
+       }
+
+    }
+
   operands[2] = temp;
   return 0;
 }