+/* Write into the appropriate registers a function return value stored
+ in VALBUF of type TYPE, given in virtual format. */
+
+void
+i386_store_return_value (struct type *type, char *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) == 1)
+ {
+ i386_store_return_value (TYPE_FIELD_TYPE (type, 0), valbuf);
+ return;
+ }
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ unsigned int fstat;
+
+ if (NUM_FREGS == 0)
+ {
+ warning ("Cannot set floating-point return value.");
+ return;
+ }
+
+ /* Returning floating-point values is a bit tricky. Apart from
+ storing the return value in %st(0), we have to simulate the
+ state of the FPU at function return point. */
+
+ if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT
+ && TARGET_LONG_DOUBLE_FORMAT == &floatformat_i387_ext)
+ {
+ /* Copy straight over. */
+ write_register_bytes (REGISTER_BYTE (FP0_REGNUM), valbuf,
+ FPU_REG_RAW_SIZE);
+ }
+ else
+ {
+ char buf[FPU_REG_RAW_SIZE];
+ DOUBLEST val;
+
+ /* Convert the value found in VALBUF to the extended
+ floating-point format used by the FPU. This is probably
+ not exactly how it would happen on the target itself, but
+ it is the best we can do. */
+ val = extract_floating (valbuf, TYPE_LENGTH (type));
+ floatformat_from_doublest (&floatformat_i387_ext, &val, buf);
+ write_register_bytes (REGISTER_BYTE (FP0_REGNUM), buf,
+ FPU_REG_RAW_SIZE);
+ }
+
+ /* Set the top of the floating-point register stack to 7. The
+ actual value doesn't really matter, but 7 is what a normal
+ function return would end up with if the program started out
+ with a freshly initialized FPU. */
+ fstat = read_register (FSTAT_REGNUM);
+ fstat |= (7 << 11);
+ write_register (FSTAT_REGNUM, fstat);
+
+ /* Mark %st(1) through %st(7) as empty. Since we set the top of
+ the floating-point register stack to 7, the appropriate value
+ for the tag word is 0x3fff. */
+ write_register (FTAG_REGNUM, 0x3fff);
+ }
+ else
+ {
+ int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM);
+ int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM);
+
+ if (len <= low_size)
+ write_register_bytes (REGISTER_BYTE (LOW_RETURN_REGNUM), valbuf, len);
+ else if (len <= (low_size + high_size))
+ {
+ write_register_bytes (REGISTER_BYTE (LOW_RETURN_REGNUM),
+ valbuf, low_size);
+ write_register_bytes (REGISTER_BYTE (HIGH_RETURN_REGNUM),
+ valbuf + low_size, len - low_size);
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ "Cannot store return value of %d bytes long.", len);
+ }
+}
+
+/* Extract from an array REGBUF containing the (raw) register state
+ the address in which a function should return its structure value,
+ as a CORE_ADDR. */
+
+CORE_ADDR
+i386_extract_struct_value_address (char *regbuf)
+{
+ return extract_address (®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)],
+ REGISTER_RAW_SIZE (LOW_RETURN_REGNUM));
+}
+\f
+
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. Perhaps %esi and %edi should go here, but
+ potentially they could be used for things other than address. */
+
+struct type *
+i386_register_virtual_type (int regnum)
+{
+ if (regnum == PC_REGNUM || regnum == FP_REGNUM || regnum == SP_REGNUM)
+ return lookup_pointer_type (builtin_type_void);
+
+ if (IS_FP_REGNUM (regnum))
+ return builtin_type_long_double;
+
+ if (IS_SSE_REGNUM (regnum))
+ return builtin_type_v4sf;
+
+ return builtin_type_int;
+}
+
+/* Return true iff register REGNUM's virtual format is different from
+ its raw format. Note that this definition assumes that the host
+ supports IEEE 32-bit floats, since it doesn't say that SSE
+ registers need conversion. Even if we can't find a counterexample,
+ this is still sloppy. */
+
+int
+i386_register_convertible (int regnum)
+{
+ return IS_FP_REGNUM (regnum);
+}
+
+/* Convert data from raw format for register REGNUM in buffer FROM to
+ virtual format with type TYPE in buffer TO. */
+
+void
+i386_register_convert_to_virtual (int regnum, struct type *type,
+ char *from, char *to)
+{
+ char buf[12];
+ DOUBLEST d;
+
+ /* We only support floating-point values. */
+ if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ {
+ warning ("Cannot convert floating-point register value "
+ "to non-floating-point type.");
+ memset (to, 0, TYPE_LENGTH (type));
+ return;
+ }
+
+ /* First add the necessary padding. */
+ memcpy (buf, from, FPU_REG_RAW_SIZE);
+ memset (buf + FPU_REG_RAW_SIZE, 0, sizeof buf - FPU_REG_RAW_SIZE);
+
+ /* Convert to TYPE. This should be a no-op, if TYPE is equivalent
+ to the extended floating-point format used by the FPU. */
+ d = extract_floating (buf, sizeof buf);
+ store_floating (to, TYPE_LENGTH (type), d);
+}
+
+/* Convert data from virtual format with type TYPE in buffer FROM to
+ raw format for register REGNUM in buffer TO. */
+
+void
+i386_register_convert_to_raw (struct type *type, int regnum,
+ char *from, char *to)
+{
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 12);
+
+ /* Simply omit the two unused bytes. */
+ memcpy (to, from, FPU_REG_RAW_SIZE);
+}
+\f
+