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