This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: tail call optimizations


On Fri, Mar 17, 2000 at 02:52:19PM -0800, Richard Henderson wrote:
> My x86 tests have just reached plum hall; it'll be a while before
> that completes.  Until then, I've not checked in the x86 support.

Passed.


r~

        * i386.c (call_insn_operand): Always allow SYMBOL_REF,
        care for HALF_PIC_P.
        (expander_call_insn_operand): Remove.
        (ix86_expand_epilogue): New arg `emit_return' to control return insn.
        * i386.h (PREDICATE_CODES): Update.
        * i386.md (all call expanders): Remove predicates, remove special
        handling for half-pic.
        (*call_1, *call_value_1): Handle SIBLING_CALL_P insns.
        (*call_pop_pic2, *call_pic2, *call_value_pop_2, *call_value_2): Remove.
        (sibcall_epilogue): New.

Index: config/i386/i386-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386-protos.h,v
retrieving revision 1.14
diff -c -p -d -r1.14 i386-protos.h
*** i386-protos.h	2000/03/07 20:39:08	1.14
--- i386-protos.h	2000/03/18 18:59:10
*************** extern void asm_output_function_prefix P
*** 30,36 ****
  extern void load_pic_register PARAMS ((void));
  extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int));
  extern void ix86_expand_prologue PARAMS ((void));
! extern void ix86_expand_epilogue PARAMS ((void));
  
  extern void ix86_output_function_block_profiler PARAMS ((FILE *, int));
  extern void ix86_output_block_profiler PARAMS ((FILE *, int));
--- 30,36 ----
  extern void load_pic_register PARAMS ((void));
  extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int));
  extern void ix86_expand_prologue PARAMS ((void));
! extern void ix86_expand_epilogue PARAMS ((int));
  
  extern void ix86_output_function_block_profiler PARAMS ((FILE *, int));
  extern void ix86_output_block_profiler PARAMS ((FILE *, int));
*************** extern int symbolic_reference_mentioned_
*** 44,50 ****
  extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
  extern int pic_symbolic_operand PARAMS ((rtx, enum machine_mode));
  extern int call_insn_operand PARAMS ((rtx, enum machine_mode));
- extern int expander_call_insn_operand PARAMS ((rtx, enum machine_mode));
  extern int constant_call_address_operand PARAMS ((rtx, enum machine_mode));
  extern int const0_operand PARAMS ((rtx, enum machine_mode));
  extern int const1_operand PARAMS ((rtx, enum machine_mode));
--- 44,49 ----
Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.c,v
retrieving revision 1.146
diff -c -p -d -r1.146 i386.c
*** i386.c	2000/03/16 16:08:35	1.146
--- i386.c	2000/03/18 18:59:10
*************** call_insn_operand (op, mode)
*** 1067,1088 ****
    if (GET_CODE (op) == CONST_INT)
      return 0;
  
!   /* Otherwise we can allow any general_operand in the address.  */
!   return general_operand (op, Pmode);
! }
! 
! /* Like call_insn_operand but allow (mem (symbol_ref ...)) even if pic.  */
! 
! int
! expander_call_insn_operand (op, mode)
!      rtx op;
!      enum machine_mode mode;
! {
!   if (GET_CODE (op) == MEM
!       && GET_CODE (XEXP (op, 0)) == SYMBOL_REF)
      return 1;
  
!   return call_insn_operand (op, mode);
  }
  
  int
--- 1067,1083 ----
    if (GET_CODE (op) == CONST_INT)
      return 0;
  
!   /* Explicitly allow SYMBOL_REF even if pic.  */
!   if (GET_CODE (op) == SYMBOL_REF)
      return 1;
  
!   /* Half-pic doesn't allow anything but registers and constants.
!      We've just taken care of the later.  */
!   if (HALF_PIC_P ())
!     return register_operand (op, Pmode);
! 
!   /* Otherwise we can allow any general_operand in the address.  */
!   return general_operand (op, Pmode);
  }
  
  int
*************** constant_call_address_operand (op, mode)
*** 1090,1098 ****
       rtx op;
       enum machine_mode mode ATTRIBUTE_UNUSED;
  {
!   return GET_CODE (op) == MEM && 
! 	 CONSTANT_ADDRESS_P (XEXP (op, 0)) && 
! 	 GET_CODE (XEXP (op, 0)) !=  CONST_INT;
  }
  
  /* Match exactly zero and one.  */
--- 1085,1093 ----
       rtx op;
       enum machine_mode mode ATTRIBUTE_UNUSED;
  {
!   return (GET_CODE (op) == MEM
! 	  && CONSTANT_ADDRESS_P (XEXP (op, 0))
! 	  && GET_CODE (XEXP (op, 0)) !=  CONST_INT);
  }
  
  /* Match exactly zero and one.  */
*************** ix86_emit_restore_regs_using_mov (pointe
*** 1997,2003 ****
  /* Restore function stack, frame, and registers. */
  
  void
! ix86_expand_epilogue ()
  {
    int nregs;
    int regno;
--- 1992,1999 ----
  /* Restore function stack, frame, and registers. */
  
  void
! ix86_expand_epilogue (emit_return)
!      int emit_return;
  {
    int nregs;
    int regno;
*************** ix86_expand_epilogue ()
*** 2081,2086 ****
--- 2077,2086 ----
  	    || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
  	  emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno)));
      }
+ 
+   /* Sibcall epilogues don't want a return instruction.  */
+   if (! emit_return)
+     return;
  
    if (current_function_pops_args && current_function_args_size)
      {
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.h,v
retrieving revision 1.104
diff -c -p -d -r1.104 i386.h
*** i386.h	2000/03/16 16:08:35	1.104
--- i386.h	2000/03/18 18:59:10
*************** typedef struct ix86_args {
*** 1230,1235 ****
--- 1230,1240 ----
  
  #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0
  
+ /* If PIC, we cannot optimize sibling calls to global functions
+    because the PLT requires %ebx live.  */
+ #define FUNCTION_OK_FOR_SIBCALL(DECL) \
+   (DECL && (! flag_pic || ! TREE_PUBLIC (DECL)))
+ 
  /* This macro is invoked just before the start of a function.
     It is used here to output code for -fpic that will load the
     return address into %ebx.  */
*************** do { long l;						\
*** 2457,2463 ****
  		       LABEL_REF, SUBREG, REG, MEM}},			\
    {"pic_symbolic_operand", {CONST}},					\
    {"call_insn_operand", {MEM}},						\
-   {"expander_call_insn_operand", {MEM}},				\
    {"constant_call_address_operand", {MEM}},				\
    {"const0_operand", {CONST_INT, CONST_DOUBLE}},			\
    {"const1_operand", {CONST_INT}},					\
--- 2462,2467 ----
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.md,v
retrieving revision 1.144
diff -c -p -d -r1.144 i386.md
*** i386.md	2000/03/16 16:08:35	1.144
--- i386.md	2000/03/18 18:59:11
***************
*** 7010,7056 ****
  
  ;; Call instructions.
  
! ;; If generating PIC code, the predicate indirect_operand will fail
! ;; for operands[0] containing symbolic references on all of the named
! ;; call* patterns.  Each named pattern is followed by an unnamed pattern
! ;; that matches any call to a symbolic CONST (ie, a symbol_ref).  The
! ;; unnamed patterns are only used while generating PIC code, because
! ;; otherwise the named patterns match.
  
  ;; Call subroutine returning no value.
  
  (define_expand "call_pop"
!   [(parallel [(call (match_operand:QI 0 "indirect_operand" "")
! 		    (match_operand:SI 1 "general_operand" ""))
  	      (set (reg:SI 7)
  		   (plus:SI (reg:SI 7)
! 			    (match_operand:SI 3 "immediate_operand" "")))])]
    ""
    "
  {
-   rtx addr;
- 
    if (operands[3] == const0_rtx)
      {
        emit_insn (gen_call (operands[0], operands[1]));
        DONE;
      }
  
    if (flag_pic)
      current_function_uses_pic_offset_table = 1;
- 
-   /* With half-pic, force the address into a register.  */
-   addr = XEXP (operands[0], 0);
-   if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
-     XEXP (operands[0], 0) = force_reg (Pmode, addr);
  
!   if (! expander_call_insn_operand (operands[0], QImode))
!     operands[0]
!       = change_address (operands[0], VOIDmode,
! 			copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
  }")
  
! (define_insn "*call_pop_pic"
    [(call (match_operand:QI 0 "call_insn_operand" "m")
  	 (match_operand:SI 1 "general_operand" "g"))
     (set (reg:SI 7) (plus:SI (reg:SI 7)
--- 7010,7045 ----
  
  ;; Call instructions.
  
! ;; The predicates normally associated with named expanders are not properly
! ;; checked for calls.  This is a bug in the generic code, but it isn't that
! ;; easy to fix.  Ignore it for now and be prepared to fix things up.
  
  ;; Call subroutine returning no value.
  
  (define_expand "call_pop"
!   [(parallel [(call (match_operand:QI 0 "" "")
! 		    (match_operand:SI 1 "" ""))
  	      (set (reg:SI 7)
  		   (plus:SI (reg:SI 7)
! 			    (match_operand:SI 3 "" "")))])]
    ""
    "
  {
    if (operands[3] == const0_rtx)
      {
        emit_insn (gen_call (operands[0], operands[1]));
        DONE;
      }
  
+   /* ??? Not true for calls to static functions.  */
    if (flag_pic)
      current_function_uses_pic_offset_table = 1;
  
!   if (! call_insn_operand (operands[0], QImode))
!     XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
  }")
  
! (define_insn "*call_pop_1"
    [(call (match_operand:QI 0 "call_insn_operand" "m")
  	 (match_operand:SI 1 "general_operand" "g"))
     (set (reg:SI 7) (plus:SI (reg:SI 7)
***************
*** 7066,7104 ****
  }"
    [(set_attr "type" "call")])
  
- (define_insn "*call_pop_pic2"
-   [(call (match_operand:QI 0 "constant_call_address_operand" "")
-          (match_operand:SI 1 "general_operand" "g"))
-    (set (reg:SI 7) (plus:SI (reg:SI 7)
-                             (match_operand:SI 3 "immediate_operand" "i")))]
-   "!HALF_PIC_P ()"
-   "call\\t%P0"
-   [(set_attr "type" "call")])
- 
  (define_expand "call"
!   [(call (match_operand:QI 0 "indirect_operand" "")
! 	 (match_operand:SI 1 "general_operand" ""))]
    ;; Operand 1 not used on the i386.
    ""
    "
  {
!   rtx addr;
! 
    if (flag_pic)
      current_function_uses_pic_offset_table = 1;
  
!   /* With half-pic, force the address into a register.  */
!   addr = XEXP (operands[0], 0);
!   if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
!     XEXP (operands[0], 0) = force_reg (Pmode, addr);
! 
!   if (! expander_call_insn_operand (operands[0], QImode))
!     operands[0]
!       = change_address (operands[0], VOIDmode,
! 			copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
  }")
  
! (define_insn "*call_pic"
    [(call (match_operand:QI 0 "call_insn_operand" "m")
  	 (match_operand:SI 1 "general_operand" "g"))]
    ;; Operand 1 not used on the i386.
--- 7055,7076 ----
  }"
    [(set_attr "type" "call")])
  
  (define_expand "call"
!   [(call (match_operand:QI 0 "" "")
! 	 (match_operand:SI 1 "" ""))]
    ;; Operand 1 not used on the i386.
    ""
    "
  {
!   /* ??? Not true for calls to static functions.  */
    if (flag_pic)
      current_function_uses_pic_offset_table = 1;
  
!   if (! call_insn_operand (operands[0], QImode))
!     XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
  }")
  
! (define_insn "*call_1"
    [(call (match_operand:QI 0 "call_insn_operand" "m")
  	 (match_operand:SI 1 "general_operand" "g"))]
    ;; Operand 1 not used on the i386.
***************
*** 7106,7135 ****
    "*
  {
    if (constant_call_address_operand (operands[0], GET_MODE (operands[0])))
!     return \"call\\t%P0\";
!   
    operands[0] = XEXP (operands[0], 0);
!   return \"call\\t%*%0\";
  }"
    [(set_attr "type" "call")])
  
- (define_insn "*call_pic2"
-   [(call (match_operand:QI 0 "constant_call_address_operand" "")
-          (match_operand:SI 1 "general_operand" "g"))]
-   "!HALF_PIC_P ()"
-   "call\\t%P0"
-   [(set_attr "type" "call")])
- 
  ;; Call subroutine, returning value in operand 0
  ;; (which must be a hard register).
  
  (define_expand "call_value_pop"
    [(parallel [(set (match_operand 0 "" "")
! 		   (call (match_operand:QI 1 "indirect_operand" "")
! 			 (match_operand:SI 2 "general_operand" "")))
  	      (set (reg:SI 7)
  		   (plus:SI (reg:SI 7)
! 			    (match_operand:SI 4 "immediate_operand" "")))])]
    ""
    "
  {
--- 7078,7108 ----
    "*
  {
    if (constant_call_address_operand (operands[0], GET_MODE (operands[0])))
!     {
!       if (SIBLING_CALL_P (insn))
! 	return \"jmp\\t%P0\";
!       else
! 	return \"call\\t%P0\";
!     }
! 
    operands[0] = XEXP (operands[0], 0);
!   if (SIBLING_CALL_P (insn))
!     return \"jmp\\t%*%0\";
!   else
!     return \"call\\t%*%0\";
  }"
    [(set_attr "type" "call")])
  
  ;; Call subroutine, returning value in operand 0
  ;; (which must be a hard register).
  
  (define_expand "call_value_pop"
    [(parallel [(set (match_operand 0 "" "")
! 		   (call (match_operand:QI 1 "" "")
! 			 (match_operand:SI 2 "" "")))
  	      (set (reg:SI 7)
  		   (plus:SI (reg:SI 7)
! 			    (match_operand:SI 4 "" "")))])]
    ""
    "
  {
***************
*** 7141,7182 ****
        DONE;
      }
  
    if (flag_pic)
      current_function_uses_pic_offset_table = 1;
  
!   /* With half-pic, force the address into a register.  */
!   addr = XEXP (operands[1], 0);
!   if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
!     XEXP (operands[1], 0) = force_reg (Pmode, addr);
! 
!   if (! expander_call_insn_operand (operands[1], QImode))
!     operands[1]
!       = change_address (operands[1], VOIDmode,
! 			copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
  }")
  
  (define_expand "call_value"
    [(set (match_operand 0 "" "")
! 	(call (match_operand:QI 1 "indirect_operand" "")
! 	      (match_operand:SI 2 "general_operand" "")))]
    ;; Operand 2 not used on the i386.
    ""
    "
  {
    rtx addr;
  
    if (flag_pic)
      current_function_uses_pic_offset_table = 1;
  
!   /* With half-pic, force the address into a register.  */
!   addr = XEXP (operands[1], 0);
!   if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
!     XEXP (operands[1], 0) = force_reg (Pmode, addr);
! 
!   if (! expander_call_insn_operand (operands[1], QImode))
!     operands[1]
!       = change_address (operands[1], VOIDmode,
! 			copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
  }")
  
  ;; Call subroutine returning any type.
--- 7114,7143 ----
        DONE;
      }
  
+   /* ??? Not true for calls to static functions.  */
    if (flag_pic)
      current_function_uses_pic_offset_table = 1;
  
!   if (! call_insn_operand (operands[1], QImode))
!     XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
  }")
  
  (define_expand "call_value"
    [(set (match_operand 0 "" "")
! 	(call (match_operand:QI 1 "" "")
! 	      (match_operand:SI 2 "" "")))]
    ;; Operand 2 not used on the i386.
    ""
    "
  {
    rtx addr;
  
+   /* ??? Not true for calls to static functions.  */
    if (flag_pic)
      current_function_uses_pic_offset_table = 1;
  
!   if (! call_insn_operand (operands[1], QImode))
!     XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
  }")
  
  ;; Call subroutine returning any type.
***************
*** 7309,7315 ****
  (define_expand "epilogue"
    [(const_int 1)]
    ""
!   "ix86_expand_epilogue (); DONE;")
  
  (define_insn "leave"
    [(set (reg:SI 7) (reg:SI 6))
--- 7270,7281 ----
  (define_expand "epilogue"
    [(const_int 1)]
    ""
!   "ix86_expand_epilogue (1); DONE;")
! 
! (define_expand "sibcall_epilogue"
!   [(const_int 1)]
!   ""
!   "ix86_expand_epilogue (0); DONE;")
  
  (define_insn "leave"
    [(set (reg:SI 7) (reg:SI 6))
***************
*** 9414,9429 ****
  }"
    [(set_attr "type" "callv")])
  
- (define_insn "*call_value_pop_2"
-   [(set (match_operand 0 "" "")
- 	(call (match_operand:QI 1 "constant_call_address_operand" "")
- 	      (match_operand:SI 2 "general_operand" "g")))
-    (set (reg:SI 7) (plus:SI (reg:SI 7)
- 			    (match_operand:SI 4 "immediate_operand" "i")))]
-   "!HALF_PIC_P ()"
-   "call\\t%P1"
-   [(set_attr "type" "callv")])
- 
  (define_insn "*call_value_1"
    [(set (match_operand 0 "" "")
  	(call (match_operand:QI 1 "call_insn_operand" "m")
--- 9380,9385 ----
***************
*** 9433,9449 ****
    "*
  {
    if (constant_call_address_operand (operands[1], GET_MODE (operands[1])))
!     return \"call\\t%P1\";
    
    operands[1] = XEXP (operands[1], 0);
!   return \"call\\t%*%1\";
  }"
-   [(set_attr "type" "callv")])
- 
- (define_insn "*call_value_2"
-   [(set (match_operand 0 "" "")
- 	(call (match_operand:QI 1 "constant_call_address_operand" "")
- 	      (match_operand:SI 2 "general_operand" "g")))]
-   "!HALF_PIC_P ()"
-   "call\\t%P1"
    [(set_attr "type" "callv")])
--- 9389,9405 ----
    "*
  {
    if (constant_call_address_operand (operands[1], GET_MODE (operands[1])))
!     {
!       if (SIBLING_CALL_P (insn))
! 	return \"jmp\\t%P1\";
!       else
! 	return \"call\\t%P1\";
!     }
    
    operands[1] = XEXP (operands[1], 0);
!   if (SIBLING_CALL_P (insn))
!     return \"jmp\\t%*%1\";
!   else
!     return \"call\\t%*%1\";
  }"
    [(set_attr "type" "callv")])

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]