While working on a modification to libgo I ran into a bug with -fsplit-stack support for 32-bit x86. When a function has a stack frame more than 256 bytes, it needs a scratch register to add add the stack frame size to the stack pointer register. This happens at the very beginning of the function, so the scratch register can be any caller saved register that does not hold a function argument. On 32-bit x86 such a register is normally available, but that may not be the case if the registers are used for parameters. The ix86_function_regparm function works out how many registers to use for parameters for a local function. It checks to make sure that it leaves a scratch register available when using -fsplit-stack, and it checks to make sure that it leaves the static chain register available if it is required. Unfortunately, it failed to check for the combination of the two, so using -fsplit-stack with a nested local function that uses a static chain and has a large enough stack frame could in some cases cause the compiler to ICE saying "-fsplit-stack does not support 2 register parameters for a nested function".
This patch fixes this case. It seems fairly obvious to me, so I plan to check it in sometime tomorrow after giving people a chance to comment. I don't have a test case in C, but future versions of libgo will implicitly include a test case. Ian 2017-03-16 Ian Lance Taylor <i...@google.com> * config/i386/i386.c (ix86_function_regparm): Save an extra register for -fsplit-stack with DECL_STATIC_CHAIN.
Index: config/i386/i386.c =================================================================== --- config/i386/i386.c (revision 246212) +++ config/i386/i386.c (working copy) @@ -7975,8 +7975,14 @@ local_regparm = 2; /* Save a register for the split stack. */ - if (local_regparm == 3 && flag_split_stack) - local_regparm = 2; + if (flag_split_stack) + { + if (local_regparm == 3) + local_regparm = 2; + else if (local_regparm == 2 + && DECL_STATIC_CHAIN (target->decl)) + local_regparm = 1; + } /* Each fixed register usage increases register pressure, so less registers should be used for argument passing.