This C++ class adds the basic support for foutline-msabi-xlogues by
manging the layout (where registers are stored based upon and other
facets of the optimization) and providing the proper symbol rtx for the
required stub.

xlouge_layout should not be used until a call to
ix86_compute_frame_layout as it's behavior is dependent upon data in
ctrl and cfun->machine. Once ix86_compute_frame_layout has been called,
the static member function xlouge_layout::get_instance can be used to
retrieve the appropriate (constant) instance of xlouge_layout.
---
 gcc/config/i386/i386.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 218 insertions(+)

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 4cc3c8f..f39b847 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -2429,6 +2429,224 @@ unsigned const 
x86_64_ms_sysv_extra_clobbered_registers[12] =
   XMM12_REG, XMM13_REG, XMM14_REG, XMM15_REG
 };
 
+enum xlogue_stub {
+  XLOGUE_STUB_SAVE,
+  XLOGUE_STUB_RESTORE,
+  XLOGUE_STUB_RESTORE_TAIL,
+  XLOGUE_STUB_SAVE_HFP,
+  XLOGUE_STUB_RESTORE_HFP,
+  XLOGUE_STUB_RESTORE_HFP_TAIL,
+
+  XLOGUE_STUB_COUNT
+};
+
+enum xlogue_stub_sets {
+  XLOGUE_SET_ALIGNED,
+  XLOGUE_SET_ALIGNED_PLUS_8,
+  XLOGUE_SET_UNALIGNED,
+
+  XLOGUE_SET_COUNT
+};
+
+/* Register save/restore layout used by an out-of-line stubs.  */
+class xlogue_layout {
+public:
+  struct reginfo {
+    unsigned regno;
+    HOST_WIDE_INT offset;      /* Offset used by stub base pointer (rax or
+                                  rsi) to where each register is stored.  */
+  };
+
+  unsigned get_nregs () const                  {return m_nregs;}
+  HOST_WIDE_INT get_stack_align_off_in () const        {return 
m_stack_align_off_in;}
+
+  const reginfo &get_reginfo (unsigned reg) const
+    {
+      gcc_assert (reg < m_nregs);
+      return m_regs[reg];
+    }
+
+  /* Returns an rtx for the stub's symbol based upon
+       1.) the specified stub (save, restore or restore_ret) and
+       2.) the value of cfun->machine->outline_ms_sysv_extra_regs and
+       3.) rather or not stack alignment is being performed.  */
+  rtx get_stub_rtx (enum xlogue_stub stub) const;
+
+  /* Returns the amount of stack space (including padding) that the stub
+     needs to store registers based upon data in the machine_function.  */
+  HOST_WIDE_INT get_stack_space_used () const
+    {
+      const struct machine_function &m = *cfun->machine;
+      unsigned last_reg = m.outline_ms_sysv_extra_regs + MIN_REGS;
+
+      gcc_assert (m.outline_ms_sysv_extra_regs <= MAX_EXTRA_REGS);
+      return m_regs[last_reg - 1].offset
+            + (m.outline_ms_sysv_pad_out ? 8 : 0)
+            + STUB_INDEX_OFFSET;
+    }
+
+  /* Returns the offset for the base pointer used by the stub.  */
+  HOST_WIDE_INT get_stub_ptr_offset () const
+    {
+      return STUB_INDEX_OFFSET + m_stack_align_off_in;
+    }
+
+  static const struct xlogue_layout &get_instance ();
+
+  static const HOST_WIDE_INT STUB_INDEX_OFFSET = 0x70;
+  static const unsigned MIN_REGS = 12;
+  static const unsigned MAX_REGS = 18;
+  static const unsigned MAX_EXTRA_REGS = MAX_REGS - MIN_REGS;
+  static const unsigned VARIANT_COUNT = MAX_EXTRA_REGS + 1;
+  static const unsigned STUB_NAME_MAX_LEN = 16;
+  static const char * const STUB_BASE_NAMES[XLOGUE_STUB_COUNT];
+  static const unsigned REG_ORDER[MAX_REGS];
+  static const unsigned REG_ORDER_REALIGN[MAX_REGS];
+
+private:
+  xlogue_layout ();
+  xlogue_layout (HOST_WIDE_INT stack_align_off_in, bool hfp);
+  xlogue_layout (const xlogue_layout &);
+  ~xlogue_layout ();
+
+  /* True if hard frame pointer is used.  */
+  bool m_hfp;
+
+  /* Max number of register this layout manages.  */
+  unsigned m_nregs;
+
+  /* Incoming offset from 16-byte alignment.  */
+  HOST_WIDE_INT m_stack_align_off_in;
+  struct reginfo m_regs[MAX_REGS];
+  rtx m_syms[XLOGUE_STUB_COUNT][VARIANT_COUNT];
+  char m_stub_names[XLOGUE_STUB_COUNT][VARIANT_COUNT][STUB_NAME_MAX_LEN];
+
+  static const struct xlogue_layout GTY(()) s_instances[XLOGUE_SET_COUNT];
+};
+
+const char * const xlogue_layout::STUB_BASE_NAMES[XLOGUE_STUB_COUNT] = {
+  "savms64",
+  "resms64",
+  "resms64x",
+  "savms64f",
+  "resms64f",
+  "resms64fx"
+};
+
+const unsigned xlogue_layout::REG_ORDER[xlogue_layout::MAX_REGS] = {
+/* The below offset values are where each register is stored for the layout
+   relative to incoming stack pointer.  The value of each m_regs[].offset will
+   be relative to the incoming base pointer (rax or rsi) used by the stub.
+
+                         FP offset     FP offset
+    Register              aligned      aligned + 8     realigned*/
+    XMM15_REG,         /* 0x10         0x18            0x10    */
+    XMM14_REG,         /* 0x20         0x28            0x20    */
+    XMM13_REG,         /* 0x30         0x38            0x30    */
+    XMM12_REG,         /* 0x40         0x48            0x40    */
+    XMM11_REG,         /* 0x50         0x58            0x50    */
+    XMM10_REG,         /* 0x60         0x68            0x60    */
+    XMM9_REG,          /* 0x70         0x78            0x70    */
+    XMM8_REG,          /* 0x80         0x88            0x80    */
+    XMM7_REG,          /* 0x90         0x98            0x90    */
+    XMM6_REG,          /* 0xa0         0xa8            0xa0    */
+    SI_REG,            /* 0xa8         0xb0            0xa8    */
+    DI_REG,            /* 0xb0         0xb8            0xb0    */
+    BX_REG,            /* 0xb8         0xc0            0xb8    */
+    BP_REG,            /* 0xc0         0xc8            N/A     */
+    R12_REG,           /* 0xc8         0xd0            0xc0    */
+    R13_REG,           /* 0xd0         0xd8            0xc8    */
+    R14_REG,           /* 0xd8         0xe0            0xd0    */
+    R15_REG,           /* 0xe0         0xe8            0xd8    */
+};
+
+const struct xlogue_layout GTY(())
+xlogue_layout::s_instances[XLOGUE_SET_COUNT] = {
+  xlogue_layout (0, false),
+  xlogue_layout (8, false),
+  xlogue_layout (0, true)
+};
+
+const struct xlogue_layout &xlogue_layout::get_instance ()
+{
+  enum xlogue_stub_sets stub_set;
+
+  if (crtl->stack_realign_needed)
+    stub_set = XLOGUE_SET_UNALIGNED;
+  else if (cfun->machine->outline_ms_sysv_pad_in)
+    stub_set = XLOGUE_SET_ALIGNED_PLUS_8;
+  else
+    stub_set = XLOGUE_SET_ALIGNED;
+
+  return s_instances[stub_set];
+}
+
+xlogue_layout::xlogue_layout (HOST_WIDE_INT stack_align_off_in, bool hfp)
+  : m_hfp (hfp) , m_nregs (hfp ? 17 : 18),
+    m_stack_align_off_in (stack_align_off_in)
+{
+  memset (m_regs, 0, sizeof (m_regs));
+  memset (m_syms, 0, sizeof (m_syms));
+  memset (m_stub_names, 0, sizeof (m_stub_names));
+
+  gcc_assert (!hfp || !stack_align_off_in);
+  gcc_assert (!(stack_align_off_in & (~8)));
+
+  HOST_WIDE_INT offset = stack_align_off_in;
+  unsigned i, j;
+  for (i = j = 0; i < MAX_REGS; ++i)
+    {
+      unsigned regno = REG_ORDER[i];
+
+      if (regno == BP_REG && hfp)
+       continue;
+      if (SSE_REGNO_P (regno))
+       {
+         offset += 16;
+         /* Verify that SSE regs are always aligned.  */
+         gcc_assert (!((stack_align_off_in + offset) & 15));
+       }
+      else
+       offset += 8;
+
+      m_regs[j].regno    = regno;
+      m_regs[j++].offset = offset - STUB_INDEX_OFFSET;
+    }
+    gcc_assert (j == m_nregs);
+}
+
+xlogue_layout::~xlogue_layout ()
+{
+}
+
+rtx xlogue_layout::get_stub_rtx (enum xlogue_stub stub) const
+{
+  const unsigned n_extra_regs = cfun->machine->outline_ms_sysv_extra_regs;
+  gcc_assert (n_extra_regs <= MAX_EXTRA_REGS);
+  gcc_assert (stub < XLOGUE_STUB_COUNT);
+
+  /* FIXME: For some reason, cached symbols go bad, so disable it for now.
+     Should we just remove the rtx cache or do we need to reset it at some
+     point? */
+  if (true || !m_syms[stub][n_extra_regs])
+    {
+      xlogue_layout *writey_this = const_cast<xlogue_layout*>(this);
+      char *stub_name = writey_this->m_stub_names[stub][n_extra_regs];
+      rtx sym;
+      int res;
+
+      res = snprintf (stub_name, STUB_NAME_MAX_LEN - 1, "__%s_%u",
+                     STUB_BASE_NAMES[stub], 12 + n_extra_regs);
+      gcc_assert (res <= (int)STUB_NAME_MAX_LEN);
+
+      sym = gen_rtx_SYMBOL_REF (Pmode, stub_name);
+      writey_this->m_syms[stub][n_extra_regs] = sym;
+    }
+
+    gcc_assert (m_syms[stub][n_extra_regs]);
+    return m_syms[stub][n_extra_regs];
+}
+
 /* Define the structure for the machine field in struct function.  */
 
 struct GTY(()) stack_local_entry {
-- 
2.9.0

Reply via email to