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