cleanup: Add and use macro MIN().
[cparser] / main.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2012 Matthias Braun <matze@braunis.de>
4  */
5 #include <config.h>
6
7 #define _GNU_SOURCE
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdbool.h>
12 #include <errno.h>
13 #include <string.h>
14 #include <assert.h>
15
16 #ifdef _WIN32
17
18 #include <fcntl.h>
19 #include <io.h>
20
21 /* no eXecute on Win32 */
22 #define X_OK 0
23 #define W_OK 2
24 #define R_OK 4
25
26 #define O_RDWR          _O_RDWR
27 #define O_CREAT         _O_CREAT
28 #define O_EXCL          _O_EXCL
29 #define O_BINARY        _O_BINARY
30
31 /* remap some names, we are not in the POSIX world */
32 #define access(fname, mode)      _access(fname, mode)
33 #define mktemp(tmpl)             _mktemp(tmpl)
34 #define open(fname, oflag, mode) _open(fname, oflag, mode)
35 #define fdopen(fd, mode)         _fdopen(fd, mode)
36 #define popen(cmd, mode)         _popen(cmd, mode)
37 #define pclose(file)             _pclose(file)
38 #define unlink(filename)         _unlink(filename)
39
40 #else
41 #include <unistd.h>
42 #define HAVE_MKSTEMP
43 #endif
44
45 #include <libfirm/firm.h>
46 #include <libfirm/be.h>
47 #include <libfirm/statev.h>
48
49 #include "adt/util.h"
50 #include "ast_t.h"
51 #include "preprocessor.h"
52 #include "token_t.h"
53 #include "types.h"
54 #include "type_hash.h"
55 #include "parser.h"
56 #include "type_t.h"
57 #include "ast2firm.h"
58 #include "diagnostic.h"
59 #include "lang_features.h"
60 #include "driver/firm_opt.h"
61 #include "driver/firm_timing.h"
62 #include "driver/firm_machine.h"
63 #include "adt/error.h"
64 #include "adt/strutil.h"
65 #include "adt/array.h"
66 #include "symbol_table.h"
67 #include "wrappergen/write_fluffy.h"
68 #include "wrappergen/write_jna.h"
69 #include "wrappergen/write_compoundsizes.h"
70 #include "revision.h"
71 #include "warning.h"
72 #include "help.h"
73 #include "mangle.h"
74 #include "printer.h"
75
76 #ifndef PREPROCESSOR
77 #ifndef __WIN32__
78 #define PREPROCESSOR "gcc -E -U__STRICT_ANSI__ -U__BLOCKS__"
79 #else
80 #define PREPROCESSOR "cpp -U__STRICT_ANSI__"
81 #endif
82 #endif
83
84 #ifndef LINKER
85 #define LINKER    "gcc"
86 #endif
87
88 #ifndef ASSEMBLER
89 #define ASSEMBLER "gcc -c -xassembler"
90 #endif
91
92 unsigned int        c_mode                    = _C89 | _C99 | _GNUC;
93 bool                byte_order_big_endian     = false;
94 bool                strict_mode               = false;
95 bool                enable_main_collect2_hack = false;
96 bool                freestanding              = false;
97 unsigned            architecture_modulo_shift = 0;
98
99 static bool               char_is_signed      = true;
100 static atomic_type_kind_t wchar_atomic_kind   = ATOMIC_TYPE_INT;
101 static unsigned           features_on         = 0;
102 static unsigned           features_off        = 0;
103 static const char        *dumpfunction        = NULL;
104 static struct obstack     file_obst;
105 static const char        *external_preprocessor = PREPROCESSOR;
106
107 static machine_triple_t *target_machine;
108 static const char       *target_triple;
109 static int               verbose;
110 static struct obstack    cppflags_obst;
111 static struct obstack    ldflags_obst;
112 static struct obstack    asflags_obst;
113 static const char       *outname;
114 static bool              define_intmax_types;
115 static const char       *input_encoding;
116 static bool              construct_dep_target;
117
118 typedef enum lang_standard_t {
119         STANDARD_DEFAULT, /* gnu99 (for C, GCC does gnu89) or gnu++98 (for C++) */
120         STANDARD_ANSI,    /* ISO C90 (for C) or ISO C++ 1998 (for C++) */
121         STANDARD_C89,     /* ISO C90 (sic) */
122         STANDARD_C89AMD1, /* ISO C90 as modified in amendment 1 */
123         STANDARD_C99,     /* ISO C99 */
124         STANDARD_C11,     /* ISO C11 */
125         STANDARD_GNU89,   /* ISO C90 plus GNU extensions (including some C99) */
126         STANDARD_GNU99,   /* ISO C99 plus GNU extensions */
127         STANDARD_GNU11,   /* ISO C11 plus GNU extensions */
128         STANDARD_CXX98,   /* ISO C++ 1998 plus amendments */
129         STANDARD_GNUXX98  /* ISO C++ 1998 plus amendments and GNU extensions */
130 } lang_standard_t;
131
132 typedef enum compilation_unit_type_t {
133         COMPILATION_UNIT_AUTODETECT,
134         COMPILATION_UNIT_C,
135         COMPILATION_UNIT_PREPROCESSED_C,
136         COMPILATION_UNIT_CXX,
137         COMPILATION_UNIT_PREPROCESSED_CXX,
138         COMPILATION_UNIT_AST,
139         COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION,
140         COMPILATION_UNIT_ASSEMBLER,
141         COMPILATION_UNIT_PREPROCESSED_ASSEMBLER,
142         COMPILATION_UNIT_OBJECT,
143         COMPILATION_UNIT_IR,
144         COMPILATION_UNIT_UNKNOWN
145 } compilation_unit_type_t;
146
147 typedef struct compilation_unit_t compilation_unit_t;
148 struct compilation_unit_t {
149         const char             *name;  /**< filename or "-" for stdin */
150         FILE                   *input; /**< input (NULL if not opened yet) */
151         bool                    input_is_pipe;
152         compilation_unit_type_t type;
153         lang_standard_t         standard;
154         translation_unit_t     *ast;
155         bool                    parse_errors;
156         compilation_unit_t     *next;
157 };
158
159 static char **temp_files;
160
161 static void get_output_name(char *buf, size_t buflen, const char *inputname,
162                             const char *newext)
163 {
164         if (inputname == NULL)
165                 inputname = "a";
166
167         char const *const last_slash = strrchr(inputname, '/');
168         char const *const filename   =
169                 last_slash != NULL ? last_slash + 1 : inputname;
170         char const *const last_dot   = strrchr(filename, '.');
171         char const *const name_end   =
172                 last_dot != NULL ? last_dot : strchr(filename, '\0');
173
174         int const len = snprintf(buf, buflen, "%.*s%s",
175                         (int)(name_end - filename), filename, newext);
176 #ifdef _WIN32
177         if (len < 0 || buflen <= (size_t)len)
178 #else
179         if (buflen <= (size_t)len)
180 #endif
181                 panic("filename too long");
182 }
183
184 static bool close_input(compilation_unit_t *unit)
185 {
186         assert(unit->input);
187         bool res;
188         if (unit->input == stdin) {
189                 res = true;
190         } else if (unit->input_is_pipe) {
191                 res = pclose(unit->input) == EXIT_SUCCESS;
192         } else {
193                 fclose(unit->input);
194                 res = true;
195         }
196         unit->input = NULL;
197         unit->name  = NULL;
198         return res;
199 }
200
201 static void print_error_summary(void)
202 {
203         if (error_count > 0) {
204                 /* parsing failed because of errors */
205                 fprintf(stderr, "%u error(s), %u warning(s)\n", error_count,
206                                 warning_count);
207         } else if (warning_count > 0) {
208                 fprintf(stderr, "%u warning(s)\n", warning_count);
209         }
210 }
211
212 static void do_parsing(compilation_unit_t *unit)
213 {
214         ir_timer_t *t_parsing = ir_timer_new();
215         timer_register(t_parsing, "Frontend: Parsing");
216         timer_start(t_parsing);
217
218         start_parsing();
219
220         switch_pp_input(unit->input, unit->name, NULL, false);
221         parse();
222         unit->ast = finish_parsing();
223         check_unclosed_conditionals();
224         close_pp_input();
225         bool res = close_input(unit);
226
227         print_error_summary();
228
229         unit->type         = COMPILATION_UNIT_AST;
230         unit->parse_errors = error_count > 0 || !res;
231         timer_stop(t_parsing);
232         if (stat_ev_enabled) {
233                 stat_ev_dbl("time_parsing", ir_timer_elapsed_sec(t_parsing));
234         }
235 }
236
237 static void add_flag(struct obstack *obst, const char *format, ...)
238 {
239         char buf[65536];
240         va_list ap;
241
242         va_start(ap, format);
243 #ifdef _WIN32
244         int len =
245 #endif
246                 vsnprintf(buf, sizeof(buf), format, ap);
247         va_end(ap);
248
249         obstack_1grow(obst, ' ');
250 #ifdef _WIN32
251         obstack_1grow(obst, '"');
252         obstack_grow(obst, buf, len);
253         obstack_1grow(obst, '"');
254 #else
255         /* escape stuff... */
256         for (char *c = buf; *c != '\0'; ++c) {
257                 switch (*c) {
258                 case ' ':
259                 case '"':
260                 case '$':
261                 case '&':
262                 case '(':
263                 case ')':
264                 case ';':
265                 case '<':
266                 case '>':
267                 case '\'':
268                 case '\\':
269                 case '\n':
270                 case '\r':
271                 case '\t':
272                 case '`':
273                 case '|':
274                         obstack_1grow(obst, '\\');
275                         /* FALLTHROUGH */
276                 default:
277                         obstack_1grow(obst, *c);
278                         break;
279                 }
280         }
281 #endif
282 }
283
284 static const char *type_to_string(type_t *type)
285 {
286         assert(type->kind == TYPE_ATOMIC);
287         return get_atomic_kind_name(type->atomic.akind);
288 }
289
290 static char const* str_lang_standard(lang_standard_t const standard)
291 {
292         switch (standard) {
293         case STANDARD_C89:     return "c89";
294         case STANDARD_C89AMD1: return "iso9899:199409";
295         case STANDARD_C99:     return "c99";
296         case STANDARD_C11:     return "c11";
297         case STANDARD_GNU89:   return "gnu89";
298         case STANDARD_GNU99:   return "gnu99";
299         case STANDARD_GNU11:   return "gnu11";
300         case STANDARD_CXX98:   return "c++98";
301         case STANDARD_GNUXX98: return "gnu++98";
302         case STANDARD_ANSI:    break;
303         case STANDARD_DEFAULT: break;
304         }
305         panic("invalid standard");
306 }
307
308 static bool run_external_preprocessor(compilation_unit_t *unit)
309 {
310         obstack_1grow(&cppflags_obst, '\0');
311         const char *flags = obstack_finish(&cppflags_obst);
312
313         const char *preprocessor = getenv("CPARSER_PP");
314         if (preprocessor != NULL) {
315                 obstack_printf(&cppflags_obst, "%s ", preprocessor);
316         } else {
317                 if (target_triple != NULL)
318                         obstack_printf(&cppflags_obst, "%s-", target_triple);
319                 obstack_printf(&cppflags_obst, "%s", external_preprocessor);
320         }
321
322         char const *lang;
323         switch (unit->type) {
324         case COMPILATION_UNIT_C:         lang = "c";                  break;
325         case COMPILATION_UNIT_CXX:       lang = "c++";                break;
326         case COMPILATION_UNIT_ASSEMBLER: lang = "assembler-with-cpp"; break;
327         default:                         lang = NULL;                 break;
328         }
329         if (lang)
330                 add_flag(&cppflags_obst, "-x%s", lang);
331
332         if (unit->type == COMPILATION_UNIT_C
333          || unit->type == COMPILATION_UNIT_CXX) {
334                 add_flag(&cppflags_obst, "-std=%s", str_lang_standard(unit->standard));
335
336                 /* setup default defines */
337                 add_flag(&cppflags_obst, "-U__WCHAR_TYPE__");
338                 add_flag(&cppflags_obst, "-D__WCHAR_TYPE__=%s", type_to_string(type_wchar_t));
339                 add_flag(&cppflags_obst, "-U__SIZE_TYPE__");
340                 add_flag(&cppflags_obst, "-D__SIZE_TYPE__=%s", type_to_string(type_size_t));
341
342                 add_flag(&cppflags_obst, "-U__VERSION__");
343                 add_flag(&cppflags_obst, "-D__VERSION__=\"%s\"", cparser_REVISION);
344
345                 if (define_intmax_types) {
346                         add_flag(&cppflags_obst, "-U__INTMAX_TYPE__");
347                         add_flag(&cppflags_obst, "-D__INTMAX_TYPE__=%s", type_to_string(type_intmax_t));
348                         add_flag(&cppflags_obst, "-U__UINTMAX_TYPE__");
349                         add_flag(&cppflags_obst, "-D__UINTMAX_TYPE__=%s", type_to_string(type_uintmax_t));
350                 }
351         }
352         if (flags[0] != '\0') {
353                 size_t len = strlen(flags);
354                 obstack_1grow(&cppflags_obst, ' ');
355                 obstack_grow(&cppflags_obst, flags, len);
356         }
357
358         /* handle dependency generation */
359         if (construct_dep_target) {
360                 static char dep_target[4096];
361                 if (outname != 0) {
362                         size_t len = strlen(outname);
363                         len = MIN(len, sizeof(dep_target) - 4); /* leave room for .d extension */
364                         memcpy(dep_target, outname, len);
365                         /* replace extension with .d if found */
366                         char *dot = &dep_target[len-1];
367                         for ( ; dot >= dep_target && *dot != '/'; --dot) {
368                                 if (*dot == '.') {
369                                         dot[1] = 'd';
370                                         len = (dot-dep_target)+2;
371                                         break;
372                                 }
373                         }
374                         dep_target[len] = '\0';
375                 } else {
376                         get_output_name(dep_target, sizeof(dep_target), unit->name, ".d");
377                 }
378
379                 add_flag(&cppflags_obst, "-MF");
380                 add_flag(&cppflags_obst, dep_target);
381         }
382         assert(unit->input == NULL);
383         add_flag(&cppflags_obst, unit->name);
384         obstack_1grow(&cppflags_obst, '\0');
385
386         char *commandline = obstack_finish(&cppflags_obst);
387         if (verbose) {
388                 puts(commandline);
389         }
390         FILE *f = popen(commandline, "r");
391         if (f == NULL) {
392                 position_t const pos = { unit->name, 0, 0, 0 };
393                 errorf(&pos, "invoking preprocessor failed");
394                 return false;
395         }
396         /* we do not really need that anymore */
397         obstack_free(&cppflags_obst, commandline);
398
399         unit->input         = f;
400         unit->input_is_pipe = true;
401         switch (unit->type) {
402         case COMPILATION_UNIT_ASSEMBLER:
403                 unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
404                 break;
405         case COMPILATION_UNIT_C:
406                 unit->type = COMPILATION_UNIT_PREPROCESSED_C;
407                 break;
408         case COMPILATION_UNIT_CXX:
409                 unit->type = COMPILATION_UNIT_PREPROCESSED_CXX;
410                 break;
411         default:
412                 unit->type = COMPILATION_UNIT_UNKNOWN;
413                 break;
414         }
415
416         return true;
417 }
418
419 static void assemble(const char *out, const char *in)
420 {
421         obstack_1grow(&asflags_obst, '\0');
422         const char *flags = obstack_finish(&asflags_obst);
423
424         const char *assembler = getenv("CPARSER_AS");
425         if (assembler != NULL) {
426                 obstack_printf(&asflags_obst, "%s", assembler);
427         } else {
428                 if (target_triple != NULL)
429                         obstack_printf(&asflags_obst, "%s-", target_triple);
430                 obstack_printf(&asflags_obst, "%s", ASSEMBLER);
431         }
432         if (flags[0] != '\0')
433                 obstack_printf(&asflags_obst, " %s", flags);
434
435         obstack_printf(&asflags_obst, " %s -o %s", in, out);
436         obstack_1grow(&asflags_obst, '\0');
437
438         char *commandline = obstack_finish(&asflags_obst);
439         if (verbose) {
440                 puts(commandline);
441         }
442         int err = system(commandline);
443         if (err != EXIT_SUCCESS) {
444                 position_t const pos = { in, 0, 0, 0 };
445                 errorf(&pos, "assembler reported an error");
446                 exit(EXIT_FAILURE);
447         }
448         obstack_free(&asflags_obst, commandline);
449 }
450
451 static void print_file_name(const char *file)
452 {
453         add_flag(&ldflags_obst, "-print-file-name=%s", file);
454
455         obstack_1grow(&ldflags_obst, '\0');
456         const char *flags = obstack_finish(&ldflags_obst);
457
458         /* construct commandline */
459         const char *linker = getenv("CPARSER_LINK");
460         if (linker != NULL) {
461                 obstack_printf(&ldflags_obst, "%s ", linker);
462         } else {
463                 if (target_triple != NULL)
464                         obstack_printf(&ldflags_obst, "%s-", target_triple);
465                 obstack_printf(&ldflags_obst, "%s ", LINKER);
466         }
467         obstack_printf(&ldflags_obst, "%s ", linker);
468         obstack_printf(&ldflags_obst, "%s", flags);
469         obstack_1grow(&ldflags_obst, '\0');
470
471         char *commandline = obstack_finish(&ldflags_obst);
472         if (verbose) {
473                 puts(commandline);
474         }
475         int err = system(commandline);
476         if (err != EXIT_SUCCESS) {
477                 position_t const pos = { file, 0, 0, 0 };
478                 errorf(&pos, "linker reported an error");
479                 exit(EXIT_FAILURE);
480         }
481         obstack_free(&ldflags_obst, commandline);
482 }
483
484 static const char *try_dir(const char *dir)
485 {
486         if (dir == NULL)
487                 return dir;
488         if (access(dir, R_OK | W_OK | X_OK) == 0)
489                 return dir;
490         return NULL;
491 }
492
493 static const char *get_tempdir(void)
494 {
495         static const char *tmpdir = NULL;
496
497         if (tmpdir != NULL)
498                 return tmpdir;
499
500         if (tmpdir == NULL)
501                 tmpdir = try_dir(getenv("TMPDIR"));
502         if (tmpdir == NULL)
503                 tmpdir = try_dir(getenv("TMP"));
504         if (tmpdir == NULL)
505                 tmpdir = try_dir(getenv("TEMP"));
506
507 #ifdef P_tmpdir
508         if (tmpdir == NULL)
509                 tmpdir = try_dir(P_tmpdir);
510 #endif
511
512         if (tmpdir == NULL)
513                 tmpdir = try_dir("/var/tmp");
514         if (tmpdir == NULL)
515                 tmpdir = try_dir("/usr/tmp");
516         if (tmpdir == NULL)
517                 tmpdir = try_dir("/tmp");
518
519         if (tmpdir == NULL)
520                 tmpdir = ".";
521
522         return tmpdir;
523 }
524
525 #ifndef HAVE_MKSTEMP
526 /* cheap and nasty mkstemp replacement */
527 static int mkstemp(char *templ)
528 {
529         mktemp(templ);
530         return open(templ, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0600);
531 }
532 #endif
533
534 /**
535  * custom version of tmpnam, which: writes to an obstack, emits no warnings
536  * during linking (like glibc/gnu ld do for tmpnam)...
537  */
538 static FILE *make_temp_file(const char *prefix, const char **name_result)
539 {
540         const char *tempdir = get_tempdir();
541         assert(obstack_object_size(&file_obst) == 0);
542         obstack_printf(&file_obst, "%s/%sXXXXXX", tempdir, prefix);
543         obstack_1grow(&file_obst, '\0');
544
545         char *name = obstack_finish(&file_obst);
546         int fd = mkstemp(name);
547         if (fd == -1) {
548                 position_t const pos = { name, 0, 0, 0 };
549                 errorf(&pos, "could not create temporary file: %s", strerror(errno));
550                 return NULL;
551         }
552         FILE *out = fdopen(fd, "w");
553         if (out == NULL) {
554                 position_t const pos = { name, 0, 0, 0 };
555                 errorf(&pos, "could not open temporary file as FILE*");
556                 return NULL;
557         }
558
559         ARR_APP1(char*, temp_files, name);
560         *name_result = name;
561         return out;
562 }
563
564 static void free_temp_files(void)
565 {
566         if (temp_files == NULL)
567                 return;
568
569         size_t n_temp_files = ARR_LEN(temp_files);
570         size_t i;
571         for (i = 0; i < n_temp_files; ++i) {
572                 char *file = temp_files[i];
573                 unlink(file);
574         }
575         DEL_ARR_F(temp_files);
576         temp_files = NULL;
577 }
578
579 typedef enum compile_mode_t {
580         BenchmarkParser,
581         PreprocessOnly,
582         ParseOnly,
583         Compile,
584         CompileDump,
585         CompileExportIR,
586         CompileAssemble,
587         CompileAssembleLink,
588         PrintAst,
589         PrintFluffy,
590         PrintJna,
591         PrintCompoundSizes,
592 } compile_mode_t;
593
594 static void usage(const char *argv0)
595 {
596         fprintf(stderr, "Usage %s [options] input [-o output]\n", argv0);
597 }
598
599 static void print_cparser_version(void)
600 {
601         printf("cparser (%s) using libFirm (%u.%u",
602                cparser_REVISION, ir_get_version_major(),
603                ir_get_version_minor());
604
605         const char *revision = ir_get_version_revision();
606         if (revision[0] != 0) {
607                 putchar('-');
608                 fputs(revision, stdout);
609         }
610
611         const char *build = ir_get_version_build();
612         if (build[0] != 0) {
613                 putchar(' ');
614                 fputs(build, stdout);
615         }
616         puts(")");
617         puts("This is free software; see the source for copying conditions.  There is NO\n"
618              "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
619 }
620
621 static void print_cparser_version_short(void)
622 {
623         puts(cparser_REVISION);
624 }
625
626 static void print_help_basic(const char *argv0)
627 {
628         usage(argv0);
629         puts("");
630         put_help("--help",                   "Display this information");
631         put_help("--version",                "Display compiler version");
632         put_help("--help-parser",            "Display information about parser options");
633         put_help("--help-warnings",          "Display information about warning options");
634         put_help("--help-codegen",           "Display information about code-generation options");
635         put_help("--help-optimization",      "Display information about optimization options");
636         put_help("--help-linker",            "Display information about linker options");
637         put_help("--help-language-tools",    "Display information about language tools options");
638         put_help("--help-debug",             "Display information about compiler debugging options");
639         put_help("--help-firm",              "Display information about direct firm options");
640         put_help("--help-all",               "Display information about all options");
641         put_help("-c",                       "Compile and assemble but do not link");
642         put_help("-E",                       "Preprocess only");
643         put_help("-S",                       "Compile but do not assembler or link");
644         put_help("-o",                       "Specify output file");
645         put_help("-v",                       "Verbose output (show invocation of sub-processes)");
646         put_help("-x",                       "Force input language:");
647         put_choice("c",                      "C");
648         put_choice("c++",                    "C++");
649         put_choice("assembler",              "Assembler (no preprocessing)");
650         put_choice("assembler-with-cpp",     "Assembler with preprocessing");
651         put_choice("none",                   "Autodetection");
652         put_help("-pipe",                    "Ignored (gcc compatibility)");
653 }
654
655 static void print_help_preprocessor(void)
656 {
657         put_help("-nostdinc",                "Do not search standard system include directories");
658         put_help("-trigraphs",               "Support ISO C trigraphs");
659         put_help("-isystem",                 "");
660         put_help("-include",                 "");
661         put_help("-I PATH",                  "");
662         put_help("-D SYMBOL[=value]",        "");
663         put_help("-U SYMBOL",                "");
664         put_help("-Wp,OPTION",               "Pass option directly to preprocessor");
665         put_help("-Xpreprocessor OPTION",    "Pass option directly to preprocessor");
666         put_help("-M",                       "");
667         put_help("-MD",                      "");
668         put_help("-MMD",                     "");
669         put_help("-MM",                      "");
670         put_help("-MP",                      "");
671         put_help("-MT",                      "");
672         put_help("-MQ",                      "");
673         put_help("-MF",                      "");
674 }
675
676 static void print_help_parser(void)
677 {
678         put_help("-finput-charset=CHARSET",  "Select encoding of input files");
679         put_help("-fmessage-length=LEN",     "Ignored (gcc compatibility)");
680         put_help("-fshort-wchar",            "Type \"wchar_t\" is unsigned short instead of int");
681         put_help("-fshow-column",            "Show the column number in diagnostic messages");
682         put_help("-fsigned-char",            "Type \"char\" is a signed type");
683         put_help("-funsigned-char",          "Type \"char\" is an unsigned type");
684         put_help("--ms",                     "Enable msvc extensions");
685         put_help("--no-ms",                  "Disable msvc extensions");
686         put_help("--gcc",                    "Enable gcc extensions");
687         put_help("--no-gcc",                 "Disable gcc extensions");
688         put_help("-std=STANDARD",            "Specify language standard:");
689         put_choice("c99",                    "ISO C99 standard");
690         put_choice("c89",                    "ISO C89 standard");
691         put_choice("c90",                    "Same as -std=c89");
692         put_choice("c11",                    "ISO C11 standard");
693         put_choice("c9x",                    "Deprecated");
694         put_choice("c++",                    "ISO C++ 98");
695         put_choice("c++98",                  "ISO C++ 98");
696         put_choice("gnu99",                  "ISO C99 + GNU extensions (default)");
697         put_choice("gnu89",                  "ISO C89 + GNU extensions");
698         put_choice("gnu11",                  "ISO C11 + GNU extensions");
699         put_choice("gnu9x",                  "Deprecated");
700         put_choice("iso9899:1990",           "ISO C89");
701         put_choice("iso9899:199409",         "ISO C90");
702         put_choice("iso9899:1999",           "ISO C99");
703         put_choice("iso9899:199x",           "Deprecated");
704         put_help("-pedantic",                "Ignored (gcc compatibility)");
705         put_help("-ansi",                    "-std=c90 (for C) or -std=c++98 (for C++)");
706         put_help("--strict",                 "Enable strict conformance checking");
707 }
708
709 static void print_help_warnings(void)
710 {
711         put_help("-f[no-]diagnostics-show-option", "Show the switch, which controls a warning, after each warning");
712         put_help("-w",                             "Disable all warnings");
713         put_help("-Wno-trigraphs",                 "Warn if input contains trigraphs");
714         put_help("-Wundef",                        "Warn if an undefined macro is used in an #if");
715         put_help("-Wmissing-include-dirs",         "Warn about missing user-specified include directories");
716         put_help("-Wendif-labels",                 "Warn about stray text after #elif and #endif");
717         put_help("-Winit-self",                    "Ignored (gcc compatibility)");
718         put_help("-Wformat-y2k",                   "Ignored (gcc compatibility)");
719         put_help("-Wformat-security",              "Ignored (gcc compatibility)");
720         put_help("-Wold-style-declaration",        "Ignored (gcc compatibility)");
721         put_help("-Wtype-limits",                  "Ignored (gcc compatibility)");
722         print_warning_opt_help();
723 }
724
725 static void print_help_optimization(void)
726 {
727         put_help("-O LEVEL",                 "Select optimization level (0-4)");
728         firm_option_help(put_help);
729         put_help("-fexpensive-optimizations","Ignored (gcc compatibility)");
730 }
731
732 static void print_help_codegeneration(void)
733 {
734         put_help("-g",                       "Generate debug information");
735         put_help("-pg",                      "Instrument code for gnu gprof");
736         put_help("-fomit-frame-pointer",     "Produce code without frame pointer where possible");
737         put_help("-ffreestanding",           "Compile in freestanding mode (see ISO C standard)");
738         put_help("-fhosted",                 "Compile in hosted (not freestanding) mode");
739         put_help("-fprofile-generate",       "Generate instrumented code to collect profile information");
740         put_help("-fprofile-use",            "Use profile information generated by instrumented binaries");
741         put_help("-ffp-precise",             "Precise floating point model");
742         put_help("-ffp-fast",                "Imprecise floating point model");
743         put_help("-ffp-strict",              "Strict floating point model");
744         put_help("-pthread",                 "Use pthread threading library");
745         put_help("-mtarget=TARGET",          "Specify target architecture as CPU-manufacturer-OS triple");
746         put_help("-mtriple=TARGET",          "Alias for -mtarget (clang compatibility)");
747         put_help("-march=ARCH",              "");
748         put_help("-mtune=ARCH",              "");
749         put_help("-mcpu=CPU",                "");
750         put_help("-mfpmath=",                "");
751         put_help("-mpreferred-stack-boundary=", "");
752         put_help("-mrtd",                    "");
753         put_help("-mregparm=",               "Not supported yet");
754         put_help("-msoft-float",             "Not supported yet");
755         put_help("-m32",                     "Generate 32bit code");
756         put_help("-m64",                     "Generate 64bit code");
757         put_help("-fverbose-asm",            "Ignored (gcc compatibility)");
758         put_help("-fjump-tables",            "Ignored (gcc compatibility)");
759         put_help("-fcommon",                 "Ignored (gcc compatibility)");
760         put_help("-foptimize-sibling-calls", "Ignored (gcc compatibility)");
761         put_help("-falign-loops",            "Ignored (gcc compatibility)");
762         put_help("-falign-jumps",            "Ignored (gcc compatibility)");
763         put_help("-falign-functions",        "Ignored (gcc compatibility)");
764         put_help("-fPIC",                    "Ignored (gcc compatibility)");
765         put_help("-ffast-math",              "Same as -ffp-fast (gcc compatibility)");
766         puts("");
767         puts("\tMost of these options can be used with a no- prefix to disable them");
768         puts("\te.g. -fno-omit-frame-pointer");
769 }
770
771 static void print_help_linker(void)
772 {
773         put_help("-l LIBRARY",               "");
774         put_help("-L PATH",                  "");
775         put_help("-s",                       "Do not produce symbol table and relocation information");
776         put_help("-shared",                  "Produce a shared library");
777         put_help("-static",                  "Produce statically linked binary");
778         put_help("-Wa,OPTION",               "Pass option directly to assembler");
779         put_help("-Xassembler OPTION",       "Pass option directly to assembler");
780         put_help("-Wl,OPTION",               "Pass option directly to linker");
781         put_help("-Xlinker OPTION",          "Pass option directly to linker");
782 }
783
784 static void print_help_debug(void)
785 {
786         put_help("--print-ast",              "Preprocess, parse and print AST");
787         put_help("--print-implicit-cast",    "");
788         put_help("--print-parenthesis",      "");
789         put_help("--benchmark",              "Preprocess and parse, produces no output");
790         put_help("--time",                   "Measure time of compiler passes");
791         put_help("--statev",                 "Produce statev output");
792         put_help("--filtev=filter",          "Set statev filter regex");
793         put_help("--dump-function func",     "Preprocess, parse and output vcg graph of func");
794         put_help("--export-ir",              "Preprocess, parse and output compiler intermediate representation");
795 }
796
797 static void print_help_language_tools(void)
798 {
799         put_help("--print-fluffy",           "Preprocess, parse and generate declarations for the fluffy language");
800         put_help("--print-jna",              "Preprocess, parse and generate declarations for JNA");
801         put_help("--jna-limit filename",     "");
802         put_help("--jna-libname name",       "");
803 }
804
805 static void print_help_firm(void)
806 {
807         put_help("-bOPTION",                 "Directly pass option to libFirm backend");
808         int res = be_parse_arg("help");
809         (void) res;
810         assert(res);
811 }
812
813 typedef enum {
814         HELP_NONE          = 0,
815         HELP_BASIC         = 1 << 0,
816         HELP_PREPROCESSOR  = 1 << 1,
817         HELP_PARSER        = 1 << 2,
818         HELP_WARNINGS      = 1 << 3,
819         HELP_OPTIMIZATION  = 1 << 4,
820         HELP_CODEGEN       = 1 << 5,
821         HELP_LINKER        = 1 << 6,
822         HELP_LANGUAGETOOLS = 1 << 7,
823         HELP_DEBUG         = 1 << 8,
824         HELP_FIRM          = 1 << 9,
825
826         HELP_ALL           = -1
827 } help_sections_t;
828
829 static void print_help(const char *argv0, help_sections_t sections)
830 {
831         if (sections & HELP_BASIC)         print_help_basic(argv0);
832         if (sections & HELP_PREPROCESSOR)  print_help_preprocessor();
833         if (sections & HELP_PARSER)        print_help_parser();
834         if (sections & HELP_WARNINGS)      print_help_warnings();
835         if (sections & HELP_OPTIMIZATION)  print_help_optimization();
836         if (sections & HELP_CODEGEN)       print_help_codegeneration();
837         if (sections & HELP_LINKER)        print_help_linker();
838         if (sections & HELP_LANGUAGETOOLS) print_help_language_tools();
839         if (sections & HELP_DEBUG)         print_help_debug();
840         if (sections & HELP_FIRM)          print_help_firm();
841 }
842
843 static void set_be_option(const char *arg)
844 {
845         int res = be_parse_arg(arg);
846         (void) res;
847         assert(res);
848 }
849
850 static compilation_unit_type_t get_unit_type_from_string(const char *string)
851 {
852         if (streq(string, "c") || streq(string, "c-header"))
853                 return COMPILATION_UNIT_C;
854         if (streq(string, "c++") || streq(string, "c++-header"))
855                 return COMPILATION_UNIT_CXX;
856         if (streq(string, "assembler"))
857                 return COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
858         if (streq(string, "assembler-with-cpp"))
859                 return COMPILATION_UNIT_ASSEMBLER;
860         if (streq(string, "none"))
861                 return COMPILATION_UNIT_AUTODETECT;
862
863         return COMPILATION_UNIT_UNKNOWN;
864 }
865
866 static bool init_os_support(void)
867 {
868         wchar_atomic_kind         = ATOMIC_TYPE_INT;
869         enable_main_collect2_hack = false;
870         define_intmax_types       = false;
871
872         if (firm_is_unixish_os(target_machine)) {
873                 set_create_ld_ident(create_name_linux_elf);
874         } else if (firm_is_darwin_os(target_machine)) {
875                 set_create_ld_ident(create_name_macho);
876                 define_intmax_types = true;
877         } else if (firm_is_windows_os(target_machine)) {
878                 wchar_atomic_kind         = ATOMIC_TYPE_USHORT;
879                 enable_main_collect2_hack = true;
880                 set_create_ld_ident(create_name_win32);
881         } else {
882                 return false;
883         }
884
885         return true;
886 }
887
888 static bool parse_target_triple(const char *arg)
889 {
890         machine_triple_t *triple = firm_parse_machine_triple(arg);
891         if (triple == NULL) {
892                 errorf(NULL, "target-triple '%s' is not in the form 'cpu_type-manufacturer-operating_system'", arg);
893                 return false;
894         }
895         target_machine = triple;
896         return true;
897 }
898
899 static unsigned decide_modulo_shift(unsigned type_size)
900 {
901         if (architecture_modulo_shift == 0)
902                 return 0;
903         return MAX(type_size, architecture_modulo_shift);
904 }
905
906 static bool is_ia32_cpu(const char *architecture)
907 {
908         return streq(architecture, "i386")
909             || streq(architecture, "i486")
910             || streq(architecture, "i586")
911             || streq(architecture, "i686")
912             || streq(architecture, "i786");
913 }
914
915 static const char *setup_isa_from_tripel(const machine_triple_t *machine)
916 {
917         const char *cpu = machine->cpu_type;
918
919         if (is_ia32_cpu(cpu)) {
920                 return "ia32";
921         } else if (streq(cpu, "x86_64")) {
922                 return "amd64";
923         } else if (streq(cpu, "sparc")) {
924                 return "sparc";
925         } else if (streq(cpu, "arm")) {
926                 return "arm";
927         } else {
928                 errorf(NULL, "unknown cpu '%s' in target-triple", cpu);
929                 return NULL;
930         }
931 }
932
933 static const char *setup_target_machine(void)
934 {
935         if (!setup_firm_for_machine(target_machine))
936                 exit(1);
937
938         const char *isa = setup_isa_from_tripel(target_machine);
939
940         if (isa == NULL)
941                 exit(1);
942
943         init_os_support();
944
945         return isa;
946 }
947
948 /**
949  * initialize cparser type properties based on a firm type
950  */
951 static void set_typeprops_type(atomic_type_properties_t* props, ir_type *type)
952 {
953         props->size             = get_type_size_bytes(type);
954         props->alignment        = get_type_alignment_bytes(type);
955         props->struct_alignment = props->alignment;
956 }
957
958 /**
959  * Copy atomic type properties except the integer conversion rank
960  */
961 static void copy_typeprops(atomic_type_properties_t *dest,
962                            const atomic_type_properties_t *src)
963 {
964         dest->size             = src->size;
965         dest->alignment        = src->alignment;
966         dest->struct_alignment = src->struct_alignment;
967         dest->flags            = src->flags;
968 }
969
970 static void init_types_and_adjust(void)
971 {
972         const backend_params *be_params = be_get_backend_param();
973         unsigned machine_size = be_params->machine_size;
974         init_types(machine_size);
975
976         atomic_type_properties_t *props = atomic_type_properties;
977
978         /* adjust types as requested by target architecture */
979         ir_type *const type_ld = be_params->type_long_double;
980         if (type_ld) {
981                 set_typeprops_type(&props[ATOMIC_TYPE_LONG_DOUBLE], type_ld);
982                 atomic_modes[ATOMIC_TYPE_LONG_DOUBLE] = get_type_mode(type_ld);
983         }
984
985         ir_type *const type_ll = be_params->type_long_long;
986         if (type_ll)
987                 set_typeprops_type(&props[ATOMIC_TYPE_LONGLONG], type_ll);
988
989         ir_type *const type_ull = be_params->type_unsigned_long_long;
990         if (type_ull)
991                 set_typeprops_type(&props[ATOMIC_TYPE_ULONGLONG], type_ull);
992
993         /* operating system ABI specifics */
994         if (firm_is_darwin_os(target_machine)) {
995                 if (is_ia32_cpu(target_machine->cpu_type)) {
996                         props[ATOMIC_TYPE_LONGLONG].struct_alignment    =  4;
997                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment   =  4;
998                         props[ATOMIC_TYPE_DOUBLE].struct_alignment      =  4;
999                         props[ATOMIC_TYPE_LONG_DOUBLE].size             = 16;
1000                         props[ATOMIC_TYPE_LONG_DOUBLE].alignment        = 16;
1001                         props[ATOMIC_TYPE_LONG_DOUBLE].struct_alignment = 16;
1002                 }
1003         } else if (firm_is_windows_os(target_machine)) {
1004                 if (is_ia32_cpu(target_machine->cpu_type)) {
1005                         props[ATOMIC_TYPE_LONGLONG].struct_alignment    =  8;
1006                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment   =  8;
1007                         props[ATOMIC_TYPE_DOUBLE].struct_alignment      =  8;
1008                 } else if (machine_size == 64) {
1009                         /* to ease porting of old c-code microsoft decided to use 32bits
1010                          * even for long */
1011                         props[ATOMIC_TYPE_LONG]  = props[ATOMIC_TYPE_INT];
1012                         props[ATOMIC_TYPE_ULONG] = props[ATOMIC_TYPE_UINT];
1013                 }
1014
1015                 /* on windows long double is not supported */
1016                 props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
1017         } else if (firm_is_unixish_os(target_machine)) {
1018                 if (is_ia32_cpu(target_machine->cpu_type)) {
1019                         props[ATOMIC_TYPE_DOUBLE].struct_alignment    = 4;
1020                         props[ATOMIC_TYPE_LONGLONG].struct_alignment  = 4;
1021                         props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
1022                 }
1023         }
1024
1025         /* stuff decided after processing operating system specifics and
1026          * commandline flags */
1027         if (char_is_signed) {
1028                 props[ATOMIC_TYPE_CHAR].flags |= ATOMIC_TYPE_FLAG_SIGNED;
1029         } else {
1030                 props[ATOMIC_TYPE_CHAR].flags &= ~ATOMIC_TYPE_FLAG_SIGNED;
1031         }
1032         /* copy over wchar_t properties (including rank) */
1033         props[ATOMIC_TYPE_WCHAR_T] = props[wchar_atomic_kind];
1034
1035         /* initialize defaults for unsupported types */
1036         if (!type_ll) {
1037                 copy_typeprops(&props[ATOMIC_TYPE_LONGLONG], &props[ATOMIC_TYPE_LONG]);
1038         }
1039         if (!type_ull) {
1040                 copy_typeprops(&props[ATOMIC_TYPE_ULONGLONG],
1041                                &props[ATOMIC_TYPE_ULONG]);
1042         }
1043         if (!type_ld) {
1044                 copy_typeprops(&props[ATOMIC_TYPE_LONG_DOUBLE],
1045                                &props[ATOMIC_TYPE_DOUBLE]);
1046         }
1047
1048         /* initialize firm pointer modes */
1049         char               name[64];
1050         unsigned           bit_size     = machine_size;
1051         unsigned           modulo_shift = decide_modulo_shift(bit_size);
1052
1053         snprintf(name, sizeof(name), "p%u", machine_size);
1054         ir_mode *ptr_mode = new_reference_mode(name, irma_twos_complement, bit_size, modulo_shift);
1055
1056         if (machine_size == 16) {
1057                 set_reference_mode_signed_eq(ptr_mode, mode_Hs);
1058                 set_reference_mode_unsigned_eq(ptr_mode, mode_Hu);
1059         } else if (machine_size == 32) {
1060                 set_reference_mode_signed_eq(ptr_mode, mode_Is);
1061                 set_reference_mode_unsigned_eq(ptr_mode, mode_Iu);
1062         } else if (machine_size == 64) {
1063                 set_reference_mode_signed_eq(ptr_mode, mode_Ls);
1064                 set_reference_mode_unsigned_eq(ptr_mode, mode_Lu);
1065         } else {
1066                 panic("strange machine_size when determining pointer modes");
1067         }
1068
1069         /* Hmm, pointers should be machine size */
1070         set_modeP_data(ptr_mode);
1071         set_modeP_code(ptr_mode);
1072
1073         byte_order_big_endian = be_params->byte_order_big_endian;
1074         if (be_params->modulo_shift_efficient) {
1075                 architecture_modulo_shift = machine_size;
1076         } else {
1077                 architecture_modulo_shift = 0;
1078         }
1079 }
1080
1081 static void setup_cmode(const compilation_unit_t *unit)
1082 {
1083         compilation_unit_type_t type     = unit->type;
1084         lang_standard_t         standard = unit->standard;
1085         if (type == COMPILATION_UNIT_PREPROCESSED_C || type == COMPILATION_UNIT_C) {
1086                 switch (standard) {
1087                 case STANDARD_C89:     c_mode = _C89;                       break;
1088                                                            /* TODO determine difference between these two */
1089                 case STANDARD_C89AMD1: c_mode = _C89;                       break;
1090                 case STANDARD_C99:     c_mode = _C89 | _C99;                break;
1091                 case STANDARD_C11:     c_mode = _C89 | _C99 | _C11;         break;
1092                 case STANDARD_GNU89:   c_mode = _C89 |               _GNUC; break;
1093                 case STANDARD_GNU11:   c_mode = _C89 | _C99 | _C11 | _GNUC; break;
1094
1095                 case STANDARD_ANSI:
1096                 case STANDARD_CXX98:
1097                 case STANDARD_GNUXX98:
1098                 case STANDARD_DEFAULT:
1099                         fprintf(stderr, "warning: command line option \"-std=%s\" is not valid for C\n", str_lang_standard(standard));
1100                         /* FALLTHROUGH */
1101                 case STANDARD_GNU99:   c_mode = _C89 | _C99 | _GNUC; break;
1102                 }
1103         } else if (type == COMPILATION_UNIT_PREPROCESSED_CXX
1104                    || type == COMPILATION_UNIT_CXX) {
1105                 switch (standard) {
1106                 case STANDARD_CXX98: c_mode = _CXX; break;
1107
1108                 case STANDARD_ANSI:
1109                 case STANDARD_C89:
1110                 case STANDARD_C89AMD1:
1111                 case STANDARD_C99:
1112                 case STANDARD_C11:
1113                 case STANDARD_GNU89:
1114                 case STANDARD_GNU99:
1115                 case STANDARD_GNU11:
1116                 case STANDARD_DEFAULT:
1117                         fprintf(stderr, "warning: command line option \"-std=%s\" is not valid for C++\n", str_lang_standard(standard));
1118                         /* FALLTHROUGH */
1119                 case STANDARD_GNUXX98: c_mode = _CXX | _GNUC; break;
1120                 }
1121         }
1122
1123         c_mode |= features_on;
1124         c_mode &= ~features_off;
1125 }
1126
1127 static void determine_unit_standard(compilation_unit_t *unit,
1128                                     lang_standard_t standard)
1129 {
1130         unit->standard = standard;
1131         switch (standard) {
1132         case STANDARD_ANSI:
1133                 switch (unit->type) {
1134                 case COMPILATION_UNIT_C:
1135                 case COMPILATION_UNIT_PREPROCESSED_C:
1136                         unit->standard = STANDARD_C89;
1137                         break;
1138                 case COMPILATION_UNIT_CXX:
1139                 case COMPILATION_UNIT_PREPROCESSED_CXX:
1140                         unit->standard = STANDARD_CXX98;
1141                         break;
1142                 default:
1143                         break;
1144                 }
1145                 break;
1146
1147         case STANDARD_DEFAULT:
1148                 switch (unit->type) {
1149                 case COMPILATION_UNIT_C:
1150                 case COMPILATION_UNIT_PREPROCESSED_C:
1151                         unit->standard = STANDARD_GNU99;
1152                         break;
1153                 case COMPILATION_UNIT_CXX:
1154                 case COMPILATION_UNIT_PREPROCESSED_CXX:
1155                         unit->standard = STANDARD_GNUXX98;
1156                         break;
1157                 default:
1158                         break;
1159                 }
1160                 break;
1161
1162         default:
1163                 break;
1164         }
1165 }
1166
1167 static bool output_preprocessor_tokens(compilation_unit_t *unit, FILE *out)
1168 {
1169         /* just here for gcc compatibility */
1170         fprintf(out, "# 1 \"%s\"\n", unit->name);
1171         fprintf(out, "# 1 \"<built-in>\"\n");
1172         fprintf(out, "# 1 \"<command-line>\"\n");
1173
1174         set_preprocessor_output(out);
1175         switch_pp_input(unit->input, unit->name, NULL, false);
1176
1177         for (;;) {
1178                 next_preprocessing_token();
1179                 if (pp_token.kind == T_EOF)
1180                         break;
1181                 emit_pp_token();
1182         }
1183
1184         fputc('\n', out);
1185         check_unclosed_conditionals();
1186         close_pp_input();
1187         print_error_summary();
1188         set_preprocessor_output(NULL);
1189
1190         if (unit->type == COMPILATION_UNIT_C) {
1191                 unit->type = COMPILATION_UNIT_PREPROCESSED_C;
1192         } else if (unit->type == COMPILATION_UNIT_CXX) {
1193                 unit->type = COMPILATION_UNIT_PREPROCESSED_CXX;
1194         }
1195         bool res = close_input(unit);
1196         return res && error_count == 0;
1197 }
1198
1199 static void copy_file(FILE *dest, FILE *input)
1200 {
1201         char buf[16384];
1202
1203         for (;;) {
1204                 size_t read = fread(buf, 1, sizeof(buf), input);
1205                 if (read == 0)
1206                         break;
1207                 if (fwrite(buf, 1, read, dest) != read) {
1208                         perror("could not write output");
1209                 }
1210         }
1211 }
1212
1213 static bool open_input(compilation_unit_t *unit)
1214 {
1215         /* input already available as FILE? */
1216         if (unit->input != NULL)
1217                 return true;
1218
1219         const char *const inputname = unit->name;
1220         unit->input_is_pipe = false;
1221         if (streq(inputname, "-")) {
1222                 unit->input   = stdin;
1223         } else {
1224                 unit->input = fopen(inputname, "r");
1225                 if (unit->input == NULL) {
1226                         position_t const pos = { inputname, 0, 0, 0 };
1227                         errorf(&pos, "could not open: %s", strerror(errno));
1228                         return false;
1229                 }
1230         }
1231         return true;
1232 }
1233
1234 static void node_counter(ir_node *node, void *env)
1235 {
1236         (void)node;
1237         unsigned long long *count = (unsigned long long*)env;
1238         ++(*count);
1239 }
1240
1241 static unsigned long long count_firm_nodes(void)
1242 {
1243         unsigned long long count = 0;
1244
1245         int n_irgs = get_irp_n_irgs();
1246         for (int i = 0; i < n_irgs; ++i) {
1247                 ir_graph *irg = get_irp_irg(i);
1248                 irg_walk_graph(irg, node_counter, NULL, &count);
1249         }
1250         return count;
1251 }
1252
1253 static int compilation_loop(compile_mode_t mode, compilation_unit_t *units,
1254                                                         lang_standard_t standard, FILE *out)
1255 {
1256         int  result                   = EXIT_SUCCESS;
1257         bool already_constructed_firm = false;
1258         for (compilation_unit_t *unit = units; unit != NULL; unit = unit->next) {
1259                 const char *const inputname = unit->name;
1260
1261                 determine_unit_standard(unit, standard);
1262                 setup_cmode(unit);
1263
1264                 stat_ev_ctx_push_str("compilation_unit", inputname);
1265
1266 again:
1267                 switch (unit->type) {
1268                 case COMPILATION_UNIT_IR: {
1269                         if (!open_input(unit)) {
1270                                 result = EXIT_FAILURE;
1271                                 break;
1272                         }
1273                         if (ir_import_file(unit->input, unit->name)) {
1274                                 position_t const pos = { inputname, 0, 0, 0 };
1275                                 errorf(&pos, "import of firm graph failed");
1276                                 result = EXIT_FAILURE;
1277                                 break;
1278                         }
1279                         unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
1280                         goto again;
1281                 }
1282                 case COMPILATION_UNIT_ASSEMBLER: {
1283                         if (external_preprocessor == NULL) {
1284                                 panic("preprocessed assembler not possible with internal preprocessor yet");
1285                         }
1286                         if (!run_external_preprocessor(unit)) {
1287                                 result = EXIT_FAILURE;
1288                                 break;
1289                         }
1290                         /* write file to output... */
1291                         FILE *asm_out;
1292                         if (mode == PreprocessOnly) {
1293                                 asm_out = out;
1294                         } else {
1295                                 asm_out = make_temp_file("ccs", &unit->name);
1296                         }
1297                         assert(unit->input != NULL);
1298                         assert(unit->input_is_pipe);
1299                         copy_file(asm_out, unit->input);
1300                         if (asm_out != out)
1301                                 fclose(asm_out);
1302                         unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
1303                         goto again;
1304                 }
1305                 case COMPILATION_UNIT_C:
1306                 case COMPILATION_UNIT_CXX:
1307                         if (external_preprocessor != NULL) {
1308                                 if (!run_external_preprocessor(unit)) {
1309                                         result = EXIT_FAILURE;
1310                                         break;
1311                                 }
1312                                 goto again;
1313                         }
1314                         /* FALLTHROUGH */
1315
1316                 case COMPILATION_UNIT_PREPROCESSED_C:
1317                 case COMPILATION_UNIT_PREPROCESSED_CXX: {
1318                         if (!open_input(unit)) {
1319                                 result = EXIT_FAILURE;
1320                                 break;
1321                         }
1322                         init_tokens();
1323
1324                         if (mode == PreprocessOnly) {
1325                                 if (!output_preprocessor_tokens(unit, out)) {
1326                                         result = EXIT_FAILURE;
1327                                         break;
1328                                 }
1329                                 break;
1330                         }
1331
1332                         /* do the actual parsing */
1333                         do_parsing(unit);
1334                         goto again;
1335                 }
1336                 case COMPILATION_UNIT_AST:
1337                         /* prints the AST even if errors occurred */
1338                         if (mode == PrintAst) {
1339                                 print_to_file(out);
1340                                 print_ast(unit->ast);
1341                         }
1342                         if (unit->parse_errors) {
1343                                 result = EXIT_FAILURE;
1344                                 break;
1345                         }
1346
1347                         if (mode == BenchmarkParser) {
1348                                 break;
1349                         } else if (mode == PrintFluffy) {
1350                                 write_fluffy_decls(out, unit->ast);
1351                                 break;
1352                         } else if (mode == PrintJna) {
1353                                 write_jna_decls(out, unit->ast);
1354                                 break;
1355                         } else if (mode == PrintCompoundSizes) {
1356                                 write_compoundsizes(out, unit->ast);
1357                                 break;
1358                         }
1359
1360                         /* build the firm graph */
1361                         ir_timer_t *t_construct = ir_timer_new();
1362                         timer_register(t_construct, "Frontend: Graph construction");
1363                         timer_start(t_construct);
1364                         if (already_constructed_firm) {
1365                                 panic("compiling multiple files/translation units not possible");
1366                         }
1367                         init_implicit_optimizations();
1368                         translation_unit_to_firm(unit->ast);
1369                         already_constructed_firm = true;
1370                         timer_stop(t_construct);
1371                         if (stat_ev_enabled) {
1372                                 stat_ev_dbl("time_graph_construction", ir_timer_elapsed_sec(t_construct));
1373                                 stat_ev_int("size_graph_construction", count_firm_nodes());
1374                         }
1375                         unit->type = COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION;
1376                         goto again;
1377
1378                 case COMPILATION_UNIT_INTERMEDIATE_REPRESENTATION:
1379                         if (mode == ParseOnly)
1380                                 break;
1381
1382                         if (mode == CompileDump) {
1383                                 /* find irg */
1384                                 ident    *id     = new_id_from_str(dumpfunction);
1385                                 ir_graph *irg    = NULL;
1386                                 int       n_irgs = get_irp_n_irgs();
1387                                 for (int i = 0; i < n_irgs; ++i) {
1388                                         ir_graph *tirg   = get_irp_irg(i);
1389                                         ident    *irg_id = get_entity_ident(get_irg_entity(tirg));
1390                                         if (irg_id == id) {
1391                                                 irg = tirg;
1392                                                 break;
1393                                         }
1394                                 }
1395
1396                                 if (irg == NULL) {
1397                                         errorf(NULL, "no graph for function '%s' found", dumpfunction);
1398                                         return EXIT_FAILURE;
1399                                 }
1400
1401                                 dump_ir_graph_file(out, irg);
1402                                 fclose(out);
1403                                 return EXIT_SUCCESS;
1404                         }
1405
1406                         if (mode == CompileExportIR) {
1407                                 ir_export_file(out);
1408                                 if (ferror(out) != 0) {
1409                                         errorf(NULL, "writing to output failed");
1410                                         return EXIT_FAILURE;
1411                                 }
1412                                 return EXIT_SUCCESS;
1413                         }
1414
1415                         FILE *asm_out;
1416                         if (mode == Compile) {
1417                                 asm_out = out;
1418                         } else {
1419                                 asm_out = make_temp_file("ccs", &unit->name);
1420                         }
1421                         ir_timer_t *t_opt_codegen = ir_timer_new();
1422                         timer_register(t_opt_codegen, "Optimization and Codegeneration");
1423                         timer_start(t_opt_codegen);
1424                         generate_code(asm_out, inputname);
1425                         timer_stop(t_opt_codegen);
1426                         if (stat_ev_enabled) {
1427                                 stat_ev_dbl("time_opt_codegen", ir_timer_elapsed_sec(t_opt_codegen));
1428                         }
1429                         if (asm_out != out) {
1430                                 fclose(asm_out);
1431                         }
1432                         unit->type = COMPILATION_UNIT_PREPROCESSED_ASSEMBLER;
1433                         goto again;
1434                 case COMPILATION_UNIT_PREPROCESSED_ASSEMBLER:
1435                         if (mode != CompileAssemble && mode != CompileAssembleLink)
1436                                 break;
1437
1438                         /* assemble */
1439                         const char *input = unit->name;
1440                         if (mode == CompileAssemble) {
1441                                 fclose(out);
1442                                 unit->name = outname;
1443                         } else {
1444                                 FILE *tempf = make_temp_file("cco", &unit->name);
1445                                 /* hackish... */
1446                                 fclose(tempf);
1447                         }
1448
1449                         assemble(unit->name, input);
1450
1451                         unit->type = COMPILATION_UNIT_OBJECT;
1452                         goto again;
1453                 case COMPILATION_UNIT_UNKNOWN:
1454                 case COMPILATION_UNIT_AUTODETECT:
1455                 case COMPILATION_UNIT_OBJECT:
1456                         break;
1457                 }
1458
1459                 stat_ev_ctx_pop("compilation_unit");
1460         }
1461         return result;
1462 }
1463
1464 static int link_program(compilation_unit_t *units)
1465 {
1466         obstack_1grow(&ldflags_obst, '\0');
1467         const char *flags = obstack_finish(&ldflags_obst);
1468
1469         /* construct commandline */
1470         const char *linker = getenv("CPARSER_LINK");
1471         if (linker != NULL) {
1472                 obstack_printf(&file_obst, "%s ", linker);
1473         } else {
1474                 if (target_triple != NULL)
1475                         obstack_printf(&file_obst, "%s-", target_triple);
1476                 obstack_printf(&file_obst, "%s ", LINKER);
1477         }
1478
1479         for (compilation_unit_t *unit = units; unit != NULL; unit = unit->next) {
1480                 if (unit->type != COMPILATION_UNIT_OBJECT)
1481                         continue;
1482
1483                 add_flag(&file_obst, "%s", unit->name);
1484         }
1485
1486         add_flag(&file_obst, "-o");
1487         add_flag(&file_obst, outname);
1488         obstack_printf(&file_obst, "%s", flags);
1489         obstack_1grow(&file_obst, '\0');
1490
1491         char *commandline = obstack_finish(&file_obst);
1492
1493         if (verbose) {
1494                 puts(commandline);
1495         }
1496         int err = system(commandline);
1497         if (err != EXIT_SUCCESS) {
1498                 errorf(NULL, "linker reported an error");
1499                 return EXIT_FAILURE;
1500         }
1501         return EXIT_SUCCESS;
1502 }
1503
1504 int main(int argc, char **argv)
1505 {
1506         const char         *print_file_name_file = NULL;
1507         compile_mode_t      mode                 = CompileAssembleLink;
1508         int                 opt_level            = 1;
1509         char                cpu_arch[16]         = "ia32";
1510         compilation_unit_t *units                = NULL;
1511         compilation_unit_t *last_unit            = NULL;
1512         bool                produce_statev       = false;
1513         const char         *filtev               = NULL;
1514         bool                profile_generate     = false;
1515         bool                profile_use          = false;
1516         bool                do_timing            = false;
1517         bool                print_timing         = false;
1518
1519         /* hack for now... */
1520         if (strstr(argv[0], "pptest") != NULL) {
1521                 extern int pptest_main(int argc, char **argv);
1522                 return pptest_main(argc, argv);
1523         }
1524
1525         temp_files = NEW_ARR_F(char*, 0);
1526         atexit(free_temp_files);
1527
1528         obstack_init(&cppflags_obst);
1529         obstack_init(&ldflags_obst);
1530         obstack_init(&asflags_obst);
1531         obstack_init(&file_obst);
1532         init_include_paths();
1533
1534 #define GET_ARG_AFTER(def, args)                                             \
1535         do {                                                                     \
1536         def = &arg[sizeof(args)-1];                                              \
1537         if (def[0] == '\0') {                                                    \
1538                 ++i;                                                                 \
1539                 if (i >= argc) {                                                     \
1540                         errorf(NULL, "expected argument after '" args "'"); \
1541                         argument_errors = true;                                          \
1542                         break;                                                           \
1543                 }                                                                    \
1544                 def = argv[i];                                                       \
1545                 if (def[0] == '-' && def[1] != '\0') {                               \
1546                         errorf(NULL, "expected argument after '" args "'"); \
1547                         argument_errors = true;                                          \
1548                         continue;                                                        \
1549                 }                                                                    \
1550         }                                                                        \
1551         } while (0)
1552
1553 #define SINGLE_OPTION(ch) (option[0] == (ch) && option[1] == '\0')
1554
1555         /* initialize this early because it has to parse options */
1556         gen_firm_init();
1557
1558         /* early options parsing (find out optimization level and OS) */
1559         for (int i = 1; i < argc; ++i) {
1560                 const char *arg = argv[i];
1561                 if (arg[0] != '-')
1562                         continue;
1563
1564                 const char *option = &arg[1];
1565                 if (option[0] == 'O') {
1566                         sscanf(&option[1], "%d", &opt_level);
1567                 }
1568         }
1569
1570         if (target_machine == NULL) {
1571                 target_machine = firm_get_host_machine();
1572         }
1573         choose_optimization_pack(opt_level);
1574         setup_target_machine();
1575
1576         /* parse rest of options */
1577         lang_standard_t         standard        = STANDARD_DEFAULT;
1578         compilation_unit_type_t forced_unittype = COMPILATION_UNIT_AUTODETECT;
1579         help_sections_t         help            = HELP_NONE;
1580         bool                    argument_errors = false;
1581         for (int i = 1; i < argc; ++i) {
1582                 const char *arg = argv[i];
1583                 if (arg[0] == '-' && arg[1] != '\0') {
1584                         /* an option */
1585                         const char *option = &arg[1];
1586                         if (option[0] == 'o') {
1587                                 GET_ARG_AFTER(outname, "-o");
1588                         } else if (option[0] == 'g') {
1589                                 /* TODO: parse -gX with 0<=X<=3... */
1590                                 set_be_option("debug=frameinfo");
1591                                 set_be_option("ia32-optcc=false");
1592                         } else if (SINGLE_OPTION('c')) {
1593                                 mode = CompileAssemble;
1594                         } else if (SINGLE_OPTION('E')) {
1595                                 mode = PreprocessOnly;
1596                         } else if (SINGLE_OPTION('s')) {
1597                                 add_flag(&ldflags_obst, "-s");
1598                         } else if (SINGLE_OPTION('S')) {
1599                                 mode = Compile;
1600                         } else if (option[0] == 'O') {
1601                                 continue;
1602                         } else if (option[0] == 'I') {
1603                                 const char *opt;
1604                                 GET_ARG_AFTER(opt, "-I");
1605                                 add_flag(&cppflags_obst, "-I%s", opt);
1606                                 append_include_path(&bracket_searchpath, opt);
1607                         } else if (option[0] == 'D') {
1608                                 const char *opt;
1609                                 GET_ARG_AFTER(opt, "-D");
1610                                 add_flag(&cppflags_obst, "-D%s", opt);
1611                         } else if (option[0] == 'U') {
1612                                 const char *opt;
1613                                 GET_ARG_AFTER(opt, "-U");
1614                                 add_flag(&cppflags_obst, "-U%s", opt);
1615                         } else if (option[0] == 'l') {
1616                                 const char *opt;
1617                                 GET_ARG_AFTER(opt, "-l");
1618                                 add_flag(&ldflags_obst, "-l%s", opt);
1619                         } else if (option[0] == 'L') {
1620                                 const char *opt;
1621                                 GET_ARG_AFTER(opt, "-L");
1622                                 add_flag(&ldflags_obst, "-L%s", opt);
1623                         } else if (SINGLE_OPTION('v')) {
1624                                 verbose = 1;
1625                         } else if (SINGLE_OPTION('w')) {
1626                                 add_flag(&cppflags_obst, "-w");
1627                                 disable_all_warnings();
1628                         } else if (option[0] == 'x') {
1629                                 const char *opt;
1630                                 GET_ARG_AFTER(opt, "-x");
1631                                 forced_unittype = get_unit_type_from_string(opt);
1632                                 if (forced_unittype == COMPILATION_UNIT_UNKNOWN) {
1633                                         errorf(NULL, "unknown language '%s'", opt);
1634                                         argument_errors = true;
1635                                 }
1636                         } else if (SINGLE_OPTION('M')) {
1637                                 mode = PreprocessOnly;
1638                                 add_flag(&cppflags_obst, "-M");
1639                         } else if (streq(option, "MMD") ||
1640                                    streq(option, "MD")) {
1641                                 construct_dep_target = true;
1642                                 add_flag(&cppflags_obst, "-%s", option);
1643                         } else if (streq(option, "MM")  ||
1644                                    streq(option, "MP")) {
1645                                 add_flag(&cppflags_obst, "-%s", option);
1646                         } else if (streq(option, "MT") ||
1647                                    streq(option, "MQ") ||
1648                                    streq(option, "MF")) {
1649                                 const char *opt;
1650                                 GET_ARG_AFTER(opt, "-MT");
1651                                 add_flag(&cppflags_obst, "-%s", option);
1652                                 add_flag(&cppflags_obst, "%s", opt);
1653                         } else if (streq(option, "include")) {
1654                                 const char *opt;
1655                                 GET_ARG_AFTER(opt, "-include");
1656                                 add_flag(&cppflags_obst, "-include");
1657                                 add_flag(&cppflags_obst, "%s", opt);
1658                         } else if (streq(option, "idirafter")) {
1659                                 const char *opt;
1660                                 GET_ARG_AFTER(opt, "-idirafter");
1661                                 add_flag(&cppflags_obst, "-idirafter");
1662                                 add_flag(&cppflags_obst, "%s", opt);
1663                                 append_include_path(&after_searchpath, opt);
1664                         } else if (streq(option, "isystem")) {
1665                                 const char *opt;
1666                                 GET_ARG_AFTER(opt, "-isystem");
1667                                 add_flag(&cppflags_obst, "-isystem");
1668                                 add_flag(&cppflags_obst, "%s", opt);
1669                                 append_include_path(&system_searchpath, opt);
1670                         } else if (streq(option, "iquote")) {
1671                                 const char *opt;
1672                                 GET_ARG_AFTER(opt, "-iquote");
1673                                 add_flag(&cppflags_obst, "-iquote");
1674                                 add_flag(&cppflags_obst, "%s", opt);
1675                                 append_include_path(&quote_searchpath, opt);
1676                         } else if (streq(option, "pthread")) {
1677                                 /* set flags for the preprocessor */
1678                                 add_flag(&cppflags_obst, "-D_REENTRANT");
1679                                 /* set flags for the linker */
1680                                 add_flag(&ldflags_obst, "-lpthread");
1681                         } else if (streq(option, "nostdinc")
1682                                         || streq(option, "trigraphs")) {
1683                                 /* pass these through to the preprocessor */
1684                                 add_flag(&cppflags_obst, "%s", arg);
1685                         } else if (streq(option, "pipe")) {
1686                                 /* here for gcc compatibility */
1687                         } else if (streq(option, "static")) {
1688                                 add_flag(&ldflags_obst, "-static");
1689                         } else if (streq(option, "shared")) {
1690                                 add_flag(&ldflags_obst, "-shared");
1691                         } else if (option[0] == 'f') {
1692                                 char const *orig_opt;
1693                                 GET_ARG_AFTER(orig_opt, "-f");
1694
1695                                 if (strstart(orig_opt, "input-charset=")) {
1696                                         char const* const encoding = strchr(orig_opt, '=') + 1;
1697                                         input_encoding = encoding;
1698                                 } else if (strstart(orig_opt, "align-loops=") ||
1699                                            strstart(orig_opt, "align-jumps=") ||
1700                                            strstart(orig_opt, "align-functions=")) {
1701                                         fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
1702                                 } else if (strstart(orig_opt, "visibility=")) {
1703                                         const char *val = strchr(orig_opt, '=')+1;
1704                                         elf_visibility_tag_t visibility
1705                                                 = get_elf_visibility_from_string(val);
1706                                         if (visibility == ELF_VISIBILITY_ERROR) {
1707                                                 errorf(NULL, "invalid visibility '%s' specified", val);
1708                                                 argument_errors = true;
1709                                         } else {
1710                                                 set_default_visibility(visibility);
1711                                         }
1712                                 } else if (strstart(orig_opt, "message-length=")) {
1713                                         /* ignore: would only affect error message format */
1714                                 } else if (streq(orig_opt, "fast-math") ||
1715                                            streq(orig_opt, "fp-fast")) {
1716                                         firm_fp_model = fp_model_fast;
1717                                 } else if (streq(orig_opt, "fp-precise")) {
1718                                         firm_fp_model = fp_model_precise;
1719                                 } else if (streq(orig_opt, "fp-strict")) {
1720                                         firm_fp_model = fp_model_strict;
1721                                 } else if (streq(orig_opt, "help")) {
1722                                         fprintf(stderr, "warning: -fhelp is deprecated\n");
1723                                         help |= HELP_OPTIMIZATION;
1724                                 } else {
1725                                         /* -f options which have an -fno- variant */
1726                                         char const *opt         = orig_opt;
1727                                         bool        truth_value = true;
1728                                         if (opt[0] == 'n' && opt[1] == 'o' && opt[2] == '-') {
1729                                                 truth_value = false;
1730                                                 opt += 3;
1731                                         }
1732
1733                                         if (streq(opt, "diagnostics-show-option")) {
1734                                                 diagnostics_show_option = truth_value;
1735                                         } else if (streq(opt, "dollars-in-identifiers")) {
1736                                                 allow_dollar_in_symbol = truth_value;
1737                                         } else if (streq(opt, "omit-frame-pointer")) {
1738                                                 set_be_option(truth_value ? "omitfp" : "omitfp=no");
1739                                         } else if (streq(opt, "short-wchar")) {
1740                                                 wchar_atomic_kind = truth_value ? ATOMIC_TYPE_USHORT
1741                                                         : ATOMIC_TYPE_INT;
1742                                         } else if (streq(opt, "show-column")) {
1743                                                 show_column = truth_value;
1744                                         } else if (streq(opt, "signed-char")) {
1745                                                 char_is_signed = truth_value;
1746                                         } else if (streq(opt, "strength-reduce")) {
1747                                                 /* does nothing, for gcc compatibility (even gcc does
1748                                                  * nothing for this switch anymore) */
1749                                         } else if (streq(opt, "syntax-only")) {
1750                                                 mode = truth_value ? ParseOnly : CompileAssembleLink;
1751                                         } else if (streq(opt, "unsigned-char")) {
1752                                                 char_is_signed = !truth_value;
1753                                         } else if (streq(opt, "freestanding")) {
1754                                                 freestanding = truth_value;
1755                                         } else if (streq(opt, "hosted")) {
1756                                                 freestanding = !truth_value;
1757                                         } else if (streq(opt, "profile-generate")) {
1758                                                 profile_generate = truth_value;
1759                                         } else if (streq(opt, "profile-use")) {
1760                                                 profile_use = truth_value;
1761                                         } else if (!truth_value &&
1762                                                    streq(opt, "asynchronous-unwind-tables")) {
1763                                             /* nothing todo, a gcc feature which we do not support
1764                                              * anyway was deactivated */
1765                                         } else if (streq(opt, "verbose-asm")) {
1766                                                 /* ignore: we always print verbose assembler */
1767                                         } else if (streq(opt, "jump-tables")             ||
1768                                                    streq(opt, "expensive-optimizations") ||
1769                                                    streq(opt, "common")                  ||
1770                                                    streq(opt, "optimize-sibling-calls")  ||
1771                                                    streq(opt, "align-loops")             ||
1772                                                    streq(opt, "align-jumps")             ||
1773                                                    streq(opt, "align-functions")         ||
1774                                                    streq(opt, "PIC")                     ||
1775                                                    streq(opt, "stack-protector")         ||
1776                                                    streq(opt, "stack-protector-all")) {
1777                                                 fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
1778                                         } else {
1779                                                 if (firm_option(orig_opt) == 0) {
1780                                                         errorf(NULL, "unknown Firm option '-f%s'", orig_opt);
1781                                                         argument_errors = true;
1782                                                         continue;
1783                                                 }
1784                                         }
1785                                 }
1786                         } else if (option[0] == 'b') {
1787                                 const char *opt;
1788                                 GET_ARG_AFTER(opt, "-b");
1789
1790                                 if (streq(opt, "help")) {
1791                                         fprintf(stderr, "warning: -bhelp is deprecated (use --help-firm)\n");
1792                                         help |= HELP_FIRM;
1793                                 } else {
1794                                         if (be_parse_arg(opt) == 0) {
1795                                                 errorf(NULL, "unknown Firm backend option '-b %s'", opt);
1796                                                 argument_errors = true;
1797                                         } else if (strstart(opt, "isa=")) {
1798                                                 strncpy(cpu_arch, opt, sizeof(cpu_arch));
1799                                         }
1800                                 }
1801                         } else if (option[0] == 'W') {
1802                                 if (strstart(option + 1, "a,")) {
1803                                         const char *opt;
1804                                         GET_ARG_AFTER(opt, "-Wa,");
1805                                         add_flag(&asflags_obst, "-Wa,%s", opt);
1806                                 } else if (strstart(option + 1, "p,")) {
1807                                         // pass options directly to the preprocessor
1808                                         const char *opt;
1809                                         GET_ARG_AFTER(opt, "-Wp,");
1810                                         add_flag(&cppflags_obst, "-Wp,%s", opt);
1811                                 } else if (strstart(option + 1, "l,")) {
1812                                         // pass options directly to the linker
1813                                         const char *opt;
1814                                         GET_ARG_AFTER(opt, "-Wl,");
1815                                         add_flag(&ldflags_obst, "-Wl,%s", opt);
1816                                 } else if (streq(option + 1, "no-trigraphs")
1817                                                         || streq(option + 1, "undef")
1818                                                         || streq(option + 1, "missing-include-dirs")
1819                                                         || streq(option + 1, "endif-labels")) {
1820                                         add_flag(&cppflags_obst, "%s", arg);
1821                                 } else if (streq(option+1, "init-self")) {
1822                                         /* ignored (same as gcc does) */
1823                                 } else if (streq(option+1, "format-y2k")
1824                                            || streq(option+1, "format-security")
1825                                            || streq(option+1, "old-style-declaration")
1826                                            || streq(option+1, "type-limits")) {
1827                                         /* ignore (gcc compatibility) */
1828                                 } else {
1829                                         set_warning_opt(&option[1]);
1830                                 }
1831                         } else if (option[0] == 'm') {
1832                                 /* -m options */
1833                                 const char *opt;
1834                                 char arch_opt[64];
1835
1836                                 GET_ARG_AFTER(opt, "-m");
1837                                 if (strstart(opt, "target=")) {
1838                                         GET_ARG_AFTER(opt, "-mtarget=");
1839                                         if (!parse_target_triple(opt)) {
1840                                                 argument_errors = true;
1841                                         } else {
1842                                                 const char *isa = setup_target_machine();
1843                                                 strncpy(cpu_arch, isa, sizeof(cpu_arch));
1844                                                 target_triple = opt;
1845                                         }
1846                                 } else if (strstart(opt, "triple=")) {
1847                                         GET_ARG_AFTER(opt, "-mtriple=");
1848                                         if (!parse_target_triple(opt)) {
1849                                                 argument_errors = true;
1850                                         } else {
1851                                                 const char *isa = setup_target_machine();
1852                                                 strncpy(cpu_arch, isa, sizeof(cpu_arch));
1853                                                 target_triple = opt;
1854                                         }
1855                                 } else if (strstart(opt, "arch=")) {
1856                                         GET_ARG_AFTER(opt, "-march=");
1857                                         snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
1858                                         int res = be_parse_arg(arch_opt);
1859                                         snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
1860                                         res &= be_parse_arg(arch_opt);
1861
1862                                         if (res == 0) {
1863                                                 errorf(NULL, "unknown architecture '%s'", arch_opt);
1864                                                 argument_errors = true;
1865                                         }
1866                                 } else if (strstart(opt, "tune=")) {
1867                                         GET_ARG_AFTER(opt, "-mtune=");
1868                                         snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
1869                                         if (be_parse_arg(arch_opt) == 0)
1870                                                 argument_errors = true;
1871                                 } else if (strstart(opt, "cpu=")) {
1872                                         GET_ARG_AFTER(opt, "-mcpu=");
1873                                         snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
1874                                         if (be_parse_arg(arch_opt) == 0)
1875                                                 argument_errors = true;
1876                                 } else if (strstart(opt, "fpmath=")) {
1877                                         GET_ARG_AFTER(opt, "-mfpmath=");
1878                                         if (streq(opt, "387"))
1879                                                 opt = "x87";
1880                                         else if (streq(opt, "sse"))
1881                                                 opt = "sse2";
1882                                         else {
1883                                                 errorf(NULL, "option -mfpmath supports only 387 or sse");
1884                                                 argument_errors = true;
1885                                         }
1886                                         if (!argument_errors) {
1887                                                 snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=%s", cpu_arch, opt);
1888                                                 if (be_parse_arg(arch_opt) == 0)
1889                                                         argument_errors = true;
1890                                         }
1891                                 } else if (strstart(opt, "preferred-stack-boundary=")) {
1892                                         GET_ARG_AFTER(opt, "-mpreferred-stack-boundary=");
1893                                         snprintf(arch_opt, sizeof(arch_opt), "%s-stackalign=%s", cpu_arch, opt);
1894                                         if (be_parse_arg(arch_opt) == 0)
1895                                                 argument_errors = true;
1896                                 } else if (streq(opt, "rtd")) {
1897                                         default_calling_convention = CC_STDCALL;
1898                                 } else if (strstart(opt, "regparm=")) {
1899                                         errorf(NULL, "regparm convention not supported yet");
1900                                         argument_errors = true;
1901                                 } else if (streq(opt, "soft-float")) {
1902                                         add_flag(&ldflags_obst, "-msoft-float");
1903                                         snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=softfloat", cpu_arch);
1904                                         if (be_parse_arg(arch_opt) == 0)
1905                                                 argument_errors = true;
1906                                 } else if (streq(opt, "sse2")) {
1907                                         /* ignore for now, our x86 backend always uses sse when
1908                                          * sse is requested */
1909                                 } else {
1910                                         long int value = strtol(opt, NULL, 10);
1911                                         if (value == 0) {
1912                                                 errorf(NULL, "wrong option '-m %s'",  opt);
1913                                                 argument_errors = true;
1914                                         } else if (value != 16 && value != 32 && value != 64) {
1915                                                 errorf(NULL, "option -m supports only 16, 32 or 64");
1916                                                 argument_errors = true;
1917                                         } else {
1918                                                 unsigned machine_size = (unsigned)value;
1919                                                 /* TODO: choose/change backend based on this */
1920                                                 add_flag(&cppflags_obst, "-m%u", machine_size);
1921                                                 add_flag(&asflags_obst, "-m%u", machine_size);
1922                                                 add_flag(&ldflags_obst, "-m%u", machine_size);
1923                                         }
1924                                 }
1925                         } else if (option[0] == 'X') {
1926                                 if (streq(option + 1, "assembler")) {
1927                                         const char *opt;
1928                                         GET_ARG_AFTER(opt, "-Xassembler");
1929                                         add_flag(&asflags_obst, "-Xassembler");
1930                                         add_flag(&asflags_obst, opt);
1931                                 } else if (streq(option + 1, "preprocessor")) {
1932                                         const char *opt;
1933                                         GET_ARG_AFTER(opt, "-Xpreprocessor");
1934                                         add_flag(&cppflags_obst, "-Xpreprocessor");
1935                                         add_flag(&cppflags_obst, opt);
1936                                 } else if (streq(option + 1, "linker")) {
1937                                         const char *opt;
1938                                         GET_ARG_AFTER(opt, "-Xlinker");
1939                                         add_flag(&ldflags_obst, "-Xlinker");
1940                                         add_flag(&ldflags_obst, opt);
1941                                 }
1942                         } else if (streq(option, "pg")) {
1943                                 set_be_option("gprof");
1944                                 add_flag(&ldflags_obst, "-pg");
1945                         } else if (streq(option, "ansi")) {
1946                                 standard = STANDARD_ANSI;
1947                         } else if (streq(option, "pedantic")) {
1948                                 fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg);
1949                         } else if (strstart(option, "std=")) {
1950                                 const char *const o = &option[4];
1951                                 standard =
1952                                         streq(o, "c++")            ? STANDARD_CXX98   :
1953                                         streq(o, "c++98")          ? STANDARD_CXX98   :
1954                                         streq(o, "c11")            ? STANDARD_C11     :
1955                                         streq(o, "c1x")            ? STANDARD_C11     : // deprecated
1956                                         streq(o, "c89")            ? STANDARD_C89     :
1957                                         streq(o, "c90")            ? STANDARD_C89     :
1958                                         streq(o, "c99")            ? STANDARD_C99     :
1959                                         streq(o, "c9x")            ? STANDARD_C99     : // deprecated
1960                                         streq(o, "gnu++98")        ? STANDARD_GNUXX98 :
1961                                         streq(o, "gnu11")          ? STANDARD_GNU11   :
1962                                         streq(o, "gnu1x")          ? STANDARD_GNU11   : // deprecated
1963                                         streq(o, "gnu89")          ? STANDARD_GNU89   :
1964                                         streq(o, "gnu99")          ? STANDARD_GNU99   :
1965                                         streq(o, "gnu9x")          ? STANDARD_GNU99   : // deprecated
1966                                         streq(o, "iso9899:1990")   ? STANDARD_C89     :
1967                                         streq(o, "iso9899:199409") ? STANDARD_C89AMD1 :
1968                                         streq(o, "iso9899:1999")   ? STANDARD_C99     :
1969                                         streq(o, "iso9899:199x")   ? STANDARD_C99     : // deprecated
1970                                         streq(o, "iso9899:2011")   ? STANDARD_C11     :
1971                                         (fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg), standard);
1972                         } else if (streq(option, "version")) {
1973                                 print_cparser_version();
1974                                 return EXIT_SUCCESS;
1975                         } else if (streq(option, "dumpversion")) {
1976                                 /* gcc compatibility option */
1977                                 print_cparser_version_short();
1978                                 return EXIT_SUCCESS;
1979                         } else if (strstart(option, "print-file-name=")) {
1980                                 GET_ARG_AFTER(print_file_name_file, "-print-file-name=");
1981                         } else if (option[0] == '-') {
1982                                 /* double dash option */
1983                                 ++option;
1984                                 if (streq(option, "gcc")) {
1985                                         features_on  |=  _GNUC;
1986                                         features_off &= ~_GNUC;
1987                                 } else if (streq(option, "no-gcc")) {
1988                                         features_on  &= ~_GNUC;
1989                                         features_off |=  _GNUC;
1990                                 } else if (streq(option, "ms")) {
1991                                         features_on  |=  _MS;
1992                                         features_off &= ~_MS;
1993                                 } else if (streq(option, "no-ms")) {
1994                                         features_on  &= ~_MS;
1995                                         features_off |=  _MS;
1996                                 } else if (streq(option, "strict")) {
1997                                         strict_mode = true;
1998                                 } else if (streq(option, "benchmark")) {
1999                                         mode = BenchmarkParser;
2000                                 } else if (streq(option, "print-ast")) {
2001                                         mode = PrintAst;
2002                                 } else if (streq(option, "print-implicit-cast")) {
2003                                         print_implicit_casts = true;
2004                                 } else if (streq(option, "print-parenthesis")) {
2005                                         print_parenthesis = true;
2006                                 } else if (streq(option, "print-fluffy")) {
2007                                         mode = PrintFluffy;
2008                                 } else if (streq(option, "print-compound-sizes")) {
2009                                         mode = PrintCompoundSizes;
2010                                 } else if (streq(option, "print-jna")) {
2011                                         mode = PrintJna;
2012                                 } else if (streq(option, "jna-limit")) {
2013                                         ++i;
2014                                         if (i >= argc) {
2015                                                 errorf(NULL, "expected argument after '--jna-limit'");
2016                                                 argument_errors = true;
2017                                                 break;
2018                                         }
2019                                         jna_limit_output(argv[i]);
2020                                 } else if (streq(option, "jna-libname")) {
2021                                         ++i;
2022                                         if (i >= argc) {
2023                                                 errorf(NULL, "expected argument after '--jna-libname'");
2024                                                 argument_errors = true;
2025                                                 break;
2026                                         }
2027                                         jna_set_libname(argv[i]);
2028                                 } else if (streq(option, "external-pp")) {
2029                                         if (i+1 < argc && argv[i+1][0] != '-') {
2030                                                 ++i;
2031                                                 external_preprocessor = argv[i+1];
2032                                         } else {
2033                                                 external_preprocessor = PREPROCESSOR;
2034                                         }
2035                                 } else if (streq(option, "no-external-pp")) {
2036                                         external_preprocessor = NULL;
2037                                 } else if (streq(option, "time")) {
2038                                         do_timing    = true;
2039                                         print_timing = true;
2040                                 } else if (streq(option, "statev")) {
2041                                         do_timing      = true;
2042                                         produce_statev = true;
2043                                 } else if (strstart(option, "filtev=")) {
2044                                         GET_ARG_AFTER(filtev, "--filtev=");
2045                                 } else if (streq(option, "version")) {
2046                                         print_cparser_version();
2047                                         return EXIT_SUCCESS;
2048                                 } else if (streq(option, "help")) {
2049                                         help |= HELP_BASIC;
2050                                 } else if (streq(option, "help-parser")) {
2051                                         help |= HELP_PARSER;
2052                                 } else if (streq(option, "help-warnings")) {
2053                                         help |= HELP_WARNINGS;
2054                                 } else if (streq(option, "help-codegen")) {
2055                                         help |= HELP_CODEGEN;
2056                                 } else if (streq(option, "help-linker")) {
2057                                         help |= HELP_LINKER;
2058                                 } else if (streq(option, "help-optimization")) {
2059                                         help |= HELP_OPTIMIZATION;
2060                                 } else if (streq(option, "help-language-tools")) {
2061                                         help |= HELP_LANGUAGETOOLS;
2062                                 } else if (streq(option, "help-debug")) {
2063                                         help |= HELP_DEBUG;
2064                                 } else if (streq(option, "help-firm")) {
2065                                         help |= HELP_FIRM;
2066                                 } else if (streq(option, "help-all")) {
2067                                         help |= HELP_ALL;
2068                                 } else if (streq(option, "dump-function")) {
2069                                         ++i;
2070                                         if (i >= argc) {
2071                                                 errorf(NULL, "expected argument after '--dump-function'");
2072                                                 argument_errors = true;
2073                                                 break;
2074                                         }
2075                                         dumpfunction = argv[i];
2076                                         mode         = CompileDump;
2077                                 } else if (streq(option, "export-ir")) {
2078                                         mode = CompileExportIR;
2079                                 } else if (streq(option, "unroll-loops")) {
2080                                         /* ignore (gcc compatibility) */
2081                                 } else {
2082                                         errorf(NULL, "unknown argument '%s'", arg);
2083                                         argument_errors = true;
2084                                 }
2085                         } else {
2086                                 errorf(NULL, "unknown argument '%s'", arg);
2087                                 argument_errors = true;
2088                         }
2089                 } else {
2090                         compilation_unit_type_t type = forced_unittype;
2091                         if (type == COMPILATION_UNIT_AUTODETECT) {
2092                                 if (streq(arg, "-")) {
2093                                         /* - implicitly means C source file */
2094                                         type = COMPILATION_UNIT_C;
2095                                 } else {
2096                                         const char *suffix = strrchr(arg, '.');
2097                                         /* Ensure there is at least one char before the suffix */
2098                                         if (suffix != NULL && suffix != arg) {
2099                                                 ++suffix;
2100                                                 type =
2101                                                         streq(suffix, "S")   ? COMPILATION_UNIT_ASSEMBLER              :
2102                                                         streq(suffix, "a")   ? COMPILATION_UNIT_OBJECT                 :
2103                                                         streq(suffix, "c")   ? COMPILATION_UNIT_C                      :
2104                                                         streq(suffix, "i")   ? COMPILATION_UNIT_PREPROCESSED_C         :
2105                                                         streq(suffix, "C")   ? COMPILATION_UNIT_CXX                    :
2106                                                         streq(suffix, "cc")  ? COMPILATION_UNIT_CXX                    :
2107                                                         streq(suffix, "cp")  ? COMPILATION_UNIT_CXX                    :
2108                                                         streq(suffix, "cpp") ? COMPILATION_UNIT_CXX                    :
2109                                                         streq(suffix, "CPP") ? COMPILATION_UNIT_CXX                    :
2110                                                         streq(suffix, "cxx") ? COMPILATION_UNIT_CXX                    :
2111                                                         streq(suffix, "c++") ? COMPILATION_UNIT_CXX                    :
2112                                                         streq(suffix, "ii")  ? COMPILATION_UNIT_PREPROCESSED_CXX       :
2113                                                         streq(suffix, "h")   ? COMPILATION_UNIT_C                      :
2114                                                         streq(suffix, "ir")  ? COMPILATION_UNIT_IR                     :
2115                                                         streq(suffix, "o")   ? COMPILATION_UNIT_OBJECT                 :
2116                                                         streq(suffix, "s")   ? COMPILATION_UNIT_PREPROCESSED_ASSEMBLER :
2117                                                         streq(suffix, "so")  ? COMPILATION_UNIT_OBJECT                 :
2118                                                         COMPILATION_UNIT_OBJECT; /* gcc behavior: unknown file extension means object file */
2119                                         }
2120                                 }
2121                         }
2122
2123                         compilation_unit_t *entry = OALLOCZ(&file_obst, compilation_unit_t);
2124                         entry->name = arg;
2125                         entry->type = type;
2126
2127                         if (last_unit != NULL) {
2128                                 last_unit->next = entry;
2129                         } else {
2130                                 units = entry;
2131                         }
2132                         last_unit = entry;
2133                 }
2134         }
2135
2136         if (help != HELP_NONE) {
2137                 print_help(argv[0], help);
2138                 return !argument_errors;
2139         }
2140
2141         if (print_file_name_file != NULL) {
2142                 print_file_name(print_file_name_file);
2143                 return EXIT_SUCCESS;
2144         }
2145         if (units == NULL) {
2146                 errorf(NULL, "no input files specified");
2147                 argument_errors = true;
2148         }
2149
2150         if (argument_errors) {
2151                 usage(argv[0]);
2152                 return EXIT_FAILURE;
2153         }
2154
2155         /* apply some effects from switches */
2156         c_mode |= features_on;
2157         c_mode &= ~features_off;
2158         if (profile_generate) {
2159                 add_flag(&ldflags_obst, "-lfirmprof");
2160                 set_be_option("profilegenerate");
2161         }
2162         if (profile_use) {
2163                 set_be_option("profileuse");
2164         }
2165
2166         init_symbol_table();
2167         init_types_and_adjust();
2168         init_typehash();
2169         init_basic_types();
2170         if (c_mode & _CXX) {
2171                 init_wchar_types(ATOMIC_TYPE_WCHAR_T);
2172         } else {
2173                 init_wchar_types(wchar_atomic_kind);
2174         }
2175         init_preprocessor();
2176         init_ast();
2177         init_parser();
2178         init_ast2firm();
2179         init_mangle();
2180
2181         if (do_timing)
2182                 timer_init();
2183
2184         char outnamebuf[4096];
2185         if (outname == NULL) {
2186                 const char *filename = units->name;
2187
2188                 switch (mode) {
2189                 case BenchmarkParser:
2190                 case PrintAst:
2191                 case PrintFluffy:
2192                 case PrintJna:
2193                 case PrintCompoundSizes:
2194                 case PreprocessOnly:
2195                 case ParseOnly:
2196                         outname = "-";
2197                         break;
2198                 case Compile:
2199                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".s");
2200                         outname = outnamebuf;
2201                         break;
2202                 case CompileAssemble:
2203                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".o");
2204                         outname = outnamebuf;
2205                         break;
2206                 case CompileDump:
2207                         get_output_name(outnamebuf, sizeof(outnamebuf), dumpfunction,
2208                                         ".vcg");
2209                         outname = outnamebuf;
2210                         break;
2211                 case CompileExportIR:
2212                         get_output_name(outnamebuf, sizeof(outnamebuf), filename, ".ir");
2213                         outname = outnamebuf;
2214                         break;
2215                 case CompileAssembleLink:
2216                         if (firm_is_windows_os(target_machine)) {
2217                                 outname = "a.exe";
2218                         } else {
2219                                 outname = "a.out";
2220                         }
2221                         break;
2222                 }
2223         }
2224
2225         assert(outname != NULL);
2226
2227         FILE *out;
2228         if (streq(outname, "-")) {
2229                 out = stdout;
2230         } else {
2231                 out = fopen(outname, "w");
2232                 if (out == NULL) {
2233                         position_t const pos = { outname, 0, 0, 0 };
2234                         errorf(&pos, "could not open for writing: %s", strerror(errno));
2235                         return EXIT_FAILURE;
2236                 }
2237         }
2238
2239         if (produce_statev && units != NULL) {
2240                 /* attempt to guess a good name for the file */
2241                 const char *first_cup = units->name;
2242                 if (first_cup != NULL) {
2243                         const char *dot = strrchr(first_cup, '.');
2244                         const char *pos = dot ? dot : first_cup + strlen(first_cup);
2245                         char        buf[pos-first_cup+1];
2246                         strncpy(buf, first_cup, pos-first_cup);
2247                         buf[pos-first_cup] = '\0';
2248
2249                         stat_ev_begin(buf, filtev);
2250                 }
2251         }
2252
2253         int result = compilation_loop(mode, units, standard, out);
2254         if (stat_ev_enabled) {
2255                 stat_ev_end();
2256         }
2257
2258         if (result != EXIT_SUCCESS) {
2259                 if (out != stdout)
2260                         unlink(outname);
2261                 return result;
2262         }
2263
2264         /* link program file */
2265         if (mode == CompileAssembleLink) {
2266                 int const link_result = link_program(units);
2267                 if (link_result != EXIT_SUCCESS) {
2268                         if (out != stdout)
2269                                 unlink(outname);
2270                         return link_result;
2271                 }
2272         }
2273
2274         if (do_timing)
2275                 timer_term(print_timing ? stderr : NULL);
2276
2277         free_temp_files();
2278         obstack_free(&cppflags_obst, NULL);
2279         obstack_free(&ldflags_obst, NULL);
2280         obstack_free(&asflags_obst, NULL);
2281         obstack_free(&file_obst, NULL);
2282
2283         gen_firm_finish();
2284         exit_mangle();
2285         exit_ast2firm();
2286         exit_parser();
2287         exit_ast();
2288         exit_preprocessor();
2289         exit_typehash();
2290         exit_types();
2291         exit_tokens();
2292         exit_symbol_table();
2293         return EXIT_SUCCESS;
2294 }