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