diff options
author | Martynas Venckus <martynas@cvs.openbsd.org> | 2008-08-27 00:31:02 +0000 |
---|---|---|
committer | Martynas Venckus <martynas@cvs.openbsd.org> | 2008-08-27 00:31:02 +0000 |
commit | 956619bc344de12d953fdca78c7ecc3086bf4f78 (patch) | |
tree | f4d96183629eac8cdca64dee3f0ed0aa3af07e39 | |
parent | 93c807fc38f9d2792768aecf961cb07e1a8d0b26 (diff) |
fix 128-bit division. gcc mangled arguments when passing to the
__udivti3, because MUST_PASS_IN_STACK always returned 1 on amd64;
pr#5780
reported by Simon Kuhnle
tested by Simon Kuhnle, sthen@, brad@
double-checked & tweak from miod@
ok sthen@, brad@
-rw-r--r-- | gnu/usr.bin/gcc/gcc/calls.c | 42 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/gcc/config/i386/i386-protos.h | 1 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/gcc/config/i386/i386.c | 15 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/gcc/config/i386/i386.h | 56 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/gcc/expr.h | 31 |
5 files changed, 100 insertions, 45 deletions
diff --git a/gnu/usr.bin/gcc/gcc/calls.c b/gnu/usr.bin/gcc/gcc/calls.c index 8c3ad6e837e..fb9d3a2d4b8 100644 --- a/gnu/usr.bin/gcc/gcc/calls.c +++ b/gnu/usr.bin/gcc/gcc/calls.c @@ -4694,3 +4694,45 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) return sibcall_failure; } + +/* Nonzero if we do not know how to pass TYPE solely in registers. + We cannot do so in the following cases: + + - if the type has variable size + - if the type is marked as addressable (it is required to be constructed + into the stack) + - if the padding and mode of the type is such that a copy into a register + would put it into the wrong part of the register. + + Which padding can't be supported depends on the byte endianness. + + A value in a register is implicitly padded at the most significant end. + On a big-endian machine, that is the lower end in memory. + So a value padded in memory at the upper end can't go in a register. + For a little-endian machine, the reverse is true. */ + +bool +default_must_pass_in_stack (enum machine_mode mode, tree type) +{ + if (!type) + return false; + + /* If the type has variable size... */ + if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + return true; + + /* If the type is marked as addressable (it is required + to be constructed into the stack)... */ + if (TREE_ADDRESSABLE (type)) + return true; + + /* If the padding and mode of the type is such that a copy into + a register would put it into the wrong part of the register. */ + if (mode == BLKmode + && int_size_in_bytes (type) % (PARM_BOUNDARY / BITS_PER_UNIT) + && (FUNCTION_ARG_PADDING (mode, type) + == (BYTES_BIG_ENDIAN ? upward : downward))) + return true; + + return false; +} diff --git a/gnu/usr.bin/gcc/gcc/config/i386/i386-protos.h b/gnu/usr.bin/gcc/gcc/config/i386/i386-protos.h index b5ddb37bb2a..1c1d650a8cc 100644 --- a/gnu/usr.bin/gcc/gcc/config/i386/i386-protos.h +++ b/gnu/usr.bin/gcc/gcc/config/i386/i386-protos.h @@ -221,6 +221,7 @@ extern int x86_field_alignment PARAMS ((tree, int)); extern rtx ix86_tls_get_addr PARAMS ((void)); extern void x86_machine_dependent_reorg PARAMS ((rtx)); +extern bool ix86_must_pass_in_stack PARAMS ((enum machine_mode mode, tree)); /* In winnt.c */ extern int i386_pe_dllexport_name_p PARAMS ((const char *)); diff --git a/gnu/usr.bin/gcc/gcc/config/i386/i386.c b/gnu/usr.bin/gcc/gcc/config/i386/i386.c index ba0b78c822d..a94bc410f22 100644 --- a/gnu/usr.bin/gcc/gcc/config/i386/i386.c +++ b/gnu/usr.bin/gcc/gcc/config/i386/i386.c @@ -1727,6 +1727,10 @@ classify_argument (mode, type, classes, bit_offset) if (bytes < 0) return 0; + if (mode != VOIDmode + && MUST_PASS_IN_STACK (mode, type)) + return 0; + if (type && AGGREGATE_TYPE_P (type)) { int i; @@ -14812,4 +14816,15 @@ x86_machine_dependent_reorg (first) } } +/* Return if we do not know how to pass TYPE solely in registers. */ +bool +ix86_must_pass_in_stack (mode, type) + enum machine_mode mode; + tree type; +{ + if (default_must_pass_in_stack (mode, type)) + return true; + return (!TARGET_64BIT && type && mode == TImode); +} + #include "gt-i386.h" diff --git a/gnu/usr.bin/gcc/gcc/config/i386/i386.h b/gnu/usr.bin/gcc/gcc/config/i386/i386.h index ead133bfb62..f8d521df5fd 100644 --- a/gnu/usr.bin/gcc/gcc/config/i386/i386.h +++ b/gnu/usr.bin/gcc/gcc/config/i386/i386.h @@ -114,10 +114,11 @@ extern int target_flags; #define MASK_MMX 0x00002000 /* Support MMX regs/builtins */ #define MASK_SSE 0x00004000 /* Support SSE regs/builtins */ #define MASK_SSE2 0x00008000 /* Support SSE2 regs/builtins */ -#define MASK_3DNOW 0x00010000 /* Support 3Dnow builtins */ -#define MASK_3DNOW_A 0x00020000 /* Support Athlon 3Dnow builtins */ -#define MASK_128BIT_LONG_DOUBLE 0x00040000 /* long double size is 128bit */ -#define MASK_64BIT 0x00080000 /* Produce 64bit code */ +#define MASK_SSE3 0x00010000 /* Support SSE3 builtins */ +#define MASK_3DNOW 0x00020000 /* Support 3Dnow builtins */ +#define MASK_3DNOW_A 0x00040000 /* Support Athlon 3Dnow builtins */ +#define MASK_128BIT_LONG_DOUBLE 0x00080000 /* long double size is 128bit */ +#define MASK_64BIT 0x00100000 /* Produce 64bit code */ /* Unused: 0x03f0000 */ @@ -271,8 +272,9 @@ extern int x86_prefetch_sse; #define ASSEMBLER_DIALECT (ix86_asm_dialect) -#define TARGET_SSE ((target_flags & (MASK_SSE | MASK_SSE2)) != 0) +#define TARGET_SSE ((target_flags & MASK_SSE) != 0) #define TARGET_SSE2 ((target_flags & MASK_SSE2) != 0) +#define TARGET_SSE3 ((target_flags & MASK_SSE3) != 0) #define TARGET_SSE_MATH ((ix86_fpmath & FPMATH_SSE) != 0) #define TARGET_MIX_SSE_I387 ((ix86_fpmath & FPMATH_SSE) \ && (ix86_fpmath & FPMATH_387)) @@ -300,6 +302,8 @@ extern int x86_prefetch_sse; { "486", 0, "" /*Deprecated.*/}, \ { "pentium", 0, "" /*Deprecated.*/}, \ { "pentiumpro", 0, "" /*Deprecated.*/}, \ + { "pni", 0, "" /*Deprecated.*/}, \ + { "no-pni", 0, "" /*Deprecated.*/}, \ { "intel-syntax", 0, "" /*Deprecated.*/}, \ { "no-intel-syntax", 0, "" /*Deprecated.*/}, \ { "rtd", MASK_RTD, \ @@ -366,6 +370,10 @@ extern int x86_prefetch_sse; N_("Support MMX, SSE and SSE2 built-in functions and code generation") }, \ { "no-sse2", -MASK_SSE2, \ N_("Do not support MMX, SSE and SSE2 built-in functions and code generation") }, \ + { "sse3", MASK_SSE3, \ + N_("Support MMX, SSE, SSE2 and SSE3 built-in functions and code generation") }, \ + { "no-sse3", -MASK_SSE3, \ + N_("Do not support MMX, SSE, SSE2 and SSE3 built-in functions and code generation") }, \ { "128bit-long-double", MASK_128BIT_LONG_DOUBLE, \ N_("sizeof(long double) is 16") }, \ { "96bit-long-double", -MASK_128BIT_LONG_DOUBLE, \ @@ -469,6 +477,10 @@ extern int x86_prefetch_sse; %n`-mpentium' is deprecated. Use `-march=pentium' or `-mcpu=pentium' instead.\n} \ %{mpentiumpro:-mcpu=pentiumpro \ %n`-mpentiumpro' is deprecated. Use `-march=pentiumpro' or `-mcpu=pentiumpro' instead.\n}} \ +%{mpni:-msse3 \ +%n`-mpni' is deprecated. Use `-msse3' instead.\n} \ +%{mno-pni:-mno-sse3 \ +%n`-mno-pni' is deprecated. Use `-mno-sse3' instead.\n} \ %{mintel-syntax:-masm=intel \ %n`-mintel-syntax' is deprecated. Use `-masm=intel' instead.\n} \ %{mno-intel-syntax:-masm=att \ @@ -554,6 +566,11 @@ extern int x86_prefetch_sse; builtin_define ("__SSE__"); \ if (TARGET_SSE2) \ builtin_define ("__SSE2__"); \ + if (TARGET_SSE3) \ + { \ + builtin_define ("__SSE3__"); \ + builtin_define ("__PNI__"); \ + } \ if (TARGET_SSE_MATH && TARGET_SSE) \ builtin_define ("__SSE_MATH__"); \ if (TARGET_SSE_MATH && TARGET_SSE2) \ @@ -1621,18 +1638,7 @@ enum reg_class definition that is usually appropriate, refer to expr.h for additional documentation. If `REG_PARM_STACK_SPACE' is defined, the argument will be computed in the stack and then loaded into a register. */ -#define MUST_PASS_IN_STACK(MODE, TYPE) \ - ((TYPE) != 0 \ - && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \ - || TREE_ADDRESSABLE (TYPE) \ - || ((MODE) == TImode) \ - || ((MODE) == BLKmode \ - && ! ((TYPE) != 0 \ - && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ - && 0 == (int_size_in_bytes (TYPE) \ - % (PARM_BOUNDARY / BITS_PER_UNIT))) \ - && (FUNCTION_ARG_PADDING (MODE, TYPE) \ - == (BYTES_BIG_ENDIAN ? upward : downward))))) +#define MUST_PASS_IN_STACK(MODE, TYPE) ix86_must_pass_in_stack ((MODE), (TYPE)) /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. @@ -2480,6 +2486,22 @@ enum ix86_builtins IX86_BUILTIN_MFENCE, IX86_BUILTIN_LFENCE, + /* Prescott New Instructions. */ + IX86_BUILTIN_ADDSUBPS, + IX86_BUILTIN_HADDPS, + IX86_BUILTIN_HSUBPS, + IX86_BUILTIN_MOVSHDUP, + IX86_BUILTIN_MOVSLDUP, + IX86_BUILTIN_ADDSUBPD, + IX86_BUILTIN_HADDPD, + IX86_BUILTIN_HSUBPD, + IX86_BUILTIN_LOADDDUP, + IX86_BUILTIN_MOVDDUP, + IX86_BUILTIN_LDDQU, + + IX86_BUILTIN_MONITOR, + IX86_BUILTIN_MWAIT, + IX86_BUILTIN_MAX }; diff --git a/gnu/usr.bin/gcc/gcc/expr.h b/gnu/usr.bin/gcc/gcc/expr.h index c38cd9946c9..c6b1e2385ba 100644 --- a/gnu/usr.bin/gcc/gcc/expr.h +++ b/gnu/usr.bin/gcc/gcc/expr.h @@ -159,34 +159,9 @@ enum direction {none, upward, downward}; /* Value has this type. */ #define PRETEND_OUTGOING_VARARGS_NAMED 0 #endif -/* Nonzero if we do not know how to pass TYPE solely in registers. - We cannot do so in the following cases: - - - if the type has variable size - - if the type is marked as addressable (it is required to be constructed - into the stack) - - if the padding and mode of the type is such that a copy into a register - would put it into the wrong part of the register. - - Which padding can't be supported depends on the byte endianness. - - A value in a register is implicitly padded at the most significant end. - On a big-endian machine, that is the lower end in memory. - So a value padded in memory at the upper end can't go in a register. - For a little-endian machine, the reverse is true. */ - -#ifndef MUST_PASS_IN_STACK -#define MUST_PASS_IN_STACK(MODE,TYPE) \ - ((TYPE) != 0 \ - && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \ - || TREE_ADDRESSABLE (TYPE) \ - || ((MODE) == BLKmode \ - && ! ((TYPE) != 0 && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ - && 0 == (int_size_in_bytes (TYPE) \ - % (PARM_BOUNDARY / BITS_PER_UNIT))) \ - && (FUNCTION_ARG_PADDING (MODE, TYPE) \ - == (BYTES_BIG_ENDIAN ? upward : downward))))) -#endif +/* Nonzero if we do not know how to pass TYPE solely in registers. */ +extern bool default_must_pass_in_stack PARAMS((enum machine_mode, tree)); +#define MUST_PASS_IN_STACK(MODE,TYPE) default_must_pass_in_stack(MODE, TYPE) /* Nonzero if type TYPE should be returned in memory. Most machines can use the following default definition. */ |