OSDN Git Service

* pa.c (ireg_or_int5_operand): New function.
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 3 Jul 1996 05:34:40 +0000 (05:34 +0000)
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 3 Jul 1996 05:34:40 +0000 (05:34 +0000)
        (output_parallel_movb, output_parallel_addb): Likewise.
        (combinable_copy, combinable_add, following_call): Likewise.
        (pa_adjust_insn_length): Handle parallel unconditional branches.
        (output_movb): Handle case were destination is %sar.
        * pa.h: Declare new functions.
        * pa.md (parallel_branch): New "type" attribute.
        (delay slot descriptions): Don't allow "parallel_branches" in
        delay slots.  Fill "parallel_branches" like "branch" insns.
        (movb patterns): Handle %sar as destination register.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@12382 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/pa/pa.c
gcc/config/pa/pa.h
gcc/config/pa/pa.md

index 9cc78a4..76a1b97 100644 (file)
@@ -383,6 +383,19 @@ arith_double_operand (op, mode)
 }
 
 /* Return truth value of whether OP is a integer which fits the
+   range constraining immediate operands in three-address insns, or
+   is an integer register.  */
+
+int
+ireg_or_int5_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return ((GET_CODE (op) == CONST_INT && INT_5_BITS (op))
+         || (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32));
+}
+
+/* Return truth value of whether OP is a integer which fits the
    range constraining immediate operands in three-address insns.  */
 
 int
@@ -3058,6 +3071,10 @@ pa_adjust_insn_length (insn, length)
          && length == 4
          && ! forward_branch_p (insn))
        return 4;
+      else if (GET_CODE (pat) == PARALLEL
+              && get_attr_type (insn) == TYPE_PARALLEL_BRANCH
+              && length == 4)
+       return 4;
       /* Adjust dbra insn with short backwards conditional branch with
         unfilled delay slot -- only for case where counter is in a
         general register register. */
@@ -3071,8 +3088,7 @@ pa_adjust_insn_length (insn, length)
       else
        return 0;
     }
-  else
-    return 0;
+  return 0;
 }
 
 /* Print operand X (an rtx) in assembler syntax to file FILE.
@@ -4364,8 +4380,10 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
          output_asm_insn ("stw %1,-16(0,%%r30)",operands);
          return "fldws -16(0,%%r30),%0";
        }
-      else
+      else if (which_alternative == 2)
        return "stw %1,%0";
+      else
+       return "mtsar %r1";
     }
 
   /* Support the second variant.  */
@@ -4432,7 +4450,7 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
        return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tfldws -16(0,%%r30),%0";
     }
   /* Deal with gross reload from memory case.  */
-  else
+  else if (which_alternative == 2)
     {
       /* Reload loop counter from memory, the store back to memory
         happens in the branch's delay slot.   */
@@ -4441,6 +4459,14 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
       else
        return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tstw %1,%0";
     }
+  /* Handle SAR as a destination.  */
+  else
+    {
+      if (get_attr_length (insn) == 8)
+       return "comb,%S2 0,%1,%3\n\tmtsar %r1";
+      else
+       return "comclr,%B2 0,%1,0\n\tbl %3,0\n\tmtsar %r1";
+    }
 }
 
 
@@ -5088,6 +5114,157 @@ jump_in_call_delay (insn)
     return 0;
 }
 
+/* Output an unconditional move and branch insn.  */
+
+char *
+output_parallel_movb (operands, length)
+     rtx *operands;
+     int length;
+{
+  /* These are the cases in which we win.  */
+  if (length == 4)
+    return "mov%I1b,tr %1,%0,%2";
+
+  /* None of these cases wins, but they don't lose either.  */
+  if (dbr_sequence_length () == 0)
+    {
+      /* Nothing in the delay slot, fake it by putting the combined
+        insn (the copy or add) in the delay slot of a bl.  */
+      if (GET_CODE (operands[1]) == CONST_INT)
+       return "bl %2,0\n\tldi %1,%0";
+      else
+       return "bl %2,0\n\tcopy %1,%0";
+    }
+  else
+    {
+      /* Something in the delay slot, but we've got a long branch.  */
+      if (GET_CODE (operands[1]) == CONST_INT)
+       return "ldi %1,%0\n\tbl %2,0";
+      else
+       return "copy %1,%0\n\tbl %2,0";
+    }
+}
+
+/* Output an unconditional add and branch insn.  */
+
+char *
+output_parallel_addb (operands, length)
+     rtx *operands;
+     int length;
+{
+  /* To make life easy we want operand0 to be the shared input/output
+     operand and operand1 to be the readonly operand.  */
+  if (operands[0] == operands[1])
+    operands[1] = operands[2];
+
+  /* These are the cases in which we win.  */
+  if (length == 4)
+    return "add%I1b,tr %1,%0,%3";
+
+  /* None of these cases win, but they don't lose either.  */
+  if (dbr_sequence_length () == 0)
+    {
+      /* Nothing in the delay slot, fake it by putting the combined
+        insn (the copy or add) in the delay slot of a bl.  */
+      return "bl %3,0\n\tadd%I1 %1,%0,%0";
+    }
+  else
+    {
+      /* Something in the delay slot, but we've got a long branch.  */
+      return "add%I1 %1,%0,%0\n\tbl %3,0";
+    }
+}
+
+/* Return nonzero if INSN represents an integer add which might be
+   combinable with an unconditional branch.  */ 
+
+combinable_add (insn)
+     rtx insn;
+{
+  rtx src, dest, prev, pattern = PATTERN (insn);
+
+  /* Must be a (set (reg) (plus (reg) (reg/5_bit_int)))  */
+  if (GET_CODE (pattern) != SET
+      || GET_CODE (SET_SRC (pattern)) != PLUS
+      || GET_CODE (SET_DEST (pattern)) != REG)
+    return 0;
+
+  src = SET_SRC (pattern);
+  dest = SET_DEST (pattern);
+
+  /* Must be an integer add.  */
+  if (GET_MODE (src) != SImode
+      || GET_MODE (dest) != SImode)
+    return 0;
+
+  /* Each operand must be an integer register and/or 5 bit immediate.  */
+  if (!ireg_or_int5_operand (dest, VOIDmode)
+       || !ireg_or_int5_operand (XEXP (src, 0), VOIDmode)
+       || !ireg_or_int5_operand (XEXP (src, 1), VOIDmode))
+    return 0;
+
+  /* The destination must also be one of the sources.  */
+  return (dest == XEXP (src, 0) || dest == XEXP (src, 1));
+}
+
+/* Return nonzero if INSN represents an integer load/copy which might be
+   combinable with an unconditional branch.  */ 
+
+combinable_copy (insn)
+     rtx insn;
+{
+  rtx src, dest, pattern = PATTERN (insn);
+  enum machine_mode mode;
+
+  /* Must be a (set (reg) (reg/5_bit_int)).  */
+  if (GET_CODE (pattern) != SET)
+    return 0;
+
+  src = SET_SRC (pattern);
+  dest = SET_DEST (pattern);
+
+  /* Must be a mode that corresponds to a single integer register.  */
+  mode = GET_MODE (dest);
+  if (mode != SImode
+      && mode != SFmode
+      && mode != HImode
+      && mode != QImode)
+    return 0;
+
+  /* Each operand must be a register or 5 bit integer.  */
+  if (!ireg_or_int5_operand (dest, VOIDmode)
+      || !ireg_or_int5_operand (src, VOIDmode))
+    return 0;
+
+  return 1;
+}
+
+/* Return nonzero if INSN (a jump insn) immediately follows a call.  This
+   is used to discourage creating parallel movb/addb insns since a jump
+   which immediately follows a call can execute in the delay slot of the
+   call.  */
+   
+following_call (insn)
+     rtx insn;
+{
+  /* Find the previous real insn, skipping NOTEs.  */
+  insn = PREV_INSN (insn);
+  while (insn && GET_CODE (insn) == NOTE)
+    insn = PREV_INSN (insn);
+
+  /* Check for CALL_INSNs and millicode calls.  */
+  if (insn
+      && (GET_CODE (insn) == CALL_INSN
+         || (GET_CODE (insn) == INSN
+             && GET_CODE (PATTERN (insn)) != SEQUENCE
+             && GET_CODE (PATTERN (insn)) != USE
+             && GET_CODE (PATTERN (insn)) != CLOBBER
+             && get_attr_type (insn) == TYPE_MILLI)))
+    return 1;
+
+  return 0;
+}
+
 
 /* We use this hook to perform a PA specific optimization which is difficult
    to do in earlier passes.
index f30da47..a6e9f86 100644 (file)
@@ -2280,6 +2280,8 @@ extern char *output_bb ();
 extern char *output_bvb ();
 extern char *output_dbra ();
 extern char *output_movb ();
+extern char *output_parallel_movb ();
+extern char *output_parallel_addb ();
 extern char *output_return ();
 extern char *output_call ();
 extern char *output_millicode_call ();
index 8c081b8..6c10b24 100644 (file)
@@ -31,7 +31,7 @@
 ;; type "binary" insns have two input operands (1,2) and one output (0)
 
 (define_attr "type"
-  "move,unary,binary,shift,nullshift,compare,load,store,uncond_branch,branch,cbranch,fbranch,call,dyncall,fpload,fpstore,fpalu,fpcc,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,multi,milli"
+  "move,unary,binary,shift,nullshift,compare,load,store,uncond_branch,branch,cbranch,fbranch,call,dyncall,fpload,fpstore,fpalu,fpcc,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,multi,milli,parallel_branch"
   (const_string "binary"))
 
 ;; Processor type (for scheduling, not code generation) -- this attribute
@@ -69,7 +69,7 @@
 
 ;; For conditional branches.
 (define_attr "in_branch_delay" "false,true"
-  (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli")
+  (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch")
                     (eq_attr "length" "4"))
                (const_string "true")
                (const_string "false")))
@@ -77,7 +77,7 @@
 ;; Disallow instructions which use the FPU since they will tie up the FPU
 ;; even if the instruction is nullified.
 (define_attr "in_nullified_branch_delay" "false,true"
-  (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl")
+  (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,parallel_branch")
                     (eq_attr "length" "4"))
                (const_string "true")
                (const_string "false")))
@@ -85,7 +85,7 @@
 ;; For calls and millicode calls.  Allow unconditional branches in the
 ;; delay slot.
 (define_attr "in_call_delay" "false,true"
-  (cond [(and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli")
+  (cond [(and (eq_attr "type" "!uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch")
              (eq_attr "length" "4"))
           (const_string "true")
         (eq_attr "type" "uncond_branch")
        (const_string "false")))
 
 
-;; Unconditional branch and call delay slot description.
-(define_delay (eq_attr "type" "uncond_branch,branch,call")
+;; Call delay slot description.
+(define_delay (eq_attr "type" "uncond_branch,call")
   [(eq_attr "in_call_delay" "true") (nil) (nil)])
 
 ;; millicode call delay slot description.  Note it disallows delay slot
-;; when TARGET_PORTABLE_RUNTIME.
+;; when TARGET_PORTABLE_RUNTIME is true.
 (define_delay (eq_attr "type" "milli")
   [(and (eq_attr "in_call_delay" "true")
        (eq (symbol_ref "TARGET_PORTABLE_RUNTIME") (const_int 0)))
    (nil) (nil)])
 
-;; Unconditional branch, return and other similar instructions.
-(define_delay (eq_attr "type" "uncond_branch,branch")
+;; Return and other similar instructions.
+(define_delay (eq_attr "type" "branch,parallel_branch")
   [(eq_attr "in_branch_delay" "true") (nil) (nil)])
 
 ;; Floating point conditional branch delay slot description and
   [(set (pc)
        (if_then_else
          (match_operator 2 "movb_comparison_operator"
-          [(match_operand:SI 1 "register_operand" "r,r,r") (const_int 0)])
+          [(match_operand:SI 1 "register_operand" "r,r,r,r") (const_int 0)])
          (label_ref (match_operand 3 "" ""))
          (pc)))
-   (set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m")
+   (set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m,!*q")
        (match_dup 1))]
   ""
 "* return output_movb (operands, insn, which_alternative, 0); "
 ;; Do not expect to understand this the first time through.
-[(set_attr "type" "cbranch,multi,multi")
+[(set_attr "type" "cbranch,multi,multi,multi")
  (set (attr "length")
       (if_then_else (eq_attr "alternative" "0")
 ;; Loop counter in register case
                  (const_int 8184))
              (const_int 12)
              (const_int 16)))
-;; Loop counter in memory case.
+;; Loop counter in memory or sar case.
 ;; Extra goo to deal with additional reload insns.
        (if_then_else
          (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
   [(set (pc)
        (if_then_else
          (match_operator 2 "movb_comparison_operator"
-          [(match_operand:SI 1 "register_operand" "r,r,r") (const_int 0)])
+          [(match_operand:SI 1 "register_operand" "r,r,r,r") (const_int 0)])
          (pc)
          (label_ref (match_operand 3 "" ""))))
-   (set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m")
+   (set (match_operand:SI 0 "register_operand" "=!r,!*f,!*m,!*q")
        (match_dup 1))]
   ""
 "* return output_movb (operands, insn, which_alternative, 1); "
 ;; Do not expect to understand this the first time through.
-[(set_attr "type" "cbranch,multi,multi")
+[(set_attr "type" "cbranch,multi,multi,multi")
  (set (attr "length")
       (if_then_else (eq_attr "alternative" "0")
 ;; Loop counter in register case
                  (const_int 8184))
              (const_int 12)
              (const_int 16)))
-;; Loop counter in memory case.
+;; Loop counter in memory or SAR case.
 ;; Extra goo to deal with additional reload insns.
        (if_then_else
          (lt (abs (minus (match_dup 3) (plus (pc) (const_int 8))))
   [(set_attr "type" "multi")
    (set_attr "length" "8")])
 
-
-;; XXX FIXME.  The function pointer comparison code is only at the FSF
-;; for documentation and merging purposes, it is _NOT_ actually used.
-;;
-;; I've been trying to get Kenner to deal with the machine independent
-;; problems for many months, and for whatever reason nothing ever seems
-;; to happen.
-;;
-;; If you want function pointer comparisons to work, first scream at
-;; Kenner to deal with the MI problems, then email me for a hack that
-;; will get the job done (law@cygnus.com).
-
 ;; Given a function pointer, canonicalize it so it can be 
 ;; reliably compared to another function pointer.  */
 (define_expand "canonicalize_funcptr_for_compare"