/* Copyright (C) 1988-2021 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
. */
#ifndef GCC_I386_FEATURES_H
#define GCC_I386_FEATURES_H
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];
}
static const char *get_stub_name (enum xlogue_stub stub,
unsigned n_extra_args);
/* 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. */
static rtx get_stub_rtx (enum xlogue_stub stub);
/* 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 + 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 class xlogue_layout &get_instance ();
static unsigned count_stub_managed_regs ();
static bool is_stub_managed_reg (unsigned regno, unsigned count);
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 = 20;
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. */
static char s_stub_names[2][XLOGUE_STUB_COUNT][VARIANT_COUNT]
[STUB_NAME_MAX_LEN];
static const xlogue_layout s_instances[XLOGUE_SET_COUNT];
};
namespace {
class scalar_chain
{
public:
scalar_chain (enum machine_mode, enum machine_mode);
virtual ~scalar_chain ();
static unsigned max_id;
/* Scalar mode. */
enum machine_mode smode;
/* Vector mode. */
enum machine_mode vmode;
/* ID of a chain. */
unsigned int chain_id;
/* A queue of instructions to be included into a chain. */
bitmap queue;
/* Instructions included into a chain. */
bitmap insns;
/* All registers defined by a chain. */
bitmap defs;
/* Registers used in both vector and sclar modes. */
bitmap defs_conv;
void build (bitmap candidates, unsigned insn_uid);
virtual int compute_convert_gain () = 0;
int convert ();
protected:
void add_to_queue (unsigned insn_uid);
void emit_conversion_insns (rtx insns, rtx_insn *pos);
private:
void add_insn (bitmap candidates, unsigned insn_uid);
void analyze_register_chain (bitmap candidates, df_ref ref);
virtual void mark_dual_mode_def (df_ref def) = 0;
virtual void convert_insn (rtx_insn *insn) = 0;
virtual void convert_registers () = 0;
};
class general_scalar_chain : public scalar_chain
{
public:
general_scalar_chain (enum machine_mode smode_, enum machine_mode vmode_);
~general_scalar_chain ();
int compute_convert_gain ();
private:
hash_map defs_map;
bitmap insns_conv;
unsigned n_sse_to_integer;
unsigned n_integer_to_sse;
void mark_dual_mode_def (df_ref def);
void convert_insn (rtx_insn *insn);
void convert_op (rtx *op, rtx_insn *insn);
void convert_reg (rtx_insn *insn, rtx dst, rtx src);
void make_vector_copies (rtx_insn *, rtx);
void convert_registers ();
int vector_const_cost (rtx exp);
};
class timode_scalar_chain : public scalar_chain
{
public:
timode_scalar_chain () : scalar_chain (TImode, V1TImode) {}
/* Convert from TImode to V1TImode is always faster. */
int compute_convert_gain () { return 1; }
private:
void mark_dual_mode_def (df_ref def);
void fix_debug_reg_uses (rtx reg);
void convert_insn (rtx_insn *insn);
/* We don't convert registers to difference size. */
void convert_registers () {}
};
} // anon namespace
bool ix86_save_reg (unsigned int regno, bool maybe_eh_return, bool ignore_outlined);
int ix86_compare_version_priority (tree decl1, tree decl2);
tree ix86_generate_version_dispatcher_body (void *node_p);
tree ix86_get_function_versions_dispatcher (void *decl);
tree ix86_mangle_decl_assembler_name (tree decl, tree id);
#endif /* GCC_I386_FEATURES_H */