Fix IA32 _Decimal128 argument-passing ABI
Joseph S. Myers
joseph@codesourcery.com
Fri Jun 27 04:30:00 GMT 2008
The IA32 ABI for passing decimal floating-point arguments (and vector
arguments) to functions was settled in GCC 4.3.1: _Decimal128
arguments and SSE vectors are 16-byte-aligned, as are structures and
unions containing such types at any level, while other arguments
(including _Decimal64) are 4-byte-aligned.
This patch implements this ABI in GDB, so fixing the following test
failures when testing with GCC 4.3 branch on i686-pc-linux-gnu:
FAIL: gdb.base/dfp-test.exp: Backtrace function with correct _Decimal128 arguments.
FAIL: gdb.base/dfp-test.exp: Correct _Decimal128 return value from called function.
FAIL: gdb.base/dfp-test.exp: Call function with mixed decimal float arguments TEST.
FAIL: gdb.base/dfp-test.exp: Call function with mixed decimal float arguments.
FAIL: gdb.base/dfp-test.exp: Call function with many mixed decimal float arguments.
OK to commit?
2008-06-26 Joseph Myers <joseph@codesourcery.com>
* i386-tdep.c (i386_16_byte_align_p): New.
(i386_push_dummy_call): Determine stack space required for
arguments going forwards allowing for 16-byte alignment, then push
arguments going forwards.
Index: i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.259
diff -u -p -r1.259 i386-tdep.c
--- i386-tdep.c 11 Jun 2008 22:03:49 -0000 1.259
+++ i386-tdep.c 26 Jun 2008 23:14:32 -0000
@@ -1521,6 +1521,32 @@ i386_get_longjmp_target (struct frame_in
}
+/* Check whether TYPE must be 16-byte-aligned when passed as a
+ function argument. 16-byte vectors, _Decimal128 and structures or
+ unions containing such types must be 16-byte-aligned; other
+ arguments are 4-byte-aligned. */
+
+static int
+i386_16_byte_align_p (struct type *type)
+{
+ type = check_typedef (type);
+ if ((TYPE_CODE (type) == TYPE_CODE_DECFLOAT
+ || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)))
+ && TYPE_LENGTH (type) == 16)
+ return 1;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ int i;
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ if (i386_16_byte_align_p (TYPE_FIELD_TYPE (type, i)))
+ return 1;
+ }
+ }
+ return 0;
+}
+
static CORE_ADDR
i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
@@ -1529,29 +1555,68 @@ i386_push_dummy_call (struct gdbarch *gd
{
gdb_byte buf[4];
int i;
+ int write_pass;
+ int args_space = 0;
+
+ /* Determine the total space required for arguments and struct
+ return address in a first pass (allowing for 16-byte-aligned
+ arguments), then push arguments in a second pass. */
- /* Push arguments in reverse order. */
- for (i = nargs - 1; i >= 0; i--)
+ for (write_pass = 0; write_pass < 2; write_pass++)
{
- int len = TYPE_LENGTH (value_enclosing_type (args[i]));
+ int args_space_used = 0;
+ int have_16_byte_aligned_arg = 0;
- /* The System V ABI says that:
+ if (struct_return)
+ {
+ if (write_pass)
+ {
+ /* Push value address. */
+ store_unsigned_integer (buf, 4, struct_addr);
+ write_memory (sp, buf, 4);
+ args_space_used += 4;
+ }
+ else
+ args_space += 4;
+ }
- "An argument's size is increased, if necessary, to make it a
- multiple of [32-bit] words. This may require tail padding,
- depending on the size of the argument."
+ for (i = 0; i < nargs; i++)
+ {
+ int len = TYPE_LENGTH (value_enclosing_type (args[i]));
- This makes sure the stack stays word-aligned. */
- sp -= (len + 3) & ~3;
- write_memory (sp, value_contents_all (args[i]), len);
- }
+ if (write_pass)
+ {
+ if (i386_16_byte_align_p (value_enclosing_type (args[i])))
+ args_space_used = align_up (args_space_used, 16);
+
+ write_memory (sp + args_space_used,
+ value_contents_all (args[i]), len);
+ /* The System V ABI says that:
+
+ "An argument's size is increased, if necessary, to make it a
+ multiple of [32-bit] words. This may require tail padding,
+ depending on the size of the argument."
+
+ This makes sure the stack stays word-aligned. */
+ args_space_used += align_up (len, 4);
+ }
+ else
+ {
+ if (i386_16_byte_align_p (value_enclosing_type (args[i])))
+ {
+ args_space = align_up (args_space, 16);
+ have_16_byte_aligned_arg = 1;
+ }
+ args_space += align_up (len, 4);
+ }
+ }
- /* Push value address. */
- if (struct_return)
- {
- sp -= 4;
- store_unsigned_integer (buf, 4, struct_addr);
- write_memory (sp, buf, 4);
+ if (!write_pass)
+ {
+ if (have_16_byte_aligned_arg)
+ args_space = align_up (args_space, 16);
+ sp -= args_space;
+ }
}
/* Store return address. */
--
Joseph S. Myers
joseph@codesourcery.com
More information about the Gdb-patches
mailing list