annotate gcc/stmt.c @ 118:fd00160c1b76

ifdef TARGET_64BIT
author mir3636
date Tue, 27 Feb 2018 15:01:35 +0900
parents 04ced10e8804
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1 /* Expands front end tree to back end RTL for GCC
111
kono
parents: 67
diff changeset
2 Copyright (C) 1987-2017 Free Software Foundation, Inc.
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
3
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
4 This file is part of GCC.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
5
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
6 GCC is free software; you can redistribute it and/or modify it under
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
7 the terms of the GNU General Public License as published by the Free
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
8 Software Foundation; either version 3, or (at your option) any later
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
9 version.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
10
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
14 for more details.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
15
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
17 along with GCC; see the file COPYING3. If not see
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
18 <http://www.gnu.org/licenses/>. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
19
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
20 /* This file handles the generation of rtl code from tree structure
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
21 above the level of expressions, using subroutines in exp*.c and emit-rtl.c.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
22 The functions whose names start with `expand_' are called by the
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
23 expander to generate RTL instructions for various kinds of constructs. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
24
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
25 #include "config.h"
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
26 #include "system.h"
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
27 #include "coretypes.h"
111
kono
parents: 67
diff changeset
28 #include "backend.h"
kono
parents: 67
diff changeset
29 #include "target.h"
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
30 #include "rtl.h"
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
31 #include "tree.h"
111
kono
parents: 67
diff changeset
32 #include "gimple.h"
kono
parents: 67
diff changeset
33 #include "cfghooks.h"
kono
parents: 67
diff changeset
34 #include "predict.h"
kono
parents: 67
diff changeset
35 #include "memmodel.h"
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
36 #include "tm_p.h"
111
kono
parents: 67
diff changeset
37 #include "optabs.h"
kono
parents: 67
diff changeset
38 #include "regs.h"
kono
parents: 67
diff changeset
39 #include "emit-rtl.h"
kono
parents: 67
diff changeset
40 #include "pretty-print.h"
kono
parents: 67
diff changeset
41 #include "diagnostic-core.h"
kono
parents: 67
diff changeset
42
kono
parents: 67
diff changeset
43 #include "fold-const.h"
kono
parents: 67
diff changeset
44 #include "varasm.h"
kono
parents: 67
diff changeset
45 #include "stor-layout.h"
kono
parents: 67
diff changeset
46 #include "dojump.h"
kono
parents: 67
diff changeset
47 #include "explow.h"
kono
parents: 67
diff changeset
48 #include "stmt.h"
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
49 #include "expr.h"
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
50 #include "langhooks.h"
111
kono
parents: 67
diff changeset
51 #include "cfganal.h"
kono
parents: 67
diff changeset
52 #include "tree-cfg.h"
kono
parents: 67
diff changeset
53 #include "params.h"
kono
parents: 67
diff changeset
54 #include "dumpfile.h"
kono
parents: 67
diff changeset
55 #include "builtins.h"
63
b7f97abdc517 update gcc from gcc-4.5.0 to gcc-4.6
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 55
diff changeset
56
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
57
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
58 /* Functions and data structures for expanding case statements. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
59
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
60 /* Case label structure, used to hold info on labels within case
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
61 statements. We handle "range" labels; for a single-value label
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
62 as in C, the high and low limits are the same.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
63
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
64 We start with a vector of case nodes sorted in ascending order, and
111
kono
parents: 67
diff changeset
65 the default label as the last element in the vector.
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
66
111
kono
parents: 67
diff changeset
67 Switch statements are expanded in jump table form.
kono
parents: 67
diff changeset
68
kono
parents: 67
diff changeset
69 */
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
70
111
kono
parents: 67
diff changeset
71 struct simple_case_node
kono
parents: 67
diff changeset
72 {
kono
parents: 67
diff changeset
73 simple_case_node (tree low, tree high, tree code_label):
kono
parents: 67
diff changeset
74 m_low (low), m_high (high), m_code_label (code_label)
kono
parents: 67
diff changeset
75 {}
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
76
111
kono
parents: 67
diff changeset
77 /* Lowest index value for this label. */
kono
parents: 67
diff changeset
78 tree m_low;
kono
parents: 67
diff changeset
79 /* Highest index value for this label. */
kono
parents: 67
diff changeset
80 tree m_high;
kono
parents: 67
diff changeset
81 /* Label to jump to when node matches. */
kono
parents: 67
diff changeset
82 tree m_code_label;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
83 };
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
84
111
kono
parents: 67
diff changeset
85 extern basic_block label_to_block_fn (struct function *, tree);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
86
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
87 static bool check_unique_operand_names (tree, tree, tree);
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
88 static char *resolve_operand_name_1 (char *, tree, tree, tree);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
89
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
90 /* Return the rtx-label that corresponds to a LABEL_DECL,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
91 creating it if necessary. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
92
111
kono
parents: 67
diff changeset
93 rtx_insn *
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
94 label_rtx (tree label)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
95 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
96 gcc_assert (TREE_CODE (label) == LABEL_DECL);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
97
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
98 if (!DECL_RTL_SET_P (label))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
99 {
111
kono
parents: 67
diff changeset
100 rtx_code_label *r = gen_label_rtx ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
101 SET_DECL_RTL (label, r);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
102 if (FORCED_LABEL (label) || DECL_NONLOCAL (label))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
103 LABEL_PRESERVE_P (r) = 1;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
104 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
105
111
kono
parents: 67
diff changeset
106 return as_a <rtx_insn *> (DECL_RTL (label));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
107 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
108
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
109 /* As above, but also put it on the forced-reference list of the
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
110 function that contains it. */
111
kono
parents: 67
diff changeset
111 rtx_insn *
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
112 force_label_rtx (tree label)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
113 {
111
kono
parents: 67
diff changeset
114 rtx_insn *ref = label_rtx (label);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
115 tree function = decl_function_context (label);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
116
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
117 gcc_assert (function);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
118
111
kono
parents: 67
diff changeset
119 vec_safe_push (forced_labels, ref);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
120 return ref;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
121 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
122
111
kono
parents: 67
diff changeset
123 /* As label_rtx, but ensures (in check build), that returned value is
kono
parents: 67
diff changeset
124 an existing label (i.e. rtx with code CODE_LABEL). */
kono
parents: 67
diff changeset
125 rtx_code_label *
kono
parents: 67
diff changeset
126 jump_target_rtx (tree label)
kono
parents: 67
diff changeset
127 {
kono
parents: 67
diff changeset
128 return as_a <rtx_code_label *> (label_rtx (label));
kono
parents: 67
diff changeset
129 }
kono
parents: 67
diff changeset
130
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
131 /* Add an unconditional jump to LABEL as the next sequential instruction. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
132
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
133 void
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
134 emit_jump (rtx label)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
135 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
136 do_pending_stack_adjust ();
111
kono
parents: 67
diff changeset
137 emit_jump_insn (targetm.gen_jump (label));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
138 emit_barrier ();
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
139 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
140
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
141 /* Handle goto statements and the labels that they can go to. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
142
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
143 /* Specify the location in the RTL code of a label LABEL,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
144 which is a LABEL_DECL tree node.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
145
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
146 This is used for the kind of label that the user can jump to with a
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
147 goto statement, and for alternatives of a switch or case statement.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
148 RTL labels generated for loops and conditionals don't go through here;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
149 they are generated directly at the RTL level, by other functions below.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
150
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
151 Note that this has nothing to do with defining label *names*.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
152 Languages vary in how they do that and what that even means. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
153
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
154 void
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
155 expand_label (tree label)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
156 {
111
kono
parents: 67
diff changeset
157 rtx_code_label *label_r = jump_target_rtx (label);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
158
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
159 do_pending_stack_adjust ();
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
160 emit_label (label_r);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
161 if (DECL_NAME (label))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
162 LABEL_NAME (DECL_RTL (label)) = IDENTIFIER_POINTER (DECL_NAME (label));
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
163
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
164 if (DECL_NONLOCAL (label))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
165 {
111
kono
parents: 67
diff changeset
166 expand_builtin_setjmp_receiver (NULL);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
167 nonlocal_goto_handler_labels
111
kono
parents: 67
diff changeset
168 = gen_rtx_INSN_LIST (VOIDmode, label_r,
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
169 nonlocal_goto_handler_labels);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
170 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
171
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
172 if (FORCED_LABEL (label))
111
kono
parents: 67
diff changeset
173 vec_safe_push<rtx_insn *> (forced_labels, label_r);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
174
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
175 if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
176 maybe_set_first_label_num (label_r);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
177 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
178
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
179 /* Parse the output constraint pointed to by *CONSTRAINT_P. It is the
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
180 OPERAND_NUMth output operand, indexed from zero. There are NINPUTS
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
181 inputs and NOUTPUTS outputs to this extended-asm. Upon return,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
182 *ALLOWS_MEM will be TRUE iff the constraint allows the use of a
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
183 memory operand. Similarly, *ALLOWS_REG will be TRUE iff the
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
184 constraint allows the use of a register operand. And, *IS_INOUT
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
185 will be true if the operand is read-write, i.e., if it is used as
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
186 an input as well as an output. If *CONSTRAINT_P is not in
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
187 canonical form, it will be made canonical. (Note that `+' will be
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
188 replaced with `=' as part of this process.)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
189
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
190 Returns TRUE if all went well; FALSE if an error occurred. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
191
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
192 bool
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
193 parse_output_constraint (const char **constraint_p, int operand_num,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
194 int ninputs, int noutputs, bool *allows_mem,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
195 bool *allows_reg, bool *is_inout)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
196 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
197 const char *constraint = *constraint_p;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
198 const char *p;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
199
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
200 /* Assume the constraint doesn't allow the use of either a register
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
201 or memory. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
202 *allows_mem = false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
203 *allows_reg = false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
204
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
205 /* Allow the `=' or `+' to not be at the beginning of the string,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
206 since it wasn't explicitly documented that way, and there is a
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
207 large body of code that puts it last. Swap the character to
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
208 the front, so as not to uglify any place else. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
209 p = strchr (constraint, '=');
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
210 if (!p)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
211 p = strchr (constraint, '+');
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
212
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
213 /* If the string doesn't contain an `=', issue an error
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
214 message. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
215 if (!p)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
216 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
217 error ("output operand constraint lacks %<=%>");
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
218 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
219 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
220
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
221 /* If the constraint begins with `+', then the operand is both read
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
222 from and written to. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
223 *is_inout = (*p == '+');
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
224
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
225 /* Canonicalize the output constraint so that it begins with `='. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
226 if (p != constraint || *is_inout)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
227 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
228 char *buf;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
229 size_t c_len = strlen (constraint);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
230
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
231 if (p != constraint)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
232 warning (0, "output constraint %qc for operand %d "
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
233 "is not at the beginning",
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
234 *p, operand_num);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
235
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
236 /* Make a copy of the constraint. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
237 buf = XALLOCAVEC (char, c_len + 1);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
238 strcpy (buf, constraint);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
239 /* Swap the first character and the `=' or `+'. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
240 buf[p - constraint] = buf[0];
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
241 /* Make sure the first character is an `='. (Until we do this,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
242 it might be a `+'.) */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
243 buf[0] = '=';
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
244 /* Replace the constraint with the canonicalized string. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
245 *constraint_p = ggc_alloc_string (buf, c_len);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
246 constraint = *constraint_p;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
247 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
248
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
249 /* Loop through the constraint string. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
250 for (p = constraint + 1; *p; p += CONSTRAINT_LEN (*p, p))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
251 switch (*p)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
252 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
253 case '+':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
254 case '=':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
255 error ("operand constraint contains incorrectly positioned "
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
256 "%<+%> or %<=%>");
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
257 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
258
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
259 case '%':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
260 if (operand_num + 1 == ninputs + noutputs)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
261 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
262 error ("%<%%%> constraint used with last operand");
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
263 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
264 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
265 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
266
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
267 case '?': case '!': case '*': case '&': case '#':
111
kono
parents: 67
diff changeset
268 case '$': case '^':
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
269 case 'E': case 'F': case 'G': case 'H':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
270 case 's': case 'i': case 'n':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
271 case 'I': case 'J': case 'K': case 'L': case 'M':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
272 case 'N': case 'O': case 'P': case ',':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
273 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
274
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
275 case '0': case '1': case '2': case '3': case '4':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
276 case '5': case '6': case '7': case '8': case '9':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
277 case '[':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
278 error ("matching constraint not valid in output operand");
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
279 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
280
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
281 case '<': case '>':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
282 /* ??? Before flow, auto inc/dec insns are not supposed to exist,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
283 excepting those that expand_call created. So match memory
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
284 and hope. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
285 *allows_mem = true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
286 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
287
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
288 case 'g': case 'X':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
289 *allows_reg = true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
290 *allows_mem = true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
291 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
292
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
293 default:
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
294 if (!ISALPHA (*p))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
295 break;
111
kono
parents: 67
diff changeset
296 enum constraint_num cn = lookup_constraint (p);
kono
parents: 67
diff changeset
297 if (reg_class_for_constraint (cn) != NO_REGS
kono
parents: 67
diff changeset
298 || insn_extra_address_constraint (cn))
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
299 *allows_reg = true;
111
kono
parents: 67
diff changeset
300 else if (insn_extra_memory_constraint (cn))
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
301 *allows_mem = true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
302 else
111
kono
parents: 67
diff changeset
303 insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
304 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
305 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
306
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
307 return true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
308 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
309
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
310 /* Similar, but for input constraints. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
311
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
312 bool
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
313 parse_input_constraint (const char **constraint_p, int input_num,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
314 int ninputs, int noutputs, int ninout,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
315 const char * const * constraints,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
316 bool *allows_mem, bool *allows_reg)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
317 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
318 const char *constraint = *constraint_p;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
319 const char *orig_constraint = constraint;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
320 size_t c_len = strlen (constraint);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
321 size_t j;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
322 bool saw_match = false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
323
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
324 /* Assume the constraint doesn't allow the use of either
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
325 a register or memory. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
326 *allows_mem = false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
327 *allows_reg = false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
328
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
329 /* Make sure constraint has neither `=', `+', nor '&'. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
330
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
331 for (j = 0; j < c_len; j += CONSTRAINT_LEN (constraint[j], constraint+j))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
332 switch (constraint[j])
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
333 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
334 case '+': case '=': case '&':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
335 if (constraint == orig_constraint)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
336 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
337 error ("input operand constraint contains %qc", constraint[j]);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
338 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
339 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
340 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
341
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
342 case '%':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
343 if (constraint == orig_constraint
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
344 && input_num + 1 == ninputs - ninout)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
345 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
346 error ("%<%%%> constraint used with last operand");
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
347 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
348 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
349 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
350
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
351 case '<': case '>':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
352 case '?': case '!': case '*': case '#':
111
kono
parents: 67
diff changeset
353 case '$': case '^':
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
354 case 'E': case 'F': case 'G': case 'H':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
355 case 's': case 'i': case 'n':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
356 case 'I': case 'J': case 'K': case 'L': case 'M':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
357 case 'N': case 'O': case 'P': case ',':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
358 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
359
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
360 /* Whether or not a numeric constraint allows a register is
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
361 decided by the matching constraint, and so there is no need
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
362 to do anything special with them. We must handle them in
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
363 the default case, so that we don't unnecessarily force
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
364 operands to memory. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
365 case '0': case '1': case '2': case '3': case '4':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
366 case '5': case '6': case '7': case '8': case '9':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
367 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
368 char *end;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
369 unsigned long match;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
370
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
371 saw_match = true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
372
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
373 match = strtoul (constraint + j, &end, 10);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
374 if (match >= (unsigned long) noutputs)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
375 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
376 error ("matching constraint references invalid operand number");
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
377 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
378 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
379
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
380 /* Try and find the real constraint for this dup. Only do this
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
381 if the matching constraint is the only alternative. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
382 if (*end == '\0'
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
383 && (j == 0 || (j == 1 && constraint[0] == '%')))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
384 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
385 constraint = constraints[match];
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
386 *constraint_p = constraint;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
387 c_len = strlen (constraint);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
388 j = 0;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
389 /* ??? At the end of the loop, we will skip the first part of
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
390 the matched constraint. This assumes not only that the
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
391 other constraint is an output constraint, but also that
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
392 the '=' or '+' come first. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
393 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
394 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
395 else
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
396 j = end - constraint;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
397 /* Anticipate increment at end of loop. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
398 j--;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
399 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
400 /* Fall through. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
401
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
402 case 'g': case 'X':
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
403 *allows_reg = true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
404 *allows_mem = true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
405 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
406
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
407 default:
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
408 if (! ISALPHA (constraint[j]))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
409 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
410 error ("invalid punctuation %qc in constraint", constraint[j]);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
411 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
412 }
111
kono
parents: 67
diff changeset
413 enum constraint_num cn = lookup_constraint (constraint + j);
kono
parents: 67
diff changeset
414 if (reg_class_for_constraint (cn) != NO_REGS
kono
parents: 67
diff changeset
415 || insn_extra_address_constraint (cn))
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
416 *allows_reg = true;
111
kono
parents: 67
diff changeset
417 else if (insn_extra_memory_constraint (cn)
kono
parents: 67
diff changeset
418 || insn_extra_special_memory_constraint (cn))
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
419 *allows_mem = true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
420 else
111
kono
parents: 67
diff changeset
421 insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
422 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
423 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
424
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
425 if (saw_match && !*allows_reg)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
426 warning (0, "matching constraint does not allow a register");
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
427
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
428 return true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
429 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
430
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
431 /* Return DECL iff there's an overlap between *REGS and DECL, where DECL
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
432 can be an asm-declared register. Called via walk_tree. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
433
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
434 static tree
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
435 decl_overlaps_hard_reg_set_p (tree *declp, int *walk_subtrees ATTRIBUTE_UNUSED,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
436 void *data)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
437 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
438 tree decl = *declp;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
439 const HARD_REG_SET *const regs = (const HARD_REG_SET *) data;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
440
111
kono
parents: 67
diff changeset
441 if (VAR_P (decl))
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
442 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
443 if (DECL_HARD_REGISTER (decl)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
444 && REG_P (DECL_RTL (decl))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
445 && REGNO (DECL_RTL (decl)) < FIRST_PSEUDO_REGISTER)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
446 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
447 rtx reg = DECL_RTL (decl);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
448
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
449 if (overlaps_hard_reg_set_p (*regs, GET_MODE (reg), REGNO (reg)))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
450 return decl;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
451 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
452 walk_subtrees = 0;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
453 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
454 else if (TYPE_P (decl) || TREE_CODE (decl) == PARM_DECL)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
455 walk_subtrees = 0;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
456 return NULL_TREE;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
457 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
458
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
459 /* If there is an overlap between *REGS and DECL, return the first overlap
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
460 found. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
461 tree
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
462 tree_overlaps_hard_reg_set (tree decl, HARD_REG_SET *regs)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
463 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
464 return walk_tree (&decl, decl_overlaps_hard_reg_set_p, regs, NULL);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
465 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
466
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
467
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
468 /* A subroutine of expand_asm_operands. Check that all operand names
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
469 are unique. Return true if so. We rely on the fact that these names
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
470 are identifiers, and so have been canonicalized by get_identifier,
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
471 so all we need are pointer comparisons. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
472
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
473 static bool
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
474 check_unique_operand_names (tree outputs, tree inputs, tree labels)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
475 {
111
kono
parents: 67
diff changeset
476 tree i, j, i_name = NULL_TREE;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
477
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
478 for (i = outputs; i ; i = TREE_CHAIN (i))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
479 {
111
kono
parents: 67
diff changeset
480 i_name = TREE_PURPOSE (TREE_PURPOSE (i));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
481 if (! i_name)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
482 continue;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
483
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
484 for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
485 if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
486 goto failure;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
487 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
488
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
489 for (i = inputs; i ; i = TREE_CHAIN (i))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
490 {
111
kono
parents: 67
diff changeset
491 i_name = TREE_PURPOSE (TREE_PURPOSE (i));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
492 if (! i_name)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
493 continue;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
494
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
495 for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
496 if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
497 goto failure;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
498 for (j = outputs; j ; j = TREE_CHAIN (j))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
499 if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
500 goto failure;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
501 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
502
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
503 for (i = labels; i ; i = TREE_CHAIN (i))
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
504 {
111
kono
parents: 67
diff changeset
505 i_name = TREE_PURPOSE (i);
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
506 if (! i_name)
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
507 continue;
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
508
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
509 for (j = TREE_CHAIN (i); j ; j = TREE_CHAIN (j))
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
510 if (simple_cst_equal (i_name, TREE_PURPOSE (j)))
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
511 goto failure;
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
512 for (j = inputs; j ; j = TREE_CHAIN (j))
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
513 if (simple_cst_equal (i_name, TREE_PURPOSE (TREE_PURPOSE (j))))
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
514 goto failure;
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
515 }
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
516
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
517 return true;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
518
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
519 failure:
111
kono
parents: 67
diff changeset
520 error ("duplicate asm operand name %qs", TREE_STRING_POINTER (i_name));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
521 return false;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
522 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
523
111
kono
parents: 67
diff changeset
524 /* Resolve the names of the operands in *POUTPUTS and *PINPUTS to numbers,
kono
parents: 67
diff changeset
525 and replace the name expansions in STRING and in the constraints to
kono
parents: 67
diff changeset
526 those numbers. This is generally done in the front end while creating
kono
parents: 67
diff changeset
527 the ASM_EXPR generic tree that eventually becomes the GIMPLE_ASM. */
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
528
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
529 tree
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
530 resolve_asm_operand_names (tree string, tree outputs, tree inputs, tree labels)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
531 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
532 char *buffer;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
533 char *p;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
534 const char *c;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
535 tree t;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
536
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
537 check_unique_operand_names (outputs, inputs, labels);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
538
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
539 /* Substitute [<name>] in input constraint strings. There should be no
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
540 named operands in output constraints. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
541 for (t = inputs; t ; t = TREE_CHAIN (t))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
542 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
543 c = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
544 if (strchr (c, '[') != NULL)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
545 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
546 p = buffer = xstrdup (c);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
547 while ((p = strchr (p, '[')) != NULL)
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
548 p = resolve_operand_name_1 (p, outputs, inputs, NULL);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
549 TREE_VALUE (TREE_PURPOSE (t))
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
550 = build_string (strlen (buffer), buffer);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
551 free (buffer);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
552 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
553 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
554
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
555 /* Now check for any needed substitutions in the template. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
556 c = TREE_STRING_POINTER (string);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
557 while ((c = strchr (c, '%')) != NULL)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
558 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
559 if (c[1] == '[')
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
560 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
561 else if (ISALPHA (c[1]) && c[2] == '[')
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
562 break;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
563 else
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
564 {
67
f6334be47118 update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents: 63
diff changeset
565 c += 1 + (c[1] == '%');
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
566 continue;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
567 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
568 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
569
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
570 if (c)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
571 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
572 /* OK, we need to make a copy so we can perform the substitutions.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
573 Assume that we will not need extra space--we get to remove '['
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
574 and ']', which means we cannot have a problem until we have more
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
575 than 999 operands. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
576 buffer = xstrdup (TREE_STRING_POINTER (string));
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
577 p = buffer + (c - TREE_STRING_POINTER (string));
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
578
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
579 while ((p = strchr (p, '%')) != NULL)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
580 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
581 if (p[1] == '[')
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
582 p += 1;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
583 else if (ISALPHA (p[1]) && p[2] == '[')
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
584 p += 2;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
585 else
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
586 {
67
f6334be47118 update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents: 63
diff changeset
587 p += 1 + (p[1] == '%');
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
588 continue;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
589 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
590
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
591 p = resolve_operand_name_1 (p, outputs, inputs, labels);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
592 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
593
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
594 string = build_string (strlen (buffer), buffer);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
595 free (buffer);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
596 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
597
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
598 return string;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
599 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
600
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
601 /* A subroutine of resolve_operand_names. P points to the '[' for a
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
602 potential named operand of the form [<name>]. In place, replace
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
603 the name and brackets with a number. Return a pointer to the
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
604 balance of the string after substitution. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
605
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
606 static char *
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
607 resolve_operand_name_1 (char *p, tree outputs, tree inputs, tree labels)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
608 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
609 char *q;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
610 int op;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
611 tree t;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
612
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
613 /* Collect the operand name. */
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
614 q = strchr (++p, ']');
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
615 if (!q)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
616 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
617 error ("missing close brace for named operand");
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
618 return strchr (p, '\0');
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
619 }
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
620 *q = '\0';
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
621
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
622 /* Resolve the name to a number. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
623 for (op = 0, t = outputs; t ; t = TREE_CHAIN (t), op++)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
624 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
625 tree name = TREE_PURPOSE (TREE_PURPOSE (t));
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
626 if (name && strcmp (TREE_STRING_POINTER (name), p) == 0)
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
627 goto found;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
628 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
629 for (t = inputs; t ; t = TREE_CHAIN (t), op++)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
630 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
631 tree name = TREE_PURPOSE (TREE_PURPOSE (t));
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
632 if (name && strcmp (TREE_STRING_POINTER (name), p) == 0)
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
633 goto found;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
634 }
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
635 for (t = labels; t ; t = TREE_CHAIN (t), op++)
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
636 {
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
637 tree name = TREE_PURPOSE (t);
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
638 if (name && strcmp (TREE_STRING_POINTER (name), p) == 0)
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
639 goto found;
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
640 }
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
641
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
642 error ("undefined named operand %qs", identifier_to_locale (p));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
643 op = 0;
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
644
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
645 found:
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
646 /* Replace the name with the number. Unfortunately, not all libraries
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
647 get the return value of sprintf correct, so search for the end of the
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
648 generated string by hand. */
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
649 sprintf (--p, "%d", op);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
650 p = strchr (p, '\0');
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
651
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
652 /* Verify the no extra buffer space assumption. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
653 gcc_assert (p <= q);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
654
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
655 /* Shift the rest of the buffer down to fill the gap. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
656 memmove (p, q + 1, strlen (q + 1) + 1);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
657
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
658 return p;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
659 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
660
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
661
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
662 /* Generate RTL to return directly from the current function.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
663 (That is, we bypass any return value.) */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
664
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
665 void
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
666 expand_naked_return (void)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
667 {
111
kono
parents: 67
diff changeset
668 rtx_code_label *end_label;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
669
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
670 clear_pending_stack_adjust ();
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
671 do_pending_stack_adjust ();
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
672
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
673 end_label = naked_return_label;
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
674 if (end_label == 0)
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
675 end_label = naked_return_label = gen_label_rtx ();
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
676
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
677 emit_jump (end_label);
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
678 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
679
111
kono
parents: 67
diff changeset
680 /* Generate code to jump to LABEL if OP0 and OP1 are equal in mode MODE. PROB
kono
parents: 67
diff changeset
681 is the probability of jumping to LABEL. */
kono
parents: 67
diff changeset
682 static void
kono
parents: 67
diff changeset
683 do_jump_if_equal (machine_mode mode, rtx op0, rtx op1, rtx_code_label *label,
kono
parents: 67
diff changeset
684 int unsignedp, profile_probability prob)
kono
parents: 67
diff changeset
685 {
kono
parents: 67
diff changeset
686 do_compare_rtx_and_jump (op0, op1, EQ, unsignedp, mode,
kono
parents: 67
diff changeset
687 NULL_RTX, NULL, label, prob);
kono
parents: 67
diff changeset
688 }
kono
parents: 67
diff changeset
689
kono
parents: 67
diff changeset
690 /* Return the sum of probabilities of outgoing edges of basic block BB. */
kono
parents: 67
diff changeset
691
kono
parents: 67
diff changeset
692 static profile_probability
kono
parents: 67
diff changeset
693 get_outgoing_edge_probs (basic_block bb)
kono
parents: 67
diff changeset
694 {
kono
parents: 67
diff changeset
695 edge e;
kono
parents: 67
diff changeset
696 edge_iterator ei;
kono
parents: 67
diff changeset
697 profile_probability prob_sum = profile_probability::never ();
kono
parents: 67
diff changeset
698 if (!bb)
kono
parents: 67
diff changeset
699 return profile_probability::never ();
kono
parents: 67
diff changeset
700 FOR_EACH_EDGE (e, ei, bb->succs)
kono
parents: 67
diff changeset
701 prob_sum += e->probability;
kono
parents: 67
diff changeset
702 return prob_sum;
kono
parents: 67
diff changeset
703 }
kono
parents: 67
diff changeset
704
kono
parents: 67
diff changeset
705 /* Computes the conditional probability of jumping to a target if the branch
kono
parents: 67
diff changeset
706 instruction is executed.
kono
parents: 67
diff changeset
707 TARGET_PROB is the estimated probability of jumping to a target relative
kono
parents: 67
diff changeset
708 to some basic block BB.
kono
parents: 67
diff changeset
709 BASE_PROB is the probability of reaching the branch instruction relative
kono
parents: 67
diff changeset
710 to the same basic block BB. */
kono
parents: 67
diff changeset
711
kono
parents: 67
diff changeset
712 static inline profile_probability
kono
parents: 67
diff changeset
713 conditional_probability (profile_probability target_prob,
kono
parents: 67
diff changeset
714 profile_probability base_prob)
kono
parents: 67
diff changeset
715 {
kono
parents: 67
diff changeset
716 return target_prob / base_prob;
kono
parents: 67
diff changeset
717 }
kono
parents: 67
diff changeset
718
kono
parents: 67
diff changeset
719 /* Generate a dispatch tabler, switching on INDEX_EXPR and jumping to
kono
parents: 67
diff changeset
720 one of the labels in CASE_LIST or to the DEFAULT_LABEL.
kono
parents: 67
diff changeset
721 MINVAL, MAXVAL, and RANGE are the extrema and range of the case
kono
parents: 67
diff changeset
722 labels in CASE_LIST. STMT_BB is the basic block containing the statement.
kono
parents: 67
diff changeset
723
kono
parents: 67
diff changeset
724 First, a jump insn is emitted. First we try "casesi". If that
kono
parents: 67
diff changeset
725 fails, try "tablejump". A target *must* have one of them (or both).
kono
parents: 67
diff changeset
726
kono
parents: 67
diff changeset
727 Then, a table with the target labels is emitted.
kono
parents: 67
diff changeset
728
kono
parents: 67
diff changeset
729 The process is unaware of the CFG. The caller has to fix up
kono
parents: 67
diff changeset
730 the CFG itself. This is done in cfgexpand.c. */
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
731
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
732 static void
111
kono
parents: 67
diff changeset
733 emit_case_dispatch_table (tree index_expr, tree index_type,
kono
parents: 67
diff changeset
734 auto_vec<simple_case_node> &case_list,
kono
parents: 67
diff changeset
735 rtx default_label,
kono
parents: 67
diff changeset
736 edge default_edge, tree minval, tree maxval,
kono
parents: 67
diff changeset
737 tree range, basic_block stmt_bb)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
738 {
111
kono
parents: 67
diff changeset
739 int i, ncases;
kono
parents: 67
diff changeset
740 rtx *labelvec;
kono
parents: 67
diff changeset
741 rtx_insn *fallback_label = label_rtx (case_list[0].m_code_label);
kono
parents: 67
diff changeset
742 rtx_code_label *table_label = gen_label_rtx ();
kono
parents: 67
diff changeset
743 bool has_gaps = false;
kono
parents: 67
diff changeset
744 profile_probability default_prob = default_edge ? default_edge->probability
kono
parents: 67
diff changeset
745 : profile_probability::never ();
kono
parents: 67
diff changeset
746 profile_probability base = get_outgoing_edge_probs (stmt_bb);
kono
parents: 67
diff changeset
747 bool try_with_tablejump = false;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
748
111
kono
parents: 67
diff changeset
749 profile_probability new_default_prob = conditional_probability (default_prob,
kono
parents: 67
diff changeset
750 base);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
751
111
kono
parents: 67
diff changeset
752 if (! try_casesi (index_type, index_expr, minval, range,
kono
parents: 67
diff changeset
753 table_label, default_label, fallback_label,
kono
parents: 67
diff changeset
754 new_default_prob))
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
755 {
111
kono
parents: 67
diff changeset
756 /* Index jumptables from zero for suitable values of minval to avoid
kono
parents: 67
diff changeset
757 a subtraction. For the rationale see:
kono
parents: 67
diff changeset
758 "http://gcc.gnu.org/ml/gcc-patches/2001-10/msg01234.html". */
kono
parents: 67
diff changeset
759 if (optimize_insn_for_speed_p ()
kono
parents: 67
diff changeset
760 && compare_tree_int (minval, 0) > 0
kono
parents: 67
diff changeset
761 && compare_tree_int (minval, 3) < 0)
kono
parents: 67
diff changeset
762 {
kono
parents: 67
diff changeset
763 minval = build_int_cst (index_type, 0);
kono
parents: 67
diff changeset
764 range = maxval;
kono
parents: 67
diff changeset
765 has_gaps = true;
kono
parents: 67
diff changeset
766 }
kono
parents: 67
diff changeset
767 try_with_tablejump = true;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
768 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
769
111
kono
parents: 67
diff changeset
770 /* Get table of labels to jump to, in order of case index. */
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
771
111
kono
parents: 67
diff changeset
772 ncases = tree_to_shwi (range) + 1;
kono
parents: 67
diff changeset
773 labelvec = XALLOCAVEC (rtx, ncases);
kono
parents: 67
diff changeset
774 memset (labelvec, 0, ncases * sizeof (rtx));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
775
111
kono
parents: 67
diff changeset
776 for (unsigned j = 0; j < case_list.length (); j++)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
777 {
111
kono
parents: 67
diff changeset
778 simple_case_node *n = &case_list[j];
kono
parents: 67
diff changeset
779 /* Compute the low and high bounds relative to the minimum
kono
parents: 67
diff changeset
780 value since that should fit in a HOST_WIDE_INT while the
kono
parents: 67
diff changeset
781 actual values may not. */
kono
parents: 67
diff changeset
782 HOST_WIDE_INT i_low
kono
parents: 67
diff changeset
783 = tree_to_uhwi (fold_build2 (MINUS_EXPR, index_type,
kono
parents: 67
diff changeset
784 n->m_low, minval));
kono
parents: 67
diff changeset
785 HOST_WIDE_INT i_high
kono
parents: 67
diff changeset
786 = tree_to_uhwi (fold_build2 (MINUS_EXPR, index_type,
kono
parents: 67
diff changeset
787 n->m_high, minval));
kono
parents: 67
diff changeset
788 HOST_WIDE_INT i;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
789
111
kono
parents: 67
diff changeset
790 for (i = i_low; i <= i_high; i ++)
kono
parents: 67
diff changeset
791 labelvec[i]
kono
parents: 67
diff changeset
792 = gen_rtx_LABEL_REF (Pmode, label_rtx (n->m_code_label));
kono
parents: 67
diff changeset
793 }
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
794
111
kono
parents: 67
diff changeset
795 /* The dispatch table may contain gaps, including at the beginning of
kono
parents: 67
diff changeset
796 the table if we tried to avoid the minval subtraction. We fill the
kono
parents: 67
diff changeset
797 dispatch table slots associated with the gaps with the default case label.
kono
parents: 67
diff changeset
798 However, in the event the default case is unreachable, we then use
kono
parents: 67
diff changeset
799 any label from one of the case statements. */
kono
parents: 67
diff changeset
800 rtx gap_label = (default_label) ? default_label : fallback_label;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
801
111
kono
parents: 67
diff changeset
802 for (i = 0; i < ncases; i++)
kono
parents: 67
diff changeset
803 if (labelvec[i] == 0)
kono
parents: 67
diff changeset
804 {
kono
parents: 67
diff changeset
805 has_gaps = true;
kono
parents: 67
diff changeset
806 labelvec[i] = gen_rtx_LABEL_REF (Pmode, gap_label);
kono
parents: 67
diff changeset
807 }
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
808
111
kono
parents: 67
diff changeset
809 if (has_gaps && default_label)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
810 {
111
kono
parents: 67
diff changeset
811 /* There is at least one entry in the jump table that jumps
kono
parents: 67
diff changeset
812 to default label. The default label can either be reached
kono
parents: 67
diff changeset
813 through the indirect jump or the direct conditional jump
kono
parents: 67
diff changeset
814 before that. Split the probability of reaching the
kono
parents: 67
diff changeset
815 default label among these two jumps. */
kono
parents: 67
diff changeset
816 new_default_prob
kono
parents: 67
diff changeset
817 = conditional_probability (default_prob.apply_scale (1, 2), base);
kono
parents: 67
diff changeset
818 default_prob = default_prob.apply_scale (1, 2);
kono
parents: 67
diff changeset
819 base -= default_prob;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
820 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
821 else
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
822 {
111
kono
parents: 67
diff changeset
823 base -= default_prob;
kono
parents: 67
diff changeset
824 default_prob = profile_probability::never ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
825 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
826
111
kono
parents: 67
diff changeset
827 if (default_edge)
kono
parents: 67
diff changeset
828 default_edge->probability = default_prob;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
829
111
kono
parents: 67
diff changeset
830 /* We have altered the probability of the default edge. So the probabilities
kono
parents: 67
diff changeset
831 of all other edges need to be adjusted so that it sums up to
kono
parents: 67
diff changeset
832 REG_BR_PROB_BASE. */
kono
parents: 67
diff changeset
833 if (base > profile_probability::never ())
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
834 {
111
kono
parents: 67
diff changeset
835 edge e;
kono
parents: 67
diff changeset
836 edge_iterator ei;
kono
parents: 67
diff changeset
837 FOR_EACH_EDGE (e, ei, stmt_bb->succs)
kono
parents: 67
diff changeset
838 e->probability /= base;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
839 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
840
111
kono
parents: 67
diff changeset
841 if (try_with_tablejump)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
842 {
111
kono
parents: 67
diff changeset
843 bool ok = try_tablejump (index_type, index_expr, minval, range,
kono
parents: 67
diff changeset
844 table_label, default_label, new_default_prob);
kono
parents: 67
diff changeset
845 gcc_assert (ok);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
846 }
111
kono
parents: 67
diff changeset
847 /* Output the table. */
kono
parents: 67
diff changeset
848 emit_label (table_label);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
849
111
kono
parents: 67
diff changeset
850 if (CASE_VECTOR_PC_RELATIVE || flag_pic)
kono
parents: 67
diff changeset
851 emit_jump_table_data (gen_rtx_ADDR_DIFF_VEC (CASE_VECTOR_MODE,
kono
parents: 67
diff changeset
852 gen_rtx_LABEL_REF (Pmode,
kono
parents: 67
diff changeset
853 table_label),
kono
parents: 67
diff changeset
854 gen_rtvec_v (ncases, labelvec),
kono
parents: 67
diff changeset
855 const0_rtx, const0_rtx));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
856 else
111
kono
parents: 67
diff changeset
857 emit_jump_table_data (gen_rtx_ADDR_VEC (CASE_VECTOR_MODE,
kono
parents: 67
diff changeset
858 gen_rtvec_v (ncases, labelvec)));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
859
111
kono
parents: 67
diff changeset
860 /* Record no drop-through after the table. */
kono
parents: 67
diff changeset
861 emit_barrier ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
862 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
863
111
kono
parents: 67
diff changeset
864 /* Terminate a case Ada or switch (C) statement
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
865 in which ORIG_INDEX is the expression to be tested.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
866 If ORIG_TYPE is not NULL, it is the original ORIG_INDEX
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
867 type as given in the source before any compiler conversions.
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
868 Generate the code to test it and jump to the right place. */
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
869
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
870 void
111
kono
parents: 67
diff changeset
871 expand_case (gswitch *stmt)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
872 {
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
873 tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE;
111
kono
parents: 67
diff changeset
874 rtx_code_label *default_label;
kono
parents: 67
diff changeset
875 unsigned int count;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
876 int i;
111
kono
parents: 67
diff changeset
877 int ncases = gimple_switch_num_labels (stmt);
55
77e2b8dfacca update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents: 19
diff changeset
878 tree index_expr = gimple_switch_index (stmt);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
879 tree index_type = TREE_TYPE (index_expr);
111
kono
parents: 67
diff changeset
880 tree elt;
kono
parents: 67
diff changeset
881 basic_block bb = gimple_bb (stmt);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
882
111
kono
parents: 67
diff changeset
883 auto_vec<simple_case_node> case_list;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
884
111
kono
parents: 67
diff changeset
885 /* An ERROR_MARK occurs for various reasons including invalid data type.
kono
parents: 67
diff changeset
886 ??? Can this still happen, with GIMPLE and all? */
kono
parents: 67
diff changeset
887 if (index_type == error_mark_node)
kono
parents: 67
diff changeset
888 return;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
889
111
kono
parents: 67
diff changeset
890 /* cleanup_tree_cfg removes all SWITCH_EXPR with their index
kono
parents: 67
diff changeset
891 expressions being INTEGER_CST. */
kono
parents: 67
diff changeset
892 gcc_assert (TREE_CODE (index_expr) != INTEGER_CST);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
893
111
kono
parents: 67
diff changeset
894 /* Optimization of switch statements with only one label has already
kono
parents: 67
diff changeset
895 occurred, so we should never see them at this point. */
kono
parents: 67
diff changeset
896 gcc_assert (ncases > 1);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
897
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
898 do_pending_stack_adjust ();
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
899
111
kono
parents: 67
diff changeset
900 /* Find the default case target label. */
kono
parents: 67
diff changeset
901 tree default_lab = CASE_LABEL (gimple_switch_default_label (stmt));
kono
parents: 67
diff changeset
902 default_label = jump_target_rtx (default_lab);
kono
parents: 67
diff changeset
903 basic_block default_bb = label_to_block_fn (cfun, default_lab);
kono
parents: 67
diff changeset
904 edge default_edge = find_edge (bb, default_bb);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
905
111
kono
parents: 67
diff changeset
906 /* Get upper and lower bounds of case values. */
kono
parents: 67
diff changeset
907 elt = gimple_switch_label (stmt, 1);
kono
parents: 67
diff changeset
908 minval = fold_convert (index_type, CASE_LOW (elt));
kono
parents: 67
diff changeset
909 elt = gimple_switch_label (stmt, ncases - 1);
kono
parents: 67
diff changeset
910 if (CASE_HIGH (elt))
kono
parents: 67
diff changeset
911 maxval = fold_convert (index_type, CASE_HIGH (elt));
kono
parents: 67
diff changeset
912 else
kono
parents: 67
diff changeset
913 maxval = fold_convert (index_type, CASE_LOW (elt));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
914
111
kono
parents: 67
diff changeset
915 /* Compute span of values. */
kono
parents: 67
diff changeset
916 range = fold_build2 (MINUS_EXPR, index_type, maxval, minval);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
917
111
kono
parents: 67
diff changeset
918 /* Listify the labels queue and gather some numbers to decide
kono
parents: 67
diff changeset
919 how to expand this switch(). */
kono
parents: 67
diff changeset
920 count = 0;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
921
111
kono
parents: 67
diff changeset
922 for (i = ncases - 1; i >= 1; --i)
kono
parents: 67
diff changeset
923 {
kono
parents: 67
diff changeset
924 elt = gimple_switch_label (stmt, i);
kono
parents: 67
diff changeset
925 tree low = CASE_LOW (elt);
kono
parents: 67
diff changeset
926 gcc_assert (low);
kono
parents: 67
diff changeset
927 tree high = CASE_HIGH (elt);
kono
parents: 67
diff changeset
928 gcc_assert (! high || tree_int_cst_lt (low, high));
kono
parents: 67
diff changeset
929 tree lab = CASE_LABEL (elt);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
930
111
kono
parents: 67
diff changeset
931 /* Count the elements.
kono
parents: 67
diff changeset
932 A range counts double, since it requires two compares. */
kono
parents: 67
diff changeset
933 count++;
kono
parents: 67
diff changeset
934 if (high)
kono
parents: 67
diff changeset
935 count++;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
936
111
kono
parents: 67
diff changeset
937 /* The bounds on the case range, LOW and HIGH, have to be converted
kono
parents: 67
diff changeset
938 to case's index type TYPE. Note that the original type of the
kono
parents: 67
diff changeset
939 case index in the source code is usually "lost" during
kono
parents: 67
diff changeset
940 gimplification due to type promotion, but the case labels retain the
kono
parents: 67
diff changeset
941 original type. Make sure to drop overflow flags. */
kono
parents: 67
diff changeset
942 low = fold_convert (index_type, low);
kono
parents: 67
diff changeset
943 if (TREE_OVERFLOW (low))
kono
parents: 67
diff changeset
944 low = wide_int_to_tree (index_type, wi::to_wide (low));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
945
111
kono
parents: 67
diff changeset
946 /* The canonical from of a case label in GIMPLE is that a simple case
kono
parents: 67
diff changeset
947 has an empty CASE_HIGH. For the casesi and tablejump expanders,
kono
parents: 67
diff changeset
948 the back ends want simple cases to have high == low. */
kono
parents: 67
diff changeset
949 if (! high)
kono
parents: 67
diff changeset
950 high = low;
kono
parents: 67
diff changeset
951 high = fold_convert (index_type, high);
kono
parents: 67
diff changeset
952 if (TREE_OVERFLOW (high))
kono
parents: 67
diff changeset
953 high = wide_int_to_tree (index_type, wi::to_wide (high));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
954
111
kono
parents: 67
diff changeset
955 case_list.safe_push (simple_case_node (low, high, lab));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
956 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
957
111
kono
parents: 67
diff changeset
958 /* cleanup_tree_cfg removes all SWITCH_EXPR with a single
kono
parents: 67
diff changeset
959 destination, such as one with a default case only.
kono
parents: 67
diff changeset
960 It also removes cases that are out of range for the switch
kono
parents: 67
diff changeset
961 type, so we should never get a zero here. */
kono
parents: 67
diff changeset
962 gcc_assert (count > 0);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
963
111
kono
parents: 67
diff changeset
964 rtx_insn *before_case = get_last_insn ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
965
111
kono
parents: 67
diff changeset
966 /* Decide how to expand this switch.
kono
parents: 67
diff changeset
967 The two options at this point are a dispatch table (casesi or
kono
parents: 67
diff changeset
968 tablejump) or a decision tree. */
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
969
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
970 {
111
kono
parents: 67
diff changeset
971 /* If the default case is unreachable, then set default_label to NULL
kono
parents: 67
diff changeset
972 so that we omit the range check when generating the dispatch table.
kono
parents: 67
diff changeset
973 We also remove the edge to the unreachable default case. The block
kono
parents: 67
diff changeset
974 itself will be automatically removed later. */
kono
parents: 67
diff changeset
975 if (EDGE_COUNT (default_edge->dest->succs) == 0
kono
parents: 67
diff changeset
976 && gimple_seq_unreachable_p (bb_seq (default_edge->dest)))
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
977 {
111
kono
parents: 67
diff changeset
978 default_label = NULL;
kono
parents: 67
diff changeset
979 remove_edge (default_edge);
kono
parents: 67
diff changeset
980 default_edge = NULL;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
981 }
111
kono
parents: 67
diff changeset
982 emit_case_dispatch_table (index_expr, index_type,
kono
parents: 67
diff changeset
983 case_list, default_label, default_edge,
kono
parents: 67
diff changeset
984 minval, maxval, range, bb);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
985 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
986
111
kono
parents: 67
diff changeset
987 reorder_insns (NEXT_INSN (before_case), get_last_insn (), before_case);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
988
111
kono
parents: 67
diff changeset
989 free_temp_slots ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
990 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
991
111
kono
parents: 67
diff changeset
992 /* Expand the dispatch to a short decrement chain if there are few cases
kono
parents: 67
diff changeset
993 to dispatch to. Likewise if neither casesi nor tablejump is available,
kono
parents: 67
diff changeset
994 or if flag_jump_tables is set. Otherwise, expand as a casesi or a
kono
parents: 67
diff changeset
995 tablejump. The index mode is always the mode of integer_type_node.
kono
parents: 67
diff changeset
996 Trap if no case matches the index.
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
997
111
kono
parents: 67
diff changeset
998 DISPATCH_INDEX is the index expression to switch on. It should be a
kono
parents: 67
diff changeset
999 memory or register operand.
kono
parents: 67
diff changeset
1000
kono
parents: 67
diff changeset
1001 DISPATCH_TABLE is a set of case labels. The set should be sorted in
kono
parents: 67
diff changeset
1002 ascending order, be contiguous, starting with value 0, and contain only
kono
parents: 67
diff changeset
1003 single-valued case labels. */
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1004
111
kono
parents: 67
diff changeset
1005 void
kono
parents: 67
diff changeset
1006 expand_sjlj_dispatch_table (rtx dispatch_index,
kono
parents: 67
diff changeset
1007 vec<tree> dispatch_table)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1008 {
111
kono
parents: 67
diff changeset
1009 tree index_type = integer_type_node;
kono
parents: 67
diff changeset
1010 machine_mode index_mode = TYPE_MODE (index_type);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1011
111
kono
parents: 67
diff changeset
1012 int ncases = dispatch_table.length ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1013
111
kono
parents: 67
diff changeset
1014 do_pending_stack_adjust ();
kono
parents: 67
diff changeset
1015 rtx_insn *before_case = get_last_insn ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1016
111
kono
parents: 67
diff changeset
1017 /* Expand as a decrement-chain if there are 5 or fewer dispatch
kono
parents: 67
diff changeset
1018 labels. This covers more than 98% of the cases in libjava,
kono
parents: 67
diff changeset
1019 and seems to be a reasonable compromise between the "old way"
kono
parents: 67
diff changeset
1020 of expanding as a decision tree or dispatch table vs. the "new
kono
parents: 67
diff changeset
1021 way" with decrement chain or dispatch table. */
kono
parents: 67
diff changeset
1022 if (dispatch_table.length () <= 5
kono
parents: 67
diff changeset
1023 || (!targetm.have_casesi () && !targetm.have_tablejump ())
kono
parents: 67
diff changeset
1024 || !flag_jump_tables)
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1025 {
111
kono
parents: 67
diff changeset
1026 /* Expand the dispatch as a decrement chain:
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1027
111
kono
parents: 67
diff changeset
1028 "switch(index) {case 0: do_0; case 1: do_1; ...; case N: do_N;}"
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1029
111
kono
parents: 67
diff changeset
1030 ==>
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1031
111
kono
parents: 67
diff changeset
1032 if (index == 0) do_0; else index--;
kono
parents: 67
diff changeset
1033 if (index == 0) do_1; else index--;
kono
parents: 67
diff changeset
1034 ...
kono
parents: 67
diff changeset
1035 if (index == 0) do_N; else index--;
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1036
111
kono
parents: 67
diff changeset
1037 This is more efficient than a dispatch table on most machines.
kono
parents: 67
diff changeset
1038 The last "index--" is redundant but the code is trivially dead
kono
parents: 67
diff changeset
1039 and will be cleaned up by later passes. */
kono
parents: 67
diff changeset
1040 rtx index = copy_to_mode_reg (index_mode, dispatch_index);
kono
parents: 67
diff changeset
1041 rtx zero = CONST0_RTX (index_mode);
kono
parents: 67
diff changeset
1042 for (int i = 0; i < ncases; i++)
kono
parents: 67
diff changeset
1043 {
kono
parents: 67
diff changeset
1044 tree elt = dispatch_table[i];
kono
parents: 67
diff changeset
1045 rtx_code_label *lab = jump_target_rtx (CASE_LABEL (elt));
kono
parents: 67
diff changeset
1046 do_jump_if_equal (index_mode, index, zero, lab, 0,
kono
parents: 67
diff changeset
1047 profile_probability::uninitialized ());
kono
parents: 67
diff changeset
1048 force_expand_binop (index_mode, sub_optab,
kono
parents: 67
diff changeset
1049 index, CONST1_RTX (index_mode),
kono
parents: 67
diff changeset
1050 index, 0, OPTAB_DIRECT);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1051 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1052 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1053 else
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1054 {
111
kono
parents: 67
diff changeset
1055 /* Similar to expand_case, but much simpler. */
kono
parents: 67
diff changeset
1056 auto_vec<simple_case_node> case_list;
kono
parents: 67
diff changeset
1057 tree index_expr = make_tree (index_type, dispatch_index);
kono
parents: 67
diff changeset
1058 tree minval = build_int_cst (index_type, 0);
kono
parents: 67
diff changeset
1059 tree maxval = CASE_LOW (dispatch_table.last ());
kono
parents: 67
diff changeset
1060 tree range = maxval;
kono
parents: 67
diff changeset
1061 rtx_code_label *default_label = gen_label_rtx ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1062
111
kono
parents: 67
diff changeset
1063 for (int i = ncases - 1; i >= 0; --i)
kono
parents: 67
diff changeset
1064 {
kono
parents: 67
diff changeset
1065 tree elt = dispatch_table[i];
kono
parents: 67
diff changeset
1066 tree high = CASE_HIGH (elt);
kono
parents: 67
diff changeset
1067 if (high == NULL_TREE)
kono
parents: 67
diff changeset
1068 high = CASE_LOW (elt);
kono
parents: 67
diff changeset
1069 case_list.safe_push (simple_case_node (CASE_LOW (elt), high,
kono
parents: 67
diff changeset
1070 CASE_LABEL (elt)));
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1071 }
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1072
111
kono
parents: 67
diff changeset
1073 emit_case_dispatch_table (index_expr, index_type,
kono
parents: 67
diff changeset
1074 case_list, default_label, NULL,
kono
parents: 67
diff changeset
1075 minval, maxval, range,
kono
parents: 67
diff changeset
1076 BLOCK_FOR_INSN (before_case));
kono
parents: 67
diff changeset
1077 emit_label (default_label);
kono
parents: 67
diff changeset
1078 }
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1079
111
kono
parents: 67
diff changeset
1080 /* Dispatching something not handled? Trap! */
kono
parents: 67
diff changeset
1081 expand_builtin_trap ();
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1082
111
kono
parents: 67
diff changeset
1083 reorder_insns (NEXT_INSN (before_case), get_last_insn (), before_case);
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1084
111
kono
parents: 67
diff changeset
1085 free_temp_slots ();
kono
parents: 67
diff changeset
1086 }
0
a06113de4d67 first commit
kent <kent@cr.ie.u-ryukyu.ac.jp>
parents:
diff changeset
1087
111
kono
parents: 67
diff changeset
1088