Commit 599aedd9 by Richard Henderson Committed by Richard Henderson

emit-rtl.c (try_split): Handle 1-1 splits of call insns properly.

        * emit-rtl.c (try_split): Handle 1-1 splits of call insns properly.

        * config/ia64/ia64.c (TARGET_FUNCTION_OK_FOR_SIBCALL): New.
        (ia64_gp_save_reg): Remove.
        (struct ia64_frame_info): Move to the beginning of the file;
        add reg_save_gp.
        (ia64_expand_call): Rearrange for new call patterns.
        (ia64_reload_gp): New.
        (ia64_split_call): New.
        (ia64_compute_frame_size): Allocate reg_save_gp.
        (ia64_expand_prologue): Save reg_save_gp.
        (ia64_expand_epilogue): Don't restore gp.
        (ia64_hard_regno_rename_ok): Remove R4 hack.
        (ia64_function_ok_for_sibcall): New.
        (ia64_output_mi_thunk): Set reload_completed, no_new_pseudos;
        call try_split on sibcall pattern.
        * config/ia64/ia64-protos.h: Update.
        * config/ia64/ia64.md (call_nogp, call_value_nogp, sibcall_nogp):
        Rename from nopic versions.  Confiscate 2nd argument to call as
        a marker.
        (call_pic, call_value_pic, sibcall_pic): Remove.
        (call_gp, call_value_gp, sibcall_gp): New.
        (builtin_setjmp_setup): Remove.
        (builtin_setjmp_receiver): Call ia64_reload_gp.

From-SVN: r64303
parent 7e38bf41
2003-03-13 Richard Henderson <rth@redhat.com>
* emit-rtl.c (try_split): Handle 1-1 splits of call insns properly.
* config/ia64/ia64.c (TARGET_FUNCTION_OK_FOR_SIBCALL): New.
(ia64_gp_save_reg): Remove.
(struct ia64_frame_info): Move to the beginning of the file;
add reg_save_gp.
(ia64_expand_call): Rearrange for new call patterns.
(ia64_reload_gp): New.
(ia64_split_call): New.
(ia64_compute_frame_size): Allocate reg_save_gp.
(ia64_expand_prologue): Save reg_save_gp.
(ia64_expand_epilogue): Don't restore gp.
(ia64_hard_regno_rename_ok): Remove R4 hack.
(ia64_function_ok_for_sibcall): New.
(ia64_output_mi_thunk): Set reload_completed, no_new_pseudos;
call try_split on sibcall pattern.
* config/ia64/ia64-protos.h: Update.
* config/ia64/ia64.md (call_nogp, call_value_nogp, sibcall_nogp):
Rename from nopic versions. Confiscate 2nd argument to call as
a marker.
(call_pic, call_value_pic, sibcall_pic): Remove.
(call_gp, call_value_gp, sibcall_gp): New.
(builtin_setjmp_setup): Remove.
(builtin_setjmp_receiver): Call ia64_reload_gp.
2003-03-12 Nathanael Nerode <neroden@gcc.gnu.org> 2003-03-12 Nathanael Nerode <neroden@gcc.gnu.org>
* config/dsp16xx/dsp16xx-protos.h, config/dsp16xx/dsp16xx.c, * config/dsp16xx/dsp16xx-protos.h, config/dsp16xx/dsp16xx.c,
......
...@@ -77,11 +77,12 @@ extern int basereg_operand PARAMS((rtx, enum machine_mode)); ...@@ -77,11 +77,12 @@ extern int basereg_operand PARAMS((rtx, enum machine_mode));
extern rtx ia64_expand_move PARAMS ((rtx, rtx)); extern rtx ia64_expand_move PARAMS ((rtx, rtx));
extern int ia64_move_ok PARAMS((rtx, rtx)); extern int ia64_move_ok PARAMS((rtx, rtx));
extern int ia64_depz_field_mask PARAMS((rtx, rtx)); extern int ia64_depz_field_mask PARAMS((rtx, rtx));
extern rtx ia64_gp_save_reg PARAMS((int));
extern rtx ia64_split_timode PARAMS((rtx[], rtx, rtx)); extern rtx ia64_split_timode PARAMS((rtx[], rtx, rtx));
extern rtx spill_tfmode_operand PARAMS((rtx, int)); extern rtx spill_tfmode_operand PARAMS((rtx, int));
extern rtx ia64_expand_compare PARAMS((enum rtx_code, enum machine_mode)); extern rtx ia64_expand_compare PARAMS((enum rtx_code, enum machine_mode));
extern void ia64_expand_call PARAMS((rtx, rtx, rtx, int)); extern void ia64_expand_call PARAMS((rtx, rtx, rtx, int));
extern void ia64_split_call PARAMS((rtx, rtx, rtx, rtx, rtx, int, int));
extern void ia64_reload_gp PARAMS((void));
extern HOST_WIDE_INT ia64_initial_elimination_offset PARAMS((int, int)); extern HOST_WIDE_INT ia64_initial_elimination_offset PARAMS((int, int));
extern void ia64_expand_prologue PARAMS((void)); extern void ia64_expand_prologue PARAMS((void));
......
...@@ -4671,7 +4671,7 @@ ...@@ -4671,7 +4671,7 @@
(use (match_operand 3 "" ""))] (use (match_operand 3 "" ""))]
"" ""
{ {
ia64_expand_call (NULL_RTX, operands[0], operands[2], 0); ia64_expand_call (NULL_RTX, operands[0], operands[2], false);
DONE; DONE;
}) })
...@@ -4682,7 +4682,7 @@ ...@@ -4682,7 +4682,7 @@
(use (match_operand 3 "" ""))] (use (match_operand 3 "" ""))]
"" ""
{ {
ia64_expand_call (NULL_RTX, operands[0], operands[2], 1); ia64_expand_call (NULL_RTX, operands[0], operands[2], true);
DONE; DONE;
}) })
...@@ -4701,7 +4701,7 @@ ...@@ -4701,7 +4701,7 @@
(use (match_operand 4 "" ""))] (use (match_operand 4 "" ""))]
"" ""
{ {
ia64_expand_call (operands[0], operands[1], operands[3], 0); ia64_expand_call (operands[0], operands[1], operands[3], false);
DONE; DONE;
}) })
...@@ -4713,7 +4713,7 @@ ...@@ -4713,7 +4713,7 @@
(use (match_operand 4 "" ""))] (use (match_operand 4 "" ""))]
"" ""
{ {
ia64_expand_call (operands[0], operands[1], operands[3], 1); ia64_expand_call (operands[0], operands[1], operands[3], true);
DONE; DONE;
}) })
...@@ -4745,59 +4745,125 @@ ...@@ -4745,59 +4745,125 @@
DONE; DONE;
}) })
(define_insn "call_nopic" (define_insn "call_nogp"
[(call (mem:DI (match_operand:DI 0 "call_operand" "b,i")) [(call (mem:DI (match_operand:DI 0 "call_operand" "?b,i"))
(match_operand 1 "" "")) (const_int 0))
(clobber (match_operand:DI 2 "register_operand" "=b,b"))] (clobber (match_operand:DI 1 "register_operand" "=b,b"))]
"" ""
"br.call%+.many %2 = %0" "br.call%+.many %1 = %0"
[(set_attr "itanium_class" "br,scall")]) [(set_attr "itanium_class" "br,scall")])
(define_insn "call_value_nopic" (define_insn "call_value_nogp"
[(set (match_operand 0 "" "") [(set (match_operand 0 "" "")
(call (mem:DI (match_operand:DI 1 "call_operand" "b,i")) (call (mem:DI (match_operand:DI 1 "call_operand" "?b,i"))
(match_operand 2 "" ""))) (const_int 0)))
(clobber (match_operand:DI 3 "register_operand" "=b,b"))] (clobber (match_operand:DI 2 "register_operand" "=b,b"))]
"" ""
"br.call%+.many %3 = %1" "br.call%+.many %2 = %1"
[(set_attr "itanium_class" "br,scall")]) [(set_attr "itanium_class" "br,scall")])
(define_insn "sibcall_nopic" (define_insn "sibcall_nogp"
[(call (mem:DI (match_operand:DI 0 "call_operand" "b,i")) [(call (mem:DI (match_operand:DI 0 "call_operand" "?b,i"))
(match_operand 1 "" "")) (const_int 0))]
(use (match_operand:DI 2 "register_operand" "=b,b"))
(use (match_operand:DI 3 "ar_pfs_reg_operand" ""))]
"" ""
"br%+.many %0" "br%+.many %0"
[(set_attr "itanium_class" "br,scall")]) [(set_attr "itanium_class" "br,scall")])
(define_insn "call_pic" (define_insn "call_gp"
[(call (mem (match_operand 0 "call_operand" "b,i")) [(call (mem (match_operand 0 "call_operand" "?r,i"))
(match_operand 1 "" "")) (const_int 1))
(use (unspec [(reg:DI 1)] UNSPEC_PIC_CALL)) (clobber (match_operand:DI 1 "register_operand" "=b,b"))
(clobber (match_operand:DI 2 "register_operand" "=b,b"))] (clobber (match_scratch:DI 2 "=&r,X"))
(clobber (match_scratch:DI 3 "=b,X"))]
"" ""
"br.call%+.many %2 = %0" "#"
[(set_attr "itanium_class" "br,scall")]) [(set_attr "itanium_class" "br,scall")])
(define_insn "call_value_pic" ;; Irritatingly, we don't have access to INSN within the split body.
;; See commentary in ia64_split_call as to why these aren't peep2.
(define_split
[(call (mem (match_operand 0 "call_operand" ""))
(const_int 1))
(clobber (match_operand:DI 1 "register_operand" ""))
(clobber (match_scratch:DI 2 ""))
(clobber (match_scratch:DI 3 ""))]
"reload_completed && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
[(const_int 0)]
{
ia64_split_call (NULL_RTX, operands[0], operands[1], operands[2],
operands[3], true, false);
DONE;
})
(define_split
[(call (mem (match_operand 0 "call_operand" ""))
(const_int 1))
(clobber (match_operand:DI 1 "register_operand" ""))
(clobber (match_scratch:DI 2 ""))
(clobber (match_scratch:DI 3 ""))]
"reload_completed"
[(const_int 0)]
{
ia64_split_call (NULL_RTX, operands[0], operands[1], operands[2],
operands[3], false, false);
DONE;
})
(define_insn "call_value_gp"
[(set (match_operand 0 "" "") [(set (match_operand 0 "" "")
(call (mem:DI (match_operand:DI 1 "call_operand" "b,i")) (call (mem:DI (match_operand:DI 1 "call_operand" "?r,i"))
(match_operand 2 "" ""))) (const_int 1)))
(use (unspec [(reg:DI 1)] UNSPEC_PIC_CALL)) (clobber (match_operand:DI 2 "register_operand" "=b,b"))
(clobber (match_operand:DI 3 "register_operand" "=b,b"))] (clobber (match_scratch:DI 3 "=&r,X"))
(clobber (match_scratch:DI 4 "=b,X"))]
"" ""
"br.call%+.many %3 = %1" "#"
[(set_attr "itanium_class" "br,scall")]) [(set_attr "itanium_class" "br,scall")])
(define_insn "sibcall_pic" (define_split
[(call (mem:DI (match_operand:DI 0 "call_operand" "bi")) [(set (match_operand 0 "" "")
(match_operand 1 "" "")) (call (mem:DI (match_operand:DI 1 "call_operand" ""))
(use (unspec [(reg:DI 1)] UNSPEC_PIC_CALL)) (const_int 1)))
(use (match_operand:DI 2 "register_operand" "=b")) (clobber (match_operand:DI 2 "register_operand" ""))
(use (match_operand:DI 3 "ar_pfs_reg_operand" ""))] (clobber (match_scratch:DI 3 ""))
(clobber (match_scratch:DI 4 ""))]
"reload_completed && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
[(const_int 0)]
{
ia64_split_call (operands[0], operands[1], operands[2], operands[3],
operands[4], true, false);
DONE;
})
(define_split
[(set (match_operand 0 "" "")
(call (mem:DI (match_operand:DI 1 "call_operand" ""))
(const_int 1)))
(clobber (match_operand:DI 2 "register_operand" ""))
(clobber (match_scratch:DI 3 ""))
(clobber (match_scratch:DI 4 ""))]
"reload_completed"
[(const_int 0)]
{
ia64_split_call (operands[0], operands[1], operands[2], operands[3],
operands[4], false, false);
DONE;
})
(define_insn_and_split "sibcall_gp"
[(call (mem:DI (match_operand:DI 0 "call_operand" "?r,i"))
(const_int 1))
(clobber (match_scratch:DI 1 "=&r,X"))
(clobber (match_scratch:DI 2 "=b,X"))]
"" ""
"br%+.many %0" "#"
"reload_completed"
[(const_int 0)]
{
ia64_split_call (NULL_RTX, operands[0], NULL_RTX, operands[1],
operands[2], true, true);
DONE;
}
[(set_attr "itanium_class" "br")]) [(set_attr "itanium_class" "br")])
(define_insn "return_internal" (define_insn "return_internal"
...@@ -5263,21 +5329,11 @@ ...@@ -5263,21 +5329,11 @@
DONE; DONE;
}) })
;; The rest of the setjmp processing happens with the nonlocal_goto expander.
;; ??? This is not tested.
(define_expand "builtin_setjmp_setup"
[(use (match_operand:DI 0 "" ""))]
""
{
emit_move_insn (ia64_gp_save_reg (0), gen_rtx_REG (DImode, GR_REG (1)));
DONE;
})
(define_expand "builtin_setjmp_receiver" (define_expand "builtin_setjmp_receiver"
[(use (match_operand:DI 0 "" ""))] [(use (match_operand:DI 0 "" ""))]
"" ""
{ {
emit_move_insn (gen_rtx_REG (DImode, GR_REG (1)), ia64_gp_save_reg (0)); ia64_reload_gp ();
DONE; DONE;
}) })
......
...@@ -3375,6 +3375,8 @@ try_split (pat, trial, last) ...@@ -3375,6 +3375,8 @@ try_split (pat, trial, last)
rtx tem; rtx tem;
rtx note, seq; rtx note, seq;
int probability; int probability;
rtx insn_last, insn;
int njumps = 0;
if (any_condjump_p (trial) if (any_condjump_p (trial)
&& (note = find_reg_note (trial, REG_BR_PROB, 0))) && (note = find_reg_note (trial, REG_BR_PROB, 0)))
...@@ -3393,172 +3395,147 @@ try_split (pat, trial, last) ...@@ -3393,172 +3395,147 @@ try_split (pat, trial, last)
after = NEXT_INSN (after); after = NEXT_INSN (after);
} }
if (seq) if (!seq)
return trial;
/* Avoid infinite loop if any insn of the result matches
the original pattern. */
insn_last = seq;
while (1)
{ {
/* Sometimes there will be only one insn in that list, this case will if (INSN_P (insn_last)
normally arise only when we want it in turn to be split (SFmode on && rtx_equal_p (PATTERN (insn_last), pat))
the 29k is an example). */ return trial;
if (NEXT_INSN (seq) != NULL_RTX) if (!NEXT_INSN (insn_last))
{ break;
rtx insn_last, insn; insn_last = NEXT_INSN (insn_last);
int njumps = 0; }
/* Avoid infinite loop if any insn of the result matches /* Mark labels. */
the original pattern. */ for (insn = insn_last; insn ; insn = PREV_INSN (insn))
insn_last = seq; {
while (1) if (GET_CODE (insn) == JUMP_INSN)
{
mark_jump_label (PATTERN (insn), insn, 0);
njumps++;
if (probability != -1
&& any_condjump_p (insn)
&& !find_reg_note (insn, REG_BR_PROB, 0))
{ {
if (INSN_P (insn_last) /* We can preserve the REG_BR_PROB notes only if exactly
&& rtx_equal_p (PATTERN (insn_last), pat)) one jump is created, otherwise the machine description
return trial; is responsible for this step using
if (NEXT_INSN (insn_last) == NULL_RTX) split_branch_probability variable. */
break; if (njumps != 1)
insn_last = NEXT_INSN (insn_last); abort ();
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_BR_PROB,
GEN_INT (probability),
REG_NOTES (insn));
} }
}
}
/* Mark labels. */ /* If we are splitting a CALL_INSN, look for the CALL_INSN
in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it. */
if (GET_CODE (trial) == CALL_INSN)
{
for (insn = insn_last; insn ; insn = PREV_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
{
CALL_INSN_FUNCTION_USAGE (insn)
= CALL_INSN_FUNCTION_USAGE (trial);
SIBLING_CALL_P (insn) = SIBLING_CALL_P (trial);
}
}
/* Copy notes, particularly those related to the CFG. */
for (note = REG_NOTES (trial); note; note = XEXP (note, 1))
{
switch (REG_NOTE_KIND (note))
{
case REG_EH_REGION:
insn = insn_last; insn = insn_last;
while (insn != NULL_RTX) while (insn != NULL_RTX)
{ {
if (GET_CODE (insn) == JUMP_INSN) if (GET_CODE (insn) == CALL_INSN
{ || (flag_non_call_exceptions
mark_jump_label (PATTERN (insn), insn, 0); && may_trap_p (PATTERN (insn))))
njumps++; REG_NOTES (insn)
if (probability != -1 = gen_rtx_EXPR_LIST (REG_EH_REGION,
&& any_condjump_p (insn) XEXP (note, 0),
&& !find_reg_note (insn, REG_BR_PROB, 0)) REG_NOTES (insn));
{
/* We can preserve the REG_BR_PROB notes only if exactly
one jump is created, otherwise the machine description
is responsible for this step using
split_branch_probability variable. */
if (njumps != 1)
abort ();
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_BR_PROB,
GEN_INT (probability),
REG_NOTES (insn));
}
}
insn = PREV_INSN (insn); insn = PREV_INSN (insn);
} }
break;
/* If we are splitting a CALL_INSN, look for the CALL_INSN case REG_NORETURN:
in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it. */ case REG_SETJMP:
if (GET_CODE (trial) == CALL_INSN) case REG_ALWAYS_RETURN:
{ insn = insn_last;
insn = insn_last; while (insn != NULL_RTX)
while (insn != NULL_RTX)
{
if (GET_CODE (insn) == CALL_INSN)
CALL_INSN_FUNCTION_USAGE (insn)
= CALL_INSN_FUNCTION_USAGE (trial);
insn = PREV_INSN (insn);
}
}
/* Copy notes, particularly those related to the CFG. */
for (note = REG_NOTES (trial); note; note = XEXP (note, 1))
{ {
switch (REG_NOTE_KIND (note)) if (GET_CODE (insn) == CALL_INSN)
{ REG_NOTES (insn)
case REG_EH_REGION: = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
insn = insn_last; XEXP (note, 0),
while (insn != NULL_RTX) REG_NOTES (insn));
{ insn = PREV_INSN (insn);
if (GET_CODE (insn) == CALL_INSN
|| (flag_non_call_exceptions
&& may_trap_p (PATTERN (insn))))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_EH_REGION,
XEXP (note, 0),
REG_NOTES (insn));
insn = PREV_INSN (insn);
}
break;
case REG_NORETURN:
case REG_SETJMP:
case REG_ALWAYS_RETURN:
insn = insn_last;
while (insn != NULL_RTX)
{
if (GET_CODE (insn) == CALL_INSN)
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),
REG_NOTES (insn));
insn = PREV_INSN (insn);
}
break;
case REG_NON_LOCAL_GOTO:
insn = insn_last;
while (insn != NULL_RTX)
{
if (GET_CODE (insn) == JUMP_INSN)
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),
REG_NOTES (insn));
insn = PREV_INSN (insn);
}
break;
default:
break;
}
} }
break;
/* If there are LABELS inside the split insns increment the case REG_NON_LOCAL_GOTO:
usage count so we don't delete the label. */ insn = insn_last;
if (GET_CODE (trial) == INSN) while (insn != NULL_RTX)
{ {
insn = insn_last; if (GET_CODE (insn) == JUMP_INSN)
while (insn != NULL_RTX) REG_NOTES (insn)
{ = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
if (GET_CODE (insn) == INSN) XEXP (note, 0),
mark_label_nuses (PATTERN (insn)); REG_NOTES (insn));
insn = PREV_INSN (insn);
insn = PREV_INSN (insn);
}
} }
break;
tem = emit_insn_after_scope (seq, trial, INSN_SCOPE (trial)); default:
break;
delete_insn (trial);
if (has_barrier)
emit_barrier_after (tem);
/* Recursively call try_split for each new insn created; by the
time control returns here that insn will be fully split, so
set LAST and continue from the insn after the one returned.
We can't use next_active_insn here since AFTER may be a note.
Ignore deleted insns, which can be occur if not optimizing. */
for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
if (! INSN_DELETED_P (tem) && INSN_P (tem))
tem = try_split (PATTERN (tem), tem, 1);
} }
/* Avoid infinite loop if the result matches the original pattern. */ }
else if (rtx_equal_p (PATTERN (seq), pat))
return trial; /* If there are LABELS inside the split insns increment the
else usage count so we don't delete the label. */
if (GET_CODE (trial) == INSN)
{
insn = insn_last;
while (insn != NULL_RTX)
{ {
PATTERN (trial) = PATTERN (seq); if (GET_CODE (insn) == INSN)
INSN_CODE (trial) = -1; mark_label_nuses (PATTERN (insn));
try_split (PATTERN (trial), trial, last);
}
/* Return either the first or the last insn, depending on which was insn = PREV_INSN (insn);
requested. */ }
return last
? (after ? PREV_INSN (after) : last_insn)
: NEXT_INSN (before);
} }
return trial; tem = emit_insn_after_scope (seq, trial, INSN_SCOPE (trial));
delete_insn (trial);
if (has_barrier)
emit_barrier_after (tem);
/* Recursively call try_split for each new insn created; by the
time control returns here that insn will be fully split, so
set LAST and continue from the insn after the one returned.
We can't use next_active_insn here since AFTER may be a note.
Ignore deleted insns, which can be occur if not optimizing. */
for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
if (! INSN_DELETED_P (tem) && INSN_P (tem))
tem = try_split (PATTERN (tem), tem, 1);
/* Return either the first or the last insn, depending on which was
requested. */
return last
? (after ? PREV_INSN (after) : last_insn)
: NEXT_INSN (before);
} }
/* Make and return an INSN rtx, initializing all its slots. /* Make and return an INSN rtx, initializing all its slots.
......
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