PR target/82002 Part 2: Correct non-immediate offset/invalid INSN
authorDaniel Santos <daniel.santos@pobox.com>
Sat, 4 Nov 2017 22:38:43 +0000 (22:38 +0000)
committerDaniel Santos <dansan@gcc.gnu.org>
Sat, 4 Nov 2017 22:38:43 +0000 (22:38 +0000)
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
gcc/config/i386/i386.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr82002-2a.c
gcc/testsuite/gcc.target/i386/pr82002-2b.c

index 806732359b657af270956a70631dea1413819b31..ec8af50fa050804e6285e3de42051db60a0de910 100644 (file)
@@ -1,3 +1,13 @@
+2017-11-04  Daniel Santos  <daniel.santos@pobox.com>
+
+       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  <law@redhat.com>
 
        * config/i386/i386.c (ix86_emit_restore_reg_using_pop): Prototype.
index 1b837554609850393bb0d419edb1e354f9edba49..4123edf982f35eca69daf32aef7b95f75231d639 100644 (file)
@@ -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.  */
index 854d957170086b7412aa256673f0f98ac7323de9..e4ab15974e06b24b077d7366cd800efd9e7e7ee6 100644 (file)
@@ -1,3 +1,8 @@
+2017-11-04  Daniel Santos  <daniel.santos@pobox.com>
+
+       gcc.target/i386/pr82002-2a.c: Change from xfail to fail.
+       gcc.target/i386/pr82002-2b.c: Likewise.
+
 2017-11-04  Andre Vehreschild  <vehre@gcc.gnu.org>
 
        * gfortran.dg/coarray/send_char_array_1.f90: New test.
index bc85080ba8e68146fd0d490979ed6cd3e2a9eb4e..c31440debe26ce8d20acfe58dce318f08f275128 100644 (file)
@@ -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
index 10e44cd7b1d18927e3645dab54f9cb1822fc8002..939e069517d166b236f52c6e6707026248ce690c 100644 (file)
@@ -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