]> gcc.gnu.org Git - gcc.git/commitdiff
ia64.c (ia64_split_tmode, [...]): Rewrite to use POST_INC/POST_DEC/POST_MODIFY instea...
authorZack Weinberg <zack@gcc.gnu.org>
Wed, 28 Jan 2004 18:13:28 +0000 (18:13 +0000)
committerZack Weinberg <zack@gcc.gnu.org>
Wed, 28 Jan 2004 18:13:28 +0000 (18:13 +0000)
2004-01-28  Zack Weinberg  <zack@codesourcery.com>
    Jim Wilson  <wilson@specifixinc.com>

* config/ia64/ia64.c (ia64_split_tmode, ia64_split_tmode_move):
Rewrite to use POST_INC/POST_DEC/POST_MODIFY instead of a
scratch pointer.
(ia64_secondary_reload_class): Delete case GR_REGS.
* config/ia64/ia64.md (movti, *movti_internal, movtf, *movtf_internal):
Do not allocate a scratch register.
(reload_inti, reload_outti, reload_intf, reload_outtf): Delete.

From-SVN: r76798

gcc/ChangeLog
gcc/config/ia64/ia64.c
gcc/config/ia64/ia64.md

index b29c3f3cd774cea691a6e6c710b34a55250394ba..9238255e2ffda412dff8b6afe4198d63ea185258 100644 (file)
@@ -1,3 +1,14 @@
+2004-01-28  Zack Weinberg  <zack@codesourcery.com>
+           Jim Wilson  <wilson@specifixinc.com>
+
+       * config/ia64/ia64.c (ia64_split_tmode, ia64_split_tmode_move):
+       Rewrite to use POST_INC/POST_DEC/POST_MODIFY instead of a
+       scratch pointer.
+       (ia64_secondary_reload_class): Delete case GR_REGS.
+       * config/ia64/ia64.md (movti, *movti_internal, movtf, *movtf_internal):
+       Do not allocate a scratch register.
+       (reload_inti, reload_outti, reload_intf, reload_outtf): Delete.
+
 2004-01-28  Jan Hubicka  <jh@suse.cz>
 
        * gcse.c (bypass_block): Prevent edges to be unified when we are
@@ -43,7 +54,7 @@
        * config/s390/s390.h (TARGET_DEFAULT): Default to !TARGET_BACKCHAIN.
        * config/s390/s390.c (s390_return_addr_rtx): Fail for all but current
        frame if !TARGET_BACKCHAIN.
-       * config/s390/s390.md ("allocate_stack"): Use pattern only if 
+       * config/s390/s390.md ("allocate_stack"): Use pattern only if
        TARGET_BACKCHAIN.
        * doc/invoke.texi (-mbackchain/-mno-backchain): Document new default.
 
index 5271081b3e9dc3c34653cd315c58100126dc1de3..12b563faadb23b31a795858ff5b0a28c4476d248 100644 (file)
@@ -1395,62 +1395,37 @@ ia64_emit_cond_move (rtx op0, rtx op1, rtx cond)
 }
 
 /* Split a post-reload TImode or TFmode reference into two DImode
-   components.  */
+   components.  This is made extra difficult by the fact that we do
+   not get any scratch registers to work with, because reload cannot
+   be prevented from giving us a scratch that overlaps the register
+   pair involved.  So instead, when addressing memory, we tweak the
+   pointer register up and back down with POST_INCs.  Or up and not
+   back down when we can get away with it.
+
+   REVERSED is true when the loads must be done in reversed order
+   (high word first) for correctness.  DEAD is true when the pointer
+   dies with the second insn we generate and therefore the second
+   address must not carry a postmodify.
+
+   May return an insn which is to be emitted after the moves.  */
 
 static rtx
-ia64_split_tmode (rtx out[2], rtx in, rtx scratch)
+ia64_split_tmode (rtx out[2], rtx in, bool reversed, bool dead)
 {
+  rtx fixup = 0;
+
   switch (GET_CODE (in))
     {
     case REG:
-      out[0] = gen_rtx_REG (DImode, REGNO (in));
-      out[1] = gen_rtx_REG (DImode, REGNO (in) + 1);
-      return NULL_RTX;
-
-    case MEM:
-      {
-       rtx base = XEXP (in, 0);
-
-       switch (GET_CODE (base))
-         {
-         case REG:
-           out[0] = adjust_address (in, DImode, 0);
-           break;
-         case POST_MODIFY:
-           base = XEXP (base, 0);
-           out[0] = adjust_address (in, DImode, 0);
-           break;
-
-         /* Since we're changing the mode, we need to change to POST_MODIFY
-            as well to preserve the size of the increment.  Either that or
-            do the update in two steps, but we've already got this scratch
-            register handy so let's use it.  */
-         case POST_INC:
-           base = XEXP (base, 0);
-           out[0]
-             = change_address (in, DImode,
-                               gen_rtx_POST_MODIFY
-                               (Pmode, base, plus_constant (base, 16)));
-           break;
-         case POST_DEC:
-           base = XEXP (base, 0);
-           out[0]
-             = change_address (in, DImode,
-                               gen_rtx_POST_MODIFY
-                               (Pmode, base, plus_constant (base, -16)));
-           break;
-         default:
-           abort ();
-         }
-
-       if (scratch == NULL_RTX)
-         abort ();
-       out[1] = change_address (in, DImode, scratch);
-       return gen_adddi3 (scratch, base, GEN_INT (8));
-      }
+      out[reversed] = gen_rtx_REG (DImode, REGNO (in));
+      out[!reversed] = gen_rtx_REG (DImode, REGNO (in) + 1);
+      break;
 
     case CONST_INT:
     case CONST_DOUBLE:
+      /* Cannot occur reversed.  */
+      if (reversed) abort ();
+      
       if (GET_MODE (in) != TFmode)
        split_double (in, &out[0], &out[1]);
       else
@@ -1477,11 +1452,108 @@ ia64_split_tmode (rtx out[2], rtx in, rtx scratch)
          out[0] = GEN_INT (p[0]);
          out[1] = GEN_INT (p[1]);
        }
-      return NULL_RTX;
+      break;
+
+    case MEM:
+      {
+       rtx base = XEXP (in, 0);
+       rtx offset;
+
+       switch (GET_CODE (base))
+         {
+         case REG:
+           if (!reversed)
+             {
+               out[0] = adjust_automodify_address
+                 (in, DImode, gen_rtx_POST_INC (Pmode, base), 0);
+               out[1] = adjust_automodify_address
+                 (in, DImode, dead ? 0 : gen_rtx_POST_DEC (Pmode, base), 8);
+             }
+           else
+             {
+               /* Reversal requires a pre-increment, which can only
+                  be done as a separate insn.  */
+               emit_insn (gen_adddi3 (base, base, GEN_INT (8)));
+               out[0] = adjust_automodify_address
+                 (in, DImode, gen_rtx_POST_DEC (Pmode, base), 8);
+               out[1] = adjust_address (in, DImode, 0);
+             }
+           break;
+
+         case POST_INC:
+           if (reversed || dead) abort ();
+           /* Just do the increment in two steps.  */
+           out[0] = adjust_automodify_address (in, DImode, 0, 0);
+           out[1] = adjust_automodify_address (in, DImode, 0, 8);
+           break;
+
+         case POST_DEC:
+           if (reversed || dead) abort ();
+           /* Add 8, subtract 24.  */
+           base = XEXP (base, 0);
+           out[0] = adjust_automodify_address
+             (in, DImode, gen_rtx_POST_INC (Pmode, base), 0);
+           out[1] = adjust_automodify_address
+             (in, DImode,
+              gen_rtx_POST_MODIFY (Pmode, base, plus_constant (base, -24)),
+              8);
+           break;
+
+         case POST_MODIFY:
+           if (reversed || dead) abort ();
+           /* Extract and adjust the modification.  This case is
+              trickier than the others, because we might have an
+              index register, or we might have a combined offset that
+              doesn't fit a signed 9-bit displacement field.  We can
+              assume the incoming expression is already legitimate.  */
+           offset = XEXP (base, 1);
+           base = XEXP (base, 0);
+
+           out[0] = adjust_automodify_address
+             (in, DImode, gen_rtx_POST_INC (Pmode, base), 0);
+
+           if (GET_CODE (XEXP (offset, 1)) == REG)
+             {
+               /* Can't adjust the postmodify to match.  Emit the
+                  original, then a separate addition insn.  */
+               out[1] = adjust_automodify_address (in, DImode, 0, 8);
+               fixup = gen_adddi3 (base, base, GEN_INT (-8));
+             }
+           else if (GET_CODE (XEXP (offset, 1)) != CONST_INT)
+             abort ();
+           else if (INTVAL (XEXP (offset, 1)) < -256 + 8)
+             {
+               /* Again the postmodify cannot be made to match, but
+                  in this case it's more efficient to get rid of the
+                  postmodify entirely and fix up with an add insn. */
+               out[1] = adjust_automodify_address (in, DImode, base, 8);
+               fixup = gen_adddi3 (base, base,
+                                   GEN_INT (INTVAL (XEXP (offset, 1)) - 8));
+             }
+           else
+             {
+               /* Combined offset still fits in the displacement field.
+                  (We cannot overflow it at the high end.)  */
+               out[1] = adjust_automodify_address
+                 (in, DImode,
+                  gen_rtx_POST_MODIFY (Pmode, base,
+                    gen_rtx_PLUS (Pmode, base,
+                                  GEN_INT (INTVAL (XEXP (offset, 1)) - 8))),
+                  8);
+             }
+           break;
+
+         default:
+           abort ();
+         }
+       break;
+      }
 
     default:
       abort ();
     }
+
+  return fixup;
 }
 
 /* Split a TImode or TFmode move instruction after reload.
@@ -1489,39 +1561,60 @@ ia64_split_tmode (rtx out[2], rtx in, rtx scratch)
 void
 ia64_split_tmode_move (rtx operands[])
 {
-  rtx adj1, adj2, in[2], out[2], insn;
-  int first;
-
-  adj1 = ia64_split_tmode (in, operands[1], operands[2]);
-  adj2 = ia64_split_tmode (out, operands[0], operands[2]);
-
-  first = 0;
-  if (reg_overlap_mentioned_p (out[0], in[1]))
-    {
-      if (reg_overlap_mentioned_p (out[1], in[0]))
-       abort ();
-      first = 1;
-    }
-
-  if (adj1 && adj2)
-    abort ();
-  if (adj1)
-    emit_insn (adj1);
-  if (adj2)
-    emit_insn (adj2);
-  insn = emit_insn (gen_rtx_SET (VOIDmode, out[first], in[first]));
-  if (GET_CODE (out[first]) == MEM
-      && GET_CODE (XEXP (out[first], 0)) == POST_MODIFY)
-    REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
-                                         XEXP (XEXP (out[first], 0), 0),
-                                         REG_NOTES (insn));
-  insn = emit_insn (gen_rtx_SET (VOIDmode, out[!first], in[!first]));
-  if (GET_CODE (out[!first]) == MEM
-      && GET_CODE (XEXP (out[!first], 0)) == POST_MODIFY)
-    REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
-                                         XEXP (XEXP (out[!first], 0), 0),
-                                         REG_NOTES (insn));
-
+  rtx in[2], out[2], insn;
+  rtx fixup[2];
+  bool dead = false;
+  bool reversed = false;
+
+  /* It is possible for reload to decide to overwrite a pointer with
+     the value it points to.  In that case we have to do the loads in
+     the appropriate order so that the pointer is not destroyed too
+     early.  Also we must not generate a postmodify for that second
+     load, or rws_access_regno will abort.  */
+  if (GET_CODE (operands[1]) == MEM
+      && reg_overlap_mentioned_p (operands[0], operands[1]))
+    {
+      rtx base = XEXP (operands[1], 0);
+      while (GET_CODE (base) != REG)
+       base = XEXP (base, 0);
+
+      if (REGNO (base) == REGNO (operands[0]))
+       reversed = true;
+      dead = true;
+    }
+  /* Another reason to do the moves in reversed order is if the first
+     element of the target register pair is also the second element of
+     the source register pair.  */
+  if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == REG
+      && REGNO (operands[0]) == REGNO (operands[1]) + 1)
+    reversed = true;
+
+  fixup[0] = ia64_split_tmode (in, operands[1], reversed, dead);
+  fixup[1] = ia64_split_tmode (out, operands[0], reversed, dead);
+
+#define MAYBE_ADD_REG_INC_NOTE(INSN, EXP)                              \
+  if (GET_CODE (EXP) == MEM                                            \
+      && (GET_CODE (XEXP (EXP, 0)) == POST_MODIFY                      \
+         || GET_CODE (XEXP (EXP, 0)) == POST_INC                       \
+         || GET_CODE (XEXP (EXP, 0)) == POST_DEC))                     \
+    REG_NOTES (INSN) = gen_rtx_EXPR_LIST (REG_INC,                     \
+                                         XEXP (XEXP (EXP, 0), 0),      \
+                                         REG_NOTES (INSN))
+
+  insn = emit_insn (gen_rtx_SET (VOIDmode, out[0], in[0]));
+  MAYBE_ADD_REG_INC_NOTE (insn, in[0]);
+  MAYBE_ADD_REG_INC_NOTE (insn, out[0]);
+
+  insn = emit_insn (gen_rtx_SET (VOIDmode, out[1], in[1]));
+  MAYBE_ADD_REG_INC_NOTE (insn, in[1]);
+  MAYBE_ADD_REG_INC_NOTE (insn, out[1]);
+
+  if (fixup[0])
+    emit_insn (fixup[0]);
+  if (fixup[1])
+    emit_insn (fixup[1]);
+
+#undef MAYBE_ADD_REG_INC_NOTE
 }
 
 /* ??? Fixing GR->FR XFmode moves during reload is hard.  You need to go
@@ -4492,13 +4585,6 @@ ia64_secondary_reload_class (enum reg_class class,
        return GR_REGS;
       break;
 
-    case GR_REGS:
-      /* Since we have no offsettable memory addresses, we need a temporary
-        to hold the address of the second word.  */
-      if (mode == TImode || mode == TFmode)
-       return GR_REGS;
-      break;
-
     default:
       break;
     }
index 635100c428167d8b9a2779853fdd474402d1f409..2713eb624aa6b52548b35c529006cd7947259f8d 100644 (file)
   [(set_attr "itanium_class" "ialu")])
 
 ;; With no offsettable memory references, we've got to have a scratch
-;; around to play with the second word.
+;; around to play with the second word.  However, in order to avoid a
+;; reload nightmare we lie, claim we don't need one, and fix it up
+;; in ia64_split_tmode_move.
 (define_expand "movti"
-  [(parallel [(set (match_operand:TI 0 "general_operand" "")
-                  (match_operand:TI 1 "general_operand" ""))
-             (clobber (match_scratch:DI 2 ""))])]
+  [(set (match_operand:TI 0 "general_operand" "")
+       (match_operand:TI 1 "general_operand" ""))]
   ""
 {
   rtx op1 = ia64_expand_move (operands[0], operands[1]);
 
 (define_insn_and_split "*movti_internal"
   [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
-       (match_operand:TI 1 "general_operand"      "ri,m,r"))
-   (clobber (match_scratch:DI 2 "=X,&r,&r"))]
+       (match_operand:TI 1 "general_operand"      "ri,m,r"))]
   "ia64_move_ok (operands[0], operands[1])"
   "#"
   "reload_completed"
   [(set_attr "itanium_class" "unknown")
    (set_attr "predicable" "no")])
 
-(define_expand "reload_inti"
-  [(parallel [(set (match_operand:TI 0 "register_operand" "=r")
-                  (match_operand:TI 1 "memory_operand" "m"))
-             (clobber (match_operand:DI 2 "register_operand" "=&r"))])]
-  ""
-  "")
-
-(define_expand "reload_outti"
-  [(parallel [(set (match_operand:TI 0 "memory_operand" "=m")
-                  (match_operand:TI 1 "register_operand" "r"))
-             (clobber (match_operand:DI 2 "register_operand" "=&r"))])]
-  ""
-  "")
-
 ;; Floating Point Moves
 ;;
 ;; Note - Patterns for SF mode moves are compulsory, but
   [(set_attr "itanium_class" "fmisc,fld,stf")])
 
 ;; Better code generation via insns that deal with TFmode register pairs
-;; directly.
-;; With no offsettable memory references, we've got to have a scratch
-;; around to play with the second word.
+;; directly.  Same concerns apply as for TImode.
 (define_expand "movtf"
-  [(parallel [(set (match_operand:TF 0 "general_operand" "")
-                  (match_operand:TF 1 "general_operand" ""))
-             (clobber (match_scratch:DI 2 ""))])]
+  [(set (match_operand:TF 0 "general_operand" "")
+       (match_operand:TF 1 "general_operand" ""))]
   ""
 {
   rtx op1 = ia64_expand_move (operands[0], operands[1]);
 
 (define_insn_and_split "*movtf_internal"
   [(set (match_operand:TF 0 "nonimmediate_operand" "=r,r,m")
-       (match_operand:TF 1 "general_operand"      "ri,m,r"))
-   (clobber (match_scratch:DI 2 "=X,&r,&r"))]
+       (match_operand:TF 1 "general_operand"      "ri,m,r"))]
   "ia64_move_ok (operands[0], operands[1])"
   "#"
   "reload_completed"
   [(set_attr "itanium_class" "unknown")
    (set_attr "predicable" "no")])
 
-(define_expand "reload_intf"
-  [(parallel [(set (match_operand:TF 0 "register_operand" "=r")
-                  (match_operand:TF 1 "memory_operand" "m"))
-             (clobber (match_operand:DI 2 "register_operand" "=&r"))])]
-  ""
-  "")
-
-(define_expand "reload_outtf"
-  [(parallel [(set (match_operand:TF 0 "memory_operand" "=m")
-                  (match_operand:TF 1 "register_operand" "r"))
-             (clobber (match_operand:DI 2 "register_operand" "=&r"))])]
-  ""
-  "")
 \f
 ;; ::::::::::::::::::::
 ;; ::
This page took 0.087501 seconds and 5 git commands to generate.