From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 58267 invoked by alias); 27 Apr 2017 08:05:07 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 57865 invoked by uid 89); 27 Apr 2017 08:05:03 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.3 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_LOW,RP_MATCHES_RCVD,SPF_PASS autolearn=ham version=3.3.2 spammy=successive, 936 X-HELO: sasl.smtp.pobox.com Received: from pb-smtp2.pobox.com (HELO sasl.smtp.pobox.com) (64.147.108.71) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 27 Apr 2017 08:04:59 +0000 Received: from sasl.smtp.pobox.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 40860883A5; Thu, 27 Apr 2017 04:05:01 -0400 (EDT) Received: from pb-smtp2.nyi.icgroup.com (unknown [127.0.0.1]) by pb-smtp2.pobox.com (Postfix) with ESMTP id 2F2E4883A3; Thu, 27 Apr 2017 04:05:01 -0400 (EDT) Received: from localhost.localdomain (unknown [76.215.41.237]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by pb-smtp2.pobox.com (Postfix) with ESMTPSA id 142288839B; Thu, 27 Apr 2017 04:04:59 -0400 (EDT) From: Daniel Santos To: gcc-patches , Uros Bizjak , Jan Hubicka Subject: [PATCH 06/12] [i386] Add class xlogue_layout and new fields to struct machine_function Date: Thu, 27 Apr 2017 08:51:00 -0000 Message-Id: <20170427080932.11703-6-daniel.santos@pobox.com> In-Reply-To: <49e81c0b-07a4-22df-d7c3-2439177ac7cf@pobox.com> References: <49e81c0b-07a4-22df-d7c3-2439177ac7cf@pobox.com> X-Pobox-Relay-ID: 35FE6B86-2B20-11E7-9758-C260AE2156B6-06139138!pb-smtp2.pobox.com X-IsSubscribed: yes X-SW-Source: 2017-04/txt/msg01353.txt.bz2 Of the new fields added to struct machine_function, call_ms2sysv is initially set in ix86_expand_call, but may later be cleared when ix86_compute_frame_layout is called (both of these are in subsequent patch). If it is not cleared, then the remaining new fields will be set in ix86_compute_frame_layout (also a subsequent patch). The new class xlogue_layout manages the layout of the stack area used by the out-of-line save & restore stubs as well as any padding needed before and after the save area. It also provides the proper symbol rtx for the requested stub based upon values of the new fields in struct machine_function, which specify how many registers are being saved, what padding is needed, etc. xlouge_layout cannot be used until stack realign flags are finalized and ix86_compute_frame_layout is called, at which point xlouge_layout::get_instance may be used to retrieve the appropriate (constant) instance of xlouge_layout. Signed-off-by: Daniel Santos --- gcc/config/i386/i386.c | 262 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/config/i386/i386.h | 18 ++++ 2 files changed, 280 insertions(+) diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 521116195cb..2da3da1f97a 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -93,6 +93,7 @@ static rtx legitimize_dllimport_symbol (rtx, bool); static rtx legitimize_pe_coff_extern_decl (rtx, bool); static rtx legitimize_pe_coff_symbol (rtx, bool); static void ix86_print_operand_address_as (FILE *, rtx, addr_space_t, bool); +static bool ix86_save_reg (unsigned int, bool, bool); #ifndef CHECK_STACK_LIMIT #define CHECK_STACK_LIMIT (-1) @@ -2432,6 +2433,267 @@ 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_HFP_ALIGNED_OR_REALIGN, + XLOGUE_SET_HFP_ALIGNED_PLUS_8, + + XLOGUE_SET_COUNT +}; + +/* Register save/restore layout used by 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]; + } + + const char *get_stub_name (enum xlogue_stub stub, + unsigned n_extra_args) const; + /* 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->call_ms2sysv_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.call_ms2sysv_extra_regs + MIN_REGS - 1; + + gcc_assert (m.call_ms2sysv_extra_regs <= MAX_EXTRA_REGS); + return m_regs[last_reg].offset + + (m.call_ms2sysv_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 unsigned compute_stub_managed_regs (HARD_REG_SET &stub_managed_regs); + + static const HOST_WIDE_INT STUB_INDEX_OFFSET = 0x70; + static const unsigned MIN_REGS = NUM_X86_64_MS_CLOBBERED_REGS; + 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 &); + + /* 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; + + /* Register order and offsets. */ + struct reginfo m_regs[MAX_REGS]; + + /* Lazy-inited cache of symbol names for stubs. */ + 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. + + s_instances: 0 1 2 3 + Offset: realigned or aligned + 8 + Register aligned aligned + 8 aligned w/HFP w/HFP */ + XMM15_REG, /* 0x10 0x18 0x10 0x18 */ + XMM14_REG, /* 0x20 0x28 0x20 0x28 */ + XMM13_REG, /* 0x30 0x38 0x30 0x38 */ + XMM12_REG, /* 0x40 0x48 0x40 0x48 */ + XMM11_REG, /* 0x50 0x58 0x50 0x58 */ + XMM10_REG, /* 0x60 0x68 0x60 0x68 */ + XMM9_REG, /* 0x70 0x78 0x70 0x78 */ + XMM8_REG, /* 0x80 0x88 0x80 0x88 */ + XMM7_REG, /* 0x90 0x98 0x90 0x98 */ + XMM6_REG, /* 0xa0 0xa8 0xa0 0xa8 */ + SI_REG, /* 0xa8 0xb0 0xa8 0xb0 */ + DI_REG, /* 0xb0 0xb8 0xb0 0xb8 */ + BX_REG, /* 0xb8 0xc0 0xb8 0xc0 */ + BP_REG, /* 0xc0 0xc8 N/A N/A */ + R12_REG, /* 0xc8 0xd0 0xc0 0xc8 */ + R13_REG, /* 0xd0 0xd8 0xc8 0xd0 */ + R14_REG, /* 0xd8 0xe0 0xd0 0xd8 */ + R15_REG, /* 0xe0 0xe8 0xd8 0xe0 */ +}; + +/* Instantiates all xlogue_layout instances. */ +const struct xlogue_layout GTY(()) +xlogue_layout::s_instances[XLOGUE_SET_COUNT] = { + xlogue_layout (0, false), + xlogue_layout (8, false), + xlogue_layout (0, true), + xlogue_layout (8, true) +}; + +/* Return an appropriate const instance of xlogue_layout based upon values + in cfun->machine and crtl. */ +const struct xlogue_layout &xlogue_layout::get_instance () +{ + enum xlogue_stub_sets stub_set; + bool aligned_plus_8 = cfun->machine->call_ms2sysv_pad_in; + + if (stack_realign_fp) + stub_set = XLOGUE_SET_HFP_ALIGNED_OR_REALIGN; + else if (frame_pointer_needed) + stub_set = aligned_plus_8 + ? XLOGUE_SET_HFP_ALIGNED_PLUS_8 + : XLOGUE_SET_HFP_ALIGNED_OR_REALIGN; + else + stub_set = aligned_plus_8 ? XLOGUE_SET_ALIGNED_PLUS_8 : XLOGUE_SET_ALIGNED; + + return s_instances[stub_set]; +} + +/* Determine which clobbered registers can be saved by the stub and store + them in stub_managed_regs. Returns the count of registers the stub will + save and restore. */ +unsigned +xlogue_layout::compute_stub_managed_regs (HARD_REG_SET &stub_managed_regs) +{ + bool hfp = frame_pointer_needed || stack_realign_fp; + + unsigned i, count; + unsigned regno; + + for (i = 0; i < NUM_X86_64_MS_CLOBBERED_REGS; ++i) + { + regno = x86_64_ms_sysv_extra_clobbered_registers[i]; + if (regno == BP_REG && hfp) + continue; + if (!ix86_save_reg (regno, false, false)) + return 0; + } + + for (count = i = 0; i < MAX_REGS; ++i) + { + regno = REG_ORDER[i]; + if (regno == BP_REG && hfp) + continue; + if (!ix86_save_reg (regno, false, false)) + break; + add_to_hard_reg_set (&stub_managed_regs, DImode, regno); + ++count; + } + gcc_assert (count >= MIN_REGS && count <= MAX_REGS); + return count; +} + +/* Constructor for xlogue_layout. */ +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_stub_names, 0, sizeof (m_stub_names)); + + 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); +} + +const char *xlogue_layout::get_stub_name (enum xlogue_stub stub, + unsigned n_extra_regs) const +{ + xlogue_layout *writey_this = const_cast(this); + char *name = writey_this->m_stub_names[stub][n_extra_regs]; + + /* Lazy init */ + if (!*name) + { + int res = snprintf (name, STUB_NAME_MAX_LEN, "__%s_%u", + STUB_BASE_NAMES[stub], MIN_REGS + n_extra_regs); + gcc_checking_assert (res <= (int)STUB_NAME_MAX_LEN); + } + + return name; +} + +/* Return rtx of a symbol ref for the entry point (based upon + cfun->machine->call_ms2sysv_extra_regs) of the specified stub. */ +rtx xlogue_layout::get_stub_rtx (enum xlogue_stub stub) const +{ + const unsigned n_extra_regs = cfun->machine->call_ms2sysv_extra_regs; + gcc_checking_assert (n_extra_regs <= MAX_EXTRA_REGS); + gcc_assert (stub < XLOGUE_STUB_COUNT); + gcc_assert (crtl->stack_realign_finalized); + + return gen_rtx_SYMBOL_REF (Pmode, get_stub_name (stub, n_extra_regs)); +} + /* Define the structure for the machine field in struct function. */ struct GTY(()) stack_local_entry { diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 645b239a768..5366f1fc88f 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2578,6 +2578,24 @@ struct GTY(()) machine_function { pass arguments and can be used for indirect sibcall. */ BOOL_BITFIELD arg_reg_available : 1; + /* If true, we're out-of-lining reg save/restore for regs clobbered + by ms_abi functions calling a sysv function. */ + BOOL_BITFIELD call_ms2sysv : 1; + + /* If true, the incoming 16-byte aligned stack has an offset (of 8) and + needs padding. */ + BOOL_BITFIELD call_ms2sysv_pad_in : 1; + + /* If true, the size of the stub save area plus inline int reg saves will + result in an 8 byte offset, so needs padding. */ + BOOL_BITFIELD call_ms2sysv_pad_out : 1; + + /* This is the number of extra registers saved by stub (valid range is + 0-6). Each additional register is only saved/restored by the stubs + if all successive ones are. (Will always be zero when using a hard + frame pointer.) */ + unsigned int call_ms2sysv_extra_regs:3; + /* During prologue/epilogue generation, the current frame state. Otherwise, the frame state at the end of the prologue. */ struct machine_frame_state fs; -- 2.11.0