Commit cbbf65e0 by Richard Henderson Committed by Richard Henderson

i386.c (call_insn_operand): Always allow SYMBOL_REF, care for HALF_PIC_P.

        * 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.

From-SVN: r32620
parent b6c5a81c
2000-03-18 Richard Henderson <rth@cygnus.com>
* 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.
2000-03-17 Richard Henderson <rth@cygnus.com> 2000-03-17 Richard Henderson <rth@cygnus.com>
* rtlanal.c (single_set): Reject if the parallel has anything * rtlanal.c (single_set): Reject if the parallel has anything
......
...@@ -30,7 +30,7 @@ extern void asm_output_function_prefix PARAMS ((FILE *, const char *)); ...@@ -30,7 +30,7 @@ extern void asm_output_function_prefix PARAMS ((FILE *, const char *));
extern void load_pic_register PARAMS ((void)); extern void load_pic_register PARAMS ((void));
extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int)); extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int));
extern void ix86_expand_prologue PARAMS ((void)); extern void ix86_expand_prologue PARAMS ((void));
extern void ix86_expand_epilogue PARAMS ((void)); extern void ix86_expand_epilogue PARAMS ((int));
extern void ix86_output_function_block_profiler PARAMS ((FILE *, int)); extern void ix86_output_function_block_profiler PARAMS ((FILE *, int));
extern void ix86_output_block_profiler PARAMS ((FILE *, int)); extern void ix86_output_block_profiler PARAMS ((FILE *, int));
...@@ -44,7 +44,6 @@ extern int symbolic_reference_mentioned_p PARAMS ((rtx)); ...@@ -44,7 +44,6 @@ extern int symbolic_reference_mentioned_p PARAMS ((rtx));
extern int symbolic_operand PARAMS ((rtx, enum machine_mode)); extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
extern int pic_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 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 constant_call_address_operand PARAMS ((rtx, enum machine_mode));
extern int const0_operand PARAMS ((rtx, enum machine_mode)); extern int const0_operand PARAMS ((rtx, enum machine_mode));
extern int const1_operand PARAMS ((rtx, enum machine_mode)); extern int const1_operand PARAMS ((rtx, enum machine_mode));
......
...@@ -1067,22 +1067,17 @@ call_insn_operand (op, mode) ...@@ -1067,22 +1067,17 @@ call_insn_operand (op, mode)
if (GET_CODE (op) == CONST_INT) if (GET_CODE (op) == CONST_INT)
return 0; return 0;
/* Otherwise we can allow any general_operand in the address. */ /* Explicitly allow SYMBOL_REF even if pic. */
return general_operand (op, Pmode); if (GET_CODE (op) == SYMBOL_REF)
}
/* 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 1;
return call_insn_operand (op, mode); /* 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 int
...@@ -1090,9 +1085,9 @@ constant_call_address_operand (op, mode) ...@@ -1090,9 +1085,9 @@ constant_call_address_operand (op, mode)
rtx op; rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED; enum machine_mode mode ATTRIBUTE_UNUSED;
{ {
return GET_CODE (op) == MEM && return (GET_CODE (op) == MEM
CONSTANT_ADDRESS_P (XEXP (op, 0)) && && CONSTANT_ADDRESS_P (XEXP (op, 0))
GET_CODE (XEXP (op, 0)) != CONST_INT; && GET_CODE (XEXP (op, 0)) != CONST_INT);
} }
/* Match exactly zero and one. */ /* Match exactly zero and one. */
...@@ -1997,7 +1992,8 @@ ix86_emit_restore_regs_using_mov (pointer, offset) ...@@ -1997,7 +1992,8 @@ ix86_emit_restore_regs_using_mov (pointer, offset)
/* Restore function stack, frame, and registers. */ /* Restore function stack, frame, and registers. */
void void
ix86_expand_epilogue () ix86_expand_epilogue (emit_return)
int emit_return;
{ {
int nregs; int nregs;
int regno; int regno;
...@@ -2082,6 +2078,10 @@ ix86_expand_epilogue () ...@@ -2082,6 +2078,10 @@ ix86_expand_epilogue ()
emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno))); 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) if (current_function_pops_args && current_function_args_size)
{ {
rtx popc = GEN_INT (current_function_pops_args); rtx popc = GEN_INT (current_function_pops_args);
......
...@@ -1230,6 +1230,11 @@ typedef struct ix86_args { ...@@ -1230,6 +1230,11 @@ typedef struct ix86_args {
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) 0 #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. /* This macro is invoked just before the start of a function.
It is used here to output code for -fpic that will load the It is used here to output code for -fpic that will load the
return address into %ebx. */ return address into %ebx. */
...@@ -2457,7 +2462,6 @@ do { long l; \ ...@@ -2457,7 +2462,6 @@ do { long l; \
LABEL_REF, SUBREG, REG, MEM}}, \ LABEL_REF, SUBREG, REG, MEM}}, \
{"pic_symbolic_operand", {CONST}}, \ {"pic_symbolic_operand", {CONST}}, \
{"call_insn_operand", {MEM}}, \ {"call_insn_operand", {MEM}}, \
{"expander_call_insn_operand", {MEM}}, \
{"constant_call_address_operand", {MEM}}, \ {"constant_call_address_operand", {MEM}}, \
{"const0_operand", {CONST_INT, CONST_DOUBLE}}, \ {"const0_operand", {CONST_INT, CONST_DOUBLE}}, \
{"const1_operand", {CONST_INT}}, \ {"const1_operand", {CONST_INT}}, \
......
...@@ -7010,47 +7010,36 @@ ...@@ -7010,47 +7010,36 @@
;; Call instructions. ;; Call instructions.
;; If generating PIC code, the predicate indirect_operand will fail ;; The predicates normally associated with named expanders are not properly
;; for operands[0] containing symbolic references on all of the named ;; checked for calls. This is a bug in the generic code, but it isn't that
;; call* patterns. Each named pattern is followed by an unnamed pattern ;; easy to fix. Ignore it for now and be prepared to fix things up.
;; 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. ;; Call subroutine returning no value.
(define_expand "call_pop" (define_expand "call_pop"
[(parallel [(call (match_operand:QI 0 "indirect_operand" "") [(parallel [(call (match_operand:QI 0 "" "")
(match_operand:SI 1 "general_operand" "")) (match_operand:SI 1 "" ""))
(set (reg:SI 7) (set (reg:SI 7)
(plus:SI (reg:SI 7) (plus:SI (reg:SI 7)
(match_operand:SI 3 "immediate_operand" "")))])] (match_operand:SI 3 "" "")))])]
"" ""
" "
{ {
rtx addr;
if (operands[3] == const0_rtx) if (operands[3] == const0_rtx)
{ {
emit_insn (gen_call (operands[0], operands[1])); emit_insn (gen_call (operands[0], operands[1]));
DONE; DONE;
} }
/* ??? Not true for calls to static functions. */
if (flag_pic) if (flag_pic)
current_function_uses_pic_offset_table = 1; current_function_uses_pic_offset_table = 1;
/* With half-pic, force the address into a register. */ if (! call_insn_operand (operands[0], QImode))
addr = XEXP (operands[0], 0); XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, 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" (define_insn "*call_pop_1"
[(call (match_operand:QI 0 "call_insn_operand" "m") [(call (match_operand:QI 0 "call_insn_operand" "m")
(match_operand:SI 1 "general_operand" "g")) (match_operand:SI 1 "general_operand" "g"))
(set (reg:SI 7) (plus:SI (reg:SI 7) (set (reg:SI 7) (plus:SI (reg:SI 7)
...@@ -7066,39 +7055,22 @@ ...@@ -7066,39 +7055,22 @@
}" }"
[(set_attr "type" "call")]) [(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" (define_expand "call"
[(call (match_operand:QI 0 "indirect_operand" "") [(call (match_operand:QI 0 "" "")
(match_operand:SI 1 "general_operand" ""))] (match_operand:SI 1 "" ""))]
;; Operand 1 not used on the i386. ;; Operand 1 not used on the i386.
"" ""
" "
{ {
rtx addr; /* ??? Not true for calls to static functions. */
if (flag_pic) if (flag_pic)
current_function_uses_pic_offset_table = 1; current_function_uses_pic_offset_table = 1;
/* With half-pic, force the address into a register. */ if (! call_insn_operand (operands[0], QImode))
addr = XEXP (operands[0], 0); XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, 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" (define_insn "*call_1"
[(call (match_operand:QI 0 "call_insn_operand" "m") [(call (match_operand:QI 0 "call_insn_operand" "m")
(match_operand:SI 1 "general_operand" "g"))] (match_operand:SI 1 "general_operand" "g"))]
;; Operand 1 not used on the i386. ;; Operand 1 not used on the i386.
...@@ -7106,30 +7078,31 @@ ...@@ -7106,30 +7078,31 @@
"* "*
{ {
if (constant_call_address_operand (operands[0], GET_MODE (operands[0]))) if (constant_call_address_operand (operands[0], GET_MODE (operands[0])))
return \"call\\t%P0\"; {
if (SIBLING_CALL_P (insn))
return \"jmp\\t%P0\";
else
return \"call\\t%P0\";
}
operands[0] = XEXP (operands[0], 0); operands[0] = XEXP (operands[0], 0);
return \"call\\t%*%0\"; if (SIBLING_CALL_P (insn))
return \"jmp\\t%*%0\";
else
return \"call\\t%*%0\";
}" }"
[(set_attr "type" "call")]) [(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 ;; Call subroutine, returning value in operand 0
;; (which must be a hard register). ;; (which must be a hard register).
(define_expand "call_value_pop" (define_expand "call_value_pop"
[(parallel [(set (match_operand 0 "" "") [(parallel [(set (match_operand 0 "" "")
(call (match_operand:QI 1 "indirect_operand" "") (call (match_operand:QI 1 "" "")
(match_operand:SI 2 "general_operand" ""))) (match_operand:SI 2 "" "")))
(set (reg:SI 7) (set (reg:SI 7)
(plus:SI (reg:SI 7) (plus:SI (reg:SI 7)
(match_operand:SI 4 "immediate_operand" "")))])] (match_operand:SI 4 "" "")))])]
"" ""
" "
{ {
...@@ -7141,42 +7114,30 @@ ...@@ -7141,42 +7114,30 @@
DONE; DONE;
} }
/* ??? Not true for calls to static functions. */
if (flag_pic) if (flag_pic)
current_function_uses_pic_offset_table = 1; current_function_uses_pic_offset_table = 1;
/* With half-pic, force the address into a register. */ if (! call_insn_operand (operands[1], QImode))
addr = XEXP (operands[1], 0); XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, 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" (define_expand "call_value"
[(set (match_operand 0 "" "") [(set (match_operand 0 "" "")
(call (match_operand:QI 1 "indirect_operand" "") (call (match_operand:QI 1 "" "")
(match_operand:SI 2 "general_operand" "")))] (match_operand:SI 2 "" "")))]
;; Operand 2 not used on the i386. ;; Operand 2 not used on the i386.
"" ""
" "
{ {
rtx addr; rtx addr;
/* ??? Not true for calls to static functions. */
if (flag_pic) if (flag_pic)
current_function_uses_pic_offset_table = 1; current_function_uses_pic_offset_table = 1;
/* With half-pic, force the address into a register. */ if (! call_insn_operand (operands[1], QImode))
addr = XEXP (operands[1], 0); XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, 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. ;; Call subroutine returning any type.
...@@ -7309,7 +7270,12 @@ ...@@ -7309,7 +7270,12 @@
(define_expand "epilogue" (define_expand "epilogue"
[(const_int 1)] [(const_int 1)]
"" ""
"ix86_expand_epilogue (); DONE;") "ix86_expand_epilogue (1); DONE;")
(define_expand "sibcall_epilogue"
[(const_int 1)]
""
"ix86_expand_epilogue (0); DONE;")
(define_insn "leave" (define_insn "leave"
[(set (reg:SI 7) (reg:SI 6)) [(set (reg:SI 7) (reg:SI 6))
...@@ -9414,16 +9380,6 @@ ...@@ -9414,16 +9380,6 @@
}" }"
[(set_attr "type" "callv")]) [(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" (define_insn "*call_value_1"
[(set (match_operand 0 "" "") [(set (match_operand 0 "" "")
(call (match_operand:QI 1 "call_insn_operand" "m") (call (match_operand:QI 1 "call_insn_operand" "m")
...@@ -9433,17 +9389,17 @@ ...@@ -9433,17 +9389,17 @@
"* "*
{ {
if (constant_call_address_operand (operands[1], GET_MODE (operands[1]))) if (constant_call_address_operand (operands[1], GET_MODE (operands[1])))
return \"call\\t%P1\"; {
if (SIBLING_CALL_P (insn))
return \"jmp\\t%P1\";
else
return \"call\\t%P1\";
}
operands[1] = XEXP (operands[1], 0); operands[1] = XEXP (operands[1], 0);
return \"call\\t%*%1\"; if (SIBLING_CALL_P (insn))
return \"jmp\\t%*%1\";
else
return \"call\\t%*%1\";
}" }"
[(set_attr "type" "callv")]) [(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")])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment