@@ -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 {