1 | /* This file contains subroutine used by the C front-end to construct GENERIC. |
2 | Copyright (C) 2000-2023 Free Software Foundation, Inc. |
3 | Written by Benjamin Chelf (chelf@codesourcery.com). |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free |
9 | Software Foundation; either version 3, or (at your option) any later |
10 | version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #include "config.h" |
22 | #include "system.h" |
23 | #include "coretypes.h" |
24 | #include "c-common.h" |
25 | #include "tree-iterator.h" |
26 | |
27 | /* Create an empty statement tree rooted at T. */ |
28 | |
29 | tree |
30 | push_stmt_list (void) |
31 | { |
32 | tree t; |
33 | t = alloc_stmt_list (); |
34 | vec_safe_push (stmt_list_stack, obj: t); |
35 | return t; |
36 | } |
37 | |
38 | /* Return TRUE if, after I, there are any nondebug stmts. */ |
39 | |
40 | static inline bool |
41 | only_debug_stmts_after_p (tree_stmt_iterator i) |
42 | { |
43 | for (tsi_next (i: &i); !tsi_end_p (i); tsi_next (i: &i)) |
44 | if (TREE_CODE (tsi_stmt (i)) != DEBUG_BEGIN_STMT) |
45 | return false; |
46 | return true; |
47 | } |
48 | |
49 | /* Finish the statement tree rooted at T. */ |
50 | |
51 | tree |
52 | pop_stmt_list (tree t) |
53 | { |
54 | tree u = NULL_TREE; |
55 | |
56 | /* Pop statement lists until we reach the target level. The extra |
57 | nestings will be due to outstanding cleanups. */ |
58 | while (1) |
59 | { |
60 | u = stmt_list_stack->pop (); |
61 | if (!stmt_list_stack->is_empty ()) |
62 | { |
63 | tree x = stmt_list_stack->last (); |
64 | STATEMENT_LIST_HAS_LABEL (x) |= STATEMENT_LIST_HAS_LABEL (u); |
65 | } |
66 | if (t == u) |
67 | break; |
68 | } |
69 | |
70 | gcc_assert (u != NULL_TREE); |
71 | |
72 | /* If the statement list is completely empty, just return it. This is |
73 | just as good small as build_empty_stmt, with the advantage that |
74 | statement lists are merged when they appended to one another. So |
75 | using the STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P |
76 | statements. */ |
77 | if (TREE_SIDE_EFFECTS (t)) |
78 | { |
79 | tree_stmt_iterator i = tsi_start (t); |
80 | |
81 | /* If the statement list contained exactly one statement, then |
82 | extract it immediately. */ |
83 | if (tsi_one_before_end_p (i)) |
84 | { |
85 | u = tsi_stmt (i); |
86 | tsi_delink (&i); |
87 | free_stmt_list (t); |
88 | t = u; |
89 | } |
90 | /* If the statement list contained a debug begin stmt and a |
91 | statement list, move the debug begin stmt into the statement |
92 | list and return it. */ |
93 | else if (!tsi_end_p (i) |
94 | && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT) |
95 | { |
96 | u = tsi_stmt (i); |
97 | tsi_next (i: &i); |
98 | if (tsi_one_before_end_p (i) |
99 | && TREE_CODE (tsi_stmt (i)) == STATEMENT_LIST) |
100 | { |
101 | tree l = tsi_stmt (i); |
102 | tsi_prev (i: &i); |
103 | tsi_delink (&i); |
104 | tsi_delink (&i); |
105 | i = tsi_start (t: l); |
106 | free_stmt_list (t); |
107 | t = l; |
108 | tsi_link_before (&i, u, TSI_SAME_STMT); |
109 | } |
110 | while (!tsi_end_p (i) |
111 | && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT) |
112 | tsi_next (i: &i); |
113 | /* If there are only debug stmts in the list, without them |
114 | we'd have an empty stmt without side effects. If there's |
115 | only one nondebug stmt, we'd have extracted the stmt and |
116 | dropped the list, and we'd take TREE_SIDE_EFFECTS from |
117 | that statement. In either case, keep the list's |
118 | TREE_SIDE_EFFECTS in sync. */ |
119 | if (tsi_end_p (i)) |
120 | TREE_SIDE_EFFECTS (t) = 0; |
121 | else if (only_debug_stmts_after_p (i)) |
122 | TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (tsi_stmt (i)); |
123 | } |
124 | } |
125 | |
126 | return t; |
127 | } |
128 | |
129 | /* Build a generic statement based on the given type of node and |
130 | arguments. Similar to `build_nt', except that we set |
131 | EXPR_LOCATION to LOC. */ |
132 | /* ??? This should be obsolete with the lineno_stmt productions |
133 | in the grammar. */ |
134 | |
135 | tree |
136 | build_stmt (location_t loc, enum tree_code code, ...) |
137 | { |
138 | tree ret; |
139 | int length, i; |
140 | va_list p; |
141 | bool side_effects; |
142 | |
143 | /* This function cannot be used to construct variably-sized nodes. */ |
144 | gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp); |
145 | |
146 | va_start (p, code); |
147 | |
148 | ret = make_node (code); |
149 | TREE_TYPE (ret) = void_type_node; |
150 | length = TREE_CODE_LENGTH (code); |
151 | SET_EXPR_LOCATION (ret, loc); |
152 | |
153 | /* TREE_SIDE_EFFECTS will already be set for statements with |
154 | implicit side effects. Here we make sure it is set for other |
155 | expressions by checking whether the parameters have side |
156 | effects. */ |
157 | |
158 | side_effects = false; |
159 | for (i = 0; i < length; i++) |
160 | { |
161 | tree t = va_arg (p, tree); |
162 | if (t && !TYPE_P (t)) |
163 | side_effects |= TREE_SIDE_EFFECTS (t); |
164 | TREE_OPERAND (ret, i) = t; |
165 | } |
166 | |
167 | TREE_SIDE_EFFECTS (ret) |= side_effects; |
168 | |
169 | va_end (p); |
170 | return ret; |
171 | } |
172 | |
173 | /* Build a REALPART_EXPR or IMAGPART_EXPR, according to CODE, from ARG. */ |
174 | |
175 | tree |
176 | build_real_imag_expr (location_t location, enum tree_code code, tree arg) |
177 | { |
178 | tree ret; |
179 | tree arg_type = TREE_TYPE (arg); |
180 | |
181 | gcc_assert (code == REALPART_EXPR || code == IMAGPART_EXPR); |
182 | |
183 | if (TREE_CODE (arg_type) == COMPLEX_TYPE) |
184 | { |
185 | ret = build1 (code, TREE_TYPE (TREE_TYPE (arg)), arg); |
186 | SET_EXPR_LOCATION (ret, location); |
187 | } |
188 | else if (INTEGRAL_TYPE_P (arg_type) || SCALAR_FLOAT_TYPE_P (arg_type)) |
189 | { |
190 | ret = (code == REALPART_EXPR |
191 | ? arg |
192 | : omit_one_operand_loc (location, arg_type, |
193 | integer_zero_node, arg)); |
194 | } |
195 | else |
196 | { |
197 | error_at (location, "wrong type argument to %s" , |
198 | code == REALPART_EXPR ? "__real" : "__imag" ); |
199 | ret = error_mark_node; |
200 | } |
201 | |
202 | return ret; |
203 | } |
204 | |