Hello! The testcase in PR58792 [1], where a function returns its result in multiple registers, triggered a very picky assert in mode-switching code. The problem was, that x86_64 didn't mark correctly all of its possible return registers, so code assumed that something went wrong here.
The mode-switching code already handles __builtin_apply builtin, which also generates multiple return registers. When a sequence of USEs is detected, maybe_builtin_apply flag is raised to bypass the assert. However, functions that pass their result in multiple registers also generate multiple USEs, so the patch clarifies that __builtin_apply situation actually applies to all multiple return register exits. The patch clarifies this situation. No functional changes (modulo converting a couple of variables to boolean type). 2013-10-19 Uros Bizjak <ubiz...@gmail.com> * mode-switching.c (create_pre_exit): Rename maybe_builtin_apply to multi_reg_return. Clarify that we are skipping USEs of multiple return registers. Use bool type where appropriate. Tested on x86_64-pc-linux-gnu and committed to mainline SVN. [1] http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58792 Uros.
Index: mode-switching.c =================================================================== --- mode-switching.c (revision 203845) +++ mode-switching.c (working copy) @@ -229,9 +229,9 @@ create_pre_exit (int n_entities, int *entity_map, int ret_start = REGNO (ret_reg); int nregs = hard_regno_nregs[ret_start][GET_MODE (ret_reg)]; int ret_end = ret_start + nregs; - int short_block = 0; - int maybe_builtin_apply = 0; - int forced_late_switch = 0; + bool short_block = false; + bool multi_reg_return = false; + bool forced_late_switch = false; rtx before_return_copy; do @@ -251,19 +251,20 @@ create_pre_exit (int n_entities, int *entity_map, copy yet, the copy must have been deleted. */ if (CALL_P (return_copy)) { - short_block = 1; + short_block = true; break; } return_copy_pat = PATTERN (return_copy); switch (GET_CODE (return_copy_pat)) { case USE: - /* Skip __builtin_apply pattern. */ + /* Skip return values in multiple registers. + __builtin_apply pattern is also handled here. */ if (GET_CODE (XEXP (return_copy_pat, 0)) == REG && (targetm.calls.function_value_regno_p (REGNO (XEXP (return_copy_pat, 0))))) { - maybe_builtin_apply = 1; + multi_reg_return = true; last_insn = return_copy; continue; } @@ -326,7 +327,7 @@ create_pre_exit (int n_entities, int *entity_map, there are no return copy insns at all. This avoids an ice on that invalid function. */ if (ret_start + nregs == ret_end) - short_block = 1; + short_block = true; break; } if (!targetm.calls.function_value_regno_p (copy_start)) @@ -354,10 +355,10 @@ create_pre_exit (int n_entities, int *entity_map, another mode than MODE_EXIT, even if it is unrelated to the return value, so we want to put the final mode switch after it. */ - if (maybe_builtin_apply + if (multi_reg_return && targetm.calls.function_value_regno_p (copy_start)) - forced_late_switch = 1; + forced_late_switch = true; /* For the SH4, floating point loads depend on fpscr, thus we might need to put the final mode switch @@ -367,7 +368,7 @@ create_pre_exit (int n_entities, int *entity_map, if (copy_start >= ret_start && copy_start + copy_num <= ret_end && OBJECT_P (SET_SRC (return_copy_pat))) - forced_late_switch = 1; + forced_late_switch = true; break; } if (copy_num == 0) @@ -379,7 +380,7 @@ create_pre_exit (int n_entities, int *entity_map, if (copy_start >= ret_start && copy_start + copy_num <= ret_end) nregs -= copy_num; - else if (!maybe_builtin_apply + else if (!multi_reg_return || !targetm.calls.function_value_regno_p (copy_start)) break; @@ -393,7 +394,7 @@ create_pre_exit (int n_entities, int *entity_map, isolated use. */ if (return_copy == BB_HEAD (src_bb)) { - short_block = 1; + short_block = true; break; } last_insn = return_copy;