Index: gcc/config/i386/i386.c =================================================================== --- gcc/config/i386/i386.c (revision 267291) +++ gcc/config/i386/i386.c (working copy) @@ -8990,6 +8990,66 @@ } static rtx +function_value_ms_32 (machine_mode orig_mode, machine_mode mode, + const_tree fntype, const_tree fn, const_tree valtype) +{ + unsigned int regno; + + /* 8-byte vector modes in %mm0. See ix86_return_in_memory for where + we normally prevent this case when mmx is not available. However + some ABIs may require the result to be returned like DImode. */ + if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 8) + regno = FIRST_MMX_REG; + + /* 16-byte vector modes in %xmm0. See ix86_return_in_memory for where + we prevent this case when sse is not available. However some ABIs + may require the result to be returned like integer TImode. */ + else if (mode == TImode + || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16)) + regno = FIRST_SSE_REG; + + /* 32-byte vector modes in %ymm0. */ + else if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 32) + regno = FIRST_SSE_REG; + + /* 64-byte vector modes in %zmm0. */ + else if (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 64) + regno = FIRST_SSE_REG; + + /* Floating point return values in %st(0) + (unless -mno-fp-ret-in-387 or aggregate type of up to 8 bytes). */ + else if (X87_FLOAT_MODE_P (mode) && TARGET_FLOAT_RETURNS_IN_80387 + && (GET_MODE_SIZE (mode) > 8 + || valtype == NULL_TREE || !AGGREGATE_TYPE_P (valtype))) + regno = FIRST_FLOAT_REG; + else + /* Most things go in %eax. */ + regno = AX_REG; + + /* Override FP return register with %xmm0 for local functions when + SSE math is enabled or for functions with sseregparm attribute. */ + if ((fn || fntype) && (mode == SFmode || mode == DFmode)) + { + int sse_level = ix86_function_sseregparm (fntype, fn, false); + if (sse_level == -1) + { + error ("calling %qD with SSE calling convention without " + "SSE/SSE2 enabled", fn); + sorry ("this is a GCC bug that can be worked around by adding " + "attribute used to function called"); + } + else if ((sse_level >= 1 && mode == SFmode) + || (sse_level == 2 && mode == DFmode)) + regno = FIRST_SSE_REG; + } + + /* OImode shouldn't be used directly. */ + gcc_assert (mode != OImode); + + return gen_rtx_REG (orig_mode, regno); +} + +static rtx function_value_64 (machine_mode orig_mode, machine_mode mode, const_tree valtype) { @@ -9063,6 +9123,13 @@ && !COMPLEX_MODE_P (mode)) regno = FIRST_SSE_REG; break; + case 8: + case 4: + if (valtype != NULL_TREE && AGGREGATE_TYPE_P (valtype)) + break; + if (mode == SFmode || mode == DFmode) + regno = FIRST_SSE_REG; + break; default: break; } @@ -9081,8 +9148,13 @@ fn = fntype_or_decl; fntype = fn ? TREE_TYPE (fn) : fntype_or_decl; - if (TARGET_64BIT && ix86_function_type_abi (fntype) == MS_ABI) - return function_value_ms_64 (orig_mode, mode, valtype); + if (ix86_function_type_abi (fntype) == MS_ABI) + { + if (TARGET_64BIT) + return function_value_ms_64 (orig_mode, mode, valtype); + else + return function_value_ms_32 (orig_mode, mode, fntype, fn, valtype); + } else if (TARGET_64BIT) return function_value_64 (orig_mode, mode, valtype); else