From dcbca208a35a734fb1098661ae4681f23b197cb9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Dec 2004 09:41:58 -0800 Subject: [PATCH] re PR target/19010 (sse and mmx parameter passing broken) PR target/19010 * config/i386/i386.c (ix86_must_pass_in_stack): Don't return true for TImode vectors. (gen_reg_or_parallel): New. (function_arg): Use it. (ix86_hard_regno_mode_ok): Test SSE1 and SSE2 separately, MMX and 3DNOW separately. (ix86_rtx_costs): Simplify FLOAT_EXTEND case. (ix86_vector_mode_supported_p): Test SSE1 and SSE2 separately. * config/i386/i386.h (VALID_SSE2_REG_MODE): Move SSE2 cases from ... (VALID_SSE_REG_MODE): ... here. * gcc.target/i386/i386.exp: New harness. * gcc.target/i386/vect-args.c: New. From-SVN: r92205 --- gcc/ChangeLog | 14 ++++ gcc/config/i386/i386.c | 87 +++++++++++++++++------ gcc/config/i386/i386.h | 8 +-- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.target/i386/i386.exp | 54 ++++++++++++++ gcc/testsuite/gcc.target/i386/vect-args.c | 33 +++++++++ 6 files changed, 173 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/i386.exp create mode 100644 gcc/testsuite/gcc.target/i386/vect-args.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7c981a64ecf4..5f618627d887 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2004-12-15 Richard Henderson + + PR target/19010 + * config/i386/i386.c (ix86_must_pass_in_stack): Don't return true + for TImode vectors. + (gen_reg_or_parallel): New. + (function_arg): Use it. + (ix86_hard_regno_mode_ok): Test SSE1 and SSE2 separately, + MMX and 3DNOW separately. + (ix86_rtx_costs): Simplify FLOAT_EXTEND case. + (ix86_vector_mode_supported_p): Test SSE1 and SSE2 separately. + * config/i386/i386.h (VALID_SSE2_REG_MODE): Move SSE2 cases from ... + (VALID_SSE_REG_MODE): ... here. + 2004-12-15 David Edelsohn * xcoffout.c (xcoffout_declare_function): Change strncpy to memcpy. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 8819ba84bb0b..6ecf8a417c56 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1943,7 +1943,12 @@ ix86_must_pass_in_stack (enum machine_mode mode, tree type) { if (must_pass_in_stack_var_size_or_pad (mode, type)) return true; - return (!TARGET_64BIT && type && mode == TImode); + + /* For 32-bit, we want TImode aggregates to go on the stack. But watch out! + The layout_type routine is crafty and tries to trick us into passing + currently unsupported vector types on the stack by using TImode. */ + return (!TARGET_64BIT && mode == TImode + && type && TREE_CODE (type) != VECTOR_TYPE); } /* Initialize a variable CUM of type CUMULATIVE_ARGS @@ -2640,6 +2645,34 @@ function_arg_advance (CUMULATIVE_ARGS *cum, /* current arg information */ return; } +/* A subroutine of function_arg. We want to pass a parameter whose nominal + type is MODE in REGNO. We try to minimize ABI variation, so MODE may not + actually be valid for REGNO with the current ISA. In this case, ALT_MODE + is used instead. It must be the same size as MODE, and must be known to + be valid for REGNO. Finally, ORIG_MODE is the original mode of the + parameter, as seen by the type system. This may be different from MODE + when we're mucking with things minimizing ABI variations. + + Returns a REG or a PARALLEL as appropriate. */ + +static rtx +gen_reg_or_parallel (enum machine_mode mode, enum machine_mode alt_mode, + enum machine_mode orig_mode, unsigned int regno) +{ + rtx tmp; + + if (HARD_REGNO_MODE_OK (regno, mode)) + tmp = gen_rtx_REG (mode, regno); + else + { + tmp = gen_rtx_REG (alt_mode, regno); + tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, const0_rtx); + tmp = gen_rtx_PARALLEL (orig_mode, gen_rtvec (1, tmp)); + } + + return tmp; +} + /* Define where to put the arguments to a function. Value is zero to push the argument on the stack, or a hard register in which to store the argument. @@ -2654,12 +2687,11 @@ function_arg_advance (CUMULATIVE_ARGS *cum, /* current arg information */ (otherwise it is an extra parameter matching an ellipsis). */ rtx -function_arg (CUMULATIVE_ARGS *cum, /* current arg information */ - enum machine_mode mode, /* current arg mode */ - tree type, /* type of the argument or 0 if lib support */ - int named) /* != 0 for normal args, == 0 for ... args */ +function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, + tree type, int named) { - rtx ret = NULL_RTX; + enum machine_mode mode = orig_mode; + rtx ret = NULL_RTX; int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; @@ -2755,7 +2787,8 @@ function_arg (CUMULATIVE_ARGS *cum, /* current arg information */ "changes the ABI"); } if (cum->sse_nregs) - ret = gen_rtx_REG (mode, cum->sse_regno + FIRST_SSE_REG); + ret = gen_reg_or_parallel (mode, TImode, orig_mode, + cum->sse_regno + FIRST_SSE_REG); } break; case V8QImode: @@ -2771,7 +2804,8 @@ function_arg (CUMULATIVE_ARGS *cum, /* current arg information */ "changes the ABI"); } if (cum->mmx_nregs) - ret = gen_rtx_REG (mode, cum->mmx_regno + FIRST_MMX_REG); + ret = gen_reg_or_parallel (mode, DImode, orig_mode, + cum->mmx_regno + FIRST_MMX_REG); } break; } @@ -13991,10 +14025,20 @@ ix86_hard_regno_mode_ok (int regno, enum machine_mode mode) if (FP_REGNO_P (regno)) return VALID_FP_MODE_P (mode); if (SSE_REGNO_P (regno)) - return (TARGET_SSE ? VALID_SSE_REG_MODE (mode) : 0); + { + if (TARGET_SSE2 && VALID_SSE2_REG_MODE (mode)) + return 1; + if (TARGET_SSE && VALID_SSE_REG_MODE (mode)) + return 1; + return 0; + } if (MMX_REGNO_P (regno)) - return (TARGET_MMX - ? VALID_MMX_REG_MODE (mode) || VALID_MMX_REG_MODE_3DNOW (mode) : 0); + { + if (TARGET_3DNOW && VALID_MMX_REG_MODE_3DNOW (mode)) + return 1; + if (TARGET_MMX && VALID_MMX_REG_MODE (mode)) + return 1; + } /* We handle both integer and floats in the general purpose registers. In future we should be able to handle vector modes as well. */ if (!VALID_INT_MODE_P (mode) && !VALID_FP_MODE_P (mode)) @@ -14372,7 +14416,9 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total) return false; case FLOAT_EXTEND: - if (!TARGET_SSE_MATH || !VALID_SSE_REG_MODE (mode)) + if (!TARGET_SSE_MATH + || mode == XFmode + || (mode == DFmode && !TARGET_SSE2)) *total = 0; return false; @@ -15164,20 +15210,15 @@ ix86_expand_vector_init (rtx target, rtx vals) static bool ix86_vector_mode_supported_p (enum machine_mode mode) { - if (TARGET_SSE - && VALID_SSE_REG_MODE (mode)) + if (TARGET_SSE && VALID_SSE_REG_MODE (mode)) return true; - - else if (TARGET_MMX - && VALID_MMX_REG_MODE (mode)) + if (TARGET_SSE2 && VALID_SSE2_REG_MODE (mode)) return true; - - else if (TARGET_3DNOW - && VALID_MMX_REG_MODE_3DNOW (mode)) + if (TARGET_MMX && VALID_MMX_REG_MODE (mode)) return true; - - else - return false; + if (TARGET_3DNOW && VALID_MMX_REG_MODE_3DNOW (mode)) + return true; + return false; } /* Worker function for TARGET_MD_ASM_CLOBBERS. diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index a16f30842689..9063d85b1a7c 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1075,14 +1075,12 @@ do { \ #define VALID_SSE2_REG_MODE(MODE) \ ((MODE) == V16QImode || (MODE) == V8HImode || (MODE) == V2DFmode \ - || (MODE) == V2DImode) + || (MODE) == V2DImode || (MODE) == DFmode \ + || VALID_MMX_REG_MODE (MODE)) #define VALID_SSE_REG_MODE(MODE) \ ((MODE) == TImode || (MODE) == V4SFmode || (MODE) == V4SImode \ - || (MODE) == SFmode || (MODE) == TFmode \ - /* Always accept SSE2 modes so that xmmintrin.h compiles. */ \ - || VALID_SSE2_REG_MODE (MODE) \ - || (TARGET_SSE2 && ((MODE) == DFmode || VALID_MMX_REG_MODE (MODE)))) + || (MODE) == SFmode || (MODE) == TFmode) #define VALID_MMX_REG_MODE_3DNOW(MODE) \ ((MODE) == V2SFmode || (MODE) == SFmode) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bfbe58fe084e..449213da5ac5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-12-15 Richard Henderson + + * gcc.target/i386/i386.exp: New harness. + * gcc.target/i386/vect-args.c: New. + 2004-12-15 David Edelsohn * gcc.dg/20040813-1.c: Skip for *-*-aix*. diff --git a/gcc/testsuite/gcc.target/i386/i386.exp b/gcc/testsuite/gcc.target/i386/i386.exp new file mode 100644 index 000000000000..4b92d4ab0a88 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/i386.exp @@ -0,0 +1,54 @@ +# Copyright (C) 1997, 2004 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't a SPARC target. +if { ![istarget i?86*-*-*] && ![istarget x86_64-*-*] } then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Special case compilation of vect-args.c so we don't have to +# replicate it 10 times. +foreach type { "" -mmmx -m3dnow -msse -msse2 } { + foreach level { "" -O } { + set flags "$type $level" + verbose -log "Testing vect-args, $flags" 1 + dg-test $srcdir/$subdir/vect-args.c $flags "" + } +} + +# Everything else. +set tests [lsort [find $srcdir/$subdir *.\[cS\]]] +set tests [prune $tests $srcdir/$subdir/vect-args.c] + +# Main loop. +dg-runtest $tests "" $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/i386/vect-args.c b/gcc/testsuite/gcc.target/i386/vect-args.c new file mode 100644 index 000000000000..94b602d913a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/vect-args.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-w" } */ + +/* SSE1 and SSE2 modes. */ +typedef unsigned char V16QImode __attribute__((vector_size(16))); +typedef unsigned short V8HImode __attribute__((vector_size(16))); +typedef unsigned int V4SImode __attribute__((vector_size(16))); +typedef unsigned long long V2DImode __attribute__((vector_size(16))); +typedef float V4SFmode __attribute__((vector_size(16))); +typedef double V2DFmode __attribute__((vector_size(16))); + +/* MMX and 3DNOW modes. */ +typedef unsigned char V8QImode __attribute__((vector_size(8))); +typedef unsigned short V4HImode __attribute__((vector_size(8))); +typedef unsigned int V2SImode __attribute__((vector_size(8))); +typedef float V2SFmode __attribute__((vector_size(8))); + +/* Test argument loading and unloading of each. */ +#define TEST(TYPE) \ +extern TYPE data_##TYPE; \ +void r_##TYPE (TYPE x) { data_##TYPE = x; } \ +void s_##TYPE (void) { r_##TYPE (data_##TYPE); } + +TEST(V16QImode) +TEST(V8HImode) +TEST(V4SImode) +TEST(V2DImode) +TEST(V4SFmode) +TEST(V2DFmode) +TEST(V8QImode) +TEST(V4HImode) +TEST(V2SImode) +TEST(V2SFmode) -- 2.43.5