Patchwork [committed] Fix call branch shortening on PA

login
register
mail settings
Submitter John David Anglin
Date Nov. 13, 2012, 1:08 a.m.
Message ID <20121113010828.GA28616@hiauly1.hia.nrc.ca>
Download mbox | patch
Permalink /patch/198516/
State New
Headers show

Comments

John David Anglin - Nov. 13, 2012, 1:08 a.m.
The attached change fixes PR target/55195.

A recent change to shorten_branches broke branch shortening on PA.  Several
years ago we changed to using function calls to estimate the length of the
call patterns because the "cond" expressions became unmanageable.  The
functions returned the maximum current length for the pattern.  This
worked because the algorithm shortened branches.  Now, when optimizing,
the algorithm starts with small length and increases from there.

The call implementation was broken in a subtle way.  It didn't mark the call
patterns as variable, so they didn't participate in branch shortening.  As
a result, branch distances for conditional forward branches were underestimated
and assembly errors started appearing in large functions.

Joern Rennecke was extremely helpful in debugging and resolving this bug.
He suggested an opaque "cond" that's never used but which tricks
genattrtab into marking the call patterns as variable.  This "cond" also
provides the minimum length for the call patterns.

This led to a another problem.  The insn_default_length for the call patterns
was now set to INT_MAX to indicate that the lengths were undefined.  Delay
slot sequence lengths became negative.  This had to be fixed with
ADJUST_INSN_LENGTH.  I needed to add two new insn types, sibcall and
sh_func_adrs, to uniquely identify these patterns in pa_adjust_insn_length
and provide the correct length.

I also removed the adjustment for a millicode insn with unfilled delay slot
because pa_attr_length_millicode_call already allocates the extra four bytes.

Tested on hppa-unknown-linux-gnu, hppa2.0w-hp-hpux11.11 and hppa64-hp-hpux11.11
with no regressions.  Committed to trunk.

Dave

Patch

Index: config/pa/pa.md
===================================================================
--- config/pa/pa.md	(revision 193396)
+++ config/pa/pa.md	(working copy)
@@ -81,7 +81,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,btable_branch,branch,cbranch,fbranch,call,dyncall,fpload,fpstore,fpalu,fpcc,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,multi,milli,parallel_branch,fpstore_load,store_fpload"
+  "move,unary,binary,shift,nullshift,compare,load,store,uncond_branch,btable_branch,branch,cbranch,fbranch,call,sibcall,dyncall,fpload,fpstore,fpalu,fpcc,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,multi,milli,sh_func_adrs,parallel_branch,fpstore_load,store_fpload"
   (const_string "binary"))
 
 (define_attr "pa_combine_type"
@@ -124,7 +124,7 @@ 
 ;; For conditional branches. Frame related instructions are not allowed
 ;; because they confuse the unwind support.
 (define_attr "in_branch_delay" "false,true"
-  (if_then_else (and (eq_attr "type" "!uncond_branch,btable_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch")
+  (if_then_else (and (eq_attr "type" "!uncond_branch,btable_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,parallel_branch")
 		     (eq_attr "length" "4")
 		     (not (match_test "RTX_FRAME_RELATED_P (insn)")))
 		(const_string "true")
@@ -133,7 +133,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,btable_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,parallel_branch")
+  (if_then_else (and (eq_attr "type" "!uncond_branch,btable_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,parallel_branch")
 		     (eq_attr "length" "4")
 		     (not (match_test "RTX_FRAME_RELATED_P (insn)")))
 		(const_string "true")
@@ -142,7 +142,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,btable_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch")
+  (cond [(and (eq_attr "type" "!uncond_branch,btable_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,parallel_branch")
 	      (eq_attr "length" "4")
 	      (not (match_test "RTX_FRAME_RELATED_P (insn)")))
 	   (const_string "true")
@@ -157,6 +157,10 @@ 
 (define_delay (eq_attr "type" "call")
   [(eq_attr "in_call_delay" "true") (nil) (nil)])
 
+;; Sibcall delay slot description.
+(define_delay (eq_attr "type" "sibcall")
+  [(eq_attr "in_call_delay" "true") (nil) (nil)])
+
 ;; Millicode call delay slot description.
 (define_delay (eq_attr "type" "milli")
   [(eq_attr "in_call_delay" "true") (nil) (nil)])
@@ -611,7 +615,7 @@ 
 ;; to assume have zero latency.
 (define_insn_reservation "Z3" 0
   (and
-    (eq_attr "type" "!load,fpload,store,fpstore,uncond_branch,btable_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch,fpcc,fpalu,fpmulsgl,fpmuldbl,fpsqrtsgl,fpsqrtdbl,fpdivsgl,fpdivdbl,fpstore_load,store_fpload")
+    (eq_attr "type" "!load,fpload,store,fpstore,uncond_branch,btable_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,parallel_branch,fpcc,fpalu,fpmulsgl,fpmuldbl,fpsqrtsgl,fpsqrtdbl,fpdivsgl,fpdivdbl,fpstore_load,store_fpload")
     (eq_attr "cpu" "8000"))
   "inm_8000,rnm_8000")
 
@@ -619,7 +623,7 @@ 
 ;; retirement unit.
 (define_insn_reservation "Z4" 0
   (and
-    (eq_attr "type" "uncond_branch,btable_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch")
+    (eq_attr "type" "uncond_branch,btable_branch,branch,cbranch,fbranch,call,sibcall,dyncall,multi,milli,sh_func_adrs,parallel_branch")
     (eq_attr "cpu" "8000"))
   "inm0_8000+inm1_8000,rnm0_8000+rnm1_8000")
 
@@ -5336,7 +5340,9 @@ 
   "!TARGET_64BIT"
   "* return pa_output_mul_insn (0, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_insn ""
   [(set (reg:SI 29) (mult:SI (reg:SI 26) (reg:SI 25)))
@@ -5347,7 +5353,9 @@ 
   "TARGET_64BIT"
   "* return pa_output_mul_insn (0, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_expand "muldi3"
   [(set (match_operand:DI 0 "register_operand" "")
@@ -5438,7 +5446,9 @@ 
   "*
    return pa_output_div_insn (operands, 0, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_insn ""
   [(set (reg:SI 29)
@@ -5452,7 +5462,9 @@ 
   "*
    return pa_output_div_insn (operands, 0, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_expand "udivsi3"
   [(set (reg:SI 26) (match_operand:SI 1 "move_src_operand" ""))
@@ -5495,7 +5507,9 @@ 
   "*
    return pa_output_div_insn (operands, 1, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_insn ""
   [(set (reg:SI 29)
@@ -5509,7 +5523,9 @@ 
   "*
    return pa_output_div_insn (operands, 1, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_expand "modsi3"
   [(set (reg:SI 26) (match_operand:SI 1 "move_src_operand" ""))
@@ -5548,7 +5564,9 @@ 
   "*
   return pa_output_mod_insn (0, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_insn ""
   [(set (reg:SI 29) (mod:SI (reg:SI 26) (reg:SI 25)))
@@ -5561,7 +5579,9 @@ 
   "*
   return pa_output_mod_insn (0, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_expand "umodsi3"
   [(set (reg:SI 26) (match_operand:SI 1 "move_src_operand" ""))
@@ -5600,7 +5620,9 @@ 
   "*
   return pa_output_mod_insn (1, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 (define_insn ""
   [(set (reg:SI 29) (umod:SI (reg:SI 26) (reg:SI 25)))
@@ -5613,7 +5635,9 @@ 
   "*
   return pa_output_mod_insn (1, insn);"
   [(set_attr "type" "milli")
-   (set (attr "length") (symbol_ref "pa_attr_length_millicode_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_millicode_call (insn)")))])
 
 ;;- and instructions
 ;; We define DImode `and` so with DImode `not` we can get
@@ -7141,7 +7165,9 @@ 
   return pa_output_call (insn, operands[0], 0);
 }"
   [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 0)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 0)")))])
 
 (define_insn "call_symref_pic"
   [(call (mem:SI (match_operand 0 "call_operand_address" ""))
@@ -7215,7 +7241,9 @@ 
   return pa_output_call (insn, operands[0], 0);
 }"
   [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 0)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 0)")))])
 
 ;; This pattern is split if it is necessary to save and restore the
 ;; PIC register.
@@ -7297,7 +7325,9 @@ 
   return pa_output_call (insn, operands[0], 0);
 }"
   [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 0)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 0)")))])
 
 (define_insn "call_reg"
   [(call (mem:SI (reg:SI 22))
@@ -7311,7 +7341,9 @@ 
   return pa_output_indirect_call (insn, gen_rtx_REG (word_mode, 22));
 }"
   [(set_attr "type" "dyncall")
-   (set (attr "length") (symbol_ref "pa_attr_length_indirect_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_indirect_call (insn)")))])
 
 ;; This pattern is split if it is necessary to save and restore the
 ;; PIC register.
@@ -7386,7 +7418,9 @@ 
   return pa_output_indirect_call (insn, gen_rtx_REG (word_mode, 22));
 }"
   [(set_attr "type" "dyncall")
-   (set (attr "length") (symbol_ref "pa_attr_length_indirect_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_indirect_call (insn)")))])
 
 ;; This pattern is split if it is necessary to save and restore the
 ;; PIC register.
@@ -7467,7 +7501,9 @@ 
   return pa_output_indirect_call (insn, operands[0]);
 }"
   [(set_attr "type" "dyncall")
-   (set (attr "length") (symbol_ref "pa_attr_length_indirect_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 12)]
+	      (symbol_ref "pa_attr_length_indirect_call (insn)")))])
 
 (define_expand "call_value"
   [(parallel [(set (match_operand 0 "" "")
@@ -7593,7 +7629,9 @@ 
   return pa_output_call (insn, operands[1], 0);
 }"
   [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 0)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 0)")))])
 
 (define_insn "call_val_symref_pic"
   [(set (match_operand 0 "" "")
@@ -7673,7 +7711,9 @@ 
   return pa_output_call (insn, operands[1], 0);
 }"
   [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 0)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 0)")))])
 
 ;; This pattern is split if it is necessary to save and restore the
 ;; PIC register.
@@ -7761,7 +7801,9 @@ 
   return pa_output_call (insn, operands[1], 0);
 }"
   [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 0)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 0)")))])
 
 (define_insn "call_val_reg"
   [(set (match_operand 0 "" "")
@@ -7776,7 +7818,9 @@ 
   return pa_output_indirect_call (insn, gen_rtx_REG (word_mode, 22));
 }"
   [(set_attr "type" "dyncall")
-   (set (attr "length") (symbol_ref "pa_attr_length_indirect_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_indirect_call (insn)")))])
 
 ;; This pattern is split if it is necessary to save and restore the
 ;; PIC register.
@@ -7857,7 +7901,9 @@ 
   return pa_output_indirect_call (insn, gen_rtx_REG (word_mode, 22));
 }"
   [(set_attr "type" "dyncall")
-   (set (attr "length") (symbol_ref "pa_attr_length_indirect_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_indirect_call (insn)")))])
 
 ;; This pattern is split if it is necessary to save and restore the
 ;; PIC register.
@@ -7944,7 +7990,9 @@ 
   return pa_output_indirect_call (insn, operands[1]);
 }"
   [(set_attr "type" "dyncall")
-   (set (attr "length") (symbol_ref "pa_attr_length_indirect_call (insn)"))])
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 12)]
+	      (symbol_ref "pa_attr_length_indirect_call (insn)")))])
 
 ;; Call subroutine returning any type.
 
@@ -8037,8 +8085,10 @@ 
   pa_output_arg_descriptor (insn);
   return pa_output_call (insn, operands[0], 1);
 }"
-  [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 1)"))])
+  [(set_attr "type" "sibcall")
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 1)")))])
 
 (define_insn "sibcall_internal_symref_64bit"
   [(call (mem:SI (match_operand 0 "call_operand_address" ""))
@@ -8052,8 +8102,10 @@ 
   pa_output_arg_descriptor (insn);
   return pa_output_call (insn, operands[0], 1);
 }"
-  [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 1)"))])
+  [(set_attr "type" "sibcall")
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 1)")))])
 
 (define_expand "sibcall_value"
   [(set (match_operand 0 "" "")
@@ -8121,8 +8173,10 @@ 
   pa_output_arg_descriptor (insn);
   return pa_output_call (insn, operands[1], 1);
 }"
-  [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 1)"))])
+  [(set_attr "type" "sibcall")
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 1)")))])
 
 (define_insn "sibcall_value_internal_symref_64bit"
   [(set (match_operand 0 "" "")
@@ -8137,8 +8191,10 @@ 
   pa_output_arg_descriptor (insn);
   return pa_output_call (insn, operands[1], 1);
 }"
-  [(set_attr "type" "call")
-   (set (attr "length") (symbol_ref "pa_attr_length_call (insn, 1)"))])
+  [(set_attr "type" "sibcall")
+   (set (attr "length")
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 8)]
+	      (symbol_ref "pa_attr_length_call (insn, 1)")))])
 
 (define_insn "nop"
   [(const_int 0)]
@@ -9174,10 +9230,11 @@ 
 				   gen_rtx_SYMBOL_REF (SImode,
 						       \"$$sh_func_adrs\"));
 }"
-  [(set_attr "type" "multi")
+  [(set_attr "type" "sh_func_adrs")
    (set (attr "length")
-	(plus (symbol_ref "pa_attr_length_millicode_call (insn)")
-	      (const_int 20)))])
+	(cond [(and (match_test "0") (eq (const_int 0) (pc))) (const_int 28)]
+	      (plus (symbol_ref "pa_attr_length_millicode_call (insn)")
+		    (const_int 20))))])
 
 ;; On the PA, the PIC register is call clobbered, so it must
 ;; be saved & restored around calls by the caller.  If the call
Index: config/pa/pa.c
===================================================================
--- config/pa/pa.c	(revision 193396)
+++ config/pa/pa.c	(working copy)
@@ -4880,13 +4880,10 @@ 
 
 
 
-/* Return any length adjustment needed by INSN which already has its length
-   computed as LENGTH.   Return zero if no adjustment is necessary.
+/* Return any length plus adjustment needed by INSN which already has
+   its length computed as LENGTH.   Return LENGTH if no adjustment is
+   necessary.
 
-   For the PA: function calls, millicode calls, and backwards short
-   conditional branches with unfilled delay slots need an adjustment by +1
-   (to account for the NOP which will be inserted into the instruction stream).
-
    Also compute the length of an inline block move here as it is too
    complicated to express as a length attribute in pa.md.  */
 int
@@ -4894,19 +4891,40 @@ 
 {
   rtx pat = PATTERN (insn);
 
+  /* If length is negative or undefined, provide initial length.  */
+  if ((unsigned int) length >= INT_MAX)
+    {
+      if (GET_CODE (pat) == SEQUENCE)
+	insn = XVECEXP (pat, 0, 0);
+
+      switch (get_attr_type (insn))
+	{
+	case TYPE_MILLI:
+	  length = pa_attr_length_millicode_call (insn);
+	  break;
+	case TYPE_CALL:
+	  length = pa_attr_length_call (insn, 0);
+	  break;
+	case TYPE_SIBCALL:
+	  length = pa_attr_length_call (insn, 1);
+	  break;
+	case TYPE_DYNCALL:
+	  length = pa_attr_length_indirect_call (insn);
+	  break;
+	case TYPE_SH_FUNC_ADRS:
+	  length = pa_attr_length_millicode_call (insn) + 20;
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
   /* Jumps inside switch tables which have unfilled delay slots need
      adjustment.  */
   if (GET_CODE (insn) == JUMP_INSN
       && GET_CODE (pat) == PARALLEL
       && get_attr_type (insn) == TYPE_BTABLE_BRANCH)
-    return 4;
-  /* Millicode insn with an unfilled delay slot.  */
-  else if (GET_CODE (insn) == INSN
-	   && GET_CODE (pat) != SEQUENCE
-	   && GET_CODE (pat) != USE
-	   && GET_CODE (pat) != CLOBBER
-	   && get_attr_type (insn) == TYPE_MILLI)
-    return 4;
+    length += 4;
   /* Block move pattern.  */
   else if (GET_CODE (insn) == INSN
 	   && GET_CODE (pat) == PARALLEL
@@ -4915,7 +4933,7 @@ 
 	   && GET_CODE (XEXP (XVECEXP (pat, 0, 0), 1)) == MEM
 	   && GET_MODE (XEXP (XVECEXP (pat, 0, 0), 0)) == BLKmode
 	   && GET_MODE (XEXP (XVECEXP (pat, 0, 0), 1)) == BLKmode)
-    return compute_movmem_length (insn) - 4;
+    length += compute_movmem_length (insn) - 4;
   /* Block clear pattern.  */
   else if (GET_CODE (insn) == INSN
 	   && GET_CODE (pat) == PARALLEL
@@ -4923,7 +4941,7 @@ 
 	   && GET_CODE (XEXP (XVECEXP (pat, 0, 0), 0)) == MEM
 	   && XEXP (XVECEXP (pat, 0, 0), 1) == const0_rtx
 	   && GET_MODE (XEXP (XVECEXP (pat, 0, 0), 0)) == BLKmode)
-    return compute_clrmem_length (insn) - 4;
+    length += compute_clrmem_length (insn) - 4;
   /* Conditional branch with an unfilled delay slot.  */
   else if (GET_CODE (insn) == JUMP_INSN && ! simplejump_p (insn))
     {
@@ -4932,11 +4950,11 @@ 
 	  && length == 4
 	  && JUMP_LABEL (insn) != NULL_RTX
 	  && ! forward_branch_p (insn))
-	return 4;
+	length += 4;
       else if (GET_CODE (pat) == PARALLEL
 	       && get_attr_type (insn) == TYPE_PARALLEL_BRANCH
 	       && length == 4)
-	return 4;
+	length += 4;
       /* Adjust dbra insn with short backwards conditional branch with
 	 unfilled delay slot -- only for case where counter is in a
 	 general register register.  */
@@ -4946,11 +4964,9 @@ 
  	       && ! FP_REG_P (XEXP (XVECEXP (pat, 0, 1), 0))
 	       && length == 4
 	       && ! forward_branch_p (insn))
-	return 4;
-      else
-	return 0;
+	length += 4;
     }
-  return 0;
+  return length;
 }
 
 /* Implement the TARGET_PRINT_OPERAND_PUNCT_VALID_P hook.  */
@@ -7511,15 +7527,13 @@ 
 
   /* Handle the common case where we are sure that the branch will
      reach the beginning of the $CODE$ subspace.  The within reach
-     form of the $$sh_func_adrs call has a length of 28.  Because
-     it has an attribute type of multi, it never has a nonzero
-     sequence length.  The length of the $$sh_func_adrs is the same
-     as certain out of reach PIC calls to other routines.  */
+     form of the $$sh_func_adrs call has a length of 28.  Because it
+     has an attribute type of sh_func_adrs, it never has a nonzero
+     sequence length (i.e., the delay slot is never filled).  */
   if (!TARGET_LONG_CALLS
-      && ((seq_length == 0
-	   && (attr_length == 12
-	       || (attr_length == 28 && get_attr_type (insn) == TYPE_MULTI)))
-	  || (seq_length != 0 && attr_length == 8)))
+      && (attr_length == 8
+	  || (attr_length == 28
+	      && get_attr_type (insn) == TYPE_SH_FUNC_ADRS)))
     {
       output_asm_insn ("{bl|b,l} %0,%2", xoperands);
     }
Index: config/pa/pa.h
===================================================================
--- config/pa/pa.h	(revision 193396)
+++ config/pa/pa.h	(working copy)
@@ -1273,8 +1273,8 @@ 
 
 /* Handling the special cases is going to get too complicated for a macro,
    just call `pa_adjust_insn_length' to do the real work.  */
-#define ADJUST_INSN_LENGTH(INSN, LENGTH)	\
-  LENGTH += pa_adjust_insn_length (INSN, LENGTH);
+#define ADJUST_INSN_LENGTH(INSN, LENGTH) \
+  ((LENGTH) = pa_adjust_insn_length ((INSN), (LENGTH)))
 
 /* Millicode insns are actually function calls with some special
    constraints on arguments and register usage.