https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88717
--- Comment #4 from 刘袋鼠 <crazylht at gmail dot com> ---
(In reply to H.J. Lu from comment #3)
> Like this
>
> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
> index d01278d866f..9b49a2c1d9c 100644
> --- a/gcc/config/i386/i386.c
> +++ b/gcc/config/i386/i386.c
> @@ -19100,7 +19100,11 @@ ix86_avx_u128_mode_entry (void)
> rtx incoming = DECL_INCOMING_RTL (arg);
>
> if (incoming && ix86_check_avx_upper_register (incoming))
> - return AVX_U128_DIRTY;
> + {
> + /* Caller is AVX_U128_DIRTY. */
> + cfun->machine->caller_avx_u128_dirty = true;
> + return AVX_U128_DIRTY;
> + }
> }
>
> return AVX_U128_CLEAN;
> @@ -19130,6 +19134,10 @@ ix86_mode_entry (int entity)
> static int
> ix86_avx_u128_mode_exit (void)
> {
> + /* Exit mode is set to AVX_U128_DIRTY if caller is AVX_U128_DIRTY. */
> + if (cfun->machine->caller_avx_u128_dirty)
> + return AVX_U128_DIRTY;
> +
> rtx reg = crtl->return_rtx;
>
> /* Exit mode is set to AVX_U128_DIRTY if there are 256bit
> diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
> index 83b025e0cf5..c053b657a55 100644
> --- a/gcc/config/i386/i386.h
> +++ b/gcc/config/i386/i386.h
> @@ -2747,6 +2747,9 @@ struct GTY(()) machine_function {
> /* If true, ENDBR is queued at function entrance. */
> BOOL_BITFIELD endbr_queued_at_entrance : 1;
>
> + /* If true, caller is AVX_U128_DIRTY. */
> + BOOL_BITFIELD caller_avx_u128_dirty : 1;
> +
> /* The largest alignment, in bytes, of stack slot actually used. */
> unsigned int max_used_stack_alignment;
My thought is AVX_U128_DIRTY would be set when ymm/zmm appeared, and
AVX_U128_CLEAN for xmm, AVX_U128_ANY for other situations. This also works for
this case.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 61dbc95c086..233f46c116b 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -18912,6 +18912,12 @@ ix86_check_avx_upper_register (const_rtx exp)
return SSE_REG_P (exp) && GET_MODE_BITSIZE (GET_MODE (exp)) > 128;
}
+/* Check if a 128bit SSE register is referenced inside of EXP. */
+static bool
+ix86_check_sse_register (const_rtx exp)
+{
+ return SSE_REG_P (exp) && GET_MODE_BITSIZE (GET_MODE (exp)) == 128;
+}
/* Return needed mode for entity in optimize_mode_switching pass. */
static int
@@ -18920,6 +18926,7 @@ ix86_avx_u128_mode_needed (rtx_insn *insn)
if (CALL_P (insn))
{
rtx link;
+ bool flag_clean = 0;
/* Needed mode is set to AVX_U128_CLEAN if there are
no 256bit or 512bit modes used in function arguments. */
@@ -18933,10 +18940,14 @@ ix86_avx_u128_mode_needed (rtx_insn *insn)
if (ix86_check_avx_upper_register (arg))
return AVX_U128_DIRTY;
+ if (ix86_check_sse_register (arg))
+ flag_clean = true;
}
}
- return AVX_U128_CLEAN;
+ if(flag_clean)
+ return AVX_U128_CLEAN;
+ return AVX_U128_ANY;
}
/* Require DIRTY mode if a 256bit or 512bit AVX register is referenced.
@@ -19033,6 +19044,15 @@ ix86_check_avx_upper_stores (rtx dest, const_rtx, void
*data)
}
}
+static void
+ix86_check_sse_stores (rtx dest, const_rtx, void *data)
+{
+ if (ix86_check_sse_register (dest))
+ {
+ bool *used = (bool *)data;
+ *used = true;
+ }
+}
/* Calculate mode of upper 128bit AVX registers after the insn. */
static int
@@ -19049,9 +19069,10 @@ ix86_avx_u128_mode_after (int mode, rtx_insn *insn)
if (CALL_P (insn))
{
bool avx_upper_reg_found = false;
+ bool sse_reg_found = false;
note_stores (pat, ix86_check_avx_upper_stores, &avx_upper_reg_found);
-
- return avx_upper_reg_found ? AVX_U128_DIRTY : AVX_U128_CLEAN;
+ note_stores (pat, ix86_check_sse_stores, &sse_reg_found);
+ return avx_upper_reg_found ? AVX_U128_DIRTY : sse_reg_found ?
AVX_U128_CLEAN : AVX_U128_ANY;
}
/* Otherwise, return current mode. Remember that if insn
@@ -19096,7 +19117,7 @@ static int
ix86_avx_u128_mode_entry (void)
{
tree arg;
-
+ bool flag_clean = false;
/* Entry mode is set to AVX_U128_DIRTY if there are
256bit or 512bit modes used in function arguments. */
for (arg = DECL_ARGUMENTS (current_function_decl); arg;
@@ -19106,9 +19127,14 @@ ix86_avx_u128_mode_entry (void)
if (incoming && ix86_check_avx_upper_register (incoming))
return AVX_U128_DIRTY;
+
+ if (incoming && ix86_check_sse_register (incoming))
+ flag_clean = true;
}
- return AVX_U128_CLEAN;
+ if (flag_clean)
+ return AVX_U128_CLEAN;
+ return AVX_U128_ANY;
}
/* Return a mode that ENTITY is assumed to be
@@ -19142,7 +19168,9 @@ ix86_avx_u128_mode_exit (void)
if (reg && ix86_check_avx_upper_register (reg))
return AVX_U128_DIRTY;
- return AVX_U128_CLEAN;
+ if (reg && ix86_check_sse_register (reg))
+ return AVX_U128_CLEAN;
+ return AVX_U128_ANY;
}
/* Return a mode that ENTITY is assumed to be