From 341cffb90200d6385141b4e5c4eb697e76128fda Mon Sep 17 00:00:00 2001
From: rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 9 May 2000 06:17:35 +0000
Subject: [PATCH]         * config/ia64/ia64-protos.h (ia64_expand_prediction):
 Declare.         * config/ia64/ia64.c (ia64_print_operand_address): Handle
 'j'.         (ia64_expand_prediction): New.        
 (emit_insn_group_barriers): Don't look at notes.  Emit barriers         as
 needed after calls.         (ia64_epilogue_uses): Mark b0 used.         *
 config/ia64/ia64.md (beq_true, beq_false): Remove.         (bne_true,
 bne_false): Remove.         (eq_return, eq_not_return, ne_return,
 ne_not_return): Remove.         (br_true, br_false): New.  Use
 predicate_operator and         ia64_expand_prediction.         (return_true,
 return_false): Likewise.         (call_internal): Use ia64_expand_prediction.
  Don't emit stop bit.         (call_internal1, call_value_internal):
 Likewise.         (call_value_internal1, call_multiple_values_internal1):
 Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33793 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                 |  37 +++++++++
 gcc/config/ia64/ia64-protos.h |   1 +
 gcc/config/ia64/ia64.c        | 125 +++++++++++++++++++++++++-----
 gcc/config/ia64/ia64.md       | 141 +++++++++++++++-------------------
 4 files changed, 204 insertions(+), 100 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6ad054e8024..95ee4579039 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,40 @@
+2000-05-08  Richard Henderson  <rth@cygnus.com>
+
+	* final.c (current_insn_predicate): New.
+	(final_scan_insn): Set it.
+	* output.h (current_insn_predicate): Declare.
+
+	* ifcvt.c (cond_exec_process_insns): New argument prob_val.
+	Attach it to call insns.
+	(cond_exec_process_if_block): Track probability for true and
+	false branches.
+	(dead_or_predicable): Likewise.
+
+	* predict.c (PROB_NEVER, PROB_VERY_UNLIKELY): New.
+	(PROB_UNLIKELY, PROB_EVEN, PROB_LIKELY): New.
+	(PROB_VERY_LIKELY, PROB_ALWAYS): New.
+	(estimate_probability, expected_value_to_br_prob): Use them.
+
+	* config/ia64/ia64-protos.h (ia64_expand_prediction): Declare.
+	* config/ia64/ia64.c (ia64_print_operand_address): Handle 'j'.
+	(ia64_expand_prediction): New.
+	(emit_insn_group_barriers): Don't look at notes.  Emit barriers
+	as needed after calls.
+	(ia64_epilogue_uses): Mark b0 used.
+	* config/ia64/ia64.md (beq_true, beq_false): Remove.
+	(bne_true, bne_false): Remove.
+	(eq_return, eq_not_return, ne_return, ne_not_return): Remove.
+	(br_true, br_false): New.  Use predicate_operator and
+	ia64_expand_prediction.
+	(return_true, return_false): Likewise.
+	(call_internal): Use ia64_expand_prediction.  Don't emit stop bit.
+	(call_internal1, call_value_internal): Likewise.
+	(call_value_internal1, call_multiple_values_internal1): Likewise.
+
+	* config/ia64/ia64.c (ia64_direct_return): Require frame size zero.
+
+	* config/ia64/ia64.md (extendsfdf2): Split only after reload.
+
 2000-05-08  Richard Henderson  <rth@cygnus.com>
 
 	* rtlanal.c (may_trap_p): Consider old-style and volatile
diff --git a/gcc/config/ia64/ia64-protos.h b/gcc/config/ia64/ia64-protos.h
index ec820b1aaa6..d8f75e0cd0d 100644
--- a/gcc/config/ia64/ia64-protos.h
+++ b/gcc/config/ia64/ia64-protos.h
@@ -61,6 +61,7 @@ extern enum reg_class ia64_secondary_reload_class PARAMS((enum reg_class,
 							  enum machine_mode,
 							  rtx));
 extern void ia64_reorg PARAMS((rtx));
+extern const char *ia64_expand_prediction PARAMS((rtx, const char *));
 #endif /* RTX_CODE */
 
 #ifdef TREE_CODE
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index da5aaa3f405..66688f6b09f 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -1695,6 +1695,7 @@ ia64_print_operand_address (stream, address)
         a floating point register emitted normally.
    I	Invert a predicate register by adding 1.
    J    Select the proper predicate register for a condition.
+   j    Select the inverse predicate register for a condition.
    O	Append .acq for volatile load.
    P	Postincrement of a MEM.
    Q	Append .rel for volatile store.
@@ -1755,7 +1756,15 @@ ia64_print_operand (file, x, code)
       return;
 
     case 'J':
-      fputs (reg_names [REGNO (XEXP (x, 0)) + (GET_CODE (x) == EQ)], file);
+    case 'j':
+      {
+	unsigned int regno = REGNO (XEXP (x, 0));
+	if (GET_CODE (x) == EQ)
+	  regno += 1;
+	if (code == 'j')
+	  regno ^= 1;
+        fputs (reg_names [regno], file);
+      }
       return;
 
     case 'O':
@@ -1864,6 +1873,47 @@ ia64_print_operand (file, x, code)
   return;
 }
 
+/* For conditional branches, returns or calls, substitute
+   sptk, dptk, dpnt, or spnt for %s.  */
+
+const char *
+ia64_expand_prediction (insn, template)
+     rtx insn;
+     const char *template;
+{
+  static char const pred_name[4][5] = {
+	"spnt", "dpnt", "dptk", "sptk"
+  };
+  static char new_template[64];
+
+  int pred_val, pred_which;
+  rtx note;
+
+  note = find_reg_note (insn, REG_BR_PROB, 0);
+  if (note)
+    {
+      pred_val = INTVAL (XEXP (note, 0));
+
+      /* Guess top and bottom 10% statically predicted.  */
+      if (pred_val < REG_BR_PROB_BASE / 10)
+	pred_which = 0;
+      else if (pred_val < REG_BR_PROB_BASE / 2)
+	pred_which = 1;
+      else if (pred_val < REG_BR_PROB_BASE * 9 / 10)
+	pred_which = 2;
+      else
+	pred_which = 3;
+    }
+  else
+    pred_which = 2;
+
+  if (strlen (template) >= sizeof (new_template) - 3)
+    abort ();
+
+  sprintf (new_template, template, pred_name[pred_which]);
+
+  return new_template;
+}
 
 
 /* This function returns the register class required for a secondary
@@ -2654,9 +2704,6 @@ static void
 emit_insn_group_barriers (insns)
      rtx insns;
 {
-  int need_barrier = 0;
-  int exception_nesting;
-  struct reg_flags flags;
   rtx insn, prev_insn;
 
   memset (rws_sum, 0, sizeof (rws_sum));
@@ -2664,31 +2711,61 @@ emit_insn_group_barriers (insns)
   prev_insn = 0;
   for (insn = insns; insn; insn = NEXT_INSN (insn))
     {
+      int need_barrier = 0;
+      struct reg_flags flags;
+
       memset (&flags, 0, sizeof (flags));
       switch (GET_CODE (insn))
 	{
 	case NOTE:
-	  switch (NOTE_LINE_NUMBER (insn))
-	    {
-	    case NOTE_INSN_EH_REGION_BEG:
-	      exception_nesting++;
-	      break;
+	  break;
 
-	    case NOTE_INSN_EH_REGION_END:
-	      exception_nesting--;
-	      break;
+	case CALL_INSN:
+	  flags.is_branch = 1;
+	  memset (rws_insn, 0, sizeof (rws_insn));
+	  need_barrier = rtx_needs_barrier (PATTERN (insn), flags, 0);
 
-	    case NOTE_INSN_EPILOGUE_BEG:
-	      break;
+	  if (need_barrier)
+	    {
+	      /* PREV_INSN null can happen if the very first insn is a
+		 volatile asm.  */
+	      if (prev_insn)
+		emit_insn_after (gen_insn_group_barrier (), prev_insn);
+	      memcpy (rws_sum, rws_insn, sizeof (rws_sum));
+	    }
 
-	    default:
-	      break;
+	  /* A call must end a group, otherwise the assembler might pack
+	     it in with a following branch and then the function return
+	     goes to the wrong place.  Do this unconditionally for 
+	     unconditional calls, simply because it (1) looks nicer and
+	     (2) keeps the data structures more accurate for the insns
+	     following the call.  */
+
+	  need_barrier = 1;
+	  if (GET_CODE (PATTERN (insn)) == COND_EXEC)
+	    {
+	      rtx next_insn = insn;
+	      do
+		next_insn = next_nonnote_insn (next_insn);
+	      while (next_insn
+		     && GET_CODE (next_insn) == INSN
+		     && (GET_CODE (PATTERN (next_insn)) == USE
+			 || GET_CODE (PATTERN (next_insn)) == CLOBBER));
+	      if (next_insn && GET_CODE (next_insn) != JUMP_INSN)
+		need_barrier = 0;
+	    }
+	  if (need_barrier)
+	    {
+	      emit_insn_after (gen_insn_group_barrier (), insn);
+	      memset (rws_sum, 0, sizeof (rws_sum));
+	      prev_insn = NULL_RTX;
 	    }
 	  break;
-
+	
 	case JUMP_INSN:
-	case CALL_INSN:
 	  flags.is_branch = 1;
+	  /* FALLTHRU */
+
 	case INSN:
 	  if (GET_CODE (PATTERN (insn)) == USE)
 	    /* Don't care about USE "insns"---those are used to
@@ -2698,7 +2775,7 @@ emit_insn_group_barriers (insns)
 	  else
 	    {
 	      memset (rws_insn, 0, sizeof (rws_insn));
-	      need_barrier = rtx_needs_barrier (PATTERN (insn), flags, 0);
+	      need_barrier |= rtx_needs_barrier (PATTERN (insn), flags, 0);
 
 	      /* Check to see if the previous instruction was a volatile
 		 asm.  */
@@ -2713,7 +2790,6 @@ emit_insn_group_barriers (insns)
 		    emit_insn_after (gen_insn_group_barrier (), prev_insn);
 		  memcpy (rws_sum, rws_insn, sizeof (rws_sum));
 		}
-	      need_barrier = 0;
 	      prev_insn = insn;
 	    }
 	  break;
@@ -2753,7 +2829,9 @@ ia64_epilogue_uses (regno)
      from such a call, we need to make sure the function restores the
      original gp-value, even if the function itself does not use the
      gp anymore.  */
-  if (regno == R_GR(1) && TARGET_CONST_GP && !(TARGET_AUTO_PIC || TARGET_NO_PIC))
+  if (regno == R_GR (1)
+      && TARGET_CONST_GP
+      && !(TARGET_AUTO_PIC || TARGET_NO_PIC))
     return 1;
 
   /* For functions defined with the syscall_linkage attribute, all input
@@ -2768,6 +2846,11 @@ ia64_epilogue_uses (regno)
 			   TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl))))
     return 1;
 
+  /* Conditional return patterns can't represent the use of `b0' as
+     the return address, so we force the value live this way.  */
+  if (regno == R_BR (0))
+    return 1;
+
   return 0;
 }
 
diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md
index 1d98ca22f6e..7ccf89dd110 100644
--- a/gcc/config/ia64/ia64.md
+++ b/gcc/config/ia64/ia64.md
@@ -2134,53 +2134,29 @@
   operands[3] = ia64_compare_op1;
 }")
 
-;; ??? Need a way to choose between dpnt and dptk.  Currently, I assume that
-;; equality tests will likely fail, and inequality tests will likely succeed.
-
-(define_insn "*beq_true"
+(define_insn "*br_true"
   [(set (pc)
-	(if_then_else (eq:CC (match_operand:CC 0 "register_operand" "c")
-			     (const_int 0))
-		      (label_ref (match_operand 1 "" ""))
+	(if_then_else (match_operator 0 "predicate_operator"
+			[(match_operand:CC 1 "register_operand" "c")
+			 (const_int 0)])
+		      (label_ref (match_operand 2 "" ""))
 		      (pc)))]
   ""
-  "(%I0) br.cond.dpnt %l1"
+  "* return ia64_expand_prediction (insn, \"(%%J0) br.cond.%s %%l2\");"
   [(set_attr "type" "B")
    (set_attr "predicable" "no")])
 
-(define_insn "*beq_false"
+(define_insn "*br_false"
   [(set (pc)
-	(if_then_else (eq:CC (match_operand:CC 0 "register_operand" "c")
-			     (const_int 0))
+	(if_then_else (match_operator 0 "predicate_operator"
+			[(match_operand:CC 1 "register_operand" "c")
+			 (const_int 0)])
 		      (pc)
-		      (label_ref (match_operand 1 "" ""))))]
-  ""
-  "(%0) br.cond.dptk %l1"
-  [(set_attr "type" "B")
-   (set_attr "predicable" "no")])
-
-(define_insn "*bne_true"
-  [(set (pc)
-	(if_then_else (ne:CC (match_operand:CC 0 "register_operand" "c")
-			     (const_int 0))
-		      (label_ref (match_operand 1 "" ""))
-		      (pc)))]
+		      (label_ref (match_operand 2 "" ""))))]
   ""
-  "(%0) br.cond.dptk %l1"
+  "* return ia64_expand_prediction (insn, \"(%%j0) br.cond.%s %%l2\");"
   [(set_attr "type" "B")
    (set_attr "predicable" "no")])
-
-(define_insn "*bne_false"
-  [(set (pc)
-	(if_then_else (ne:CC (match_operand:CC 0 "register_operand" "c")
-			     (const_int 0))
-		      (pc)
-		      (label_ref (match_operand 1 "" ""))))]
-  ""
-  "(%I0) br.cond.dpnt %l1"
-  [(set_attr "type" "B")
-   (set_attr "predicable" "no")])
-
 
 ;; ::::::::::::::::::::
 ;; ::
@@ -2716,16 +2692,19 @@
   operands[2] = gen_reg_rtx (DImode);
 }")
 
-;; ??? A call must end a group, otherwise, the assembler might pack it in
-;; a group with a following branch, and then the function return goes to the
-;; wrong place.  We could perhaps handle this in emit_insn_group_barriers.
-
 (define_insn "call_internal"
   [(call (mem:DI (match_operand:DI 0 "call_operand" "bi"))
 	 (match_operand 1 "" ""))
    (clobber (match_operand:DI 2 "register_operand" "=b"))]
   ""
-  "br.call.sptk.many %2 = %0 ;;"
+  "*
+{
+  operands[3] = current_insn_predicate;
+  if (operands[3] != NULL_RTX)
+    return ia64_expand_prediction (insn, \"(%%J3) br.call.%s.many %2 = %0\");
+  else
+    return \"br.call.sptk.many %2 = %0\";
+}"
   [(set_attr "type" "B")])
 
 (define_insn "*call_internal1"
@@ -2734,7 +2713,14 @@
    (use (reg:DI 1))
    (clobber (match_operand:DI 2 "register_operand" "=b"))]
   ""
-  "br.call.sptk.many %2 = %0 ;;"
+  "*
+{
+  operands[3] = current_insn_predicate;
+  if (operands[3] != NULL_RTX)
+    return ia64_expand_prediction (insn, \"(%%J3) br.call.%s.many %2 = %0\");
+  else
+    return \"br.call.sptk.many %2 = %0\";
+}"
   [(set_attr "type" "B")])
 
 ;; Subroutine call instruction returning a value.  Operand 0 is the hard
@@ -2928,17 +2914,20 @@
       = gen_rtx_SET (VOIDmode, XEXP (XVECEXP (operands[0], 0, i), 0), call);
 }")
 
-;; ??? A call must end a group, otherwise, the assembler might pack it in
-;; a group with a following branch, and then the function return goes to the
-;; wrong place.  We could perhaps handle this in emit_insn_group_barriers.
-
 (define_insn "call_value_internal"
   [(set (match_operand 0 "register_operand" "=rf")
 	(call (mem:DI (match_operand:DI 1 "call_operand" "bi"))
 	      (match_operand 2 "" "")))
    (clobber (match_operand:DI 3 "register_operand" "=b"))]
   ""
-  "br.call.sptk.many %3 = %1 ;;"
+  "*
+{
+  operands[4] = current_insn_predicate;
+  if (operands[4] != NULL_RTX)
+    return ia64_expand_prediction (insn, \"(%%J4) br.call.%s.many %3 = %1\");
+  else
+    return \"br.call.sptk.many %3 = %1\";
+}"
   [(set_attr "type" "B")])
 
 (define_insn "*call_value_internal1"
@@ -2948,7 +2937,14 @@
    (use (reg:DI 1))
    (clobber (match_operand:DI 3 "register_operand" "=b"))]
   ""
-  "br.call.sptk.many %3 = %1 ;;"
+  "*
+{
+  operands[4] = current_insn_predicate;
+  if (operands[4] != NULL_RTX)
+    return ia64_expand_prediction (insn, \"(%%J4) br.call.%s.many %3 = %1\");
+  else
+    return \"br.call.sptk.many %3 = %1\";
+}"
   [(set_attr "type" "B")])
 
 (define_insn "*call_multiple_values_internal1"
@@ -2959,7 +2955,14 @@
 		    (use (reg:DI 1))
 		    (clobber (match_operand:DI 4 "register_operand" "=b"))])]
   ""
-  "br.call.sptk.many %4 = %2 ;;"
+  "*
+{
+  operands[5] = current_insn_predicate;
+  if (operands[5] != NULL_RTX)
+    return ia64_expand_prediction (insn, \"(%%J5) br.call.%s.many %4 = %2\");
+  else
+    return \"br.call.sptk.many %4 = %2\";
+}"
   [(set_attr "type" "B")])
 
 ;; Call subroutine returning any type.
@@ -3004,47 +3007,27 @@
   "br.ret.sptk.many rp"
   [(set_attr "type" "B")])
 
-(define_insn "*eq_return"
-  [(set (pc)
-	(if_then_else (eq:CC (match_operand:CC 0 "register_operand" "c")
-			     (const_int 0))
-		      (return)
-		      (pc)))]
-  "ia64_direct_return ()"
-  "(%I0) br.ret.sptk.many rp"
-  [(set_attr "type" "B")
-   (set_attr "predicable" "no")])
-
-(define_insn "*eq_not_return"
-  [(set (pc)
-	(if_then_else (eq:CC (match_operand:CC 0 "register_operand" "c")
-			     (const_int 0))
-		      (pc)
-		      (return)))]
-  "ia64_direct_return ()"
-  "(%0) br.ret.sptk.many rp"
-  [(set_attr "type" "B")
-   (set_attr "predicable" "no")])
-
-(define_insn "*ne_return"
+(define_insn "*return_true"
   [(set (pc)
-	(if_then_else (ne (match_operand:CC 0 "register_operand" "c")
-			  (const_int 0))
+	(if_then_else (match_operator 0 "predicate_operator"
+			[(match_operand:CC 1 "register_operand" "c")
+			 (const_int 0)])
 		      (return)
 		      (pc)))]
   "ia64_direct_return ()"
-  "(%0) br.ret.sptk.many rp"
+  "* return ia64_expand_prediction (insn, \"(%%J0) br.ret.%s.many rp\");"
   [(set_attr "type" "B")
    (set_attr "predicable" "no")])
 
-(define_insn "*ne_not_return"
+(define_insn "*return_false"
   [(set (pc)
-	(if_then_else (ne (match_operand:CC 0 "register_operand" "c")
-			  (const_int 0))
+	(if_then_else (match_operator 0 "predicate_operator"
+			[(match_operand:CC 1 "register_operand" "c")
+			 (const_int 0)])
 		      (pc)
 		      (return)))]
   "ia64_direct_return ()"
-  "(%I0) br.ret.sptk.many rp"
+  "* return ia64_expand_prediction (insn, \"(%%j0) br.ret.%s.many rp\");"
   [(set_attr "type" "B")
    (set_attr "predicable" "no")])
 
-- 
GitLab