summaryrefslogtreecommitdiff
path: root/gcc/config/i386/i386-features.h
blob: 09fe3402de3a92889e892808876d7de005350b0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/* Copyright (C) 1988-2019 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
<http://www.gnu.org/licenses/>.  */

#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<rtx, rtx> 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 */