Update STV pass to properly count cost of XMM register push. In 32-bit mode, to convert XMM register push in DImode, we do an XMM store in DImode, followed by 2 memory pushes in SImode, instead of 2 integer register pushes in SImode. To convert XM register push in SImode, we do an XMM register to integer register move in SImode, followed an integer register push in SImode, instead of an integer register push in SImode. In 64-bit mode, we do an XMM register to integer register move in SImode or DImode, followed an integer register push in SImode or DImode, instead of an integer register push SImode or DImode.
Tested on Linux/x86 and Linux/x86-64. OK for master? Thanks. H.J. -- gcc/ PR target/95021 * config/i386/i386-features.c (general_scalar_chain::general_scalar_chain): Initialize n_sse_push. (general_scalar_chain::mark_dual_mode_def): Add a df_ref argument for reference. Increment n_sse_push for XMM register push. (timode_scalar_chain::mark_dual_mode_def): Add a dummy df_ref argument. (scalar_chain::analyze_register_chain): Pass chain->ref to mark_dual_mode_def. (general_scalar_chain::compute_convert_gain): Count cost of XMM register push. * config/i386/i386-features.h (scalar_chain::mark_dual_mode_def): Add a df_ref argument. (general_scalar_chain): Add n_sse_push. (general_scalar_chain::mark_dual_mode_def): Add a df_ref argument. (timode_scalar_chain::mark_dual_mode_def): Add a df_ref argument. gcc/testsuite/ PR target/95021 * gcc.target/i386/pr95021-1.c: New test. * gcc.target/i386/pr95021-2.c: Likewise. --- gcc/config/i386/i386-features.c | 33 ++++++++++++++++++++--- gcc/config/i386/i386-features.h | 7 ++--- gcc/testsuite/gcc.target/i386/pr95021-1.c | 25 +++++++++++++++++ gcc/testsuite/gcc.target/i386/pr95021-2.c | 25 +++++++++++++++++ 4 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr95021-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr95021-2.c diff --git a/gcc/config/i386/i386-features.c b/gcc/config/i386/i386-features.c index 78fb373db6e..c85ab41350c 100644 --- a/gcc/config/i386/i386-features.c +++ b/gcc/config/i386/i386-features.c @@ -326,6 +326,7 @@ general_scalar_chain::general_scalar_chain (enum machine_mode smode_, insns_conv = BITMAP_ALLOC (NULL); n_sse_to_integer = 0; n_integer_to_sse = 0; + n_sse_push = 0; } general_scalar_chain::~general_scalar_chain () @@ -337,7 +338,7 @@ general_scalar_chain::~general_scalar_chain () conversion. */ void -general_scalar_chain::mark_dual_mode_def (df_ref def) +general_scalar_chain::mark_dual_mode_def (df_ref def, df_ref ref) { gcc_assert (DF_REF_REG_DEF_P (def)); @@ -356,6 +357,12 @@ general_scalar_chain::mark_dual_mode_def (df_ref def) if (!reg_new) return; n_sse_to_integer++; + rtx_insn *insn = DF_REF_INSN (ref); + rtx set = single_set (insn); + /* Count XMM register push. */ + if (set + && push_operand (SET_DEST (set), GET_MODE (SET_DEST (set)))) + n_sse_push++; } if (dump_file) @@ -367,7 +374,7 @@ general_scalar_chain::mark_dual_mode_def (df_ref def) /* For TImode conversion, it is unused. */ void -timode_scalar_chain::mark_dual_mode_def (df_ref) +timode_scalar_chain::mark_dual_mode_def (df_ref, df_ref) { gcc_unreachable (); } @@ -408,14 +415,14 @@ scalar_chain::analyze_register_chain (bitmap candidates, df_ref ref) if (dump_file) fprintf (dump_file, " r%d def in insn %d isn't convertible\n", DF_REF_REGNO (chain->ref), uid); - mark_dual_mode_def (chain->ref); + mark_dual_mode_def (chain->ref, chain->ref); } else { if (dump_file) fprintf (dump_file, " r%d use in insn %d isn't convertible\n", DF_REF_REGNO (chain->ref), uid); - mark_dual_mode_def (ref); + mark_dual_mode_def (ref, chain->ref); } } } @@ -627,6 +634,24 @@ general_scalar_chain::compute_convert_gain () are at the moment. */ cost += n_integer_to_sse * ix86_cost->sse_to_integer; + /* In 32-bit mode, to convert XMM register push in DImode, we do + an XMM store in DImode, followed by 2 memory pushes in SImode, + instead of 2 integer register pushes in SImode. To convert XM + register push in SImode, we do an XMM register to integer register + move in SImode, followed an integer register push in SImode, + instead of an integer register push in SImode. In 64-bit mode, + we do an XMM register to integer register move in SImode or DImode, + followed an integer register push in SImode or DImode, instead of + an integer register push SImode or DImode. */ + if (n_sse_push) + { + if (TARGET_64BIT || m == 1) + cost += n_sse_push * ix86_cost->sse_to_integer; + else + cost += n_sse_push * (ix86_cost->sse_store[sse_cost_idx] + + m * ix86_cost->int_load[2]); + } + if (dump_file) fprintf (dump_file, " Registers conversion cost: %d\n", cost); diff --git a/gcc/config/i386/i386-features.h b/gcc/config/i386/i386-features.h index ee6b10f12c1..3358015dc89 100644 --- a/gcc/config/i386/i386-features.h +++ b/gcc/config/i386/i386-features.h @@ -159,7 +159,7 @@ class scalar_chain private: void add_insn (bitmap candidates, unsigned insn_uid); void analyze_register_chain (bitmap candidates, df_ref ref); - virtual void mark_dual_mode_def (df_ref def) = 0; + virtual void mark_dual_mode_def (df_ref def, df_ref ref) = 0; virtual void convert_insn (rtx_insn *insn) = 0; virtual void convert_registers () = 0; }; @@ -175,7 +175,8 @@ class general_scalar_chain : public scalar_chain bitmap insns_conv; unsigned n_sse_to_integer; unsigned n_integer_to_sse; - void mark_dual_mode_def (df_ref def); + unsigned n_sse_push; + void mark_dual_mode_def (df_ref def, df_ref ref); void convert_insn (rtx_insn *insn); void convert_op (rtx *op, rtx_insn *insn); void convert_reg (rtx_insn *insn, rtx dst, rtx src); @@ -193,7 +194,7 @@ class timode_scalar_chain : public scalar_chain int compute_convert_gain () { return 1; } private: - void mark_dual_mode_def (df_ref def); + void mark_dual_mode_def (df_ref def, df_ref ref); void fix_debug_reg_uses (rtx reg); void convert_insn (rtx_insn *insn); /* We don't convert registers to difference size. */ diff --git a/gcc/testsuite/gcc.target/i386/pr95021-1.c b/gcc/testsuite/gcc.target/i386/pr95021-1.c new file mode 100644 index 00000000000..b47ba332e81 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95021-1.c @@ -0,0 +1,25 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -msse2 -mstv -mregparm=0 -W" } */ +/* { dg-final { scan-assembler-not "xmm" } } */ + +typedef long long a; +struct __jmp_buf_tag { +}; +typedef struct __jmp_buf_tag sigjmp_buf[1]; +sigjmp_buf jmp_buf; +int __sigsetjmp (sigjmp_buf, int); +typedef struct { + a target; +} b; +extern a *target_p; +b *c; +extern void foo (a); +void +d(void) +{ + if (__sigsetjmp(jmp_buf, 1)) { + a target = *target_p; + c->target = target; + foo(target); + } +} diff --git a/gcc/testsuite/gcc.target/i386/pr95021-2.c b/gcc/testsuite/gcc.target/i386/pr95021-2.c new file mode 100644 index 00000000000..b213b5db072 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr95021-2.c @@ -0,0 +1,25 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -msse2 -mstv -mregparm=3 -W" } */ +/* { dg-final { scan-assembler "movq\[ \t\]+\[^\n\]*, %xmm" } } */ + +typedef long long a; +struct __jmp_buf_tag { +}; +typedef struct __jmp_buf_tag sigjmp_buf[1]; +sigjmp_buf jmp_buf; +int __sigsetjmp (sigjmp_buf, int); +typedef struct { + a target; +} b; +extern a *target_p; +b *c; +extern void foo (a); +void +d(void) +{ + if (__sigsetjmp(jmp_buf, 1)) { + a target = *target_p; + c->target = target; + foo(target); + } +} -- 2.26.2