This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
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")])