From 069a0102575cea4217c41eab66c8304d38715846 Mon Sep 17 00:00:00 2001 From: martynas Date: Wed, 27 Aug 2008 00:31:01 +0000 Subject: [PATCH] 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@ --- gnu/usr.bin/gcc/gcc/calls.c | 42 +++++++++++++++++++ gnu/usr.bin/gcc/gcc/config/i386/i386-protos.h | 1 + gnu/usr.bin/gcc/gcc/config/i386/i386.c | 15 +++++++ gnu/usr.bin/gcc/gcc/config/i386/i386.h | 13 +----- gnu/usr.bin/gcc/gcc/expr.h | 31 ++------------ 5 files changed, 62 insertions(+), 40 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 796b48bf347..f8d521df5fd 100644 --- a/gnu/usr.bin/gcc/gcc/config/i386/i386.h +++ b/gnu/usr.bin/gcc/gcc/config/i386/i386.h @@ -1638,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. 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. */ -- 2.20.1