#include "diagnostic.h"
#include "lang_features.h"
#include "driver/firm_opt.h"
-#include "driver/firm_cmdline.h"
#include "driver/firm_timing.h"
+#include "driver/firm_machine.h"
#include "adt/error.h"
+#include "adt/strutil.h"
#include "wrappergen/write_fluffy.h"
-#include "wrappergen/write_caml.h"
#include "wrappergen/write_jna.h"
#include "revision.h"
#include "warning.h"
+#include "help.h"
#include "mangle.h"
#include "printer.h"
#ifndef PREPROCESSOR
#ifndef __WIN32__
-#define PREPROCESSOR "gcc -E -m32 -U__STRICT_ANSI__"
+#define PREPROCESSOR "gcc -E -U__STRICT_ANSI__"
#else
-#define PREPROCESSOR "cpp -m32 -U__STRICT_ANSI__"
+#define PREPROCESSOR "cpp -U__STRICT_ANSI__"
#endif
#endif
#ifndef LINKER
-#define LINKER "gcc -m32"
+#define LINKER "gcc"
#endif
#ifndef ASSEMBLER
-#ifdef __APPLE__
-#define ASSEMBLER "gcc -m32 -c -xassembler"
-#else
-#define ASSEMBLER "as --32"
-#endif
+#define ASSEMBLER "gcc -c -xassembler"
#endif
-unsigned int c_mode = _C89 | _ANSI | _C99 | _GNUC;
-unsigned int machine_size = 32;
-bool byte_order_big_endian = false;
-bool char_is_signed = true;
-bool strict_mode = false;
-bool use_builtins = false;
-bool have_const_functions = false;
-atomic_type_kind_t wchar_atomic_kind = ATOMIC_TYPE_INT;
-unsigned force_long_double_size = 0;
-bool enable_main_collect2_hack = false;
-bool freestanding = false;
-
-/* to switch on printing of implicit casts */
-extern bool print_implicit_casts;
-
-/* to switch on printing of parenthesis to indicate operator precedence */
-extern bool print_parenthesis;
-
-static const char *target_triple;
-static int verbose;
-static struct obstack cppflags_obst, ldflags_obst;
-static char dep_target[1024];
-static const char *outname;
+unsigned int c_mode = _C89 | _ANSI | _C99 | _GNUC;
+bool byte_order_big_endian = false;
+bool strict_mode = false;
+bool enable_main_collect2_hack = false;
+bool freestanding = false;
+unsigned architecture_modulo_shift = 0;
+
+static bool char_is_signed = true;
+static atomic_type_kind_t wchar_atomic_kind = ATOMIC_TYPE_INT;
+
+static machine_triple_t *target_machine;
+static const char *target_triple;
+static int verbose;
+static struct obstack cppflags_obst;
+static struct obstack ldflags_obst;
+static struct obstack asflags_obst;
+static char dep_target[1024];
+static const char *outname;
+static bool define_intmax_types;
+static const char *input_encoding;
typedef enum lang_standard_t {
STANDARD_DEFAULT, /* gnu99 (for C, GCC does gnu89) or gnu++98 (for C++) */
static file_list_entry_t *temp_files;
-static void initialize_firm(void)
-{
- firm_early_init();
-}
-
static void get_output_name(char *buf, size_t buflen, const char *inputname,
const char *newext)
{
panic("filename too long");
}
-#include "gen_builtins.h"
-
static translation_unit_t *do_parsing(FILE *const in, const char *const input_name)
{
start_parsing();
- if (use_builtins) {
- lexer_open_buffer(builtins, sizeof(builtins)-1, "<builtin>");
- parse();
- }
-
- lexer_open_stream(in, input_name);
+ input_t *input = input_from_stream(in, input_encoding);
+ lexer_switch_input(input, input_name);
parse();
-
translation_unit_t *unit = finish_parsing();
+ input_free(input);
+
return unit;
}
static void lextest(FILE *in, const char *fname)
{
- lexer_open_stream(in, fname);
+ input_t *input = input_from_stream(in, input_encoding);
+ lexer_switch_input(input, fname);
do {
lexer_next_preprocessing_token();
print_token(stdout, &lexer_token);
putchar('\n');
- } while (lexer_token.type != T_EOF);
+ } while (lexer_token.kind != T_EOF);
+ input_free(input);
}
static void add_flag(struct obstack *obst, const char *format, ...)
add_flag(&cppflags_obst, "-U__VERSION__");
add_flag(&cppflags_obst, "-D__VERSION__=\"%s\"", cparser_REVISION);
+ if (define_intmax_types) {
+ add_flag(&cppflags_obst, "-U__INTMAX_TYPE__");
+ add_flag(&cppflags_obst, "-D__INTMAX_TYPE__=%s", type_to_string(type_intmax_t));
+ add_flag(&cppflags_obst, "-U__UINTMAX_TYPE__");
+ add_flag(&cppflags_obst, "-D__UINTMAX_TYPE__=%s", type_to_string(type_uintmax_t));
+ }
+
if (flags[0] != '\0') {
size_t len = strlen(flags);
obstack_1grow(&cppflags_obst, ' ');
}
}
add_flag(&cppflags_obst, fname);
-
obstack_1grow(&cppflags_obst, '\0');
- char *buf = obstack_finish(&cppflags_obst);
+
+ char *commandline = obstack_finish(&cppflags_obst);
if (verbose) {
- puts(buf);
+ puts(commandline);
}
-
- FILE *f = popen(buf, "r");
+ FILE *f = popen(commandline, "r");
if (f == NULL) {
fprintf(stderr, "invoking preprocessor failed\n");
exit(EXIT_FAILURE);
}
-
- /* we don't really need that anymore */
- obstack_free(&cppflags_obst, buf);
+ /* we do not really need that anymore */
+ obstack_free(&cppflags_obst, commandline);
return f;
}
static void assemble(const char *out, const char *in)
{
- struct obstack asflags_obst;
- char *buf;
-
- obstack_init(&asflags_obst);
+ obstack_1grow(&asflags_obst, '\0');
+ const char *flags = obstack_finish(&asflags_obst);
const char *assembler = getenv("CPARSER_AS");
if (assembler != NULL) {
- obstack_printf(&asflags_obst, "%s ", assembler);
+ obstack_printf(&asflags_obst, "%s", assembler);
} else {
if (target_triple != NULL)
obstack_printf(&asflags_obst, "%s-", target_triple);
- obstack_printf(&asflags_obst, "%s ", ASSEMBLER);
+ obstack_printf(&asflags_obst, "%s", ASSEMBLER);
}
+ if (flags[0] != '\0')
+ obstack_printf(&asflags_obst, " %s", flags);
- obstack_printf(&asflags_obst, "%s -o %s", in, out);
+ obstack_printf(&asflags_obst, " %s -o %s", in, out);
obstack_1grow(&asflags_obst, '\0');
- buf = obstack_finish(&asflags_obst);
+ char *commandline = obstack_finish(&asflags_obst);
if (verbose) {
- puts(buf);
+ puts(commandline);
}
-
- int err = system(buf);
- if (err != 0) {
+ int err = system(commandline);
+ if (err != EXIT_SUCCESS) {
fprintf(stderr, "assembler reported an error\n");
exit(EXIT_FAILURE);
}
-
- obstack_free(&asflags_obst, NULL);
+ obstack_free(&asflags_obst, commandline);
}
static void print_file_name(const char *file)
obstack_1grow(&ldflags_obst, '\0');
char *commandline = obstack_finish(&ldflags_obst);
-
if (verbose) {
puts(commandline);
}
fprintf(stderr, "linker reported an error\n");
exit(EXIT_FAILURE);
}
+ obstack_free(&ldflags_obst, commandline);
}
static const char *try_dir(const char *dir)
int fd = mkstemp(buffer);
if (fd == -1) {
- fprintf(stderr, "couldn't create temporary file: %s\n",
+ fprintf(stderr, "could not create temporary file: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
FILE *out = fdopen(fd, "w");
if (out == NULL) {
- fprintf(stderr, "couldn't create temporary file FILE*\n");
+ fprintf(stderr, "could not create temporary file FILE*\n");
exit(EXIT_FAILURE);
}
LexTest,
PrintAst,
PrintFluffy,
- PrintCaml,
PrintJna
} compile_mode_t;
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
}
-static void print_help(const char *argv0)
+static void print_help_basic(const char *argv0)
{
usage(argv0);
puts("");
- puts("\t-fhelp Display help about firm optimisation options");
- puts("\t-bhelp Display help about firm backend options");
- puts("A big number of gcc flags is also supported");
+ put_help("--help", "Display this information");
+ put_help("--version", "Display compiler version");
+ put_help("--help-parser", "Display information about parser options");
+ put_help("--help-warnings", "Display information about warning options");
+ put_help("--help-codegen", "Display information about code-generation options");
+ put_help("--help-optimization", "Display information about optimization options");
+ put_help("--help-linker", "Display information about linker options");
+ put_help("--help-language-tools", "Display information about language tools options");
+ put_help("--help-debug", "Display information about compiler debugging options");
+ put_help("--help-firm", "Display information about direct firm options");
+ put_help("--help-all", "Display information about all options");
+ put_help("-c", "Compile and assemble but do not link");
+ put_help("-E", "Preprocess only");
+ put_help("-S", "Compile but do not assembler or link");
+ put_help("-o", "Specify output file");
+ put_help("-v", "Verbose output (show invocation of sub-processes)");
+ put_help("-x", "Force input language:");
+ put_choice("c", "C");
+ put_choice("c++", "C++");
+ put_choice("assembler", "Assembler (no preprocessing)");
+ put_choice("assembler-with-cpp", "Assembler with preprocessing");
+ put_choice("none", "Autodetection");
+ put_help("-pipe", "Ignored (gcc compatibility)");
}
-static void set_be_option(const char *arg)
+static void print_help_preprocessor(void)
{
- int res = be_parse_arg(arg);
+ put_help("-nostdinc", "Do not search standard system include directories");
+ put_help("-trigraphs", "Support ISO C trigraphs");
+ put_help("-isystem", "");
+ put_help("-include", "");
+ put_help("-I PATH", "");
+ put_help("-D SYMBOL[=value]", "");
+ put_help("-U SYMBOL", "");
+ put_help("-Wp,OPTION", "Pass option directly to preprocessor");
+ put_help("-M", "");
+ put_help("-MD", "");
+ put_help("-MMD", "");
+ put_help("-MM", "");
+ put_help("-MP", "");
+ put_help("-MT", "");
+ put_help("-MQ", "");
+ put_help("-MF", "");
+}
+
+static void print_help_parser(void)
+{
+ put_help("-finput-charset=CHARSET", "Select encoding of input files");
+ put_help("-fmessage-length=LEN", "Ignored (gcc compatibility)");
+ put_help("-fshort-wchar", "Type \"wchar_t\" is unsigned short instead of int");
+ put_help("-fshow-column", "Show the column number in diagnostic messages");
+ put_help("-fsigned-char", "Type \"char\" is a signed type");
+ put_help("-funsigned-char", "Type \"char\" is an unsigned type");
+ put_help("--ms", "Enable msvc extensions");
+ put_help("--no-ms", "Disable msvc extensions");
+ put_help("--gcc", "Enable gcc extensions");
+ put_help("--no-gcc", "Disable gcc extensions");
+ put_help("-std=STANDARD", "Specify language standard:");
+ put_choice("c99", "ISO C99 standard");
+ put_choice("c89", "ISO C89 standard");
+ put_choice("c9x", "Deprecated");
+ put_choice("c++", "ISO C++ 98");
+ put_choice("c++98", "ISO C++ 98");
+ put_choice("gnu99", "ISO C99 + GNU extensions (default)");
+ put_choice("gnu89", "ISO C89 + GNU extensions");
+ put_choice("gnu9x", "Deprecated");
+ put_choice("iso9899:1990", "ISO C89");
+ put_choice("iso9899:199409", "ISO C90");
+ put_choice("iso9899:1999", "ISO C99");
+ put_choice("iso9899:199x", "Deprecated");
+ put_help("-pedantic", "Ignored (gcc compatibility)");
+ put_help("-ansi", "Ignored (gcc compatibility)");
+ put_help("--strict", "Enable strict conformance checking");
+}
+
+static void print_help_warnings(void)
+{
+ put_help("-f[no-]diagnostics-show-option", "Show the switch, which controls a warning, after each warning");
+ put_help("-w", "Disable all warnings");
+ put_help("-Wno-trigraphs", "Warn if input contains trigraphs");
+ put_help("-Wundef", "Warn if an undefined macro is used in an #if");
+ put_help("-Wmissing-include-dirs", "Warn about missing user-specified include directories");
+ put_help("-Wendif-labels", "Warn about stray text after #elif and #endif");
+ put_help("-Winit-self", "Ignored (gcc compatibility)");
+ put_help("-Wformat-y2k", "Ignored (gcc compatibility)");
+ put_help("-Wformat-security", "Ignored (gcc compatibility)");
+ put_help("-Wold-style-declaration", "Ignored (gcc compatibility)");
+ put_help("-Wtype-limits", "Ignored (gcc compatibility)");
+ print_warning_opt_help();
+}
+
+static void print_help_optimization(void)
+{
+ put_help("-O LEVEL", "Select optimization level (0-4)");
+ firm_option_help(put_help);
+ put_help("-fexpensive-optimizations","Ignored (gcc compatibility)");
+}
+
+static void print_help_codegeneration(void)
+{
+ put_help("-g", "Generate debug information");
+ put_help("-pg", "Instrument code for gnu gprof");
+ put_help("-fomit-frame-pointer", "Produce code without frame pointer where possible");
+ put_help("-ffreestanding", "Compile in freestanding mode (see ISO C standard)");
+ put_help("-fhosted", "Compile in hosted (not freestanding) mode");
+ put_help("-fprofile-generate", "Generate instrumented code to collect profile information");
+ put_help("-fprofile-use", "Use profile information generated by instrumented binaries");
+ put_help("-ffp-precise", "Precise floating point model");
+ put_help("-ffp-fast", "Imprecise floating point model");
+ put_help("-ffp-strict", "Strict floating point model");
+ put_help("-pthread", "Use pthread threading library");
+ put_help("-mtarget=TARGET", "Specify target architecture as CPU-manufacturer-OS triple");
+ put_help("-mtriple=TARGET", "Alias for -mtarget (clang compatibility)");
+ put_help("-march=ARCH", "");
+ put_help("-mtune=ARCH", "");
+ put_help("-mcpu=CPU", "");
+ put_help("-mfpmath=", "");
+ put_help("-mpreferred-stack-boundary=", "");
+ put_help("-mrtd", "");
+ put_help("-mregparm=", "Not supported yet");
+ put_help("-msoft-float", "Not supported yet");
+ put_help("-m32", "Generate 32bit code");
+ put_help("-m64", "Generate 64bit code");
+ put_help("-fverbose-asm", "Ignored (gcc compatibility)");
+ put_help("-fjump-tables", "Ignored (gcc compatibility)");
+ put_help("-fcommon", "Ignored (gcc compatibility)");
+ put_help("-foptimize-sibling-calls", "Ignored (gcc compatibility)");
+ put_help("-falign-loops", "Ignored (gcc compatibility)");
+ put_help("-falign-jumps", "Ignored (gcc compatibility)");
+ put_help("-falign-functions", "Ignored (gcc compatibility)");
+ put_help("-fPIC", "Ignored (gcc compatibility)");
+ put_help("-ffast-math", "Same as -ffp-fast (gcc compatibility)");
+ puts("");
+ puts("\tMost of these options can be used with a no- prefix to disable them");
+ puts("\te.g. -fno-omit-frame-pointer");
+}
+
+static void print_help_linker(void)
+{
+ put_help("-l LIBRARY", "");
+ put_help("-L PATH", "");
+ put_help("-shared", "Produce a shared library");
+ put_help("-static", "Produce statically linked binary");
+ put_help("-Wl,OPTION", "Pass option directly to linker");
+}
+
+static void print_help_debug(void)
+{
+ put_help("--lextest", "Preprocess and tokenize only");
+ put_help("--print-ast", "Preprocess, parse and print AST");
+ put_help("--print-implicit-cast", "");
+ put_help("--print-parenthesis", "");
+ put_help("--benchmark", "Preprocess and parse, produces no output");
+ put_help("--time", "Measure time of compiler passes");
+ put_help("--dump-function func", "Preprocess, parse and output vcg graph of func");
+ put_help("--export-ir", "Preprocess, parse and output compiler intermediate representation");
+}
+
+static void print_help_language_tools(void)
+{
+ put_help("--print-fluffy", "Preprocess, parse and generate declarations for the fluffy language");
+ put_help("--print-jna", "Preprocess, parse and generate declarations for JNA");
+ put_help("--jna-limit filename", "");
+ put_help("--jna-libname name", "");
+}
+
+static void print_help_firm(void)
+{
+ put_help("-bOPTION", "Directly pass option to libFirm backend");
+ int res = be_parse_arg("help");
(void) res;
assert(res);
}
-static void set_option(const char *arg)
+typedef enum {
+ HELP_NONE = 0,
+ HELP_BASIC = 1u << 0,
+ HELP_PREPROCESSOR = 1u << 1,
+ HELP_PARSER = 1u << 2,
+ HELP_WARNINGS = 1u << 3,
+ HELP_OPTIMIZATION = 1u << 4,
+ HELP_CODEGEN = 1u << 5,
+ HELP_LINKER = 1u << 6,
+ HELP_LANGUAGETOOLS = 1u << 7,
+ HELP_DEBUG = 1u << 8,
+ HELP_FIRM = 1u << 9,
+
+ HELP_ALL = (unsigned)-1
+} help_sections_t;
+
+static void print_help(const char *argv0, help_sections_t sections)
+{
+ if (sections & HELP_BASIC) print_help_basic(argv0);
+ if (sections & HELP_PREPROCESSOR) print_help_preprocessor();
+ if (sections & HELP_PARSER) print_help_parser();
+ if (sections & HELP_WARNINGS) print_help_warnings();
+ if (sections & HELP_OPTIMIZATION) print_help_optimization();
+ if (sections & HELP_CODEGEN) print_help_codegeneration();
+ if (sections & HELP_LINKER) print_help_linker();
+ if (sections & HELP_LANGUAGETOOLS) print_help_language_tools();
+ if (sections & HELP_DEBUG) print_help_debug();
+ if (sections & HELP_FIRM) print_help_firm();
+}
+
+static void set_be_option(const char *arg)
{
- int res = firm_option(arg);
+ int res = be_parse_arg(arg);
(void) res;
assert(res);
}
while (!feof(input) && !ferror(dest)) {
size_t read = fread(buf, 1, sizeof(buf), input);
if (fwrite(buf, 1, read, dest) != read) {
- perror("couldn't write output");
+ perror("could not write output");
}
}
}
-static inline bool streq(char const* a, char const* b)
-{
- return strcmp(a, b) == 0;
-}
-
-static inline bool strstart(char const* str, char const* start)
-{
- do {
- if (*start == '\0')
- return true;
- } while (*str++ == *start++);
- return false;
-}
-
static FILE *open_file(const char *filename)
{
if (streq(filename, "-")) {
FILE *in = fopen(filename, "r");
if (in == NULL) {
- fprintf(stderr, "Couldn't open '%s': %s\n", filename,
+ fprintf(stderr, "Could not open '%s': %s\n", filename,
strerror(errno));
exit(EXIT_FAILURE);
}
return FILETYPE_UNKNOWN;
}
-/**
- * Initialize firm codegeneration for a specific operating system.
- * The argument is the operating system part of a target-triple */
-static bool set_os_support(const char *os)
+static bool is_windows_os(const char *os)
{
+ return strstr(os, "mingw") != NULL || streq(os, "win32");
+}
+
+static bool is_unixish_os(const char *os)
+{
+ return strstr(os, "linux") != NULL || strstr(os, "bsd") != NULL
+ || streq(os, "solaris");
+}
+
+static bool is_darwin_os(const char *os)
+{
+ return streq(os, "darwin");
+}
+
+static bool init_os_support(void)
+{
+ const char *os = target_machine->operating_system;
wchar_atomic_kind = ATOMIC_TYPE_INT;
- force_long_double_size = 0;
enable_main_collect2_hack = false;
+ define_intmax_types = false;
- if (strstr(os, "linux") != NULL || strstr(os, "bsd") != NULL
- || streq(os, "solaris")) {
- set_be_option("ia32-gasmode=elf");
+ if (is_unixish_os(os)) {
set_create_ld_ident(create_name_linux_elf);
- } else if (streq(os, "darwin")) {
- force_long_double_size = 16;
- set_be_option("ia32-gasmode=macho");
- set_be_option("ia32-stackalign=4");
- set_be_option("pic=true");
+ } else if (is_darwin_os(os)) {
set_create_ld_ident(create_name_macho);
- } else if (strstr(os, "mingw") != NULL || streq(os, "win32")) {
+ define_intmax_types = true;
+ } else if (is_windows_os(os)) {
wchar_atomic_kind = ATOMIC_TYPE_USHORT;
enable_main_collect2_hack = true;
- set_be_option("ia32-gasmode=mingw");
set_create_ld_ident(create_name_win32);
} else {
return false;
static bool parse_target_triple(const char *arg)
{
- const char *manufacturer = strchr(arg, '-');
- if (manufacturer == NULL) {
+ machine_triple_t *triple = firm_parse_machine_triple(arg);
+ if (triple == NULL) {
fprintf(stderr, "Target-triple is not in the form 'cpu_type-manufacturer-operating_system'\n");
return false;
}
- manufacturer += 1;
+ target_machine = triple;
+ return true;
+}
- const char *os = strchr(manufacturer, '-');
- if (os == NULL) {
- fprintf(stderr, "Target-triple is not in the form 'cpu_type-manufacturer-operating_system'\n");
- return false;
+static unsigned decide_modulo_shift(unsigned type_size)
+{
+ if (architecture_modulo_shift == 0)
+ return 0;
+ if (type_size < architecture_modulo_shift)
+ return architecture_modulo_shift;
+ return type_size;
+}
+
+static bool is_ia32_cpu(const char *architecture)
+{
+ return streq(architecture, "i386")
+ || streq(architecture, "i486")
+ || streq(architecture, "i586")
+ || streq(architecture, "i686")
+ || streq(architecture, "i786");
+}
+
+static const char *setup_isa_from_tripel(const machine_triple_t *machine)
+{
+ const char *cpu = machine->cpu_type;
+
+ if (is_ia32_cpu(cpu)) {
+ return "ia32";
+ } else if (streq(cpu, "x86_64")) {
+ return "amd64";
+ } else if (streq(cpu, "sparc")) {
+ return "sparc";
+ } else if (streq(cpu, "arm")) {
+ return "arm";
+ } else {
+ fprintf(stderr, "Unknown cpu '%s' in target-triple\n", cpu);
+ return NULL;
+ }
+}
+
+static const char *setup_target_machine(void)
+{
+ if (!setup_firm_for_machine(target_machine))
+ exit(1);
+
+ const char *isa = setup_isa_from_tripel(target_machine);
+
+ if (isa == NULL)
+ exit(1);
+
+ init_os_support();
+
+ return isa;
+}
+
+/**
+ * initialize cparser type properties based on a firm type
+ */
+static void set_typeprops_type(atomic_type_properties_t* props, ir_type *type)
+{
+ props->size = get_type_size_bytes(type);
+ props->alignment = get_type_alignment_bytes(type);
+ props->struct_alignment = props->alignment;
+}
+
+/**
+ * Copy atomic type properties except the integer conversion rank
+ */
+static void copy_typeprops(atomic_type_properties_t *dest,
+ const atomic_type_properties_t *src)
+{
+ dest->size = src->size;
+ dest->alignment = src->alignment;
+ dest->struct_alignment = src->struct_alignment;
+ dest->flags = src->flags;
+}
+
+static void init_types_and_adjust(void)
+{
+ const backend_params *be_params = be_get_backend_param();
+ unsigned machine_size = be_params->machine_size;
+ init_types(machine_size);
+
+ atomic_type_properties_t *props = atomic_type_properties;
+
+ /* adjust types as requested by target architecture */
+ ir_type *type_long_double = be_params->type_long_double;
+ if (type_long_double != NULL)
+ set_typeprops_type(&props[ATOMIC_TYPE_LONG_DOUBLE], type_long_double);
+
+ ir_type *type_long_long = be_params->type_long_long;
+ if (type_long_long != NULL)
+ set_typeprops_type(&props[ATOMIC_TYPE_LONGLONG], type_long_long);
+
+ ir_type *type_unsigned_long_long = be_params->type_unsigned_long_long;
+ if (type_long_long != NULL)
+ set_typeprops_type(&props[ATOMIC_TYPE_ULONGLONG], type_unsigned_long_long);
+
+ /* operating system ABI specifics */
+ const char *os = target_machine->operating_system;
+ if (is_darwin_os(os)) {
+ if (machine_size == 32) {
+ props[ATOMIC_TYPE_DOUBLE].struct_alignment = 4;
+ props[ATOMIC_TYPE_LONG_DOUBLE].size = 16;
+ props[ATOMIC_TYPE_LONG_DOUBLE].alignment = 16;
+ }
+ } else if (is_windows_os(os)) {
+ if (machine_size == 64) {
+ /* to ease porting of old c-code microsoft decided to use 32bits
+ * even for long */
+ props[ATOMIC_TYPE_LONG] = props[ATOMIC_TYPE_INT];
+ props[ATOMIC_TYPE_ULONG] = props[ATOMIC_TYPE_UINT];
+ }
+
+ /* on windows long double is not supported */
+ props[ATOMIC_TYPE_LONG_DOUBLE] = props[ATOMIC_TYPE_DOUBLE];
+ } else if (is_unixish_os(os)) {
+ if (is_ia32_cpu(target_machine->cpu_type)) {
+ /* System V has a broken alignment for double so we have to add
+ * a hack here */
+ props[ATOMIC_TYPE_DOUBLE].struct_alignment = 4;
+ props[ATOMIC_TYPE_LONGLONG].struct_alignment = 4;
+ props[ATOMIC_TYPE_ULONGLONG].struct_alignment = 4;
+ }
}
- os += 1;
-
- /* Note: Triples are more or less defined by what the config.guess and
- * config.sub scripts from GNU autoconf emit. We have to lookup there what
- * triples are possible */
-
- /* process cpu type */
- if (strstart(arg, "i386-")) {
- be_parse_arg("isa=ia32");
- be_parse_arg("ia32-arch=i386");
- } else if (strstart(arg, "i486-")) {
- be_parse_arg("isa=ia32");
- be_parse_arg("ia32-arch=i486");
- } else if (strstart(arg, "i586-")) {
- be_parse_arg("isa=ia32");
- be_parse_arg("ia32-arch=i586");
- } else if (strstart(arg, "i686-")) {
- be_parse_arg("isa=ia32");
- be_parse_arg("ia32-arch=i686");
- } else if (strstart(arg, "i786-")) {
- be_parse_arg("isa=ia32");
- be_parse_arg("ia32-arch=pentium4");
- } else if (strstart(arg, "x86_64")) {
- be_parse_arg("isa=amd64");
- } else if (strstart(arg, "sparc-")) {
- be_parse_arg("isa=sparc");
- } else if (strstart(arg, "arm-")) {
- be_parse_arg("isa=arm");
+
+ /* stuff decided after processing operating system specifics and
+ * commandline flags */
+ if (char_is_signed) {
+ props[ATOMIC_TYPE_CHAR].flags |= ATOMIC_TYPE_FLAG_SIGNED;
} else {
- fprintf(stderr, "Unknown cpu in triple '%s'\n", arg);
- return false;
+ props[ATOMIC_TYPE_CHAR].flags &= ~ATOMIC_TYPE_FLAG_SIGNED;
}
+ /* copy over wchar_t properties (including rank) */
+ props[ATOMIC_TYPE_WCHAR_T] = props[wchar_atomic_kind];
- /* process manufacturer, alot of people incorrectly leave out the
- * manufacturer instead of using unknown- */
- if (strstart(manufacturer, "linux")) {
- os = manufacturer;
- manufacturer = "unknown-";
+ /* initialize defaults for unsupported types */
+ if (type_long_long == NULL) {
+ copy_typeprops(&props[ATOMIC_TYPE_LONGLONG], &props[ATOMIC_TYPE_LONG]);
+ }
+ if (type_unsigned_long_long == NULL) {
+ copy_typeprops(&props[ATOMIC_TYPE_ULONGLONG],
+ &props[ATOMIC_TYPE_ULONG]);
+ }
+ if (type_long_double == NULL) {
+ copy_typeprops(&props[ATOMIC_TYPE_LONG_DOUBLE],
+ &props[ATOMIC_TYPE_DOUBLE]);
}
- /* process operating system */
- if (!set_os_support(os)) {
- fprintf(stderr, "Unknown operating system '%s' in triple '%s'\n", os, arg);
- return false;
+ /* initialize firm pointer modes */
+ char name[64];
+ ir_mode_sort sort = irms_reference;
+ unsigned bit_size = machine_size;
+ bool is_signed = 0;
+ ir_mode_arithmetic arithmetic = irma_twos_complement;
+ unsigned modulo_shift = decide_modulo_shift(bit_size);
+
+ snprintf(name, sizeof(name), "p%u", machine_size);
+ ir_mode *ptr_mode = new_ir_mode(name, sort, bit_size, is_signed, arithmetic,
+ modulo_shift);
+
+ if (machine_size == 16) {
+ set_reference_mode_signed_eq(ptr_mode, mode_Hs);
+ set_reference_mode_unsigned_eq(ptr_mode, mode_Hu);
+ } else if (machine_size == 32) {
+ set_reference_mode_signed_eq(ptr_mode, mode_Is);
+ set_reference_mode_unsigned_eq(ptr_mode, mode_Iu);
+ } else if (machine_size == 64) {
+ set_reference_mode_signed_eq(ptr_mode, mode_Ls);
+ set_reference_mode_unsigned_eq(ptr_mode, mode_Lu);
+ } else {
+ panic("strange machine_size when determining pointer modes");
}
- target_triple = arg;
- return true;
+ /* Hmm, pointers should be machine size */
+ set_modeP_data(ptr_mode);
+ set_modeP_code(ptr_mode);
+
+ byte_order_big_endian = be_params->byte_order_big_endian;
+ if (be_params->modulo_shift_efficient) {
+ architecture_modulo_shift = machine_size;
+ } else {
+ architecture_modulo_shift = 0;
+ }
}
int main(int argc, char **argv)
{
- initialize_firm();
+ firm_early_init();
const char *dumpfunction = NULL;
const char *print_file_name_file = NULL;
file_list_entry_t *last_file = NULL;
bool construct_dep_target = false;
bool do_timing = false;
+ bool profile_generate = false;
+ bool profile_use = false;
struct obstack file_obst;
atexit(free_temp_files);
obstack_init(&cppflags_obst);
obstack_init(&ldflags_obst);
+ obstack_init(&asflags_obst);
obstack_init(&file_obst);
#define GET_ARG_AFTER(def, args) \
+ do { \
def = &arg[sizeof(args)-1]; \
- if (def[0] == '\0') { \
+ if (def[0] == '\0') { \
++i; \
- if (i >= argc) { \
+ if (i >= argc) { \
fprintf(stderr, "error: expected argument after '" args "'\n"); \
argument_errors = true; \
break; \
} \
def = argv[i]; \
- if (def[0] == '-' && def[1] != '\0') { \
+ if (def[0] == '-' && def[1] != '\0') { \
fprintf(stderr, "error: expected argument after '" args "'\n"); \
argument_errors = true; \
continue; \
} \
- }
+ } \
+ } while (0)
#define SINGLE_OPTION(ch) (option[0] == (ch) && option[1] == '\0')
- /* early options parsing (find out optimisation level and OS) */
+ /* early options parsing (find out optimization level and OS) */
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (arg[0] != '-')
}
}
- /* Guess host OS */
-#if defined(_WIN32) || defined(__CYGWIN__)
- set_os_support("win32");
-#elif defined(__APPLE__)
- set_os_support("darwin");
-#else
- set_os_support("linux");
-#endif
-
- /* apply optimisation level */
- switch(opt_level) {
- case 0:
- set_option("no-opt");
- break;
- case 1:
- set_option("no-inline");
- break;
- default:
- case 4:
- /* use_builtins = true; */
- /* fallthrough */
- case 3:
- set_option("thread-jumps");
- set_option("if-conversion");
- /* fallthrough */
- case 2:
- set_option("strict-aliasing");
- set_option("inline");
- set_option("deconv");
- set_be_option("omitfp");
- break;
- }
-
const char *target = getenv("TARGET");
if (target != NULL)
parse_target_triple(target);
+ if (target_machine == NULL) {
+ target_machine = firm_get_host_machine();
+ }
+ choose_optimization_pack(opt_level);
+ setup_target_machine();
/* parse rest of options */
- standard = STANDARD_DEFAULT;
- unsigned features_on = 0;
- unsigned features_off = 0;
- filetype_t forced_filetype = FILETYPE_AUTODETECT;
- bool help_displayed = false;
- bool argument_errors = false;
+ standard = STANDARD_DEFAULT;
+ unsigned features_on = 0;
+ unsigned features_off = 0;
+ filetype_t forced_filetype = FILETYPE_AUTODETECT;
+ help_sections_t help = HELP_NONE;
+ bool argument_errors = false;
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (arg[0] == '-' && arg[1] != '\0') {
} else if (SINGLE_OPTION('v')) {
verbose = 1;
} else if (SINGLE_OPTION('w')) {
- memset(&warning, 0, sizeof(warning));
+ disable_all_warnings();
} else if (option[0] == 'x') {
const char *opt;
GET_ARG_AFTER(opt, "-x");
if (strstart(orig_opt, "input-charset=")) {
char const* const encoding = strchr(orig_opt, '=') + 1;
- select_input_encoding(encoding);
- } else if (streq(orig_opt, "verbose-asm")) {
- /* ignore: we always print verbose assembler */
+ input_encoding = encoding;
+ } else if (strstart(orig_opt, "align-loops=") ||
+ strstart(orig_opt, "align-jumps=") ||
+ strstart(orig_opt, "align-functions=")) {
+ fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
+ } else if (strstart(orig_opt, "visibility=")) {
+ const char *val = strchr(orig_opt, '=')+1;
+ elf_visibility_tag_t visibility
+ = get_elf_visibility_from_string(val);
+ if (visibility == ELF_VISIBILITY_ERROR) {
+ fprintf(stderr, "invalid visibility '%s' specified\n",
+ val);
+ argument_errors = true;
+ } else {
+ set_default_visibility(visibility);
+ }
+ } else if (strstart(orig_opt, "message-length=")) {
+ /* ignore: would only affect error message format */
+ } else if (streq(orig_opt, "fast-math") ||
+ streq(orig_opt, "fp-fast")) {
+ firm_fp_model = fp_model_fast;
+ } else if (streq(orig_opt, "fp-precise")) {
+ firm_fp_model = fp_model_precise;
+ } else if (streq(orig_opt, "fp-strict")) {
+ firm_fp_model = fp_model_strict;
+ } else if (streq(orig_opt, "help")) {
+ fprintf(stderr, "warning: -fhelp is deprecated\n");
+ help |= HELP_OPTIMIZATION;
} else {
+ /* -f options which have an -fno- variant */
char const *opt = orig_opt;
bool truth_value = true;
if (opt[0] == 'n' && opt[1] == 'o' && opt[2] == '-') {
opt += 3;
}
- if (streq(opt, "builtins")) {
- use_builtins = truth_value;
+ if (streq(opt, "diagnostics-show-option")) {
+ diagnostics_show_option = truth_value;
} else if (streq(opt, "dollars-in-identifiers")) {
allow_dollar_in_symbol = truth_value;
} else if (streq(opt, "omit-frame-pointer")) {
} else if (streq(opt, "short-wchar")) {
wchar_atomic_kind = truth_value ? ATOMIC_TYPE_USHORT
: ATOMIC_TYPE_INT;
+ } else if (streq(opt, "show-column")) {
+ show_column = truth_value;
} else if (streq(opt, "signed-char")) {
char_is_signed = truth_value;
} else if (streq(opt, "strength-reduce")) {
- firm_option(truth_value ? "strength-red" : "no-strength-red");
+ /* does nothing, for gcc compatibility (even gcc does
+ * nothing for this switch anymore) */
} else if (streq(opt, "syntax-only")) {
mode = truth_value ? ParseOnly : CompileAssembleLink;
} else if (streq(opt, "unsigned-char")) {
char_is_signed = !truth_value;
} else if (streq(opt, "freestanding")) {
- freestanding = true;
+ freestanding = truth_value;
} else if (streq(opt, "hosted")) {
- freestanding = false;
- } else if (truth_value == false &&
+ freestanding = !truth_value;
+ } else if (streq(opt, "profile-generate")) {
+ profile_generate = truth_value;
+ } else if (streq(opt, "profile-use")) {
+ profile_use = truth_value;
+ } else if (!truth_value &&
streq(opt, "asynchronous-unwind-tables")) {
- /* nothing todo, a gcc feature which we don't support
+ /* nothing todo, a gcc feature which we do not support
* anyway was deactivated */
- } else if (strstart(orig_opt, "align-loops=") ||
- strstart(orig_opt, "align-jumps=") ||
- strstart(orig_opt, "align-functions=")) {
- fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
- } else if (strstart(orig_opt, "message-length=")) {
- /* ignore: would only affect error message format */
- } else if (streq(opt, "fast-math") ||
- streq(opt, "jump-tables") ||
+ } else if (streq(opt, "verbose-asm")) {
+ /* ignore: we always print verbose assembler */
+ } else if (streq(opt, "jump-tables") ||
streq(opt, "expensive-optimizations") ||
streq(opt, "common") ||
streq(opt, "optimize-sibling-calls") ||
streq(opt, "align-loops") ||
streq(opt, "align-jumps") ||
streq(opt, "align-functions") ||
- streq(opt, "PIC")) {
+ streq(opt, "PIC") ||
+ streq(opt, "stack-protector") ||
+ streq(opt, "stack-protector-all")) {
fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
} else {
int res = firm_option(orig_opt);
orig_opt);
argument_errors = true;
continue;
- } else if (res == -1) {
- help_displayed = true;
}
}
}
} else if (option[0] == 'b') {
const char *opt;
GET_ARG_AFTER(opt, "-b");
- int res = be_parse_arg(opt);
- if (res == 0) {
- fprintf(stderr, "error: unknown Firm backend option '-b %s'\n",
- opt);
- argument_errors = true;
- } else if (res == -1) {
- help_displayed = true;
- } else if (strstart(opt, "isa=")) {
- strncpy(cpu_arch, opt, sizeof(cpu_arch));
+
+ if (streq(opt, "help")) {
+ fprintf(stderr, "warning: -bhelp is deprecated (use --help-firm)\n");
+ help |= HELP_FIRM;
+ } else {
+ int res = be_parse_arg(opt);
+ if (res == 0) {
+ fprintf(stderr, "error: unknown Firm backend option '-b %s'\n",
+ opt);
+ argument_errors = true;
+ } else if (strstart(opt, "isa=")) {
+ strncpy(cpu_arch, opt, sizeof(cpu_arch));
+ }
}
} else if (option[0] == 'W') {
- if (option[1] == '\0') {
- /* ignore -W, our defaults are already quite verbose */
- } else if (strstart(option + 1, "p,")) {
+ if (strstart(option + 1, "p,")) {
// pass options directly to the preprocessor
const char *opt;
GET_ARG_AFTER(opt, "-Wp,");
GET_ARG_AFTER(opt, "-Wl,");
add_flag(&ldflags_obst, "-Wl,%s", opt);
} else if (streq(option + 1, "no-trigraphs")
- || streq(option + 1, "undef")) {
+ || streq(option + 1, "undef")
+ || streq(option + 1, "missing-include-dirs")
+ || streq(option + 1, "endif-labels")) {
add_flag(&cppflags_obst, "%s", arg);
+ } else if (streq(option+1, "init-self")) {
+ /* ignored (asme as gcc does) */
+ } else if (streq(option+1, "format-y2k")
+ || streq(option+1, "format-security")
+ || streq(option+1, "old-style-declaration")
+ || streq(option+1, "type-limits")) {
+ /* ignore (gcc compatibility) */
} else {
set_warning_opt(&option[1]);
}
GET_ARG_AFTER(opt, "-m");
if (strstart(opt, "target=")) {
GET_ARG_AFTER(opt, "-mtarget=");
- if (!parse_target_triple(opt))
+ if (!parse_target_triple(opt)) {
argument_errors = true;
+ } else {
+ const char *isa = setup_target_machine();
+ strncpy(cpu_arch, isa, sizeof(cpu_arch));
+ target_triple = opt;
+ }
} else if (strstart(opt, "triple=")) {
GET_ARG_AFTER(opt, "-mtriple=");
- if (!parse_target_triple(opt))
+ if (!parse_target_triple(opt)) {
argument_errors = true;
+ } else {
+ const char *isa = setup_target_machine();
+ strncpy(cpu_arch, isa, sizeof(cpu_arch));
+ target_triple = opt;
+ }
} else if (strstart(opt, "arch=")) {
GET_ARG_AFTER(opt, "-march=");
snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
int res = be_parse_arg(arch_opt);
+ snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
+ res &= be_parse_arg(arch_opt);
+
if (res == 0) {
fprintf(stderr, "Unknown architecture '%s'\n", arch_opt);
argument_errors = true;
- } else {
- snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
- int res = be_parse_arg(arch_opt);
- if (res == 0)
- argument_errors = true;
}
} else if (strstart(opt, "tune=")) {
GET_ARG_AFTER(opt, "-mtune=");
else if (streq(opt, "sse"))
opt = "sse2";
else {
- fprintf(stderr, "error: option -mfpumath supports only 387 or sse\n");
+ fprintf(stderr, "error: option -mfpmath supports only 387 or sse\n");
argument_errors = true;
}
if (!argument_errors) {
int res = be_parse_arg(arch_opt);
if (res == 0)
argument_errors = true;
- } else if (streq(opt, "omit-leaf-frame-pointer")) {
- set_be_option("omitleaffp=1");
- } else if (streq(opt, "no-omit-leaf-frame-pointer")) {
- set_be_option("omitleaffp=0");
} else if (streq(opt, "rtd")) {
default_calling_convention = CC_STDCALL;
} else if (strstart(opt, "regparm=")) {
fprintf(stderr, "error: regparm convention not supported yet\n");
argument_errors = true;
} else if (streq(opt, "soft-float")) {
- fprintf(stderr, "error: software floatingpoint not supported yet\n");
- argument_errors = true;
+ add_flag(&ldflags_obst, "-msoft-float");
+ snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=softfloat", cpu_arch);
+ int res = be_parse_arg(arch_opt);
+ if (res == 0)
+ argument_errors = true;
} else {
long int value = strtol(opt, NULL, 10);
if (value == 0) {
fprintf(stderr, "error: option -m supports only 16, 32 or 64\n");
argument_errors = true;
} else {
- machine_size = (unsigned int)value;
+ unsigned machine_size = (unsigned)value;
+ /* TODO: choose/change backend based on this */
+ add_flag(&cppflags_obst, "-m%u", machine_size);
+ add_flag(&asflags_obst, "-m%u", machine_size);
+ add_flag(&ldflags_obst, "-m%u", machine_size);
}
}
} else if (streq(option, "pg")) {
} else if (streq(option, "pedantic") ||
streq(option, "ansi")) {
fprintf(stderr, "warning: ignoring gcc option '%s'\n", arg);
- } else if (streq(option, "shared")) {
- add_flag(&ldflags_obst, "-shared");
} else if (strstart(option, "std=")) {
const char *const o = &option[4];
standard =
print_parenthesis = true;
} else if (streq(option, "print-fluffy")) {
mode = PrintFluffy;
- } else if (streq(option, "print-caml")) {
- mode = PrintCaml;
} else if (streq(option, "print-jna")) {
mode = PrintJna;
} else if (streq(option, "jna-limit")) {
print_cparser_version();
return EXIT_SUCCESS;
} else if (streq(option, "help")) {
- print_help(argv[0]);
- help_displayed = true;
+ help |= HELP_BASIC;
+ } else if (streq(option, "help-parser")) {
+ help |= HELP_PARSER;
+ } else if (streq(option, "help-warnings")) {
+ help |= HELP_WARNINGS;
+ } else if (streq(option, "help-codegen")) {
+ help |= HELP_CODEGEN;
+ } else if (streq(option, "help-linker")) {
+ help |= HELP_LINKER;
+ } else if (streq(option, "help-optimization")) {
+ help |= HELP_OPTIMIZATION;
+ } else if (streq(option, "help-language-tools")) {
+ help |= HELP_LANGUAGETOOLS;
+ } else if (streq(option, "help-debug")) {
+ help |= HELP_DEBUG;
+ } else if (streq(option, "help-firm")) {
+ help |= HELP_FIRM;
+ } else if (streq(option, "help-all")) {
+ help |= HELP_ALL;
} else if (streq(option, "dump-function")) {
++i;
if (i >= argc) {
streq(suffix, "S") ? FILETYPE_ASSEMBLER :
streq(suffix, "a") ? FILETYPE_OBJECT :
streq(suffix, "c") ? FILETYPE_C :
+ streq(suffix, "i") ? FILETYPE_PREPROCESSED_C :
streq(suffix, "C") ? FILETYPE_CXX :
streq(suffix, "cc") ? FILETYPE_CXX :
streq(suffix, "cp") ? FILETYPE_CXX :
streq(suffix, "CPP") ? FILETYPE_CXX :
streq(suffix, "cxx") ? FILETYPE_CXX :
streq(suffix, "c++") ? FILETYPE_CXX :
- streq(suffix, "ii") ? FILETYPE_CXX :
+ streq(suffix, "ii") ? FILETYPE_PREPROCESSED_CXX :
streq(suffix, "h") ? FILETYPE_C :
streq(suffix, "ir") ? FILETYPE_IR :
streq(suffix, "o") ? FILETYPE_OBJECT :
}
}
- if (help_displayed) {
+ if (help != HELP_NONE) {
+ print_help(argv[0], help);
return !argument_errors;
}
return EXIT_FAILURE;
}
- /* we do the lowering in ast2firm */
- firm_opt.lower_bitfields = FALSE;
-
- /* set the c_mode here, types depends on it */
+ /* apply some effects from switches */
c_mode |= features_on;
c_mode &= ~features_off;
+ if (profile_generate) {
+ add_flag(&ldflags_obst, "-lfirmprof");
+ set_be_option("profilegenerate");
+ }
+ if (profile_use) {
+ set_be_option("profileuse");
+ }
gen_firm_init();
- byte_order_big_endian = be_get_backend_param()->byte_order_big_endian;
init_symbol_table();
- init_types();
+ init_types_and_adjust();
init_typehash();
init_basic_types();
+ if (wchar_atomic_kind == ATOMIC_TYPE_INT)
+ init_wchar_types(type_int);
+ else if (wchar_atomic_kind == ATOMIC_TYPE_SHORT)
+ init_wchar_types(type_short);
+ else
+ panic("unexpected wchar type");
init_lexer();
init_ast();
init_parser();
case BenchmarkParser:
case PrintAst:
case PrintFluffy:
- case PrintCaml:
case PrintJna:
case LexTest:
case PreprocessOnly:
} else {
out = fopen(outname, "w");
if (out == NULL) {
- fprintf(stderr, "Couldn't open '%s' for writing: %s\n", outname,
+ fprintf(stderr, "Could not open '%s' for writing: %s\n", outname,
strerror(errno));
return EXIT_FAILURE;
}
preprocessed_in = preprocess(filename, filetype);
if (mode == PreprocessOnly) {
copy_file(out, preprocessed_in);
- int result = pclose(preprocessed_in);
+ int pp_result = pclose(preprocessed_in);
fclose(out);
/* remove output file in case of error */
- if (out != stdout && result != EXIT_SUCCESS) {
+ if (out != stdout && pp_result != EXIT_SUCCESS) {
unlink(outname);
}
- return result;
+ return pp_result;
}
in = preprocessed_in;
} else if (mode == PrintFluffy) {
write_fluffy_decls(out, unit);
continue;
- } else if (mode == PrintCaml) {
- write_caml_decls(out, unit);
- continue;
} else if (mode == PrintJna) {
write_jna_decls(out, unit);
continue;
return EXIT_SUCCESS;
}
- gen_firm_finish(asm_out, filename, have_const_functions);
+ gen_firm_finish(asm_out, filename);
if (asm_out != out) {
fclose(asm_out);
}
obstack_free(&cppflags_obst, NULL);
obstack_free(&ldflags_obst, NULL);
+ obstack_free(&asflags_obst, NULL);
obstack_free(&file_obst, NULL);
exit_mangle();