]>
Commit | Line | Data |
---|---|---|
41299f41 | 1 | /* Generate code from machine description to extract operands from insn as rtl. |
8d9254fc | 2 | Copyright (C) 1987-2020 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 AH |
36 | `z' then 'A' through to 'Z' when going into a vector. We assume here that |
37 | only the first operand of an rtl expression is a vector. genrecog.c makes | |
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 * | |
9771b263 | 217 | VEC_char_to_string (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: | |
240 | case CC0: | |
241 | case CONST_INT: | |
242 | case SYMBOL_REF: | |
243 | return; | |
244 | ||
245 | case MATCH_OPERAND: | |
246 | case MATCH_SCRATCH: | |
5d2d3e43 | 247 | VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0), |
245fc639 | 248 | VEC_char_to_string (acc->pathstr)); |
41299f41 TW |
249 | break; |
250 | ||
41299f41 | 251 | case MATCH_OPERATOR: |
245fc639 | 252 | case MATCH_PARALLEL: |
5d2d3e43 | 253 | VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0), |
245fc639 | 254 | VEC_char_to_string (acc->pathstr)); |
9482d6de | 255 | |
41299f41 TW |
256 | for (i = XVECLEN (x, 2) - 1; i >= 0; i--) |
257 | { | |
085e8246 | 258 | push_pathstr_operand (i, code != MATCH_OPERATOR, acc); |
5d2d3e43 | 259 | walk_rtx (info, XVECEXP (x, 2, i), acc); |
9771b263 | 260 | acc->pathstr.pop (); |
245fc639 | 261 | } |
41299f41 TW |
262 | return; |
263 | ||
245fc639 ZW |
264 | case MATCH_DUP: |
265 | case MATCH_PAR_DUP: | |
266 | case MATCH_OP_DUP: | |
9771b263 DN |
267 | acc->duplocs.safe_push (VEC_char_to_string (acc->pathstr)); |
268 | acc->dupnums.safe_push (XINT (x, 0)); | |
9482d6de | 269 | |
245fc639 ZW |
270 | if (code == MATCH_DUP) |
271 | break; | |
41299f41 | 272 | |
245fc639 ZW |
273 | for (i = XVECLEN (x, 1) - 1; i >= 0; i--) |
274 | { | |
085e8246 | 275 | push_pathstr_operand (i, code != MATCH_OP_DUP, acc); |
5d2d3e43 | 276 | walk_rtx (info, XVECEXP (x, 1, i), acc); |
9771b263 | 277 | acc->pathstr.pop (); |
245fc639 | 278 | } |
41299f41 | 279 | return; |
ccd043a9 RL |
280 | |
281 | default: | |
282 | break; | |
41299f41 TW |
283 | } |
284 | ||
41299f41 TW |
285 | fmt = GET_RTX_FORMAT (code); |
286 | len = GET_RTX_LENGTH (code); | |
287 | for (i = 0; i < len; i++) | |
288 | { | |
41299f41 TW |
289 | if (fmt[i] == 'e' || fmt[i] == 'u') |
290 | { | |
085e8246 | 291 | push_pathstr_operand (i, false, acc); |
5d2d3e43 | 292 | walk_rtx (info, XEXP (x, i), acc); |
9771b263 | 293 | acc->pathstr.pop (); |
41299f41 TW |
294 | } |
295 | else if (fmt[i] == 'E') | |
296 | { | |
297 | int j; | |
298 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) | |
299 | { | |
085e8246 | 300 | push_pathstr_operand (j, true, acc); |
5d2d3e43 | 301 | walk_rtx (info, XVECEXP (x, i, j), acc); |
9771b263 | 302 | acc->pathstr.pop (); |
41299f41 TW |
303 | } |
304 | } | |
305 | } | |
306 | } | |
307 | ||
308 | /* Given a PATH, representing a path down the instruction's | |
309 | pattern from the root to a certain point, output code to | |
310 | evaluate to the rtx at that point. */ | |
311 | ||
312 | static void | |
3d7aafde | 313 | print_path (const char *path) |
41299f41 | 314 | { |
b3694847 SS |
315 | int len = strlen (path); |
316 | int i; | |
9482d6de | 317 | |
07704a9a RE |
318 | if (len == 0) |
319 | { | |
320 | /* Don't emit "pat", since we may try to take the address of it, | |
321 | which isn't what is intended. */ | |
245fc639 | 322 | fputs ("PATTERN (insn)", stdout); |
07704a9a RE |
323 | return; |
324 | } | |
325 | ||
9482d6de | 326 | /* We first write out the operations (XEXP or XVECEXP) in reverse |
245fc639 | 327 | order, then write "pat", then the indices in forward order. */ |
9482d6de | 328 | |
6a87d634 | 329 | for (i = len - 1; i >= 0 ; i--) |
41299f41 | 330 | { |
085e8246 | 331 | if (ISLOWER (path[i]) || ISUPPER (path[i])) |
245fc639 ZW |
332 | fputs ("XVECEXP (", stdout); |
333 | else if (ISDIGIT (path[i])) | |
334 | fputs ("XEXP (", stdout); | |
9482d6de | 335 | else |
b2d59f6f | 336 | gcc_unreachable (); |
41299f41 | 337 | } |
3d7aafde | 338 | |
245fc639 | 339 | fputs ("pat", stdout); |
9482d6de RK |
340 | |
341 | for (i = 0; i < len; i++) | |
41299f41 | 342 | { |
085e8246 AH |
343 | if (ISUPPER (path[i])) |
344 | printf (", 0, %d)", path[i] - UPPER_OFFSET); | |
345 | else if (ISLOWER (path[i])) | |
9482d6de | 346 | printf (", 0, %d)", path[i] - 'a'); |
c3284718 | 347 | else if (ISDIGIT (path[i])) |
9482d6de RK |
348 | printf (", %d)", path[i] - '0'); |
349 | else | |
b2d59f6f | 350 | gcc_unreachable (); |
41299f41 TW |
351 | } |
352 | } | |
353 | \f | |
245fc639 ZW |
354 | static void |
355 | print_header (void) | |
356 | { | |
357 | /* N.B. Code below avoids putting squiggle braces in column 1 inside | |
358 | a string, because this confuses some editors' syntax highlighting | |
359 | engines. */ | |
360 | ||
361 | puts ("\ | |
362 | /* Generated automatically by the program `genextract'\n\ | |
363 | from the machine description file `md'. */\n\ | |
364 | \n\ | |
8fcc61f8 | 365 | #define IN_TARGET_CODE 1\n\ |
245fc639 ZW |
366 | #include \"config.h\"\n\ |
367 | #include \"system.h\"\n\ | |
368 | #include \"coretypes.h\"\n\ | |
369 | #include \"tm.h\"\n\ | |
370 | #include \"rtl.h\"\n\ | |
371 | #include \"insn-config.h\"\n\ | |
372 | #include \"recog.h\"\n\ | |
79a3f089 | 373 | #include \"diagnostic-core.h\"\n\ |
245fc639 ZW |
374 | \n\ |
375 | /* This variable is used as the \"location\" of any missing operand\n\ | |
376 | whose numbers are skipped by a given pattern. */\n\ | |
377 | static rtx junk ATTRIBUTE_UNUSED;\n"); | |
378 | ||
379 | puts ("\ | |
380 | void\n\ | |
d0bffe55 | 381 | insn_extract (rtx_insn *insn)\n{\n\ |
245fc639 ZW |
382 | rtx *ro = recog_data.operand;\n\ |
383 | rtx **ro_loc = recog_data.operand_loc;\n\ | |
384 | rtx pat = PATTERN (insn);\n\ | |
385 | int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\ | |
386 | \n\ | |
7f71272e MM |
387 | if (flag_checking)\n\ |
388 | {\n\ | |
389 | memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\ | |
390 | memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\ | |
391 | }\n"); | |
245fc639 ZW |
392 | |
393 | puts ("\ | |
394 | switch (INSN_CODE (insn))\n\ | |
395 | {\n\ | |
396 | default:\n\ | |
397 | /* Control reaches here if insn_extract has been called with an\n\ | |
398 | unrecognizable insn (code -1), or an insn whose INSN_CODE\n\ | |
399 | corresponds to a DEFINE_EXPAND in the machine description;\n\ | |
400 | either way, a bug. */\n\ | |
401 | if (INSN_CODE (insn) < 0)\n\ | |
402 | fatal_insn (\"unrecognizable insn:\", insn);\n\ | |
403 | else\n\ | |
404 | fatal_insn (\"insn with invalid code number:\", insn);\n"); | |
405 | } | |
c1b59dce | 406 | |
41299f41 | 407 | int |
66b0fe8f | 408 | main (int argc, const char **argv) |
41299f41 | 409 | { |
245fc639 | 410 | unsigned int i; |
9482d6de RK |
411 | struct extraction *p; |
412 | struct code_ptr *link; | |
8ad1aa56 | 413 | const char *name; |
41299f41 | 414 | |
f8b6598e | 415 | progname = "genextract"; |
41299f41 | 416 | |
600ab3fc | 417 | if (!init_rtx_reader_args (argc, argv)) |
c88c0d42 | 418 | return (FATAL_EXIT_CODE); |
41299f41 | 419 | |
41299f41 TW |
420 | /* Read the machine description. */ |
421 | ||
5d2d3e43 RS |
422 | md_rtx_info info; |
423 | while (read_md_rtx (&info)) | |
424 | switch (GET_CODE (info.def)) | |
425 | { | |
426 | case DEFINE_INSN: | |
427 | gen_insn (&info); | |
428 | break; | |
9482d6de | 429 | |
5d2d3e43 | 430 | case DEFINE_PEEPHOLE: |
41299f41 | 431 | { |
5ed6ace5 | 432 | struct code_ptr *link = XNEW (struct code_ptr); |
9482d6de | 433 | |
5d2d3e43 | 434 | link->insn_code = info.index; |
9482d6de RK |
435 | link->next = peepholes; |
436 | peepholes = link; | |
41299f41 | 437 | } |
5d2d3e43 RS |
438 | break; |
439 | ||
440 | default: | |
441 | break; | |
9482d6de | 442 | } |
41299f41 | 443 | |
7ddf71e3 PB |
444 | if (have_error) |
445 | return FATAL_EXIT_CODE; | |
446 | ||
245fc639 ZW |
447 | print_header (); |
448 | ||
9482d6de RK |
449 | /* Write out code to handle peepholes and the insn_codes that it should |
450 | be called for. */ | |
451 | if (peepholes) | |
41299f41 | 452 | { |
9482d6de RK |
453 | for (link = peepholes; link; link = link->next) |
454 | printf (" case %d:\n", link->insn_code); | |
455 | ||
41299f41 TW |
456 | /* The vector in the insn says how many operands it has. |
457 | And all it contains are operands. In fact, the vector was | |
2dbbe435 HPN |
458 | created just for the sake of this function. We need to set the |
459 | location of the operands for sake of simplifications after | |
460 | extraction, like eliminating subregs. */ | |
245fc639 ZW |
461 | puts (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n" |
462 | " ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n" | |
463 | " break;\n"); | |
9482d6de RK |
464 | } |
465 | ||
466 | /* Write out all the ways to extract insn operands. */ | |
467 | for (p = extractions; p; p = p->next) | |
468 | { | |
469 | for (link = p->insns; link; link = link->next) | |
8ad1aa56 ZW |
470 | { |
471 | i = link->insn_code; | |
472 | name = get_insn_name (i); | |
473 | if (name) | |
474 | printf (" case %d: /* %s */\n", i, name); | |
475 | else | |
476 | printf (" case %d:\n", i); | |
477 | } | |
3d7aafde | 478 | |
9482d6de RK |
479 | for (i = 0; i < p->op_count; i++) |
480 | { | |
481 | if (p->oplocs[i] == 0) | |
482 | { | |
483 | printf (" ro[%d] = const0_rtx;\n", i); | |
8b5ba7f8 | 484 | printf (" ro_loc[%d] = &junk;\n", i); |
9482d6de RK |
485 | } |
486 | else | |
487 | { | |
488 | printf (" ro[%d] = *(ro_loc[%d] = &", i, i); | |
489 | print_path (p->oplocs[i]); | |
245fc639 | 490 | puts (");"); |
9482d6de RK |
491 | } |
492 | } | |
493 | ||
494 | for (i = 0; i < p->dup_count; i++) | |
495 | { | |
1ccbefce | 496 | printf (" recog_data.dup_loc[%d] = &", i); |
9482d6de | 497 | print_path (p->duplocs[i]); |
245fc639 | 498 | puts (";"); |
1ccbefce | 499 | printf (" recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]); |
9482d6de RK |
500 | } |
501 | ||
245fc639 | 502 | puts (" break;\n"); |
41299f41 TW |
503 | } |
504 | ||
245fc639 | 505 | puts (" }\n}"); |
41299f41 | 506 | fflush (stdout); |
c1b59dce | 507 | return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
41299f41 | 508 | } |