From 173399a0b4910ce027194cf4cc21d2a8856180d7 Mon Sep 17 00:00:00 2001 From: Daniel Santos Date: Sat, 4 Nov 2017 22:38:43 +0000 Subject: [PATCH] PR target/82002 Part 2: Correct non-immediate offset/invalid INSN When we are realigning the stack pointer, making an ms_abi to sysv_abi call and allocating 2GiB or more on the stack we end up with an invalid INSN due to a non-immediate offset. This occurs both with and without -mcall-ms2sysv-xlogues. Additionally, the stack allocation with -mcall-ms2sysv-xlogues is ignoring (silently disabling) stack checking, stack clash checking and probing. This patch fixes these problems by: 1. No longer allocate stack space in ix86_emit_outlined_ms2sysv_save. 2. Rearrange where we emit SSE saves or stub call: a. Before frame allocation when offset from frame to save area is >= 2GiB. b. After frame allocation when frame is < 2GiB. (Stack allocations prior to the stub call can't be combined with those afterwards, so this is better when possible.) 3. Modify choose_baseaddr to take an optional scratch_regno argument and never return rtx that cannot be used as an immediate. gcc: config/i386/i386.c (choose_basereg): Use optional scratch register and add assertion. (x86_emit_outlined_ms2sysv_save): Use scratch register when needed, and don't allocate stack. (ix86_expand_prologue): Rearrange where SSE saves/stub call is emitted, correct wrong allocation with -mcall-ms2sysv-xlogues. (ix86_emit_outlined_ms2sysv_restore): Fix non-immediate offsets. gcc/testsuite: gcc.target/i386/pr82002-2a.c: Change from xfail to fail. gcc.target/i386/pr82002-2b.c: Likewise. From-SVN: r254412 --- gcc/ChangeLog | 10 ++++ gcc/config/i386/i386.c | 62 +++++++++++++++++----- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.target/i386/pr82002-2a.c | 2 - gcc/testsuite/gcc.target/i386/pr82002-2b.c | 2 - 5 files changed, 64 insertions(+), 17 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 806732359b6..ec8af50fa05 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2017-11-04 Daniel Santos + + config/i386/i386.c (choose_basereg): Use optional scratch + register and add assertion. + (x86_emit_outlined_ms2sysv_save): Use scratch register when + needed, and don't allocate stack. + (ix86_expand_prologue): Rearrange where SSE saves/stub call is + emitted, correct wrong allocation with -mcall-ms2sysv-xlogues. + (ix86_emit_outlined_ms2sysv_restore): Fix non-immediate offsets. + 2017-11-03 Jeff Law * config/i386/i386.c (ix86_emit_restore_reg_using_pop): Prototype. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 1b837554609..4123edf982f 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -11517,12 +11517,15 @@ choose_basereg (HOST_WIDE_INT cfa_offset, rtx &base_reg, an alignment value (in bits) that is preferred or zero and will recieve the alignment of the base register that was selected, irrespective of rather or not CFA_OFFSET is a multiple of that - alignment value. + alignment value. If it is possible for the base register offset to be + non-immediate then SCRATCH_REGNO should specify a scratch register to + use. The valid base registers are taken from CFUN->MACHINE->FS. */ static rtx -choose_baseaddr (HOST_WIDE_INT cfa_offset, unsigned int *align) +choose_baseaddr (HOST_WIDE_INT cfa_offset, unsigned int *align, + unsigned int scratch_regno = INVALID_REGNUM) { rtx base_reg = NULL; HOST_WIDE_INT base_offset = 0; @@ -11536,6 +11539,19 @@ choose_baseaddr (HOST_WIDE_INT cfa_offset, unsigned int *align) choose_basereg (cfa_offset, base_reg, base_offset, 0, align); gcc_assert (base_reg != NULL); + + rtx base_offset_rtx = GEN_INT (base_offset); + + if (!x86_64_immediate_operand (base_offset_rtx, Pmode)) + { + gcc_assert (scratch_regno != INVALID_REGNUM); + + rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno); + emit_move_insn (scratch_reg, base_offset_rtx); + + return gen_rtx_PLUS (Pmode, base_reg, scratch_reg); + } + return plus_constant (Pmode, base_reg, base_offset); } @@ -12801,23 +12817,19 @@ ix86_emit_outlined_ms2sysv_save (const struct ix86_frame &frame) rtx sym, addr; rtx rax = gen_rtx_REG (word_mode, AX_REG); const struct xlogue_layout &xlogue = xlogue_layout::get_instance (); - HOST_WIDE_INT allocate = frame.stack_pointer_offset - m->fs.sp_offset; /* AL should only be live with sysv_abi. */ gcc_assert (!ix86_eax_live_at_start_p ()); + gcc_assert (m->fs.sp_offset >= frame.sse_reg_save_offset); /* Setup RAX as the stub's base pointer. We use stack_realign_offset rather we've actually realigned the stack or not. */ align = GET_MODE_ALIGNMENT (V4SFmode); addr = choose_baseaddr (frame.stack_realign_offset - + xlogue.get_stub_ptr_offset (), &align); + + xlogue.get_stub_ptr_offset (), &align, AX_REG); gcc_assert (align >= GET_MODE_ALIGNMENT (V4SFmode)); - emit_insn (gen_rtx_SET (rax, addr)); - /* Allocate stack if not already done. */ - if (allocate > 0) - pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-allocate), -1, false); + emit_insn (gen_rtx_SET (rax, addr)); /* Get the stub symbol. */ sym = xlogue.get_stub_rtx (frame_pointer_needed ? XLOGUE_STUB_SAVE_HFP @@ -12849,6 +12861,7 @@ ix86_expand_prologue (void) HOST_WIDE_INT allocate; bool int_registers_saved; bool sse_registers_saved; + bool save_stub_call_needed; rtx static_chain = NULL_RTX; if (ix86_function_naked (current_function_decl)) @@ -13024,6 +13037,8 @@ ix86_expand_prologue (void) int_registers_saved = (frame.nregs == 0); sse_registers_saved = (frame.nsseregs == 0); + save_stub_call_needed = (m->call_ms2sysv); + gcc_assert (sse_registers_saved || !save_stub_call_needed); if (frame_pointer_needed && !m->fs.fp_valid) { @@ -13118,10 +13133,28 @@ ix86_expand_prologue (void) target. */ if (TARGET_SEH) m->fs.sp_valid = false; - } - if (m->call_ms2sysv) - ix86_emit_outlined_ms2sysv_save (frame); + /* If SP offset is non-immediate after allocation of the stack frame, + then emit SSE saves or stub call prior to allocating the rest of the + stack frame. This is less efficient for the out-of-line stub because + we can't combine allocations across the call barrier, but it's better + than using a scratch register. */ + else if (!x86_64_immediate_operand (GEN_INT (frame.stack_pointer_offset + - m->fs.sp_realigned_offset), + Pmode)) + { + if (!sse_registers_saved) + { + ix86_emit_save_sse_regs_using_mov (frame.sse_reg_save_offset); + sse_registers_saved = true; + } + else if (save_stub_call_needed) + { + ix86_emit_outlined_ms2sysv_save (frame); + save_stub_call_needed = false; + } + } + } allocate = frame.stack_pointer_offset - m->fs.sp_offset; @@ -13349,6 +13382,8 @@ ix86_expand_prologue (void) ix86_emit_save_regs_using_mov (frame.reg_save_offset); if (!sse_registers_saved) ix86_emit_save_sse_regs_using_mov (frame.sse_reg_save_offset); + else if (save_stub_call_needed) + ix86_emit_outlined_ms2sysv_save (frame); /* For the mcount profiling on 32 bit PIC mode we need to emit SET_GOT in PROLOGUE. */ @@ -13589,8 +13624,9 @@ ix86_emit_outlined_ms2sysv_restore (const struct ix86_frame &frame, /* Setup RSI as the stub's base pointer. */ align = GET_MODE_ALIGNMENT (V4SFmode); - tmp = choose_baseaddr (rsi_offset, &align); + tmp = choose_baseaddr (rsi_offset, &align, SI_REG); gcc_assert (align >= GET_MODE_ALIGNMENT (V4SFmode)); + emit_insn (gen_rtx_SET (rsi, tmp)); /* Get a symbol for the stub. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 854d9571700..e4ab15974e0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-11-04 Daniel Santos + + gcc.target/i386/pr82002-2a.c: Change from xfail to fail. + gcc.target/i386/pr82002-2b.c: Likewise. + 2017-11-04 Andre Vehreschild * gfortran.dg/coarray/send_char_array_1.f90: New test. diff --git a/gcc/testsuite/gcc.target/i386/pr82002-2a.c b/gcc/testsuite/gcc.target/i386/pr82002-2a.c index bc85080ba8e..c31440debe2 100644 --- a/gcc/testsuite/gcc.target/i386/pr82002-2a.c +++ b/gcc/testsuite/gcc.target/i386/pr82002-2a.c @@ -1,7 +1,5 @@ /* { dg-do compile { target lp64 } } */ /* { dg-options "-Ofast -mstackrealign -mabi=ms" } */ -/* { dg-xfail-if "" { *-*-* } } */ -/* { dg-xfail-run-if "" { *-*-* } } */ void __attribute__((sysv_abi)) a (char *); void diff --git a/gcc/testsuite/gcc.target/i386/pr82002-2b.c b/gcc/testsuite/gcc.target/i386/pr82002-2b.c index 10e44cd7b1d..939e069517d 100644 --- a/gcc/testsuite/gcc.target/i386/pr82002-2b.c +++ b/gcc/testsuite/gcc.target/i386/pr82002-2b.c @@ -1,7 +1,5 @@ /* { dg-do compile { target lp64 } } */ /* { dg-options "-Ofast -mstackrealign -mabi=ms -mcall-ms2sysv-xlogues" } */ -/* { dg-xfail-if "" { *-*-* } } */ -/* { dg-xfail-run-if "" { *-*-* } } */ void __attribute__((sysv_abi)) a (char *); void -- 2.30.2