8ff4c0623798f630123f93130f85a2ed284996b0
[cparser] / main.c
1 #include <config.h>
2
3 #define _GNU_SOURCE
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdbool.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <assert.h>
12
13 #ifndef WITH_LIBCORE
14 #define WITH_LIBCORE
15 #endif
16
17 #include <libfirm/firm.h>
18 #include <libfirm/be.h>
19
20 #include "lexer.h"
21 #include "token_t.h"
22 #include "type_hash.h"
23 #include "parser.h"
24 #include "ast2firm.h"
25 #include "adt/error.h"
26 #include "write_fluffy.h"
27
28 #ifndef PREPROCESSOR
29 #define PREPROCESSOR "cpp -std=c99 -U__WCHAR_TYPE__ -D__WCHAR_TYPE__=int"
30 #endif
31
32 #ifndef LINKER
33 #define LINKER       "gcc"
34 #endif
35
36 #ifndef ASSEMBLER
37 #define ASSEMBLER "as"
38 #endif
39
40 #ifdef _WIN32
41 /* remap some names */
42 #define popen(cmd, mode)  _popen(cmd, mode)
43 #define pclose(file)      _pclose(file)
44 #endif /* _WIN32 */
45
46 static int  verbose;
47 static bool do_dump;
48
49 static const ir_settings_if_conv_t *if_conv_info = NULL;
50 static const backend_params        *be_params    = NULL;
51
52 static void initialize_firm(void)
53 {
54         be_opt_register();
55         firm_init_options(NULL, 0, NULL);
56
57         firm_parameter_t params;
58         memset(&params, 0, sizeof(params));
59
60         params.size = sizeof(params);
61         params.enable_statistics = 0;
62         params.initialize_local_func = uninitialized_local_var;
63         params.cc_mask = 0;
64         params.builtin_dbg = NULL;
65
66         /* initialize backend */
67         be_params = be_init();
68         ir_set_debug_retrieve(retrieve_dbg);
69         params.arch_op_settings = be_params->arch_op_settings;
70         if_conv_info            = be_params->if_conv_info;
71
72         (void) if_conv_info; /* avoid unused warning */
73
74         /* intialize firm itself */
75         init_firm(&params);
76         dbg_init(NULL, NULL, dbg_snprint);
77
78         set_opt_constant_folding(1);
79         set_opt_unreachable_code(1);
80         set_opt_control_flow_straightening(1);
81         set_opt_control_flow_weak_simplification(1);
82         set_opt_control_flow_strong_simplification(1);
83         set_opt_dyn_meth_dispatch(1);
84         set_opt_normalize(1);
85         set_opt_precise_exc_context(0);
86         set_opt_strength_red(0);
87         set_opt_fragile_ops(0);
88         set_opt_optimize_class_casts(0);
89         set_opt_suppress_downcast_optimization(0);
90         set_opt_remove_confirm(1);
91         set_opt_scalar_replacement(1);
92         set_opt_ldst_only_null_ptr_exceptions(1);
93         set_opt_alias_analysis(1);
94
95         dump_consts_local(1);
96         dump_keepalive_edges(1);
97 }
98
99 static void dump(ir_graph *irg, const char *suffix)
100 {
101         if(do_dump) {
102                 dump_ir_block_graph(irg, suffix);
103         }
104 }
105
106 static void get_output_name(char *buf, size_t buflen, const char *inputname,
107                             const char *newext)
108 {
109         size_t last_dot = 0xffffffff;
110         size_t i = 0;
111
112         if(inputname == NULL) {
113                 snprintf(buf, buflen, "a%s", newext);
114                 return;
115         }
116
117         for(const char *c = inputname; *c != 0; ++c) {
118                 if(*c == '.')
119                         last_dot = i;
120                 ++i;
121         }
122         if(last_dot == 0xffffffff)
123                 last_dot = i;
124
125         if(last_dot >= buflen)
126                 panic("filename too long");
127         memcpy(buf, inputname, last_dot);
128
129         size_t extlen = strlen(newext) + 1;
130         if(extlen + last_dot >= buflen)
131                 panic("filename too long");
132         memcpy(buf+last_dot, newext, extlen);
133 }
134
135 static translation_unit_t *do_parsing(FILE *const in, const char *const input)
136 {
137         lexer_open_stream(in, input);
138         translation_unit_t *unit = parse();
139         return unit;
140 }
141
142 static void lextest(FILE *in, const char *fname)
143 {
144         lexer_open_stream(in, fname);
145
146         do {
147                 lexer_next_preprocessing_token();
148                 print_token(stdout, &lexer_token);
149                 puts("");
150         } while(lexer_token.type != T_EOF);
151 }
152
153 static void emit(FILE *out, const char *input_name)
154 {
155         be_main(out, input_name);
156 }
157
158 static FILE* preprocess(FILE* in, const char *fname)
159 {
160         char buf[4096];
161
162         if(in != stdin) {
163                 snprintf(buf, sizeof(buf), PREPROCESSOR " %s", fname);
164         } else {
165                 /* read from stdin */
166                 snprintf(buf, sizeof(buf), PREPROCESSOR " -");
167         }
168
169         if(verbose) {
170                 puts(buf);
171         }
172         FILE* f = popen(buf, "r");
173         if (f == NULL) {
174                 fprintf(stderr, "invoking preprocessor failed\n");
175                 exit(1);
176         }
177         return f;
178 }
179
180 static void do_link(const char *out, const char *in)
181 {
182         char buf[4096];
183
184         snprintf(buf, sizeof(buf), "%s %s -o %s", LINKER, in, out);
185         if(verbose) {
186                 puts(buf);
187         }
188         int err = system(buf);
189         if(err != 0) {
190                 fprintf(stderr, "linker reported an error\n");
191                 exit(1);
192         }
193 }
194
195 static void assemble(const char *out, const char *in)
196 {
197         char buf[4096];
198
199         snprintf(buf, sizeof(buf), "%s %s -o %s", ASSEMBLER, in, out);
200         if(verbose) {
201                 puts(buf);
202         }
203
204         int err = system(buf);
205         if(err != 0) {
206                 fprintf(stderr, "assembler reported an error\n");
207                 exit(1);
208         }
209 }
210
211 static const char *try_dir(const char *dir)
212 {
213         if(dir == NULL)
214                 return dir;
215         if(access(dir, R_OK | W_OK | X_OK) == 0)
216                 return dir;
217         return NULL;
218 }
219
220 static const char *get_tempdir(void)
221 {
222         static const char *tmpdir = NULL;
223
224         if(tmpdir != NULL)
225                 return tmpdir;
226
227         if(tmpdir == NULL)
228                 tmpdir = try_dir(getenv("TMPDIR"));
229         if(tmpdir == NULL)
230                 tmpdir = try_dir(getenv("TMP"));
231         if(tmpdir == NULL)
232                 tmpdir = try_dir(getenv("TEMP"));
233
234 #ifdef P_tmpdir
235         if(tmpdir == NULL)
236                 tmpdir = try_dir(P_tmpdir);
237 #endif
238
239         if(tmpdir == NULL)
240                 tmpdir = try_dir("/var/tmp");
241         if(tmpdir == NULL)
242                 tmpdir = try_dir("/usr/tmp");
243         if(tmpdir == NULL)
244                 tmpdir = try_dir("/tmp");
245
246         if(tmpdir == NULL)
247                 tmpdir = ".";
248
249         return tmpdir;
250 }
251
252 /**
253  * an own version of tmpnam, which: writes in a buffer, appends a user specified
254  * suffix, emits no warnings during linking (like glibc/gnu ld do for tmpnam)...
255  */
256 static FILE *make_temp_file(char *buffer, size_t buflen,
257                             const char *prefix, const char *suffix)
258 {
259         const char *tempdir = get_tempdir();
260
261         /* oh well... mkstemp doesn't accept a suffix after XXXXXX... */
262         (void) suffix;
263         suffix = "";
264
265         snprintf(buffer, buflen, "%s/%sXXXXXX%s", tempdir, prefix, suffix);
266
267         int fd = mkstemp(buffer);
268         if(fd == -1) {
269                 fprintf(stderr, "couldn't create temporary file: %s\n",
270                         strerror(errno));
271                 exit(1);
272         }
273         FILE *out = fdopen(fd, "w");
274         if(out == NULL) {
275                 fprintf(stderr, "couldn't create temporary file FILE*\n");
276                 exit(1);
277         }
278
279         return out;
280 }
281
282 static void create_firm_prog(translation_unit_t *unit)
283 {
284         translation_unit_to_firm(unit);
285
286         //dump_globals_as_text(dump_verbosity_max, "-globals");
287
288         int n_irgs = get_irp_n_irgs();
289         for(int i = 0; i < n_irgs; ++i) {
290                 ir_graph *const irg = get_irp_irg(i);
291                 dump(irg, "-start");
292         }
293
294         lower_params_t params;
295
296         params.def_ptr_alignment    = 4;
297         params.flags                = LF_COMPOUND_RETURN | LF_RETURN_HIDDEN;
298         params.hidden_params        = ADD_HIDDEN_ALWAYS_IN_FRONT;
299         params.find_pointer_type    = NULL;
300         params.ret_compound_in_regs = NULL;
301         lower_calls_with_compounds(&params);
302
303         lower_highlevel();
304
305         for(int i = 0; i < n_irgs; ++i) {
306                 ir_graph *const irg = get_irp_irg(i);
307                 dump(irg, "-lower");
308         }
309 }
310
311 static void optimize(void)
312 {
313         int         arr_len;
314         ir_entity **keep_methods;
315
316         cgana(&arr_len, &keep_methods);
317         gc_irgs(arr_len, keep_methods);
318         free(keep_methods);
319
320         optimize_funccalls(0);
321
322         lwrdw_param_t lwrdw_param = {
323                 1,
324                 1,
325                 mode_Ls, mode_Lu,
326                 mode_Is, mode_Iu,
327                 def_create_intrinsic_fkt,
328                 NULL
329         };
330         if (be_params->arch_create_intrinsic_fkt) {
331                 lwrdw_param.create_intrinsic = be_params->arch_create_intrinsic_fkt;
332                 lwrdw_param.ctx              = be_params->create_intrinsic_ctx;
333         }
334
335         for(int i = 0; i < get_irp_n_irgs(); ++i) {
336                 ir_graph *irg = get_irp_irg(i);
337
338                 optimize_graph_df(irg);
339                 dump(irg, "-01-localopt");
340                 place_code(irg);
341                 dump(irg, "-02-place");
342                 optimize_cf(irg);
343                 dump(irg, "-03-cf");
344                 lower_dw_ops(&lwrdw_param);
345                 dump(irg, "-04-dw");
346                 optimize_graph_df(irg);
347                 dump(irg, "-05-localopt");
348                 optimize_cf(irg);
349                 dump(irg, "-06-cf");
350         }
351 }
352
353 typedef enum compile_mode_t {
354         Compile,
355         CompileDump,
356         CompileAssemble,
357         CompileAssembleLink,
358         LexTest,
359         PrintAst,
360         PrintFluffy
361 } compile_mode_t;
362
363 static void usage(const char *argv0)
364 {
365         fprintf(stderr, "Usage %s input [-o output] [-c]\n", argv0);
366 }
367
368 int main(int argc, char **argv)
369 {
370         initialize_firm();
371
372         init_symbol_table();
373         init_tokens();
374         init_types();
375         init_typehash();
376         init_lexer();
377         init_ast();
378         init_parser();
379         init_ast2firm();
380
381         const char *input        = NULL;
382         const char *outname      = NULL;
383         const char *dumpfunction = NULL;
384         compile_mode_t mode = CompileAssembleLink;
385
386         for(int i = 1; i < argc; ++i) {
387                 const char *arg = argv[i];
388                 if(strcmp(arg, "-o") == 0) {
389                         ++i;
390                         if(i >= argc) {
391                                 usage(argv[0]);
392                                 return 1;
393                         }
394                         outname = argv[i];
395                 } else if(strcmp(arg, "-c") == 0) {
396                         mode = CompileAssemble;
397                 } else if(strcmp(arg, "-S") == 0) {
398                         mode = Compile;
399                 } else if(strcmp(arg, "--lextest") == 0) {
400                         mode = LexTest;
401                 } else if(strcmp(arg, "--print-ast") == 0) {
402                         mode = PrintAst;
403                 } else if(strcmp(arg, "--print-fluffy") == 0) {
404                         mode = PrintFluffy;
405                 } else if(strcmp(arg, "--dump") == 0) {
406                         do_dump = true;
407                 } else if(strcmp(arg, "--dump-function") == 0) {
408                         ++i;
409                         if(i >= argc) {
410                                 usage(argv[0]);
411                                 return 1;
412                         }
413                         dumpfunction = argv[i];
414                         mode         = CompileDump;
415                 } else if(strcmp(arg, "-v") == 0) {
416                         verbose = 1;
417                 } else if(arg[0] == '-' && arg[1] == 'f') {
418                         const char *opt = &arg[2];
419                         if(opt[0] == 0) {
420                                 ++i;
421                                 if(i >= argc) {
422                                         usage(argv[0]);
423                                         return 1;
424                                 }
425                                 opt = argv[i];
426                                 if(opt[0] == '-') {
427                                         usage(argv[0]);
428                                         return 1;
429                                 }
430                         }
431                         //firm_option(opt);
432                 } else if(arg[0] == '-' && arg[1] == 'b') {
433                         const char *opt = &arg[2];
434                         if(opt[0] == 0) {
435                                 ++i;
436                                 if(i >= argc) {
437                                         usage(argv[0]);
438                                         return 1;
439                                 }
440                                 opt = argv[i];
441                                 if(opt[0] == '-') {
442                                         usage(argv[0]);
443                                         return 1;
444                                 }
445                         }
446                         //be_parse_arg(opt);
447                 } else if(arg[0] == '-') {
448                         if (arg[1] == '\0') {
449                                 input = "-";
450                         } else if (arg[1] == 'D' ||
451                                         arg[1] == 'O' ||
452                                         arg[1] == 'f' ||
453                                         arg[1] == 'W' ||
454                                         arg[1] == 'g' ||
455                                         strncmp(arg + 1, "std=", 4) == 0) {
456                                 fprintf(stderr, "Warning: Ignoring option '%s'\n", arg);
457                         } else {
458                                 usage(argv[0]);
459                                 return 1;
460                         }
461                 } else {
462                         if(input != NULL) {
463                                 fprintf(stderr, "Error: multiple input files specified\n");
464                                 usage(argv[0]);
465                                 return 1;
466                         } else {
467                                 input = arg;
468                         }
469                 }
470         }
471
472         FILE *out;
473         char  outnamebuf[4096];
474         if(outname == NULL) {
475                 switch(mode) {
476                 case PrintAst:
477                 case PrintFluffy:
478                 case LexTest:
479                         break;
480                 case Compile:
481                         get_output_name(outnamebuf, sizeof(outnamebuf), input, ".s");
482                         outname = outnamebuf;
483                         break;
484                 case CompileAssemble:
485                         get_output_name(outnamebuf, sizeof(outnamebuf), input, ".o");
486                         outname = outnamebuf;
487                         break;
488                 case CompileDump:
489                         get_output_name(outnamebuf, sizeof(outnamebuf), dumpfunction,
490                                         ".vcg");
491                         outname = outnamebuf;
492                         break;
493                 case CompileAssembleLink:
494                         outname = "a.out";
495                         break;
496                 }
497                 assert(outname != NULL);
498         }
499
500         if(strcmp(outname, "-") == 0) {
501                 out = stdout;
502         } else {
503                 out = fopen(outname, "w");
504                 if(out == NULL) {
505                         fprintf(stderr, "Couldn't open '%s' for writing: %s\n", outname,
506                                 strerror(errno));
507                         return 1;
508                 }
509         }
510
511         FILE *in;
512         if(input == NULL) {
513                 fprintf(stderr, "%s: no input files\n", argv[0]);
514                 return 1;
515         } else if(strcmp(input, "-") == 0) {
516                 in    = stdin;
517                 input = "<stdin>";
518         } else {
519                 in = fopen(input, "r");
520                 if(in == NULL) {
521                         fprintf(stderr, "Couldn't open '%s': %s\n", input, strerror(errno));
522                         return 1;
523                 }
524         }
525
526         if(mode == LexTest) {
527                 lextest(in, input);
528                 fclose(in);
529                 return 0;
530         }
531
532         FILE *preprocessed_in = preprocess(in, input);
533         translation_unit_t *const unit = do_parsing(preprocessed_in, input);
534         pclose(preprocessed_in);
535         if(unit == NULL)
536                 return 1;
537
538         if(mode == PrintAst) {
539                 ast_set_output(out);
540                 print_ast(unit);
541                 return 0;
542         }
543         if(mode == PrintFluffy) {
544                 write_fluffy_decls(out, unit);
545         }
546
547         create_firm_prog(unit);
548         optimize();
549
550         if(mode == CompileDump) {
551                 /* find irg */
552                 ident    *id     = new_id_from_str(dumpfunction);
553                 ir_graph *irg    = NULL;
554                 int       n_irgs = get_irp_n_irgs();
555                 for(int i = 0; i < n_irgs; ++i) {
556                         ir_graph *tirg   = get_irp_irg(i);
557                         ident    *irg_id = get_entity_ident(get_irg_entity(tirg));
558                         if(irg_id == id) {
559                                 irg = tirg;
560                                 break;
561                         }
562                 }
563
564                 if(irg == NULL) {
565                         fprintf(stderr, "No graph for function '%s' found\n", dumpfunction);
566                         return 1;
567                 }
568
569                 dump_ir_block_graph_file(irg, out);
570                 fclose(out);
571                 return 0;
572         }
573
574         /* generate code and emit assembler */
575         FILE *asm_out;
576         char  asm_tempfile[1024];
577         if(mode == Compile) {
578                 asm_out = out;
579         } else {
580                 asm_out
581                         = make_temp_file(asm_tempfile, sizeof(asm_tempfile), "cc", ".s");
582         }
583         emit(asm_out, input);
584         fclose(asm_out);
585
586         /* assemble assembler and create object file */
587         char obj_tfile[1024];
588         if(mode == CompileAssemble || mode == CompileAssembleLink) {
589                 const char *obj_outfile;
590                 if(mode == CompileAssemble) {
591                         fclose(out);
592                         obj_outfile = outname;
593                 } else {
594                         FILE *tempf
595                                 = make_temp_file(obj_tfile, sizeof(obj_tfile), "cc", ".o");
596                         fclose(tempf);
597                         obj_outfile = obj_tfile;
598                 }
599
600                 assemble(obj_outfile, asm_tempfile);
601         }
602
603         /* link object file */
604         if(mode == CompileAssembleLink) {
605                 do_link(outname, obj_tfile);
606         }
607
608         exit_ast2firm();
609         exit_parser();
610         exit_ast();
611         exit_lexer();
612         exit_typehash();
613         exit_types();
614         exit_tokens();
615         exit_symbol_table();
616         return 0;
617 }