17 #include <libfirm/firm.h>
18 #include <libfirm/be.h>
22 #include "type_hash.h"
25 #include "driver/firm_cmdline.h"
26 #include "adt/error.h"
27 #include "write_fluffy.h"
28 #include "driver/firm_opt.h"
31 #define PREPROCESSOR "cpp -std=c99 -U__WCHAR_TYPE__ -D__WCHAR_TYPE__=int"
39 #define ASSEMBLER "as"
43 /* remap some names */
44 #define popen(cmd, mode) _popen(cmd, mode)
45 #define pclose(file) _pclose(file)
51 static void initialize_firm(void)
56 dump_keepalive_edges(1);
59 static void dump(ir_graph *irg, const char *suffix)
62 dump_ir_block_graph(irg, suffix);
66 static void get_output_name(char *buf, size_t buflen, const char *inputname,
69 size_t last_dot = 0xffffffff;
72 if(inputname == NULL) {
73 snprintf(buf, buflen, "a%s", newext);
77 for(const char *c = inputname; *c != 0; ++c) {
82 if(last_dot == 0xffffffff)
85 if(last_dot >= buflen)
86 panic("filename too long");
87 memcpy(buf, inputname, last_dot);
89 size_t extlen = strlen(newext) + 1;
90 if(extlen + last_dot >= buflen)
91 panic("filename too long");
92 memcpy(buf+last_dot, newext, extlen);
95 static translation_unit_t *do_parsing(FILE *const in, const char *const input)
97 lexer_open_stream(in, input);
98 translation_unit_t *unit = parse();
102 static void lextest(FILE *in, const char *fname)
104 lexer_open_stream(in, fname);
107 lexer_next_preprocessing_token();
108 print_token(stdout, &lexer_token);
110 } while(lexer_token.type != T_EOF);
113 static FILE* preprocess(FILE* in, const char *fname)
118 snprintf(buf, sizeof(buf), PREPROCESSOR " %s", fname);
120 /* read from stdin */
121 snprintf(buf, sizeof(buf), PREPROCESSOR " -");
127 FILE* f = popen(buf, "r");
129 fprintf(stderr, "invoking preprocessor failed\n");
135 static void do_link(const char *out, const char *in)
139 snprintf(buf, sizeof(buf), "%s %s -o %s", LINKER, in, out);
143 int err = system(buf);
145 fprintf(stderr, "linker reported an error\n");
150 static void assemble(const char *out, const char *in)
154 snprintf(buf, sizeof(buf), "%s %s -o %s", ASSEMBLER, in, out);
159 int err = system(buf);
161 fprintf(stderr, "assembler reported an error\n");
166 static const char *try_dir(const char *dir)
170 if(access(dir, R_OK | W_OK | X_OK) == 0)
175 static const char *get_tempdir(void)
177 static const char *tmpdir = NULL;
183 tmpdir = try_dir(getenv("TMPDIR"));
185 tmpdir = try_dir(getenv("TMP"));
187 tmpdir = try_dir(getenv("TEMP"));
191 tmpdir = try_dir(P_tmpdir);
195 tmpdir = try_dir("/var/tmp");
197 tmpdir = try_dir("/usr/tmp");
199 tmpdir = try_dir("/tmp");
208 * an own version of tmpnam, which: writes in a buffer, appends a user specified
209 * suffix, emits no warnings during linking (like glibc/gnu ld do for tmpnam)...
211 static FILE *make_temp_file(char *buffer, size_t buflen,
212 const char *prefix, const char *suffix)
214 const char *tempdir = get_tempdir();
216 /* oh well... mkstemp doesn't accept a suffix after XXXXXX... */
220 snprintf(buffer, buflen, "%s/%sXXXXXX%s", tempdir, prefix, suffix);
222 int fd = mkstemp(buffer);
224 fprintf(stderr, "couldn't create temporary file: %s\n",
228 FILE *out = fdopen(fd, "w");
230 fprintf(stderr, "couldn't create temporary file FILE*\n");
238 * Do the necessary lowering for compound parameters.
240 void lower_compound_params(void)
242 lower_params_t params;
244 params.def_ptr_alignment = 4;
245 params.flags = LF_COMPOUND_RETURN | LF_RETURN_HIDDEN;
246 params.hidden_params = ADD_HIDDEN_ALWAYS_IN_FRONT;
247 params.find_pointer_type = NULL;
248 params.ret_compound_in_regs = NULL;
249 lower_calls_with_compounds(¶ms);
252 static void create_firm_prog(translation_unit_t *unit)
254 translation_unit_to_firm(unit);
256 //dump_globals_as_text(dump_verbosity_max, "-globals");
258 int n_irgs = get_irp_n_irgs();
259 for(int i = 0; i < n_irgs; ++i) {
260 ir_graph *const irg = get_irp_irg(i);
264 lower_compound_params();
267 for(int i = 0; i < n_irgs; ++i) {
268 ir_graph *const irg = get_irp_irg(i);
273 typedef enum compile_mode_t {
283 static void usage(const char *argv0)
285 fprintf(stderr, "Usage %s input [-o output] [-c]\n", argv0);
288 int main(int argc, char **argv)
301 const char *input = NULL;
302 const char *outname = NULL;
303 const char *dumpfunction = NULL;
304 compile_mode_t mode = CompileAssembleLink;
306 for(int i = 1; i < argc; ++i) {
307 const char *arg = argv[i];
308 if(strncmp(arg, "-o", 2) == 0) {
310 if(outname[0] == '\0') {
318 } else if(strcmp(arg, "-c") == 0) {
319 mode = CompileAssemble;
320 } else if(strcmp(arg, "-S") == 0) {
322 } else if(strcmp(arg, "--lextest") == 0) {
324 } else if(strcmp(arg, "--print-ast") == 0) {
326 } else if(strcmp(arg, "--print-fluffy") == 0) {
328 } else if(strcmp(arg, "--dump") == 0) {
330 } else if(strcmp(arg, "--dump-function") == 0) {
336 dumpfunction = argv[i];
338 } else if(strcmp(arg, "-v") == 0) {
340 } else if(arg[0] == '-' && arg[1] == 'f') {
341 const char *opt = &arg[2];
354 int res = firm_option(opt);
356 fprintf(stderr, "Error: unknown Firm option %s\n", opt);
359 } else if (res == -1) { /* help option */
362 } else if(arg[0] == '-' && arg[1] == 'b') {
363 const char *opt = &arg[2];
376 int res = firm_be_option(opt);
378 fprintf(stderr, "Error: unknown Firm backend option %s\n", opt);
381 } else if (res == -1) { /* help option */
384 } else if(arg[0] == '-') {
385 if (arg[1] == '\0') {
387 } else if (arg[1] == 'D' ||
392 strncmp(arg + 1, "std=", 4) == 0) {
393 fprintf(stderr, "Warning: Ignoring option '%s'\n", arg);
400 fprintf(stderr, "Error: multiple input files specified\n");
410 char outnamebuf[4096];
411 if(outname == NULL) {
418 get_output_name(outnamebuf, sizeof(outnamebuf), input, ".s");
419 outname = outnamebuf;
421 case CompileAssemble:
422 get_output_name(outnamebuf, sizeof(outnamebuf), input, ".o");
423 outname = outnamebuf;
426 get_output_name(outnamebuf, sizeof(outnamebuf), dumpfunction,
428 outname = outnamebuf;
430 case CompileAssembleLink:
434 assert(outname != NULL);
437 if(strcmp(outname, "-") == 0) {
440 out = fopen(outname, "w");
442 fprintf(stderr, "Couldn't open '%s' for writing: %s\n", outname,
450 fprintf(stderr, "%s: no input files\n", argv[0]);
452 } else if(strcmp(input, "-") == 0) {
456 in = fopen(input, "r");
458 fprintf(stderr, "Couldn't open '%s': %s\n", input, strerror(errno));
463 if(mode == LexTest) {
469 FILE *preprocessed_in = preprocess(in, input);
470 translation_unit_t *const unit = do_parsing(preprocessed_in, input);
471 pclose(preprocessed_in);
475 if(mode == PrintAst) {
480 if(mode == PrintFluffy) {
481 write_fluffy_decls(out, unit);
485 create_firm_prog(unit);
488 char asm_tempfile[1024];
489 if(mode == CompileDump) {
491 firm_be_opt.selection = BE_NONE;
492 } else if(mode == Compile) {
496 = make_temp_file(asm_tempfile, sizeof(asm_tempfile), "cc", ".s");
498 gen_firm_finish(asm_out, input, /*c_mode=*/1, /*firm_const_exists=*/0);
500 if(mode == CompileDump) {
502 ident *id = new_id_from_str(dumpfunction);
503 ir_graph *irg = NULL;
504 int n_irgs = get_irp_n_irgs();
505 for(int i = 0; i < n_irgs; ++i) {
506 ir_graph *tirg = get_irp_irg(i);
507 ident *irg_id = get_entity_ident(get_irg_entity(tirg));
515 fprintf(stderr, "No graph for function '%s' found\n", dumpfunction);
519 dump_ir_block_graph_file(irg, out);
526 /* assemble assembler and create object file */
527 char obj_tfile[1024];
528 if(mode == CompileAssemble || mode == CompileAssembleLink) {
529 const char *obj_outfile;
530 if(mode == CompileAssemble) {
532 obj_outfile = outname;
535 = make_temp_file(obj_tfile, sizeof(obj_tfile), "cc", ".o");
537 obj_outfile = obj_tfile;
540 assemble(obj_outfile, asm_tempfile);
543 /* link object file */
544 if(mode == CompileAssembleLink) {
545 do_link(outname, obj_tfile);