1 /* Copyright (C) 1988-2020 Free Software Foundation, Inc.
2 
3 This file is part of GCC.
4 
5 GCC is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9 
10 GCC is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with GCC; see the file COPYING3.  If not see
17 <http://www.gnu.org/licenses/>.  */
18 
19 #ifndef GCC_I386_FEATURES_H
20 #define GCC_I386_FEATURES_H
21 
22 enum xlogue_stub {
23   XLOGUE_STUB_SAVE,
24   XLOGUE_STUB_RESTORE,
25   XLOGUE_STUB_RESTORE_TAIL,
26   XLOGUE_STUB_SAVE_HFP,
27   XLOGUE_STUB_RESTORE_HFP,
28   XLOGUE_STUB_RESTORE_HFP_TAIL,
29 
30   XLOGUE_STUB_COUNT
31 };
32 
33 enum xlogue_stub_sets {
34   XLOGUE_SET_ALIGNED,
35   XLOGUE_SET_ALIGNED_PLUS_8,
36   XLOGUE_SET_HFP_ALIGNED_OR_REALIGN,
37   XLOGUE_SET_HFP_ALIGNED_PLUS_8,
38 
39   XLOGUE_SET_COUNT
40 };
41 
42 /* Register save/restore layout used by out-of-line stubs.  */
43 class xlogue_layout {
44 public:
45   struct reginfo
46   {
47     unsigned regno;
48     HOST_WIDE_INT offset;	/* Offset used by stub base pointer (rax or
49 				   rsi) to where each register is stored.  */
50   };
51 
get_nregs()52   unsigned get_nregs () const			{return m_nregs;}
get_stack_align_off_in()53   HOST_WIDE_INT get_stack_align_off_in () const	{return m_stack_align_off_in;}
54 
get_reginfo(unsigned reg)55   const reginfo &get_reginfo (unsigned reg) const
56   {
57     gcc_assert (reg < m_nregs);
58     return m_regs[reg];
59   }
60 
61   static const char *get_stub_name (enum xlogue_stub stub,
62 				    unsigned n_extra_args);
63 
64   /* Returns an rtx for the stub's symbol based upon
65        1.) the specified stub (save, restore or restore_ret) and
66        2.) the value of cfun->machine->call_ms2sysv_extra_regs and
67        3.) rather or not stack alignment is being performed.  */
68   static rtx get_stub_rtx (enum xlogue_stub stub);
69 
70   /* Returns the amount of stack space (including padding) that the stub
71      needs to store registers based upon data in the machine_function.  */
get_stack_space_used()72   HOST_WIDE_INT get_stack_space_used () const
73   {
74     const struct machine_function *m = cfun->machine;
75     unsigned last_reg = m->call_ms2sysv_extra_regs + MIN_REGS - 1;
76 
77     gcc_assert (m->call_ms2sysv_extra_regs <= MAX_EXTRA_REGS);
78     return m_regs[last_reg].offset + STUB_INDEX_OFFSET;
79   }
80 
81   /* Returns the offset for the base pointer used by the stub.  */
get_stub_ptr_offset()82   HOST_WIDE_INT get_stub_ptr_offset () const
83   {
84     return STUB_INDEX_OFFSET + m_stack_align_off_in;
85   }
86 
87   static const class xlogue_layout &get_instance ();
88   static unsigned count_stub_managed_regs ();
89   static bool is_stub_managed_reg (unsigned regno, unsigned count);
90 
91   static const HOST_WIDE_INT STUB_INDEX_OFFSET = 0x70;
92   static const unsigned MIN_REGS = NUM_X86_64_MS_CLOBBERED_REGS;
93   static const unsigned MAX_REGS = 18;
94   static const unsigned MAX_EXTRA_REGS = MAX_REGS - MIN_REGS;
95   static const unsigned VARIANT_COUNT = MAX_EXTRA_REGS + 1;
96   static const unsigned STUB_NAME_MAX_LEN = 20;
97   static const char * const STUB_BASE_NAMES[XLOGUE_STUB_COUNT];
98   static const unsigned REG_ORDER[MAX_REGS];
99   static const unsigned REG_ORDER_REALIGN[MAX_REGS];
100 
101 private:
102   xlogue_layout ();
103   xlogue_layout (HOST_WIDE_INT stack_align_off_in, bool hfp);
104   xlogue_layout (const xlogue_layout &);
105 
106   /* True if hard frame pointer is used.  */
107   bool m_hfp;
108 
109   /* Max number of register this layout manages.  */
110   unsigned m_nregs;
111 
112   /* Incoming offset from 16-byte alignment.  */
113   HOST_WIDE_INT m_stack_align_off_in;
114 
115   /* Register order and offsets.  */
116   struct reginfo m_regs[MAX_REGS];
117 
118   /* Lazy-inited cache of symbol names for stubs.  */
119   static char s_stub_names[2][XLOGUE_STUB_COUNT][VARIANT_COUNT]
120 			  [STUB_NAME_MAX_LEN];
121 
122   static const xlogue_layout s_instances[XLOGUE_SET_COUNT];
123 };
124 
125 namespace {
126 
127 class scalar_chain
128 {
129  public:
130   scalar_chain (enum machine_mode, enum machine_mode);
131   virtual ~scalar_chain ();
132 
133   static unsigned max_id;
134 
135   /* Scalar mode.  */
136   enum machine_mode smode;
137   /* Vector mode.  */
138   enum machine_mode vmode;
139 
140   /* ID of a chain.  */
141   unsigned int chain_id;
142   /* A queue of instructions to be included into a chain.  */
143   bitmap queue;
144   /* Instructions included into a chain.  */
145   bitmap insns;
146   /* All registers defined by a chain.  */
147   bitmap defs;
148   /* Registers used in both vector and sclar modes.  */
149   bitmap defs_conv;
150 
151   void build (bitmap candidates, unsigned insn_uid);
152   virtual int compute_convert_gain () = 0;
153   int convert ();
154 
155  protected:
156   void add_to_queue (unsigned insn_uid);
157   void emit_conversion_insns (rtx insns, rtx_insn *pos);
158 
159  private:
160   void add_insn (bitmap candidates, unsigned insn_uid);
161   void analyze_register_chain (bitmap candidates, df_ref ref);
162   virtual void mark_dual_mode_def (df_ref def) = 0;
163   virtual void convert_insn (rtx_insn *insn) = 0;
164   virtual void convert_registers () = 0;
165 };
166 
167 class general_scalar_chain : public scalar_chain
168 {
169  public:
170   general_scalar_chain (enum machine_mode smode_, enum machine_mode vmode_);
171   ~general_scalar_chain ();
172   int compute_convert_gain ();
173  private:
174   hash_map<rtx, rtx> defs_map;
175   bitmap insns_conv;
176   unsigned n_sse_to_integer;
177   unsigned n_integer_to_sse;
178   void mark_dual_mode_def (df_ref def);
179   void convert_insn (rtx_insn *insn);
180   void convert_op (rtx *op, rtx_insn *insn);
181   void convert_reg (rtx_insn *insn, rtx dst, rtx src);
182   void make_vector_copies (rtx_insn *, rtx);
183   void convert_registers ();
184   int vector_const_cost (rtx exp);
185 };
186 
187 class timode_scalar_chain : public scalar_chain
188 {
189  public:
timode_scalar_chain()190   timode_scalar_chain () : scalar_chain (TImode, V1TImode) {}
191 
192   /* Convert from TImode to V1TImode is always faster.  */
compute_convert_gain()193   int compute_convert_gain () { return 1; }
194 
195  private:
196   void mark_dual_mode_def (df_ref def);
197   void fix_debug_reg_uses (rtx reg);
198   void convert_insn (rtx_insn *insn);
199   /* We don't convert registers to difference size.  */
convert_registers()200   void convert_registers () {}
201 };
202 
203 } // anon namespace
204 
205 bool ix86_save_reg (unsigned int regno, bool maybe_eh_return, bool ignore_outlined);
206 int ix86_compare_version_priority (tree decl1, tree decl2);
207 tree ix86_generate_version_dispatcher_body (void *node_p);
208 tree ix86_get_function_versions_dispatcher (void *decl);
209 tree ix86_mangle_decl_assembler_name (tree decl, tree id);
210 
211 
212 #endif  /* GCC_I386_FEATURES_H */
213