aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimplify_reg_info.h
blob: b56b225ac01c932f56396ac62429a9238ee69c43 (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
/* gimplify_reg_info is used during gimplification while walking over
   operands and their corresponding constraints of asm statements in order to
   detect errors.

   m_alt_output is a mapping describing which registers are potentially used in
   which alternative over all outputs.  Similarly for m_alt_input but over all
   inputs.

   m_early_clobbered_alt is a mapping describing which register is early
   clobbered in which alternative over all outputs.

   m_early_clobbered_output is the counter part to the prior one, i.e., it
   is a mapping describing which register is early clobbered in which operand
   over all alternatives.

   m_reg_asm_output is the set of registers (including register pairs) used for
   register asm output operands.

   m_reg_asm_input similar as m_reg_asm_output but for inputs.  */

#include "regs.h"

class gimplify_reg_info
{
  HARD_REG_SET *m_buf;
  HARD_REG_SET *m_alt_output;
  HARD_REG_SET *m_alt_input;
  HARD_REG_SET *m_early_clobbered_alt;
  HARD_REG_SET *m_early_clobbered_output;
  HARD_REG_SET m_reg_asm_output;
  HARD_REG_SET m_reg_asm_input;
  const unsigned m_num_alternatives;
  const unsigned m_num_outputs;
  /* Member m_clobbered describes all the registers marked as clobbered in an
     asm statement, i.e., this is the clobbers list of an extended asm

     asm asm-qualifiers ( AssemblerTemplate
		 : OutputOperands
		 [ : InputOperands
		 [ : Clobbers ] ])

     and is not to be confused with the early clobbers sets.  */
  HARD_REG_SET m_clobbered;

  /* Return the first overlapping register of REGS and REGNO:MODE or -1.  */
  int test (const HARD_REG_SET &regs, int regno) const
  {
    machine_mode mode = TYPE_MODE (TREE_TYPE (operand));

    if (TEST_HARD_REG_BIT (regs, regno))
      return regno;

    int end_regno = end_hard_regno (mode, regno);
    while (++regno < end_regno)
      if (TEST_HARD_REG_BIT (regs, regno))
	return regno;

    return -1;
  }

public:
  tree operand;

  gimplify_reg_info (unsigned num_alternatives,
		     unsigned num_outputs)
    : m_num_alternatives{num_alternatives}
    , m_num_outputs{num_outputs}
  {
    CLEAR_HARD_REG_SET (m_reg_asm_output);
    CLEAR_HARD_REG_SET (m_reg_asm_input);
    CLEAR_HARD_REG_SET (m_clobbered);

    /* If there are no alternatives, then there are no outputs/inputs and there
       is nothing to do on our end.  Thus, we are dealing most likely with a
       basic asm.  */
    if (num_alternatives == 0)
      return;

    unsigned buf_size = num_alternatives * 3 + num_outputs;
    m_buf = new HARD_REG_SET[buf_size];
    for (unsigned i = 0; i < buf_size; ++i)
      CLEAR_HARD_REG_SET (m_buf[i]);
    m_alt_output = &m_buf[0];
    m_alt_input = &m_buf[num_alternatives];
    m_early_clobbered_alt = &m_buf[num_alternatives * 2];
    if (num_outputs > 0)
      m_early_clobbered_output = &m_buf[num_alternatives * 3];
    else
      m_early_clobbered_output = nullptr;
  }

  ~gimplify_reg_info ()
  {
    if (m_num_alternatives > 0)
      delete[] m_buf;
  }

  void set_output (unsigned alt, int regno)
  {
    gcc_checking_assert (alt < m_num_alternatives);
    machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
    add_to_hard_reg_set (&m_alt_output[alt], mode, regno);
  }

  void set_input (unsigned alt, int regno)
  {
    gcc_checking_assert (alt < m_num_alternatives);
    machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
    add_to_hard_reg_set (&m_alt_input[alt], mode, regno);
  }

  int test_alt_output (unsigned alt, int regno) const
  {
    gcc_checking_assert (alt < m_num_alternatives);
    return test (m_alt_output[alt], regno);
  }

  int test_alt_input (unsigned alt, int regno) const
  {
    gcc_checking_assert (alt < m_num_alternatives);
    return test (m_alt_input[alt], regno);
  }

  void set_reg_asm_output (int regno)
  {
    machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
    add_to_hard_reg_set (&m_reg_asm_output, mode, regno);
  }

  int test_reg_asm_output (int regno) const
  {
    return test (m_reg_asm_output, regno);
  }

  void set_reg_asm_input (int regno)
  {
    machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
    add_to_hard_reg_set (&m_reg_asm_input, mode, regno);
  }

  int test_reg_asm_input (int regno) const
  {
    return test (m_reg_asm_input, regno);
  }

  void set_early_clobbered (unsigned alt, unsigned output, int regno)
  {
    gcc_checking_assert (alt < m_num_alternatives);
    gcc_checking_assert (output < m_num_outputs);
    machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
    add_to_hard_reg_set (&m_early_clobbered_alt[alt], mode, regno);
    add_to_hard_reg_set (&m_early_clobbered_output[output], mode, regno);
  }

  bool test_early_clobbered_alt (unsigned alt, int regno) const
  {
    gcc_checking_assert (alt < m_num_alternatives);
    return TEST_HARD_REG_BIT (m_early_clobbered_alt[alt], regno);
  }

  bool is_early_clobbered_in_any_output_unequal (unsigned operand,
						 int regno) const
  {
    gcc_checking_assert (operand < m_num_outputs);
    for (unsigned op = 0; op < m_num_outputs; ++op)
      if (op != operand
	  && TEST_HARD_REG_BIT (m_early_clobbered_output[op], regno))
	return true;
    return false;
  }

  void set_clobbered (int regno)
  {
    SET_HARD_REG_BIT (m_clobbered, regno);
  }

  bool is_clobbered (int regno) const
  {
    machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
    return overlaps_hard_reg_set_p (m_clobbered, mode, regno);
  }
};