Print this page
11972 resync smatch

@@ -21,10 +21,11 @@
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
 #include <ctype.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>

@@ -38,24 +39,23 @@
 #include "allocate.h"
 #include "token.h"
 #include "parse.h"
 #include "symbol.h"
 #include "expression.h"
+#include "evaluate.h"
 #include "scope.h"
 #include "linearize.h"
 #include "target.h"
+#include "machine.h"
 #include "version.h"
+#include "bits.h"
 
-static const char *progname;
-
-int sparse_errors = 0;
-int sparse_warnings = 0;
-
-int verbose, optimize, optimize_size, preprocessing;
+int verbose, optimize_level, optimize_size, preprocessing;
 int die_if_error = 0;
 int parse_error;
 int has_error = 0;
+int do_output = 0;
 
 #ifndef __GNUC__
 # define __GNUC__ 2
 # define __GNUC_MINOR__ 95
 # define __GNUC_PATCHLEVEL__ 0

@@ -63,24 +63,28 @@
 
 int gcc_major = __GNUC__;
 int gcc_minor = __GNUC_MINOR__;
 int gcc_patchlevel = __GNUC_PATCHLEVEL__;
 
+const char *base_filename;
+
+static const char *diag_prefix = "";
 static const char *gcc_base_dir = GCC_BASE;
 static const char *multiarch_dir = MULTIARCH_TRIPLET;
+static const char *outfile = NULL;
 
 struct token *skip_to(struct token *token, int op)
 {
         while (!match_op(token, op) && !eof_token(token))
                 token = token->next;
         return token;
 }
 
+static struct token bad_token = { .pos.type = TOKEN_BAD };
 struct token *expect(struct token *token, int op, const char *where)
 {
         if (!match_op(token, op)) {
-                static struct token bad_token;
                 if (token != &bad_token) {
                         bad_token.next = token;
                         sparse_error(token->pos, "Expected %s %s", show_special(op), where);
                         sparse_error(token->pos, "got %s", show_token(token));
                 }

@@ -89,10 +93,25 @@
                 return &bad_token;
         }
         return token->next;
 }
 
+///
+// issue an error message on new parsing errors
+// @token: the current token
+// @errmsg: the error message
+// If the current token is from a previous error, an error message
+// has already been issued, so nothing more is done.
+// Otherwise, @errmsg is displayed followed by the current token.
+void unexpected(struct token *token, const char *errmsg)
+{
+        if (token == &bad_token)
+                return;
+        sparse_error(token->pos, "%s", errmsg);
+        sparse_error(token->pos, "got %s", show_token(token));
+}
+
 unsigned int hexval(unsigned int c)
 {
         int retval = 256;
         switch (c) {
         case '0'...'9':

@@ -111,18 +130,23 @@
 static void do_warn(const char *type, struct position pos, const char * fmt, va_list args)
 {
         static char buffer[512];
         const char *name;
 
+        /* Shut up warnings if position is bad_token.pos */
+        if (pos.type == TOKEN_BAD)
+                return;
+
         vsprintf(buffer, fmt, args);    
         name = stream_name(pos.stream);
                 
+        fflush(stdout);
         fprintf(stderr, "%s: %s:%d:%d: %s%s\n",
-                progname, name, pos.line, pos.pos, type, buffer);
+                diag_prefix, name, pos.line, pos.pos, type, buffer);
 }
 
-static int max_warnings = 100;
+unsigned int fmax_warnings = 100;
 static int show_info = 1;
 
 void info(struct position pos, const char * fmt, ...)
 {
         va_list args;

@@ -139,10 +163,13 @@
         static int errors = 0;
 
         parse_error = 1;
         die_if_error = 1;
         show_info = 1;
+        /* Shut up warnings if position is bad_token.pos */
+        if (pos.type == TOKEN_BAD)
+                return;
         /* Shut up warnings after an error */
         has_error |= ERROR_CURR_PHASE;
         if (errors > 100) {
                 static int once = 0;
                 show_info = 0;

@@ -165,16 +192,16 @@
                 do_error(pos, fmt, args);
                 va_end(args);
                 return;
         }
 
-        if (!max_warnings || has_error) {
+        if (!fmax_warnings || has_error) {
                 show_info = 0;
                 return;
         }
 
-        if (!--max_warnings) {
+        if (!--fmax_warnings) {
                 show_info = 0;
                 fmt = "too many warnings";
         }
 
         va_start(args, fmt);

@@ -217,20 +244,22 @@
 
         va_start(args, fmt);
         vsnprintf(buffer, sizeof(buffer), fmt, args);
         va_end(args);
 
-        fprintf(stderr, "%s: %s\n", progname, buffer);
+        fprintf(stderr, "%s: %s\n", diag_prefix, buffer);
         exit(1);
 }
 
 static struct token *pre_buffer_begin = NULL;
 static struct token *pre_buffer_end = NULL;
 
 int Waddress = 0;
 int Waddress_space = 1;
 int Wbitwise = 1;
+int Wbitwise_pointer = 0;
+int Wcast_from_as = 0;
 int Wcast_to_as = 0;
 int Wcast_truncate = 1;
 int Wconstant_suffix = 0;
 int Wconstexpr_not_const = 0;
 int Wcontext = 1;

@@ -239,10 +268,11 @@
 int Wdefault_bitfield_sign = 0;
 int Wdesignated_init = 1;
 int Wdo_while = 0;
 int Wimplicit_int = 1;
 int Winit_cstring = 0;
+int Wint_to_pointer_cast = 1;
 int Wenum_mismatch = 1;
 int Wexternal_function_has_definition = 1;
 int Wsparse_error = 0;
 int Wmemcpy_max_count = 1;
 int Wnon_pointer_null = 1;

@@ -252,13 +282,16 @@
 int Woverride_init = 1;
 int Woverride_init_all = 0;
 int Woverride_init_whole_range = 0;
 int Wparen_string = 0;
 int Wpointer_arith = 0;
+int Wpointer_to_int_cast = 1;
 int Wptr_subtraction_blows = 0;
 int Wreturn_void = 0;
 int Wshadow = 0;
+int Wshift_count_negative = 1;
+int Wshift_count_overflow = 1;
 int Wsizeof_bool = 0;
 int Wstrict_prototypes = 1;
 int Wtautological_compare = 0;
 int Wtransparent_union = 0;
 int Wtypesign = 0;

@@ -266,17 +299,24 @@
 int Wuninitialized = 1;
 int Wunknown_attribute = 0;
 int Wvla = 1;
 
 int dump_macro_defs = 0;
+int dump_macros_only = 0;
 
-int dbg_entry = 0;
+int dbg_compound = 0;
 int dbg_dead = 0;
+int dbg_domtree = 0;
+int dbg_entry = 0;
+int dbg_ir = 0;
+int dbg_postorder = 0;
 
+unsigned long fdump_ir;
 int fmem_report = 0;
-int fdump_linearize;
 unsigned long long fmemcpy_max_count = 100000;
+unsigned long fpasses = ~0UL;
+int funsigned_char = UNSIGNED_CHAR;
 
 int preprocess_only;
 
 static enum { STANDARD_C89,
               STANDARD_C94,

@@ -284,29 +324,14 @@
               STANDARD_C11,
               STANDARD_GNU11,
               STANDARD_GNU89,
               STANDARD_GNU99, } standard = STANDARD_GNU89;
 
-#define ARCH_LP32  0
-#define ARCH_LP64  1
-#define ARCH_LLP64 2
-
-#ifdef __x86_64__
-#define ARCH_M64_DEFAULT ARCH_LP64
-#else
-#define ARCH_M64_DEFAULT ARCH_LP32
-#endif
-
 int arch_m64 = ARCH_M64_DEFAULT;
 int arch_msize_long = 0;
-
-#ifdef __BIG_ENDIAN__
-#define ARCH_BIG_ENDIAN 1
-#else
-#define ARCH_BIG_ENDIAN 0
-#endif
 int arch_big_endian = ARCH_BIG_ENDIAN;
+int arch_mach = MACH_NATIVE;
 
 
 #define CMDLINE_INCLUDE 20
 static int cmdline_include_nr = 0;
 static char *cmdline_include[CMDLINE_INCLUDE];

@@ -431,12 +456,14 @@
 
 static char **handle_switch_m(char *arg, char **next)
 {
         if (!strcmp(arg, "m64")) {
                 arch_m64 = ARCH_LP64;
-        } else if (!strcmp(arg, "m32")) {
+        } else if (!strcmp(arg, "m32") || !strcmp(arg, "m16")) {
                 arch_m64 = ARCH_LP32;
+        } else if (!strcmp(arg, "mx32")) {
+                arch_m64 = ARCH_X32;
         } else if (!strcmp(arg, "msize-llp64")) {
                 arch_m64 = ARCH_LLP64;
         } else if (!strcmp(arg, "msize-long")) {
                 arch_msize_long = 1;
         } else if (!strcmp(arg, "multiarch-dir")) {

@@ -447,48 +474,10 @@
                 arch_big_endian = 0;
         }
         return next;
 }
 
-static void handle_arch_m64_finalize(void)
-{
-        switch (arch_m64) {
-        case ARCH_LP32:
-                /* default values */
-#if defined(__x86_64__) || defined (__i386)
-                add_pre_buffer("#weak_define __i386__ 1\n");
-                add_pre_buffer("#weak_define __i386 1\n");
-                add_pre_buffer("#weak_define i386 1\n");
-#endif
-                return;
-        case ARCH_LP64:
-                bits_in_long = 64;
-                max_int_alignment = 8;
-                size_t_ctype = &ulong_ctype;
-                ssize_t_ctype = &long_ctype;
-                add_pre_buffer("#weak_define __LP64__ 1\n");
-                add_pre_buffer("#weak_define __LP64 1\n");
-                add_pre_buffer("#weak_define _LP64 1\n");
-                goto case_64bit_common;
-        case ARCH_LLP64:
-                bits_in_long = 32;
-                max_int_alignment = 4;
-                size_t_ctype = &ullong_ctype;
-                ssize_t_ctype = &llong_ctype;
-                add_pre_buffer("#weak_define __LLP64__ 1\n");
-                goto case_64bit_common;
-        case_64bit_common:
-                bits_in_pointer = 64;
-                pointer_alignment = 8;
-#if defined(__x86_64__) || defined (__i386)
-                add_pre_buffer("#weak_define __x86_64__ 1\n");
-                add_pre_buffer("#weak_define __x86_64 1\n");
-#endif
-                break;
-        }
-}
-
 static void handle_arch_msize_long_finalize(void)
 {
         if (arch_msize_long) {
                 size_t_ctype = &ulong_ctype;
                 ssize_t_ctype = &long_ctype;

@@ -495,52 +484,165 @@
         }
 }
 
 static void handle_arch_finalize(void)
 {
-        handle_arch_m64_finalize();
         handle_arch_msize_long_finalize();
 }
 
+static const char *match_option(const char *arg, const char *prefix)
+{
+        unsigned int n = strlen(prefix);
+        if (strncmp(arg, prefix, n) == 0)
+                return arg + n;
+        return NULL;
+}
 
-static int handle_simple_switch(const char *arg, const char *name, int *flag)
+
+struct mask_map {
+        const char *name;
+        unsigned long mask;
+};
+
+static int apply_mask(unsigned long *val, const char *str, unsigned len, const struct mask_map *map, int neg)
 {
+        const char *name;
+
+        for (;(name = map->name); map++) {
+                if (!strncmp(name, str, len) && !name[len]) {
+                        if (neg == 0)
+                                *val |= map->mask;
+                        else
+                                *val &= ~map->mask;
+                        return 0;
+                }
+        }
+        return 1;
+}
+
+static int handle_suboption_mask(const char *arg, const char *opt, const struct mask_map *map, unsigned long *flag)
+{
+        if (*opt == '\0') {
+                apply_mask(flag, "", 0, map, 0);
+                return 1;
+        }
+        if (*opt++ != '=')
+                return 0;
+        while (1) {
+                unsigned int len = strcspn(opt, ",+");
+                int neg = 0;
+                if (len == 0)
+                        goto end;
+                if (!strncmp(opt, "no-", 3)) {
+                        opt += 3;
+                        len -= 3;
+                        neg = 1;
+                }
+                if (apply_mask(flag, opt, len, map, neg))
+                        die("error: wrong option '%.*s' for \'%s\'", len, opt, arg);
+
+end:
+                opt += len;
+                if (*opt++ == '\0')
+                        break;
+        }
+        return 1;
+}
+
+
+#define OPT_INVERSE     1
+struct flag {
+        const char *name;
+        int *flag;
+        int (*fun)(const char *arg, const char *opt, const struct flag *, int options);
+        unsigned long mask;
+};
+
+static int handle_switches(const char *ori, const char *opt, const struct flag *flags)
+{
+        const char *arg = opt;
         int val = 1;
 
         // Prefixe "no-" mean to turn flag off.
         if (strncmp(arg, "no-", 3) == 0) {
                 arg += 3;
                 val = 0;
         }
 
-        if (strcmp(arg, name) == 0) {
-                *flag = val;
+        for (; flags->name; flags++) {
+                const char *opt = match_option(arg, flags->name);
+                int rc;
+
+                if (!opt)
+                        continue;
+
+                if (flags->fun) {
+                        int options = 0;
+                        if (!val)
+                                options |= OPT_INVERSE;
+                        if ((rc = flags->fun(ori, opt, flags, options)))
+                                return rc;
+                }
+
+                // boolean flag
+                if (opt[0] == '\0' && flags->flag) {
+                        if (flags->mask & OPT_INVERSE)
+                                val = !val;
+                        *flags->flag = val;
                 return 1;
         }
+        }
 
         // not handled
         return 0;
 }
 
+
+#define OPTNUM_ZERO_IS_INF              1
+#define OPTNUM_UNLIMITED                2
+
+#define OPT_NUMERIC(NAME, TYPE, FUNCTION)       \
+static int opt_##NAME(const char *arg, const char *opt, TYPE *ptr, int flag)    \
+{                                                                       \
+        char *end;                                                      \
+        TYPE val;                                                       \
+                                                                        \
+        val = FUNCTION(opt, &end, 0);                                   \
+        if (*end != '\0' || end == opt) {                               \
+                if ((flag & OPTNUM_UNLIMITED) && !strcmp(opt, "unlimited"))     \
+                        val = ~val;                                     \
+                else                                                    \
+                        die("error: wrong argument to \'%s\'", arg);    \
+        }                                                               \
+        if ((flag & OPTNUM_ZERO_IS_INF) && val == 0)                    \
+                val = ~val;                                             \
+        *ptr = val;                                                     \
+        return 1;                                                       \
+}
+
+OPT_NUMERIC(ullong, unsigned long long, strtoull)
+OPT_NUMERIC(uint, unsigned int, strtoul)
+
+
 static char **handle_switch_o(char *arg, char **next)
 {
         if (!strcmp (arg, "o")) {       // "-o foo"
                 if (!*++next)
                         die("argument to '-o' is missing");
+                outfile = *next;
         }
         // else "-ofoo"
 
         return next;
 }
 
-static const struct warning {
-        const char *name;
-        int *flag;
-} warnings[] = {
+static const struct flag warnings[] = {
         { "address", &Waddress },
         { "address-space", &Waddress_space },
         { "bitwise", &Wbitwise },
+        { "bitwise-pointer", &Wbitwise_pointer},
+        { "cast-from-as", &Wcast_from_as },
         { "cast-to-as", &Wcast_to_as },
         { "cast-truncate", &Wcast_truncate },
         { "constant-suffix", &Wconstant_suffix },
         { "constexpr-not-const", &Wconstexpr_not_const},
         { "context", &Wcontext },

@@ -551,21 +653,25 @@
         { "do-while", &Wdo_while },
         { "enum-mismatch", &Wenum_mismatch },
         { "external-function-has-definition", &Wexternal_function_has_definition },
         { "implicit-int", &Wimplicit_int },
         { "init-cstring", &Winit_cstring },
+        { "int-to-pointer-cast", &Wint_to_pointer_cast },
         { "memcpy-max-count", &Wmemcpy_max_count },
         { "non-pointer-null", &Wnon_pointer_null },
         { "old-initializer", &Wold_initializer },
         { "old-style-definition", &Wold_style_definition },
         { "one-bit-signed-bitfield", &Wone_bit_signed_bitfield },
         { "override-init", &Woverride_init },
         { "override-init-all", &Woverride_init_all },
         { "paren-string", &Wparen_string },
+        { "pointer-to-int-cast", &Wpointer_to_int_cast },
         { "ptr-subtraction-blows", &Wptr_subtraction_blows },
         { "return-void", &Wreturn_void },
         { "shadow", &Wshadow },
+        { "shift-count-negative", &Wshift_count_negative },
+        { "shift-count-overflow", &Wshift_count_overflow },
         { "sizeof-bool", &Wsizeof_bool },
         { "strict-prototypes", &Wstrict_prototypes },
         { "pointer-arith", &Wpointer_arith },
         { "sparse-error", &Wsparse_error },
         { "tautological-compare", &Wtautological_compare },

@@ -582,11 +688,11 @@
         WARNING_ON,
         WARNING_FORCE_OFF
 };
 
 
-static char **handle_onoff_switch(char *arg, char **next, const struct warning warnings[], int n)
+static char **handle_onoff_switch(char *arg, char **next, const struct flag warnings[], int n)
 {
         int flag = WARNING_ON;
         char *p = arg + 1;
         unsigned i;
 

@@ -593,10 +699,11 @@
         if (!strcmp(p, "sparse-all")) {
                 for (i = 0; i < n; i++) {
                         if (*warnings[i].flag != WARNING_FORCE_OFF && warnings[i].flag != &Wsparse_error)
                                 *warnings[i].flag = WARNING_ON;
                 }
+                return NULL;
         }
 
         // Prefixes "no" and "no-" mean to turn warning off.
         if (p[0] == 'n' && p[1] == 'o') {
                 p += 2;

@@ -624,13 +731,17 @@
 
         // Unknown.
         return next;
 }
 
-static struct warning debugs[] = {
-        { "entry", &dbg_entry},
+static struct flag debugs[] = {
+        { "compound", &dbg_compound},
         { "dead", &dbg_dead},
+        { "domtree", &dbg_domtree},
+        { "entry", &dbg_entry},
+        { "ir", &dbg_ir},
+        { "postorder", &dbg_postorder},
 };
 
 
 static char **handle_switch_v(char *arg, char **next)
 {

@@ -643,25 +754,43 @@
                 verbose++;
         } while (*++arg == 'v');
         return next;
 }
 
-static struct warning dumps[] = {
-        { "D", &dump_macro_defs},
-};
-
 static char **handle_switch_d(char *arg, char **next)
 {
-        char ** ret = handle_onoff_switch(arg, next, dumps, ARRAY_SIZE(dumps));
-        if (ret)
-                return ret;
+        char *arg_char = arg + 1;
 
+        /*
+         * -d<CHARS>, where <CHARS> is a sequence of characters, not preceded
+         * by a space. If you specify characters whose behaviour conflicts,
+         * the result is undefined.
+         */
+        while (*arg_char) {
+                switch (*arg_char) {
+                case 'M': /* dump just the macro definitions */
+                        dump_macros_only = 1;
+                        dump_macro_defs = 0;
+                        break;
+                case 'D': /* like 'M', but also output pre-processed text */
+                        dump_macro_defs = 1;
+                        dump_macros_only = 0;
+                        break;
+                case 'N': /* like 'D', but only output macro names not bodies */
+                        break;
+                case 'I': /* like 'D', but also output #include directives */
+                        break;
+                case 'U': /* like 'D', but only output expanded macros */
+                        break;
+                }
+                arg_char++;
+        }
         return next;
 }
 
 
-static void handle_onoff_switch_finalize(const struct warning warnings[], int n)
+static void handle_onoff_switch_finalize(const struct flag warnings[], int n)
 {
         unsigned i;
 
         for (i = 0; i < n; i++) {
                 if (*warnings[i].flag == WARNING_FORCE_OFF)

@@ -715,92 +844,119 @@
 static char **handle_switch_O(char *arg, char **next)
 {
         int level = 1;
         if (arg[1] >= '0' && arg[1] <= '9')
                 level = arg[1] - '0';
-        optimize = level;
+        optimize_level = level;
         optimize_size = arg[1] == 's';
         return next;
 }
 
-static char **handle_switch_fmemcpy_max_count(char *arg, char **next)
+static int handle_ftabstop(const char *arg, const char *opt, const struct flag *flag, int options)
 {
-        unsigned long long val;
+        unsigned long val;
         char *end;
 
-        val = strtoull(arg, &end, 0);
-        if (*end != '\0' || end == arg)
-                die("error: missing argument to \"-fmemcpy-max-count=\"");
+        if (*opt == '\0')
+                die("error: missing argument to \"%s\"", arg);
 
-        if (val == 0)
-                val = ~0ULL;
-        fmemcpy_max_count = val;
-        return next;
-}
-
-static char **handle_switch_ftabstop(char *arg, char **next)
-{
-        char *end;
-        unsigned long val;
-
-        if (*arg == '\0')
-                die("error: missing argument to \"-ftabstop=\"");
-
         /* we silently ignore silly values */
-        val = strtoul(arg, &end, 10);
+        val = strtoul(opt, &end, 10);
         if (*end == '\0' && 1 <= val && val <= 100)
                 tabstop = val;
 
-        return next;
+        return 1;
 }
 
-static int funsigned_char;
-static void handle_funsigned_char(void)
+static int handle_fpasses(const char *arg, const char *opt, const struct flag *flag, int options)
 {
-        if (funsigned_char) {
-                char_ctype.ctype.modifiers &= ~MOD_SIGNED;
-                char_ctype.ctype.modifiers |= MOD_UNSIGNED;
+        unsigned long mask;
+
+        mask = flag->mask;
+        if (*opt == '\0') {
+                if (options & OPT_INVERSE)
+                        fpasses &= ~mask;
+                else
+                        fpasses |=  mask;
+                return 1;
         }
+        if (options & OPT_INVERSE)
+                return 0;
+        if (!strcmp(opt, "-enable")) {
+                fpasses |= mask;
+                return 1;
+        }
+        if (!strcmp(opt, "-disable")) {
+                fpasses &= ~mask;
+                return 1;
+        }
+        if (!strcmp(opt, "=last")) {
+                // clear everything above
+                mask |= mask - 1;
+                fpasses &= mask;
+                return 1;
+        }
+        return 0;
 }
 
-        static char **handle_switch_fdump(char *arg, char **next)
+static int handle_fdiagnostic_prefix(const char *arg, const char *opt, const struct flag *flag, int options)
 {
-        if (!strncmp(arg, "linearize", 9)) {
-                arg += 9;
-                if (*arg == '\0')
-                        fdump_linearize = 1;
-                else if (!strcmp(arg, "=only"))
-                        fdump_linearize = 2;
-                else
-                        goto err;
+        switch (*opt) {
+        case '\0':
+                diag_prefix = "sparse";
+                return 1;
+        case '=':
+                diag_prefix = xasprintf("%s", opt+1);
+                return 1;
+        default:
+                return 0;
         }
+}
 
-        /* ignore others flags */
-        return next;
+static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options)
+{
+        static const struct mask_map dump_ir_options[] = {
+                { "",                   PASS_LINEARIZE },
+                { "linearize",          PASS_LINEARIZE },
+                { "mem2reg",            PASS_MEM2REG },
+                { "final",              PASS_FINAL },
+                { },
+        };
 
-err:
-        die("error: unknown flag \"-fdump-%s\"", arg);
+        return handle_suboption_mask(arg, opt, dump_ir_options, &fdump_ir);
 }
 
-static char **handle_switch_f(char *arg, char **next)
+static int handle_fmemcpy_max_count(const char *arg, const char *opt, const struct flag *flag, int options)
 {
-        arg++;
+        opt_ullong(arg, opt, &fmemcpy_max_count, OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED);
+        return 1;
+}
 
-        if (!strncmp(arg, "tabstop=", 8))
-                return handle_switch_ftabstop(arg+8, next);
-        if (!strncmp(arg, "dump-", 5))
-                return handle_switch_fdump(arg+5, next);
-        if (!strncmp(arg, "memcpy-max-count=", 17))
-                return handle_switch_fmemcpy_max_count(arg+17, next);
+static int handle_fmax_warnings(const char *arg, const char *opt, const struct flag *flag, int options)
+{
+        opt_uint(arg, opt, &fmax_warnings, OPTNUM_UNLIMITED);
+        return 1;
+}
 
-        if (!strcmp(arg, "unsigned-char")) {
-                funsigned_char = 1;
-                return next;
-        }
+static struct flag fflags[] = {
+        { "diagnostic-prefix",  NULL,   handle_fdiagnostic_prefix },
+        { "dump-ir",            NULL,   handle_fdump_ir },
+        { "linearize",          NULL,   handle_fpasses, PASS_LINEARIZE },
+        { "max-warnings=",      NULL,   handle_fmax_warnings },
+        { "mem-report",         &fmem_report },
+        { "memcpy-max-count=",  NULL,   handle_fmemcpy_max_count },
+        { "tabstop=",           NULL,   handle_ftabstop },
+        { "mem2reg",            NULL,   handle_fpasses, PASS_MEM2REG },
+        { "optim",              NULL,   handle_fpasses, PASS_OPTIM },
+        { "signed-char",        &funsigned_char, NULL,  OPT_INVERSE },
+        { "unsigned-char",      &funsigned_char, NULL, },
+        { },
+};
 
-        /* handle switches w/ arguments above, boolean and only boolean below */
-        if (handle_simple_switch(arg, "mem-report", &fmem_report))
+static char **handle_switch_f(char *arg, char **next)
+{
+        if (handle_switches(arg-1, arg+1, fflags))
                 return next;
 
         return next;
 }
 

@@ -818,16 +974,13 @@
                 standard = STANDARD_C89;
 
         return next;
 }
 
-static char **handle_switch_s(char *arg, char **next)
+static char **handle_switch_s(const char *arg, char **next)
 {
-        if (!strncmp (arg, "std=", 4))
-        {
-                arg += 4;
-
+        if ((arg = match_option(arg, "std="))) {
                 if (!strcmp (arg, "c89") ||
                     !strcmp (arg, "iso9899:1990"))
                         standard = STANDARD_C89;
 
                 else if (!strcmp (arg, "iso9899:199409"))

@@ -894,10 +1047,17 @@
                 return handle_base_dir(arg, next);
 
         return next;
 }
 
+static char **handle_switch_x(char *arg, char **next)
+{
+        if (!*++next)
+                die("missing argument for -x option");
+        return next;
+}
+
 static char **handle_version(char *arg, char **next)
 {
         printf("%s\n", SPARSE_VERSION);
         exit(0);
 }

@@ -908,11 +1068,10 @@
 
         /* Ignore smatch's --param-mapper */
         if (strcmp(arg, "-mapper") == 0)
                 return next;
 
-
         /* For now just skip any '--param=*' or '--param *' */
         if (*arg == '\0') {
                 value = *++next;
         } else if (isspace((unsigned char)*arg) || *arg == '=') {
                 value = ++arg;

@@ -970,10 +1129,11 @@
         case 'O': return handle_switch_O(arg, next);
         case 's': return handle_switch_s(arg, next);
         case 'U': return handle_switch_U(arg, next);
         case 'v': return handle_switch_v(arg, next);
         case 'W': return handle_switch_W(arg, next);
+        case 'x': return handle_switch_x(arg, next);
         case '-': return handle_long_options(arg + 1, next);
         default:
                 break;
         }
 

@@ -982,250 +1142,287 @@
          * they're probably gcc switches
          */
         return next;
 }
 
-static void predefined_sizeof(const char *name, unsigned bits)
+#define PTYPE_SIZEOF    (1U << 0)
+#define PTYPE_T         (1U << 1)
+#define PTYPE_MAX       (1U << 2)
+#define PTYPE_MIN       (1U << 3)
+#define PTYPE_WIDTH     (1U << 4)
+#define PTYPE_TYPE      (1U << 5)
+#define PTYPE_ALL       (PTYPE_MAX|PTYPE_SIZEOF|PTYPE_WIDTH)
+#define PTYPE_ALL_T     (PTYPE_MAX|PTYPE_SIZEOF|PTYPE_WIDTH|PTYPE_T)
+
+static void predefined_sizeof(const char *name, const char *suffix, unsigned bits)
 {
-        add_pre_buffer("#weak_define __SIZEOF_%s__ %d\n", name, bits/8);
+        char buf[32];
+
+        snprintf(buf, sizeof(buf), "__SIZEOF_%s%s__", name, suffix);
+        predefine(buf, 1, "%d", bits/8);
 }
 
-static void predefined_max(const char *name, const char *suffix, unsigned bits)
+static void predefined_width(const char *name, unsigned bits)
 {
-        unsigned long long max = (1ULL << (bits - 1 )) - 1;
+        char buf[32];
 
-        add_pre_buffer("#weak_define __%s_MAX__ %#llx%s\n", name, max, suffix);
+        snprintf(buf, sizeof(buf), "__%s_WIDTH__", name);
+        predefine(buf, 1, "%d", bits);
 }
 
-static void predefined_type_size(const char *name, const char *suffix, unsigned bits)
+static void predefined_max(const char *name, struct symbol *type)
 {
-        predefined_max(name, suffix, bits);
-        predefined_sizeof(name, bits);
+        const char *suffix = builtin_type_suffix(type);
+        unsigned bits = type->bit_size - is_signed_type(type);
+        unsigned long long max = bits_mask(bits);
+        char buf[32];
+
+        snprintf(buf, sizeof(buf), "__%s_MAX__", name);
+        predefine(buf, 1, "%#llx%s", max, suffix);
 }
 
-static void predefined_macros(void)
+static void predefined_min(const char *name, struct symbol *type)
 {
-        add_pre_buffer("#define __CHECKER__ 1\n");
+        const char *suffix = builtin_type_suffix(type);
+        char buf[32];
 
-        predefined_sizeof("SHORT", bits_in_short);
-        predefined_max("SHRT", "", bits_in_short);
-        predefined_max("SCHAR", "", bits_in_char);
-        predefined_max("WCHAR", "", bits_in_wchar);
-        add_pre_buffer("#weak_define __CHAR_BIT__ %d\n", bits_in_char);
+        snprintf(buf, sizeof(buf), "__%s_MIN__", name);
 
-        predefined_type_size("INT", "", bits_in_int);
-        predefined_type_size("LONG", "L", bits_in_long);
-        predefined_type_size("LONG_LONG", "LL", bits_in_longlong);
+        if (is_signed_type(type))
+                predefine(buf, 1, "(-__%s_MAX__ - 1)", name);
+        else
+                predefine(buf, 1, "0%s", suffix);
+}
 
-        predefined_sizeof("INT128", 128);
+static void predefined_type(const char *name, struct symbol *type)
+{
+        const char *typename = builtin_typename(type);
+        add_pre_buffer("#weak_define __%s_TYPE__ %s\n", name, typename);
+}
 
-        predefined_sizeof("SIZE_T", bits_in_pointer);
-        predefined_sizeof("PTRDIFF_T", bits_in_pointer);
-        predefined_sizeof("POINTER", bits_in_pointer);
+static void predefined_ctype(const char *name, struct symbol *type, int flags)
+{
+        unsigned bits = type->bit_size;
 
-        predefined_sizeof("FLOAT", bits_in_float);
-        predefined_sizeof("DOUBLE", bits_in_double);
-        predefined_sizeof("LONG_DOUBLE", bits_in_longdouble);
+        if (flags & PTYPE_SIZEOF) {
+                const char *suffix = (flags & PTYPE_T) ? "_T" : "";
+                predefined_sizeof(name, suffix, bits);
+        }
+        if (flags & PTYPE_MAX)
+                predefined_max(name, type);
+        if (flags & PTYPE_MIN)
+                predefined_min(name, type);
+        if (flags & PTYPE_TYPE)
+                predefined_type(name, type);
+        if (flags & PTYPE_WIDTH)
+                predefined_width(name, bits);
+}
 
-        add_pre_buffer("#weak_define __%s_ENDIAN__ 1\n",
-                arch_big_endian ? "BIG" : "LITTLE");
+static void predefined_macros(void)
+{
+        predefine("__CHECKER__", 0, "1");
+        predefine("__GNUC__", 1, "%d", gcc_major);
+        predefine("__GNUC_MINOR__", 1, "%d", gcc_minor);
+        predefine("__GNUC_PATCHLEVEL__", 1, "%d", gcc_patchlevel);
 
-        add_pre_buffer("#weak_define __ORDER_LITTLE_ENDIAN__ 1234\n");
-        add_pre_buffer("#weak_define __ORDER_BIG_ENDIAN__ 4321\n");
-        add_pre_buffer("#weak_define __ORDER_PDP_ENDIAN__ 3412\n");
-        add_pre_buffer("#weak_define __BYTE_ORDER__ __ORDER_%s_ENDIAN__\n",
-                arch_big_endian ? "BIG" : "LITTLE");
+        predefine("__STDC__", 1, "1");
+        switch (standard) {
+        case STANDARD_C89:
+                predefine("__STRICT_ANSI__", 1, "1");
+                break;
 
-        add_pre_buffer("#weak_define __PRAGMA_REDEFINE_EXTNAME 1\n");
+        case STANDARD_C94:
+                predefine("__STDC_VERSION__", 1, "199409L");
+                predefine("__STRICT_ANSI__", 1, "1");
+                break;
 
-        /*
-         * This is far from perfect...
-         */
-#ifdef  __sun
-        add_pre_buffer("#weak_define __unix__ 1\n");
-        add_pre_buffer("#weak_define __unix 1\n");
-        add_pre_buffer("#weak_define unix 1\n");
-        add_pre_buffer("#weak_define __sun__ 1\n");
-        add_pre_buffer("#weak_define __sun 1\n");
-        add_pre_buffer("#weak_define sun 1\n");
-        add_pre_buffer("#weak_define __svr4__ 1\n");
-#endif
-}
+        case STANDARD_C99:
+                predefine("__STDC_VERSION__", 1, "199901L");
+                predefine("__STRICT_ANSI__", 1, "1");
+                break;
 
-void declare_builtin_functions(void)
-{
-        /* Gaah. gcc knows tons of builtin <string.h> functions */
-        add_pre_buffer("extern void *__builtin_memchr(const void *, int, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern void *__builtin_memcpy(void *, const void *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern void *__builtin_mempcpy(void *, const void *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern void *__builtin_memmove(void *, const void *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern void *__builtin_memset(void *, int, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern int __builtin_memcmp(const void *, const void *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern char *__builtin_strcat(char *, const char *);\n");
-        add_pre_buffer("extern char *__builtin_strncat(char *, const char *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern int __builtin_strcmp(const char *, const char *);\n");
-        add_pre_buffer("extern int __builtin_strncmp(const char *, const char *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern int __builtin_strcasecmp(const char *, const char *);\n");
-        add_pre_buffer("extern int __builtin_strncasecmp(const char *, const char *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern char *__builtin_strchr(const char *, int);\n");
-        add_pre_buffer("extern char *__builtin_strrchr(const char *, int);\n");
-        add_pre_buffer("extern char *__builtin_strcpy(char *, const char *);\n");
-        add_pre_buffer("extern char *__builtin_strncpy(char *, const char *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern char *__builtin_strdup(const char *);\n");
-        add_pre_buffer("extern char *__builtin_strndup(const char *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern __SIZE_TYPE__ __builtin_strspn(const char *, const char *);\n");
-        add_pre_buffer("extern __SIZE_TYPE__ __builtin_strcspn(const char *, const char *);\n");
-        add_pre_buffer("extern char * __builtin_strpbrk(const char *, const char *);\n");
-        add_pre_buffer("extern char* __builtin_stpcpy(const char *, const char*);\n");
-        add_pre_buffer("extern char* __builtin_stpncpy(const char *, const char*, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern __SIZE_TYPE__ __builtin_strlen(const char *);\n");
-        add_pre_buffer("extern char *__builtin_strstr(const char *, const char *);\n");
-        add_pre_buffer("extern char *__builtin_strcasestr(const char *, const char *);\n");
-        add_pre_buffer("extern char *__builtin_strnstr(const char *, const char *, __SIZE_TYPE__);\n");
+        case STANDARD_GNU89:
+        default:
+                break;
 
-        /* And even some from <strings.h> */
-        add_pre_buffer("extern int  __builtin_bcmp(const void *, const void *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern void __builtin_bcopy(const void *, void *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern void __builtin_bzero(void *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern char*__builtin_index(const char *, int);\n");
-        add_pre_buffer("extern char*__builtin_rindex(const char *, int);\n");
+        case STANDARD_GNU99:
+                predefine("__STDC_VERSION__", 1, "199901L");
+                break;
 
-        /* And bitwise operations.. */
-        add_pre_buffer("extern int __builtin_clrsb(int);\n");
-        add_pre_buffer("extern int __builtin_clrsbl(long);\n");
-        add_pre_buffer("extern int __builtin_clrsbll(long long);\n");
-        add_pre_buffer("extern int __builtin_clz(int);\n");
-        add_pre_buffer("extern int __builtin_clzl(long);\n");
-        add_pre_buffer("extern int __builtin_clzll(long long);\n");
-        add_pre_buffer("extern int __builtin_ctz(int);\n");
-        add_pre_buffer("extern int __builtin_ctzl(long);\n");
-        add_pre_buffer("extern int __builtin_ctzll(long long);\n");
-        add_pre_buffer("extern int __builtin_ffs(int);\n");
-        add_pre_buffer("extern int __builtin_ffsl(long);\n");
-        add_pre_buffer("extern int __builtin_ffsll(long long);\n");
-        add_pre_buffer("extern int __builtin_parity(unsigned int);\n");
-        add_pre_buffer("extern int __builtin_parityl(unsigned long);\n");
-        add_pre_buffer("extern int __builtin_parityll(unsigned long long);\n");
-        add_pre_buffer("extern int __builtin_popcount(unsigned int);\n");
-        add_pre_buffer("extern int __builtin_popcountl(unsigned long);\n");
-        add_pre_buffer("extern int __builtin_popcountll(unsigned long long);\n");
+        case STANDARD_C11:
+                predefine("__STRICT_ANSI__", 1, "1");
+        case STANDARD_GNU11:
+                predefine("__STDC_NO_ATOMICS__", 1, "1");
+                predefine("__STDC_NO_COMPLEX__", 1, "1");
+                predefine("__STDC_NO_THREADS__", 1, "1");
+                predefine("__STDC_VERSION__", 1, "201112L");
+                break;
+        }
 
-        /* And byte swaps.. */
-        add_pre_buffer("extern unsigned short __builtin_bswap16(unsigned short);\n");
-        add_pre_buffer("extern unsigned int __builtin_bswap32(unsigned int);\n");
-        add_pre_buffer("extern unsigned long long __builtin_bswap64(unsigned long long);\n");
+        predefine("__CHAR_BIT__", 1, "%d", bits_in_char);
+        if (funsigned_char)
+                predefine("__CHAR_UNSIGNED__", 1, "1");
 
-        /* And atomic memory access functions.. */
-        add_pre_buffer("extern int __sync_fetch_and_add(void *, ...);\n");
-        add_pre_buffer("extern int __sync_fetch_and_sub(void *, ...);\n");
-        add_pre_buffer("extern int __sync_fetch_and_or(void *, ...);\n");
-        add_pre_buffer("extern int __sync_fetch_and_and(void *, ...);\n");
-        add_pre_buffer("extern int __sync_fetch_and_xor(void *, ...);\n");
-        add_pre_buffer("extern int __sync_fetch_and_nand(void *, ...);\n");
-        add_pre_buffer("extern int __sync_add_and_fetch(void *, ...);\n");
-        add_pre_buffer("extern int __sync_sub_and_fetch(void *, ...);\n");
-        add_pre_buffer("extern int __sync_or_and_fetch(void *, ...);\n");
-        add_pre_buffer("extern int __sync_and_and_fetch(void *, ...);\n");
-        add_pre_buffer("extern int __sync_xor_and_fetch(void *, ...);\n");
-        add_pre_buffer("extern int __sync_nand_and_fetch(void *, ...);\n");
-        add_pre_buffer("extern int __sync_bool_compare_and_swap(void *, ...);\n");
-        add_pre_buffer("extern int __sync_val_compare_and_swap(void *, ...);\n");
-        add_pre_buffer("extern void __sync_synchronize();\n");
-        add_pre_buffer("extern int __sync_lock_test_and_set(void *, ...);\n");
-        add_pre_buffer("extern void __sync_lock_release(void *, ...);\n");
+        predefined_ctype("SHORT",     &short_ctype, PTYPE_SIZEOF);
+        predefined_ctype("SHRT",      &short_ctype, PTYPE_MAX|PTYPE_WIDTH);
+        predefined_ctype("SCHAR",     &schar_ctype, PTYPE_MAX|PTYPE_WIDTH);
+        predefined_ctype("WCHAR",      wchar_ctype, PTYPE_ALL_T|PTYPE_MIN|PTYPE_TYPE);
+        predefined_ctype("WINT",        wint_ctype, PTYPE_ALL_T|PTYPE_MIN|PTYPE_TYPE);
+        predefined_ctype("CHAR16",   &ushort_ctype, PTYPE_TYPE);
+        predefined_ctype("CHAR32",     &uint_ctype, PTYPE_TYPE);
 
-        /* And some random ones.. */
-        add_pre_buffer("extern void *__builtin_return_address(unsigned int);\n");
-        add_pre_buffer("extern void *__builtin_extract_return_addr(void *);\n");
-        add_pre_buffer("extern void *__builtin_frame_address(unsigned int);\n");
-        add_pre_buffer("extern void __builtin_trap(void);\n");
-        add_pre_buffer("extern void *__builtin_alloca(__SIZE_TYPE__);\n");
-        add_pre_buffer("extern void __builtin_prefetch (const void *, ...);\n");
-        add_pre_buffer("extern long __builtin_alpha_extbl(long, long);\n");
-        add_pre_buffer("extern long __builtin_alpha_extwl(long, long);\n");
-        add_pre_buffer("extern long __builtin_alpha_insbl(long, long);\n");
-        add_pre_buffer("extern long __builtin_alpha_inswl(long, long);\n");
-        add_pre_buffer("extern long __builtin_alpha_insql(long, long);\n");
-        add_pre_buffer("extern long __builtin_alpha_inslh(long, long);\n");
-        add_pre_buffer("extern long __builtin_alpha_cmpbge(long, long);\n");
-        add_pre_buffer("extern int  __builtin_abs(int);\n");
-        add_pre_buffer("extern long __builtin_labs(long);\n");
-        add_pre_buffer("extern long long __builtin_llabs(long long);\n");
-        add_pre_buffer("extern double __builtin_fabs(double);\n");
-        add_pre_buffer("extern __SIZE_TYPE__ __builtin_va_arg_pack_len(void);\n");
+        predefined_ctype("INT",         &int_ctype, PTYPE_ALL);
+        predefined_ctype("LONG",       &long_ctype, PTYPE_ALL);
+        predefined_ctype("LONG_LONG", &llong_ctype, PTYPE_ALL);
 
-        /* Add Blackfin-specific stuff */
-        add_pre_buffer(
-                "#ifdef __bfin__\n"
-                "extern void __builtin_bfin_csync(void);\n"
-                "extern void __builtin_bfin_ssync(void);\n"
-                "extern int __builtin_bfin_norm_fr1x32(int);\n"
-                "#endif\n"
-        );
+        predefined_ctype("INT8",      &schar_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("UINT8",     &uchar_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("INT16",     &short_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("UINT16",   &ushort_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("INT32",      int32_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("UINT32",    uint32_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("INT64",      int64_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("UINT64",    uint64_ctype, PTYPE_MAX|PTYPE_TYPE);
 
-        /* And some floating point stuff.. */
-        add_pre_buffer("extern int __builtin_isgreater(float, float);\n");
-        add_pre_buffer("extern int __builtin_isgreaterequal(float, float);\n");
-        add_pre_buffer("extern int __builtin_isless(float, float);\n");
-        add_pre_buffer("extern int __builtin_islessequal(float, float);\n");
-        add_pre_buffer("extern int __builtin_islessgreater(float, float);\n");
-        add_pre_buffer("extern int __builtin_isunordered(float, float);\n");
+        predefined_sizeof("INT128", "", 128);
 
-        /* And some INFINITY / NAN stuff.. */
-        add_pre_buffer("extern double __builtin_huge_val(void);\n");
-        add_pre_buffer("extern float __builtin_huge_valf(void);\n");
-        add_pre_buffer("extern long double __builtin_huge_vall(void);\n");
-        add_pre_buffer("extern double __builtin_inf(void);\n");
-        add_pre_buffer("extern float __builtin_inff(void);\n");
-        add_pre_buffer("extern long double __builtin_infl(void);\n");
-        add_pre_buffer("extern double __builtin_nan(const char *);\n");
-        add_pre_buffer("extern float __builtin_nanf(const char *);\n");
-        add_pre_buffer("extern long double __builtin_nanl(const char *);\n");
-        add_pre_buffer("extern int __builtin_isinf_sign(float);\n");
-        add_pre_buffer("extern int __builtin_isfinite(float);\n");
-        add_pre_buffer("extern int __builtin_isnan(float);\n");
+        predefined_ctype("INTMAX",    intmax_ctype, PTYPE_MAX|PTYPE_TYPE|PTYPE_WIDTH);
+        predefined_ctype("UINTMAX",  uintmax_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("INTPTR",   ssize_t_ctype, PTYPE_MAX|PTYPE_TYPE|PTYPE_WIDTH);
+        predefined_ctype("UINTPTR",   size_t_ctype, PTYPE_MAX|PTYPE_TYPE);
+        predefined_ctype("PTRDIFF",  ssize_t_ctype, PTYPE_ALL_T|PTYPE_TYPE);
+        predefined_ctype("SIZE",      size_t_ctype, PTYPE_ALL_T|PTYPE_TYPE);
+        predefined_ctype("POINTER",     &ptr_ctype, PTYPE_SIZEOF);
 
-        /* And some __FORTIFY_SOURCE ones.. */
-        add_pre_buffer ("extern __SIZE_TYPE__ __builtin_object_size(const void *, int);\n");
-        add_pre_buffer ("extern void * __builtin___memcpy_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern void * __builtin___memmove_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern void * __builtin___mempcpy_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern void * __builtin___memset_chk(void *, int, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern int __builtin___sprintf_chk(char *, int, __SIZE_TYPE__, const char *, ...);\n");
-        add_pre_buffer ("extern int __builtin___snprintf_chk(char *, __SIZE_TYPE__, int , __SIZE_TYPE__, const char *, ...);\n");
-        add_pre_buffer ("extern char * __builtin___stpcpy_chk(char *, const char *, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern char * __builtin___strcat_chk(char *, const char *, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern char * __builtin___strcpy_chk(char *, const char *, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern char * __builtin___strncat_chk(char *, const char *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern char * __builtin___strncpy_chk(char *, const char *, __SIZE_TYPE__, __SIZE_TYPE__);\n");
-        add_pre_buffer ("extern int __builtin___vsprintf_chk(char *, int, __SIZE_TYPE__, const char *, __builtin_va_list);\n");
-        add_pre_buffer ("extern int __builtin___vsnprintf_chk(char *, __SIZE_TYPE__, int, __SIZE_TYPE__, const char *, __builtin_va_list ap);\n");
-        add_pre_buffer ("extern void __builtin_unreachable(void);\n");
+        predefined_sizeof("FLOAT", "", bits_in_float);
+        predefined_sizeof("DOUBLE", "", bits_in_double);
+        predefined_sizeof("LONG_DOUBLE", "", bits_in_longdouble);
 
-        /* And some from <stdlib.h> */
-        add_pre_buffer("extern void __builtin_abort(void);\n");
-        add_pre_buffer("extern void *__builtin_calloc(__SIZE_TYPE__, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern void __builtin_exit(int);\n");
-        add_pre_buffer("extern void *__builtin_malloc(__SIZE_TYPE__);\n");
-        add_pre_buffer("extern void *__builtin_realloc(void *, __SIZE_TYPE__);\n");
-        add_pre_buffer("extern void __builtin_free(void *);\n");
+        predefine("__ORDER_LITTLE_ENDIAN__", 1, "1234");
+        predefine("__ORDER_BIG_ENDIAN__", 1, "4321");
+        predefine("__ORDER_PDP_ENDIAN__", 1, "3412");
+        if (arch_big_endian) {
+                predefine("__BIG_ENDIAN__", 1, "1");
+                predefine("__BYTE_ORDER__", 1, "__ORDER_BIG_ENDIAN__");
+        } else {
+                predefine("__LITTLE_ENDIAN__", 1, "1");
+                predefine("__BYTE_ORDER__", 1, "__ORDER_LITTLE_ENDIAN__");
+        }
 
-        /* And some from <stdio.h> */
-        add_pre_buffer("extern int __builtin_printf(const char *, ...);\n");
-        add_pre_buffer("extern int __builtin_sprintf(char *, const char *, ...);\n");
-        add_pre_buffer("extern int __builtin_snprintf(char *, __SIZE_TYPE__, const char *, ...);\n");
-        add_pre_buffer("extern int __builtin_puts(const char *);\n");
-        add_pre_buffer("extern int __builtin_vprintf(const char *, __builtin_va_list);\n");
-        add_pre_buffer("extern int __builtin_vsprintf(char *, const char *, __builtin_va_list);\n");
-        add_pre_buffer("extern int __builtin_vsnprintf(char *, __SIZE_TYPE__, const char *, __builtin_va_list ap);\n");
+        if (optimize_level)
+                predefine("__OPTIMIZE__", 0, "1");
+        if (optimize_size)
+                predefine("__OPTIMIZE_SIZE__", 0, "1");
+
+        // Temporary hacks
+        predefine("__extension__", 0, NULL);
+        predefine("__pragma__", 0, NULL);
+
+        switch (arch_m64) {
+        case ARCH_LP32:
+                break;
+        case ARCH_X32:
+                predefine("__ILP32__", 1, "1");
+                predefine("_ILP32", 1, "1");
+                break;
+        case ARCH_LP64:
+                predefine("__LP64__", 1, "1");
+                predefine("__LP64", 1, "1");
+                predefine("_LP64", 1, "1");
+                break;
+        case ARCH_LLP64:
+                predefine("__LLP64__", 1, "1");
+                break;
+        }
+
+        switch (arch_mach) {
+        case MACH_ARM64:
+                predefine("__aarch64__", 1, "1");
+                break;
+        case MACH_ARM:
+                predefine("__arm__", 1, "1");
+                break;
+        case MACH_M68K:
+                predefine("__m68k__", 1, "1");
+                break;
+        case MACH_MIPS64:
+                if (arch_m64 == ARCH_LP64)
+                        predefine("__mips64", 1, "64");
+                /* fall-through */
+        case MACH_MIPS32:
+                predefine("__mips", 1, "%d", ptr_ctype.bit_size);
+                predefine("_MIPS_SZINT", 1, "%d", int_ctype.bit_size);
+                predefine("_MIPS_SZLONG", 1, "%d", long_ctype.bit_size);
+                predefine("_MIPS_SZPTR", 1, "%d", ptr_ctype.bit_size);
+                break;
+        case MACH_PPC64:
+                if (arch_m64 == ARCH_LP64) {
+                        predefine("__powerpc64__", 1, "1");
+                        predefine("__ppc64__", 1, "1");
+                        predefine("__PPC64__", 1, "1");
+                }
+                /* fall-through */
+        case MACH_PPC32:
+                predefine("__powerpc__", 1, "1");
+                predefine("__powerpc", 1, "1");
+                predefine("__ppc__", 1, "1");
+                predefine("__PPC__", 1, "1");
+                break;
+        case MACH_RISCV64:
+        case MACH_RISCV32:
+                predefine("__riscv", 1, "1");
+                predefine("__riscv_xlen", 1, "%d", ptr_ctype.bit_size);
+                break;
+        case MACH_S390X:
+                predefine("__zarch__", 1, "1");
+                predefine("__s390x__", 1, "1");
+                predefine("__s390__", 1, "1");
+                break;
+        case MACH_SPARC64:
+                if (arch_m64 == ARCH_LP64) {
+                        predefine("__sparc_v9__", 1, "1");
+                        predefine("__sparcv9__", 1, "1");
+                        predefine("__sparcv9", 1, "1");
+                        predefine("__sparc64__", 1, "1");
+                        predefine("__arch64__", 1, "1");
+                }
+                /* fall-through */
+        case MACH_SPARC32:
+                predefine("__sparc__", 1, "1");
+                predefine("__sparc", 1, "1");
+                break;
+        case MACH_X86_64:
+                if (arch_m64 != ARCH_LP32) {
+                        predefine("__x86_64__", 1, "1");
+                        predefine("__x86_64", 1, "1");
+                        break;
+                }
+                /* fall-through */
+        case MACH_I386:
+                predefine("__i386__", 1, "1");
+                predefine("__i386", 1, "1");
+                predefine("i386", 1, "1");
+                break;
+        }
+
+        predefine("__PRAGMA_REDEFINE_EXTNAME", 1, "1");
+
+#ifdef  __sun
+        predefine("__unix__", 1, "1");
+        predefine("__unix", 1, "1");
+        predefine("unix", 1, "1");
+        predefine("__sun__", 1, "1");
+        predefine("__sun", 1, "1");
+        predefine("sun", 1, "1");
+        predefine("__svr4__", 1, "1");
+#endif
 }
 
-void create_builtin_stream(void)
+static void create_builtin_stream(void)
 {
-        add_pre_buffer("#weak_define __GNUC__ %d\n", gcc_major);
-        add_pre_buffer("#weak_define __GNUC_MINOR__ %d\n", gcc_minor);
-        add_pre_buffer("#weak_define __GNUC_PATCHLEVEL__ %d\n", gcc_patchlevel);
+        // Temporary hack
+        add_pre_buffer("#define _Pragma(x)\n");
 
         /* add the multiarch include directories, if any */
         if (multiarch_dir && *multiarch_dir) {
                 add_pre_buffer("#add_system \"/usr/include/%s\"\n", multiarch_dir);
                 add_pre_buffer("#add_system \"/usr/local/include/%s\"\n", multiarch_dir);

@@ -1234,61 +1431,12 @@
         /* We add compiler headers path here because we have to parse
          * the arguments to get it, falling back to default. */
         add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir);
         add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir);
 
-        add_pre_buffer("#define __extension__\n");
-        add_pre_buffer("#define __pragma__\n");
-        add_pre_buffer("#define _Pragma(x)\n");
-
-        // gcc defines __SIZE_TYPE__ to be size_t.  For linux/i86 and
-        // solaris/sparc that is really "unsigned int" and for linux/x86_64
-        // it is "long unsigned int".  In either case we can probably
-        // get away with this.  We need the #weak_define as cgcc will define
-        // the right __SIZE_TYPE__.
-        if (size_t_ctype == &ulong_ctype)
-                add_pre_buffer("#weak_define __SIZE_TYPE__ long unsigned int\n");
-        else
-                add_pre_buffer("#weak_define __SIZE_TYPE__ unsigned int\n");
-        add_pre_buffer("#weak_define __STDC__ 1\n");
-
-        switch (standard)
-        {
-                case STANDARD_C89:
-                        add_pre_buffer("#weak_define __STRICT_ANSI__\n");
-                        break;
-
-                case STANDARD_C94:
-                        add_pre_buffer("#weak_define __STDC_VERSION__ 199409L\n");
-                        add_pre_buffer("#weak_define __STRICT_ANSI__\n");
-                        break;
-
-                case STANDARD_C99:
-                        add_pre_buffer("#weak_define __STDC_VERSION__ 199901L\n");
-                        add_pre_buffer("#weak_define __STRICT_ANSI__\n");
-                        break;
-
-                case STANDARD_GNU89:
-                        break;
-
-                case STANDARD_GNU99:
-                        add_pre_buffer("#weak_define __STDC_VERSION__ 199901L\n");
-                        break;
-
-                case STANDARD_C11:
-                        add_pre_buffer("#weak_define __STRICT_ANSI__ 1\n");
-                case STANDARD_GNU11:
-                        add_pre_buffer("#weak_define __STDC_NO_ATOMICS__ 1\n");
-                        add_pre_buffer("#weak_define __STDC_NO_COMPLEX__ 1\n");
-                        add_pre_buffer("#weak_define __STDC_NO_THREADS__ 1\n");
-                        add_pre_buffer("#weak_define __STDC_VERSION__ 201112L\n");
-                        break;
-
-                default:
-                        assert (0);
-        }
-
+        add_pre_buffer("#define __has_builtin(x) 0\n");
+        add_pre_buffer("#define __has_attribute(x) 0\n");
         add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
         add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n");
         add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n");
         add_pre_buffer("#define __builtin_va_arg(arg,type)  ({ type __va_arg_ret = *(type *)(arg); arg += sizeof(type); __va_arg_ret; })\n");
         add_pre_buffer("#define __builtin_va_alist (*(void *)0)\n");

@@ -1296,29 +1444,25 @@
         add_pre_buffer("#define __builtin_va_copy(dest, src) ({ dest = src; (void)0; })\n");
         add_pre_buffer("#define __builtin_ms_va_copy(dest, src) ({ dest = src; (void)0; })\n");
         add_pre_buffer("#define __builtin_va_end(arg)\n");
         add_pre_buffer("#define __builtin_ms_va_end(arg)\n");
         add_pre_buffer("#define __builtin_va_arg_pack()\n");
-
-        /* FIXME! We need to do these as special magic macros at expansion time! */
-        add_pre_buffer("#define __BASE_FILE__ \"base_file.c\"\n");
-
-        if (optimize)
-                add_pre_buffer("#define __OPTIMIZE__ 1\n");
-        if (optimize_size)
-                add_pre_buffer("#define __OPTIMIZE_SIZE__ 1\n");
 }
 
 static struct symbol_list *sparse_tokenstream(struct token *token)
 {
         int builtin = token && !token->pos.stream;
 
         // Preprocess the stream
         token = preprocess(token);
 
-        if (dump_macro_defs && !builtin)
+        if (dump_macro_defs || dump_macros_only) {
+                if (!builtin)
                 dump_macro_definitions();
+                if (dump_macros_only)
+                        return NULL;
+        }
 
         if (preprocess_only) {
                 while (!eof_token(token)) {
                         int prec = 1;
                         struct token *next = token->next;

@@ -1355,25 +1499,20 @@
         } else {
                 fd = open(filename, O_RDONLY);
                 if (fd < 0)
                         die("No such file: %s", filename);
         }
+        base_filename = filename;
 
         // Tokenize the input stream
         token = tokenize(filename, fd, NULL, includepath);
         store_all_tokens(token);
         close(fd);
 
         return sparse_tokenstream(token);
 }
 
-static int endswith(const char *str, const char *suffix)
-{
-        const char *found = strstr(str, suffix);
-        return (found && strcmp(found, suffix) == 0);
-}
-
 /*
  * This handles the "-include" directive etc: we're in global
  * scope, and all types/macros etc will affect all the following
  * files.
  *

@@ -1391,20 +1530,26 @@
                 add_pre_buffer("#argv_include \"%s\"\n", cmdline_include[i]);
 
         return sparse_tokenstream(pre_buffer_begin);
 }
 
+static int endswith(const char *str, const char *suffix)
+{
+        const char *found = strstr(str, suffix);
+        return (found && strcmp(found, suffix) == 0);
+}
+
 struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **filelist)
 {
         char **args;
         struct symbol_list *list;
 
         // Initialize symbol stream first, so that we can add defines etc
         init_symbols();
         init_include_path();
 
-        progname = argv[0];
+        diag_prefix = argv[0];
 
         args = argv;
         for (;;) {
                 char *arg = *++args;
                 if (!arg)

@@ -1417,27 +1562,36 @@
 
                 if (endswith(arg, ".a") || endswith(arg, ".so") ||
                     endswith(arg, ".so.1") || endswith(arg, ".o"))
                         continue;
 
-                add_ptr_list_notag(filelist, arg);
+                add_ptr_list(filelist, arg);
         }
         handle_switch_W_finalize();
         handle_switch_v_finalize();
 
-        handle_arch_finalize();
+        // Redirect stdout if needed
+        if (dump_macro_defs || preprocess_only)
+                do_output = 1;
+        if (do_output && outfile && strcmp(outfile, "-")) {
+                if (!freopen(outfile, "w", stdout))
+                        die("error: cannot open %s: %s", outfile, strerror(errno));
+        }
 
+        if (fdump_ir == 0)
+                fdump_ir = PASS_FINAL;
+
         list = NULL;
-        if (!ptr_list_empty(filelist)) {
+        if (filelist) {
                 // Initialize type system
+                init_target();
+                handle_arch_finalize();
                 init_ctype();
-                handle_funsigned_char();
 
-                create_builtin_stream();
                 predefined_macros();
-                if (!preprocess_only)
-                        declare_builtin_functions();
+                create_builtin_stream();
+                declare_builtins();
 
                 list = sparse_initial();
 
                 /*
                  * Protect the initial token allocations, since