]>
Commit | Line | Data |
---|---|---|
41299f41 | 1 | /* Generate code from machine description to extract operands from insn as rtl. |
a945c346 | 2 | Copyright (C) 1987-2024 Free Software Foundation, Inc. |
41299f41 | 3 | |
1322177d | 4 | This file is part of GCC. |
41299f41 | 5 | |
1322177d LB |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free | |
9dcd6f09 | 8 | Software Foundation; either version 3, or (at your option) any later |
1322177d | 9 | version. |
41299f41 | 10 | |
1322177d LB |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | for more details. | |
41299f41 TW |
15 | |
16 | You should have received a copy of the GNU General Public License | |
9dcd6f09 NC |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
41299f41 TW |
19 | |
20 | ||
4977bab6 | 21 | #include "bconfig.h" |
0b93b64e | 22 | #include "system.h" |
4977bab6 ZW |
23 | #include "coretypes.h" |
24 | #include "tm.h" | |
41299f41 | 25 | #include "rtl.h" |
f8b6598e | 26 | #include "errors.h" |
10692477 | 27 | #include "read-md.h" |
c88c0d42 | 28 | #include "gensupport.h" |
41299f41 | 29 | |
9482d6de | 30 | /* This structure contains all the information needed to describe one |
3d7aafde | 31 | set of extractions methods. Each method may be used by more than |
9482d6de RK |
32 | one pattern if the operands are in the same place. |
33 | ||
34 | The string for each operand describes that path to the operand and | |
35 | contains `0' through `9' when going into an expression and `a' through | |
085e8246 | 36 | `z' then 'A' through to 'Z' when going into a vector. We assume here that |
e53b6e56 | 37 | only the first operand of an rtl expression is a vector. genrecog.cc makes |
085e8246 AH |
38 | the same assumption (and uses the same representation) and it is currently |
39 | true. */ | |
9482d6de | 40 | |
245fc639 ZW |
41 | typedef char *locstr; |
42 | ||
9482d6de RK |
43 | struct extraction |
44 | { | |
245fc639 ZW |
45 | unsigned int op_count; |
46 | unsigned int dup_count; | |
47 | locstr *oplocs; | |
48 | locstr *duplocs; | |
49 | int *dupnums; | |
9482d6de RK |
50 | struct code_ptr *insns; |
51 | struct extraction *next; | |
52 | }; | |
53 | ||
245fc639 | 54 | /* Holds a single insn code that uses an extraction method. */ |
9482d6de RK |
55 | struct code_ptr |
56 | { | |
57 | int insn_code; | |
58 | struct code_ptr *next; | |
59 | }; | |
60 | ||
245fc639 | 61 | /* All extractions needed for this machine description. */ |
9482d6de RK |
62 | static struct extraction *extractions; |
63 | ||
245fc639 ZW |
64 | /* All insn codes for old-style peepholes. */ |
65 | static struct code_ptr *peepholes; | |
41299f41 | 66 | |
245fc639 ZW |
67 | /* This structure is used by gen_insn and walk_rtx to accumulate the |
68 | data that will be used to produce an extractions structure. */ | |
41299f41 | 69 | |
41299f41 | 70 | |
6c1dae73 | 71 | class accum_extract |
245fc639 | 72 | { |
6c1dae73 | 73 | public: |
3cc578b9 TS |
74 | accum_extract () : oplocs (10), duplocs (10), dupnums (10), pathstr (20) {} |
75 | ||
76 | auto_vec<locstr> oplocs; | |
77 | auto_vec<locstr> duplocs; | |
78 | auto_vec<int> dupnums; | |
79 | auto_vec<char> pathstr; | |
245fc639 | 80 | }; |
41299f41 | 81 | |
245fc639 | 82 | /* Forward declarations. */ |
99b1c316 | 83 | static void walk_rtx (md_rtx_info *, rtx, class accum_extract *); |
f8b6598e | 84 | |
085e8246 AH |
85 | #define UPPER_OFFSET ('A' - ('z' - 'a' + 1)) |
86 | ||
87 | /* Convert integer OPERAND into a character - either into [a-zA-Z] for vector | |
88 | operands or [0-9] for integer operands - and push onto the end of the path | |
89 | in ACC. */ | |
90 | static void | |
91 | push_pathstr_operand (int operand, bool is_vector, | |
99b1c316 | 92 | class accum_extract *acc) |
085e8246 AH |
93 | { |
94 | if (is_vector && 'a' + operand > 'z') | |
95 | acc->pathstr.safe_push (operand + UPPER_OFFSET); | |
96 | else if (is_vector) | |
97 | acc->pathstr.safe_push (operand + 'a'); | |
98 | else | |
99 | acc->pathstr.safe_push (operand + '0'); | |
100 | } | |
101 | ||
41299f41 | 102 | static void |
5d2d3e43 | 103 | gen_insn (md_rtx_info *info) |
41299f41 | 104 | { |
b3694847 | 105 | int i; |
245fc639 | 106 | unsigned int op_count, dup_count, j; |
b3694847 SS |
107 | struct extraction *p; |
108 | struct code_ptr *link; | |
99b1c316 | 109 | class accum_extract acc; |
41299f41 | 110 | |
41299f41 TW |
111 | /* Walk the insn's pattern, remembering at all times the path |
112 | down to the walking point. */ | |
113 | ||
5d2d3e43 | 114 | rtx insn = info->def; |
41299f41 | 115 | if (XVECLEN (insn, 1) == 1) |
5d2d3e43 | 116 | walk_rtx (info, XVECEXP (insn, 1, 0), &acc); |
41299f41 TW |
117 | else |
118 | for (i = XVECLEN (insn, 1) - 1; i >= 0; i--) | |
119 | { | |
085e8246 | 120 | push_pathstr_operand (i, true, &acc); |
5d2d3e43 | 121 | walk_rtx (info, XVECEXP (insn, 1, i), &acc); |
9771b263 | 122 | acc.pathstr.pop (); |
41299f41 | 123 | } |
41299f41 | 124 | |
245fc639 | 125 | link = XNEW (struct code_ptr); |
5d2d3e43 | 126 | link->insn_code = info->index; |
9482d6de | 127 | |
0f41302f | 128 | /* See if we find something that already had this extraction method. */ |
9482d6de | 129 | |
9771b263 DN |
130 | op_count = acc.oplocs.length (); |
131 | dup_count = acc.duplocs.length (); | |
132 | gcc_assert (dup_count == acc.dupnums.length ()); | |
245fc639 | 133 | |
9482d6de | 134 | for (p = extractions; p; p = p->next) |
41299f41 | 135 | { |
9482d6de RK |
136 | if (p->op_count != op_count || p->dup_count != dup_count) |
137 | continue; | |
138 | ||
245fc639 ZW |
139 | for (j = 0; j < op_count; j++) |
140 | { | |
141 | char *a = p->oplocs[j]; | |
9771b263 | 142 | char *b = acc.oplocs[j]; |
245fc639 ZW |
143 | if (a != b && (!a || !b || strcmp (a, b))) |
144 | break; | |
145 | } | |
9482d6de | 146 | |
245fc639 | 147 | if (j != op_count) |
9482d6de RK |
148 | continue; |
149 | ||
245fc639 | 150 | for (j = 0; j < dup_count; j++) |
9771b263 DN |
151 | if (p->dupnums[j] != acc.dupnums[j] |
152 | || strcmp (p->duplocs[j], acc.duplocs[j])) | |
9482d6de RK |
153 | break; |
154 | ||
245fc639 | 155 | if (j != dup_count) |
9482d6de RK |
156 | continue; |
157 | ||
158 | /* This extraction is the same as ours. Just link us in. */ | |
159 | link->next = p->insns; | |
160 | p->insns = link; | |
3cc578b9 | 161 | return; |
41299f41 TW |
162 | } |
163 | ||
245fc639 ZW |
164 | /* Otherwise, make a new extraction method. We stash the arrays |
165 | after the extraction structure in memory. */ | |
41299f41 | 166 | |
7cbb2a85 | 167 | p = XNEWVAR (struct extraction, sizeof (struct extraction) |
245fc639 ZW |
168 | + op_count*sizeof (char *) |
169 | + dup_count*sizeof (char *) | |
170 | + dup_count*sizeof (int)); | |
9482d6de RK |
171 | p->op_count = op_count; |
172 | p->dup_count = dup_count; | |
173 | p->next = extractions; | |
174 | extractions = p; | |
175 | p->insns = link; | |
176 | link->next = 0; | |
177 | ||
245fc639 ZW |
178 | p->oplocs = (char **)((char *)p + sizeof (struct extraction)); |
179 | p->duplocs = p->oplocs + op_count; | |
180 | p->dupnums = (int *)(p->duplocs + dup_count); | |
9482d6de | 181 | |
c3284718 RS |
182 | memcpy (p->oplocs, acc.oplocs.address (), op_count * sizeof (locstr)); |
183 | memcpy (p->duplocs, acc.duplocs.address (), dup_count * sizeof (locstr)); | |
184 | memcpy (p->dupnums, acc.dupnums.address (), dup_count * sizeof (int)); | |
9482d6de RK |
185 | } |
186 | \f | |
9771b263 | 187 | /* Helper subroutine of walk_rtx: given a vec<locstr>, an index, and a |
245fc639 ZW |
188 | string, insert the string at the index, which should either already |
189 | exist and be NULL, or not yet exist within the vector. In the latter | |
5d2d3e43 RS |
190 | case the vector is enlarged as appropriate. INFO describes the |
191 | containing define_* expression. */ | |
41299f41 | 192 | static void |
5d2d3e43 RS |
193 | VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp, |
194 | unsigned int ix, char *str) | |
245fc639 | 195 | { |
9771b263 | 196 | if (ix < (*vp).length ()) |
245fc639 | 197 | { |
9771b263 | 198 | if ((*vp)[ix]) |
7ddf71e3 | 199 | { |
5d2d3e43 | 200 | message_at (info->loc, "repeated operand number %d", ix); |
7ddf71e3 PB |
201 | have_error = 1; |
202 | } | |
203 | else | |
9771b263 | 204 | (*vp)[ix] = str; |
245fc639 ZW |
205 | } |
206 | else | |
207 | { | |
9771b263 DN |
208 | while (ix > (*vp).length ()) |
209 | vp->safe_push (NULL); | |
210 | vp->safe_push (str); | |
245fc639 ZW |
211 | } |
212 | } | |
213 | ||
9771b263 | 214 | /* Another helper subroutine of walk_rtx: given a vec<char>, convert it |
245fc639 ZW |
215 | to a NUL-terminated string in malloc memory. */ |
216 | static char * | |
00dcc88a | 217 | VEC_char_to_string (const vec<char> &v) |
245fc639 | 218 | { |
9771b263 | 219 | size_t n = v.length (); |
5ed6ace5 | 220 | char *s = XNEWVEC (char, n + 1); |
9771b263 | 221 | memcpy (s, v.address (), n); |
245fc639 ZW |
222 | s[n] = '\0'; |
223 | return s; | |
224 | } | |
225 | ||
226 | static void | |
99b1c316 | 227 | walk_rtx (md_rtx_info *info, rtx x, class accum_extract *acc) |
41299f41 | 228 | { |
b3694847 | 229 | RTX_CODE code; |
085e8246 | 230 | int i, len; |
b3694847 | 231 | const char *fmt; |
41299f41 TW |
232 | |
233 | if (x == 0) | |
234 | return; | |
235 | ||
236 | code = GET_CODE (x); | |
41299f41 TW |
237 | switch (code) |
238 | { | |
239 | case PC: | |
41299f41 TW |
240 | case CONST_INT: |
241 | case SYMBOL_REF: | |
242 | return; | |
243 | ||
244 | case MATCH_OPERAND: | |
245 | case MATCH_SCRATCH: | |
5d2d3e43 | 246 | VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0), |
245fc639 | 247 | VEC_char_to_string (acc->pathstr)); |
41299f41 TW |
248 | break; |
249 | ||
41299f41 | 250 | case MATCH_OPERATOR: |
245fc639 | 251 | case MATCH_PARALLEL: |
5d2d3e43 | 252 | VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0), |
245fc639 | 253 | VEC_char_to_string (acc->pathstr)); |
9482d6de | 254 | |
41299f41 TW |
255 | for (i = XVECLEN (x, 2) - 1; i >= 0; i--) |
256 | { | |
085e8246 | 257 | push_pathstr_operand (i, code != MATCH_OPERATOR, acc); |
5d2d3e43 | 258 | walk_rtx (info, XVECEXP (x, 2, i), acc); |
9771b263 | 259 | acc->pathstr.pop (); |
245fc639 | 260 | } |
41299f41 TW |
261 | return; |
262 | ||
245fc639 ZW |
263 | case MATCH_DUP: |
264 | case MATCH_PAR_DUP: | |
265 | case MATCH_OP_DUP: | |
9771b263 DN |
266 | acc->duplocs.safe_push (VEC_char_to_string (acc->pathstr)); |
267 | acc->dupnums.safe_push (XINT (x, 0)); | |
9482d6de | 268 | |
245fc639 ZW |
269 | if (code == MATCH_DUP) |
270 | break; | |
41299f41 | 271 | |
245fc639 ZW |
272 | for (i = XVECLEN (x, 1) - 1; i >= 0; i--) |
273 | { | |
085e8246 | 274 | push_pathstr_operand (i, code != MATCH_OP_DUP, acc); |
5d2d3e43 | 275 | walk_rtx (info, XVECEXP (x, 1, i), acc); |
9771b263 | 276 | acc->pathstr.pop (); |
245fc639 | 277 | } |
41299f41 | 278 | return; |
ccd043a9 RL |
279 | |
280 | default: | |
281 | break; | |
41299f41 TW |
282 | } |
283 | ||
41299f41 TW |
284 | fmt = GET_RTX_FORMAT (code); |
285 | len = GET_RTX_LENGTH (code); | |
286 | for (i = 0; i < len; i++) | |
287 | { | |
41299f41 TW |
288 | if (fmt[i] == 'e' || fmt[i] == 'u') |
289 | { | |
085e8246 | 290 | push_pathstr_operand (i, false, acc); |
5d2d3e43 | 291 | walk_rtx (info, XEXP (x, i), acc); |
9771b263 | 292 | acc->pathstr.pop (); |
41299f41 TW |
293 | } |
294 | else if (fmt[i] == 'E') | |
295 | { | |
296 | int j; | |
297 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) | |
298 | { | |
085e8246 | 299 | push_pathstr_operand (j, true, acc); |
5d2d3e43 | 300 | walk_rtx (info, XVECEXP (x, i, j), acc); |
9771b263 | 301 | acc->pathstr.pop (); |
41299f41 TW |
302 | } |
303 | } | |
304 | } | |
305 | } | |
306 | ||
307 | /* Given a PATH, representing a path down the instruction's | |
308 | pattern from the root to a certain point, output code to | |
309 | evaluate to the rtx at that point. */ | |
310 | ||
311 | static void | |
3d7aafde | 312 | print_path (const char *path) |
41299f41 | 313 | { |
b3694847 SS |
314 | int len = strlen (path); |
315 | int i; | |
9482d6de | 316 | |
07704a9a RE |
317 | if (len == 0) |
318 | { | |
319 | /* Don't emit "pat", since we may try to take the address of it, | |
320 | which isn't what is intended. */ | |
245fc639 | 321 | fputs ("PATTERN (insn)", stdout); |
07704a9a RE |
322 | return; |
323 | } | |
324 | ||
9482d6de | 325 | /* We first write out the operations (XEXP or XVECEXP) in reverse |
245fc639 | 326 | order, then write "pat", then the indices in forward order. */ |
9482d6de | 327 | |
6a87d634 | 328 | for (i = len - 1; i >= 0 ; i--) |
41299f41 | 329 | { |
085e8246 | 330 | if (ISLOWER (path[i]) || ISUPPER (path[i])) |
245fc639 ZW |
331 | fputs ("XVECEXP (", stdout); |
332 | else if (ISDIGIT (path[i])) | |
333 | fputs ("XEXP (", stdout); | |
9482d6de | 334 | else |
b2d59f6f | 335 | gcc_unreachable (); |
41299f41 | 336 | } |
3d7aafde | 337 | |
245fc639 | 338 | fputs ("pat", stdout); |
9482d6de RK |
339 | |
340 | for (i = 0; i < len; i++) | |
41299f41 | 341 | { |
085e8246 AH |
342 | if (ISUPPER (path[i])) |
343 | printf (", 0, %d)", path[i] - UPPER_OFFSET); | |
344 | else if (ISLOWER (path[i])) | |
9482d6de | 345 | printf (", 0, %d)", path[i] - 'a'); |
c3284718 | 346 | else if (ISDIGIT (path[i])) |
9482d6de RK |
347 | printf (", %d)", path[i] - '0'); |
348 | else | |
b2d59f6f | 349 | gcc_unreachable (); |
41299f41 TW |
350 | } |
351 | } | |
352 | \f | |
245fc639 ZW |
353 | static void |
354 | print_header (void) | |
355 | { | |
356 | /* N.B. Code below avoids putting squiggle braces in column 1 inside | |
357 | a string, because this confuses some editors' syntax highlighting | |
358 | engines. */ | |
359 | ||
360 | puts ("\ | |
361 | /* Generated automatically by the program `genextract'\n\ | |
362 | from the machine description file `md'. */\n\ | |
363 | \n\ | |
8fcc61f8 | 364 | #define IN_TARGET_CODE 1\n\ |
245fc639 ZW |
365 | #include \"config.h\"\n\ |
366 | #include \"system.h\"\n\ | |
367 | #include \"coretypes.h\"\n\ | |
368 | #include \"tm.h\"\n\ | |
369 | #include \"rtl.h\"\n\ | |
370 | #include \"insn-config.h\"\n\ | |
371 | #include \"recog.h\"\n\ | |
79a3f089 | 372 | #include \"diagnostic-core.h\"\n\ |
245fc639 ZW |
373 | \n\ |
374 | /* This variable is used as the \"location\" of any missing operand\n\ | |
375 | whose numbers are skipped by a given pattern. */\n\ | |
376 | static rtx junk ATTRIBUTE_UNUSED;\n"); | |
377 | ||
378 | puts ("\ | |
379 | void\n\ | |
d0bffe55 | 380 | insn_extract (rtx_insn *insn)\n{\n\ |
245fc639 ZW |
381 | rtx *ro = recog_data.operand;\n\ |
382 | rtx **ro_loc = recog_data.operand_loc;\n\ | |
383 | rtx pat = PATTERN (insn);\n\ | |
384 | int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\ | |
385 | \n\ | |
7f71272e MM |
386 | if (flag_checking)\n\ |
387 | {\n\ | |
388 | memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\ | |
389 | memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\ | |
390 | }\n"); | |
245fc639 ZW |
391 | |
392 | puts ("\ | |
393 | switch (INSN_CODE (insn))\n\ | |
394 | {\n\ | |
395 | default:\n\ | |
396 | /* Control reaches here if insn_extract has been called with an\n\ | |
397 | unrecognizable insn (code -1), or an insn whose INSN_CODE\n\ | |
398 | corresponds to a DEFINE_EXPAND in the machine description;\n\ | |
399 | either way, a bug. */\n\ | |
400 | if (INSN_CODE (insn) < 0)\n\ | |
401 | fatal_insn (\"unrecognizable insn:\", insn);\n\ | |
402 | else\n\ | |
403 | fatal_insn (\"insn with invalid code number:\", insn);\n"); | |
404 | } | |
c1b59dce | 405 | |
41299f41 | 406 | int |
66b0fe8f | 407 | main (int argc, const char **argv) |
41299f41 | 408 | { |
245fc639 | 409 | unsigned int i; |
9482d6de RK |
410 | struct extraction *p; |
411 | struct code_ptr *link; | |
8ad1aa56 | 412 | const char *name; |
41299f41 | 413 | |
f8b6598e | 414 | progname = "genextract"; |
41299f41 | 415 | |
600ab3fc | 416 | if (!init_rtx_reader_args (argc, argv)) |
c88c0d42 | 417 | return (FATAL_EXIT_CODE); |
41299f41 | 418 | |
41299f41 TW |
419 | /* Read the machine description. */ |
420 | ||
5d2d3e43 RS |
421 | md_rtx_info info; |
422 | while (read_md_rtx (&info)) | |
423 | switch (GET_CODE (info.def)) | |
424 | { | |
425 | case DEFINE_INSN: | |
426 | gen_insn (&info); | |
427 | break; | |
9482d6de | 428 | |
5d2d3e43 | 429 | case DEFINE_PEEPHOLE: |
41299f41 | 430 | { |
5ed6ace5 | 431 | struct code_ptr *link = XNEW (struct code_ptr); |
9482d6de | 432 | |
5d2d3e43 | 433 | link->insn_code = info.index; |
9482d6de RK |
434 | link->next = peepholes; |
435 | peepholes = link; | |
41299f41 | 436 | } |
5d2d3e43 RS |
437 | break; |
438 | ||
439 | default: | |
440 | break; | |
9482d6de | 441 | } |
41299f41 | 442 | |
7ddf71e3 PB |
443 | if (have_error) |
444 | return FATAL_EXIT_CODE; | |
445 | ||
245fc639 ZW |
446 | print_header (); |
447 | ||
9482d6de RK |
448 | /* Write out code to handle peepholes and the insn_codes that it should |
449 | be called for. */ | |
450 | if (peepholes) | |
41299f41 | 451 | { |
9482d6de RK |
452 | for (link = peepholes; link; link = link->next) |
453 | printf (" case %d:\n", link->insn_code); | |
454 | ||
41299f41 TW |
455 | /* The vector in the insn says how many operands it has. |
456 | And all it contains are operands. In fact, the vector was | |
2dbbe435 HPN |
457 | created just for the sake of this function. We need to set the |
458 | location of the operands for sake of simplifications after | |
459 | extraction, like eliminating subregs. */ | |
245fc639 ZW |
460 | puts (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n" |
461 | " ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n" | |
462 | " break;\n"); | |
9482d6de RK |
463 | } |
464 | ||
465 | /* Write out all the ways to extract insn operands. */ | |
466 | for (p = extractions; p; p = p->next) | |
467 | { | |
468 | for (link = p->insns; link; link = link->next) | |
8ad1aa56 ZW |
469 | { |
470 | i = link->insn_code; | |
471 | name = get_insn_name (i); | |
472 | if (name) | |
473 | printf (" case %d: /* %s */\n", i, name); | |
474 | else | |
475 | printf (" case %d:\n", i); | |
476 | } | |
3d7aafde | 477 | |
9482d6de RK |
478 | for (i = 0; i < p->op_count; i++) |
479 | { | |
480 | if (p->oplocs[i] == 0) | |
481 | { | |
482 | printf (" ro[%d] = const0_rtx;\n", i); | |
8b5ba7f8 | 483 | printf (" ro_loc[%d] = &junk;\n", i); |
9482d6de RK |
484 | } |
485 | else | |
486 | { | |
487 | printf (" ro[%d] = *(ro_loc[%d] = &", i, i); | |
488 | print_path (p->oplocs[i]); | |
245fc639 | 489 | puts (");"); |
9482d6de RK |
490 | } |
491 | } | |
492 | ||
493 | for (i = 0; i < p->dup_count; i++) | |
494 | { | |
1ccbefce | 495 | printf (" recog_data.dup_loc[%d] = &", i); |
9482d6de | 496 | print_path (p->duplocs[i]); |
245fc639 | 497 | puts (";"); |
1ccbefce | 498 | printf (" recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]); |
9482d6de RK |
499 | } |
500 | ||
245fc639 | 501 | puts (" break;\n"); |
41299f41 TW |
502 | } |
503 | ||
245fc639 | 504 | puts (" }\n}"); |
41299f41 | 505 | fflush (stdout); |
c1b59dce | 506 | return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
41299f41 | 507 | } |