diff --git a/libtcc.c b/libtcc.c
index 72f53c0a..bf137248 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -634,11 +634,9 @@ static int tcc_compile(TCCState *s1)
 
         preprocess_start(s1);
         tccgen_start(s1);
-
 #ifdef INC_DEBUG
         printf("%s: **** new file\n", file->filename);
 #endif
-
         ch = file->buf_ptr[0];
         tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
         parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;
@@ -1801,6 +1799,8 @@ reparse:
                 s->dflag = 3;
             else if (*optarg == 'M')
                 s->dflag = 7;
+            else if (*optarg == 'T')
+                s->do_test = argc;
             else if (isnum(*optarg))
                 g_debug = atoi(optarg);
             else
diff --git a/tcc.c b/tcc.c
index 6e8cdbaf..b502df1f 100644
--- a/tcc.c
+++ b/tcc.c
@@ -282,6 +282,8 @@ redo:
         n = s->nb_files;
         if (n == 0)
             tcc_error("no input files\n");
+        if (s->do_test)
+            tcc_tool_test(s, argc, argv); /* maybe never returns */
 
         if (s->output_type == TCC_OUTPUT_PREPROCESS) {
             if (!s->outfile) {
diff --git a/tcc.h b/tcc.h
index 5d2cbde1..4113028e 100644
--- a/tcc.h
+++ b/tcc.h
@@ -813,6 +813,7 @@ struct TCCState {
     int option_pthread; /* -pthread option */
     int argc;
     char **argv;
+    int do_test;
 };
 
 struct filespec {
diff --git a/tccgen.c b/tccgen.c
index 3cc61089..60ae198d 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -50,7 +50,9 @@ ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack p
 ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop;
 
 ST_DATA int const_wanted; /* true if constant wanted */
-ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
+ST_DATA int nocode_wanted; /* no code generation wanted */
+#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */
+#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */
 ST_DATA int global_expr;  /* true if compound literals must be allocated globally (used during initializers parsing */
 ST_DATA CType func_vt; /* current function return type (used by return instruction) */
 ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
@@ -230,7 +232,7 @@ ST_FUNC void tccgen_start(TCCState *s1)
     anon_sym = SYM_FIRST_ANOM;
     section_sym = 0;
     const_wanted = 0;
-    nocode_wanted = 1;
+    nocode_wanted = 0x80000000;
 
     /* define some often used types */
     int_type.t = VT_INT;
@@ -1206,14 +1208,12 @@ ST_FUNC int gv(int rc)
     } else {
         if (is_float(vtop->type.t) && 
             (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
-            unsigned long offset;
             /* CPUs usually cannot use float constants, so we store them
                generically in data segment */
             size = type_size(&vtop->type, &align);
-	    offset = section_add(data_section, size, align);
-            vpush_ref(&vtop->type, data_section, offset, size);
+            vpush_ref(&vtop->type, data_section, data_section->data_offset, size);
 	    vswap();
-	    init_putv(&vtop->type, data_section, offset);
+	    init_putv(&vtop->type, data_section, data_section->data_offset);
 	    vtop->r |= VT_LVAL;
         }
 #ifdef CONFIG_TCC_BCHECK
@@ -2329,6 +2329,11 @@ static void gen_cvt_ftoi1(int t)
 static void force_charshort_cast(int t)
 {
     int bits, dbt;
+
+    /* cannot cast static initializers */
+    if (STATIC_DATA_WANTED)
+	return;
+
     dbt = t & VT_BTYPE;
     /* XXX: add optimization if lvalue : just change type and offset */
     if (dbt == VT_BYTE)
@@ -3405,12 +3410,9 @@ static void struct_layout(CType *type, AttributeDef *ad)
 //#define BF_DEBUG
 
     for (f = type->ref->next; f; f = f->next) {
-        if (f->type.t & VT_BITFIELD) {
+        if (f->type.t & VT_BITFIELD)
             bit_size = BIT_SIZE(f->type.t);
-            /* in pcc mode, long long bitfields have type int if they fit */
-            if (pcc && (f->type.t & VT_BTYPE) == VT_LLONG && bit_size <= 32)
-                f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT;
-        } else
+        else
             bit_size = -1;
         size = type_size(&f->type, &align);
         a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0;
@@ -3479,6 +3481,10 @@ static void struct_layout(CType *type, AttributeDef *ad)
                         goto new_field;
                 }
 
+                /* in pcc mode, long long bitfields have type int if they fit */
+                if (size == 8 && bit_size <= 32)
+                    f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT, size = 4;
+
                 while (bit_pos >= align * 8)
                     c += align, bit_pos -= align * 8;
                 offset = c;
@@ -4558,8 +4564,10 @@ ST_FUNC void unary(void)
             type.t |= VT_ARRAY;
             type.ref->c = len;
             vpush_ref(&type, data_section, data_section->data_offset, len);
-            ptr = section_ptr_add(data_section, len);
-            memcpy(ptr, funcname, len);
+            if (!NODATA_WANTED) {
+                ptr = section_ptr_add(data_section, len);
+                memcpy(ptr, funcname, len);
+            }
             next();
         }
         break;
@@ -6314,7 +6322,7 @@ static int decl_designator(CType *type, Section *sec, unsigned long c,
 		vstore();
 	    }
 	    vpop();
-	} else {
+        } else if (!NODATA_WANTED) {
 	    c_end = c + nb_elems * elem_size;
 	    if (c_end > sec->data_allocated)
 	        section_realloc(sec, c_end);
@@ -6348,9 +6356,25 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
         /* XXX: generate error if incorrect relocation */
         gen_assign_cast(&dtype);
         bt = type->t & VT_BTYPE;
+
+        if ((vtop->r & VT_SYM)
+            && bt != VT_PTR
+            && bt != VT_FUNC
+            && (bt != (PTR_SIZE == 8 ? VT_LLONG : VT_INT)
+                || (type->t & VT_BITFIELD))
+            && !((vtop->r & VT_CONST) && vtop->sym->v >= SYM_FIRST_ANOM)
+            )
+            tcc_error("initializer element is not computable at load time");
+
+        if (NODATA_WANTED) {
+            vtop--;
+            return;
+        }
+
 	size = type_size(type, &align);
 	section_reserve(sec, c + size);
         ptr = sec->data + c;
+
         /* XXX: make code faster ? */
 	if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) &&
 	    vtop->sym->v >= SYM_FIRST_ANOM &&
@@ -6404,20 +6428,6 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
 		}
 	    }
 	} else {
-            if ((vtop->r & VT_SYM) &&
-		(bt == VT_BYTE ||
-		 bt == VT_SHORT ||
-		 bt == VT_DOUBLE ||
-		 bt == VT_LDOUBLE ||
-#if PTR_SIZE == 8
-		 bt == VT_INT ||
-#else
-		 bt == VT_LLONG ||
-#endif
-                 (type->t & VT_BITFIELD)
-		))
-	      tcc_error("initializer element is not computable at load time");
-
             if (type->t & VT_BITFIELD) {
                 int bit_pos, bit_size, bits, n;
                 unsigned char *p, v, m;
@@ -6598,7 +6608,8 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
                        string in global variable, we handle it
                        specifically */
                     if (sec && tok == TOK_STR && size1 == 1) {
-                        memcpy(sec->data + c + len, tokc.str.data, nb);
+                        if (!NODATA_WANTED)
+                            memcpy(sec->data + c + len, tokc.str.data, nb);
                     } else {
                         for(i=0;i<nb;i++) {
                             if (tok == TOK_STR)
@@ -6714,6 +6725,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
     Section *sec;
     Sym *flexible_array;
     Sym *sym = NULL;
+    int saved_nocode_wanted = nocode_wanted;
+#ifdef CONFIG_TCC_BCHECK
+    int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
+#endif
+
+    if (type->t & VT_STATIC)
+        nocode_wanted |= NODATA_WANTED ? 0x40000000 : 0x80000000;
 
     flexible_array = NULL;
     if ((type->t & VT_BTYPE) == VT_STRUCT) {
@@ -6779,10 +6797,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
     } else if (ad->a.packed) {
         align = 1;
     }
+
+    if (NODATA_WANTED)
+        size = 0, align = 1;
+
     if ((r & VT_VALMASK) == VT_LOCAL) {
         sec = NULL;
 #ifdef CONFIG_TCC_BCHECK
-        if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) {
+        if (bcheck && (type->t & VT_ARRAY)) {
             loc--;
         }
 #endif
@@ -6792,7 +6814,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
         /* handles bounds */
         /* XXX: currently, since we do only one pass, we cannot track
            '&' operators, so we add only arrays */
-        if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) {
+        if (bcheck && (type->t & VT_ARRAY)) {
             addr_t *bounds_ptr;
             /* add padding between regions */
             loc--;
@@ -6860,7 +6882,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
 	    addr = section_add(sec, size, align);
 #ifdef CONFIG_TCC_BCHECK
             /* add padding if bound check */
-            if (tcc_state->do_bounds_check)
+            if (bcheck)
                 section_add(sec, 1, 1);
 #endif
         } else {
@@ -6888,7 +6910,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
 #ifdef CONFIG_TCC_BCHECK
         /* handles bounds now because the symbol must be defined
            before for the relocation */
-        if (tcc_state->do_bounds_check) {
+        if (bcheck) {
             addr_t *bounds_ptr;
 
             greloca(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR, 0);
@@ -6903,6 +6925,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
     if (type->t & VT_VLA) {
         int a;
 
+        if (NODATA_WANTED)
+            goto no_alloc;
+
         /* save current stack pointer */
         if (vlas_in_scope == 0) {
             if (vla_sp_root_loc == -1)
@@ -6935,6 +6960,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
         end_macro();
         restore_parse_state(&saved_parse_state);
     }
+
+    nocode_wanted = saved_nocode_wanted;
 }
 
 /* parse a function defined by symbol 'sym' and generate its code in
@@ -6978,7 +7005,7 @@ static void gen_function(Sym *sym)
     func_vt.t = VT_VOID; /* for safety */
     func_var = 0; /* for safety */
     ind = 0; /* for safety */
-    nocode_wanted = 1;
+    nocode_wanted = 0x80000000;
     check_vstack();
 }
 
diff --git a/tcctools.c b/tcctools.c
index 53d88be6..0e2755bf 100644
--- a/tcctools.c
+++ b/tcctools.c
@@ -544,3 +544,108 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
 }
 
 /* -------------------------------------------------------------- */
+/* run test snippets from file */
+
+static char *readfile(const char *fname)
+{
+    char *buf;
+    int fsize;
+    FILE *fi;
+    fi = fopen(fname, "rb");
+    if (!fi)
+        return NULL;
+    fseek(fi, 0, SEEK_END);
+    fsize = ftell(fi);
+    fseek(fi, 0, SEEK_SET);
+    buf = tcc_malloc(fsize + 1);
+    fread(buf, fsize, 1, fi);
+    fclose(fi);
+    buf[fsize] = 0;
+    return buf;
+}
+
+static int run_prog(const char *prog, int ac, char **av)
+{
+    TCCState *s;
+    int (*func)(int, char**);
+    int ret = -10000;
+
+    s = tcc_new();
+    tcc_parse_args(s, &ac, &av, 1);
+    tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
+    if (tcc_compile_string(s, prog) == -1)
+        goto done;
+    if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0)
+        goto done;
+    func = tcc_get_symbol(s, "main");
+    if (!func)
+        goto done;
+    ret = func(ac, av);
+done:
+    tcc_delete(s);
+    return ret;
+}
+
+static char *trimback(char *a, char *e)
+{
+    while (e > a && (unsigned char)e[-1] <= ' ')
+	--e;
+    *e = 0;;
+    return a;
+}
+
+ST_FUNC int tcc_tool_test(TCCState *s, int argc, char **argv)
+{
+    const char *fname;
+    char *buf, *p, *a, *b, *e, tmp[100];
+    int r = 0, c, n;
+    const char sep[] = "/*-* test";
+
+    n = s->do_test - argc;
+    if (!n)
+        return 0;
+    fname = argv[0], argv -= n, argc += n;
+
+    buf = readfile(fname);
+    if (NULL == buf)
+        return -1;
+    p = strstr(buf, sep);
+    if (!p) {
+        tcc_free(buf);
+        return -1;
+    }
+
+    while (*p) {
+        a = p, p = strchr(p, '\n');
+        if (NULL == p)
+            break;
+        *p++ = 0;
+        b = p, p = strstr(p, sep);
+        if (NULL == p)
+            p = strchr(b, 0);
+        c = *p, *p = 0;
+
+        trimback(a, b);
+        if (r)
+            printf("\n");
+        printf("%s\n", a);
+        fflush(stdout);
+
+        e = a += sizeof sep - 5;
+        while (*e && *e != ':')
+            ++e;
+        if (!*e || e - a > 32)
+            e = a + 4;
+        n = snprintf(tmp, sizeof tmp, "#line 1 \"%.*s\"\n", (int)(e - a), a);
+        if (b - buf >= n)
+            b = memcpy(b - n, tmp, n);
+        n = run_prog(b, argc, argv);
+        if (n != -10000)
+            printf("returns %d\n", n);
+        *p = c, ++r;
+    }
+    tcc_free(buf);
+    exit(0);
+}
+
+/* -------------------------------------------------------------- */
diff --git a/tests/tests2/95_bitfields.c b/tests/tests2/95_bitfields.c
index 1ec9781e..7edbeed1 100644
--- a/tests/tests2/95_bitfields.c
+++ b/tests/tests2/95_bitfields.c
@@ -58,7 +58,7 @@
     struct M P __s {
         long long x : 45;
         long long : 2;
-        long long y : 35;
+        long long y : 30;
         unsigned long long z : 38;
         char a; short b;
     };
diff --git a/tests/tests2/95_bitfields_ms.expect b/tests/tests2/95_bitfields_ms.expect
index f4eb2d36..6b5c3f95 100644
--- a/tests/tests2/95_bitfields_ms.expect
+++ b/tests/tests2/95_bitfields_ms.expect
@@ -23,8 +23,8 @@ values      : 03 ffffffff 0f fffffff8 78
 align/size  : 4 8
 
 ---- TEST 5 - MS-BITFIELDS ----
-bits in use : 00000000FFFF00FF0000003FFFFFFFFF00000007FFFFFFFF00001FFFFFFFFFFF
-bits as set : 0000000000770044000000000000007800000007F00000000000000123456789
+bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 0000000000770044000000000000007800000000300000000000000123456789
 values      : 0000000123456789 fffffffff0000000 0000000000000078 44 77
 align/size  : 8 32
 
@@ -61,8 +61,8 @@ values      : 03 ffffffff 0f fffffff8 78
 align/size  : 1 8
 
 ---- TEST 5 - MS-BITFIELDS - PACKED ----
-bits in use : FFFFFF0000003FFFFFFFFF00000007FFFFFFFF00001FFFFFFFFFFF
-bits as set : 007744000000000000007800000007F00000000000000123456789
+bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 007744000000000000007800000000300000000000000123456789
 values      : 0000000123456789 fffffffff0000000 0000000000000078 44 77
 align/size  : 1 27
 
@@ -99,8 +99,8 @@ values      : 03 ffffffff 0f fffffff8 78
 align/size  : 4 8
 
 ---- TEST 5 - MS-BITFIELDS - WITH ALIGN ----
-bits in use : 00000000FFFF00FF0000003FFFFFFFFF00000007FFFFFFFF00001FFFFFFFFFFF
-bits as set : 0000000000770044000000000000007800000007F00000000000000123456789
+bits in use : 00000000FFFF00FF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 0000000000770044000000000000007800000000300000000000000123456789
 values      : 0000000123456789 fffffffff0000000 0000000000000078 44 77
 align/size  : 8 32
 
@@ -137,8 +137,8 @@ values      : 03 ffffffff 0f fffffff8 78
 align/size  : 1 8
 
 ---- TEST 5 - MS-BITFIELDS - PACKED - WITH ALIGN ----
-bits in use : FFFFFF0000003FFFFFFFFF00000007FFFFFFFF00001FFFFFFFFFFF
-bits as set : 007744000000000000007800000007F00000000000000123456789
+bits in use : FFFFFF0000003FFFFFFFFF000000003FFFFFFF00001FFFFFFFFFFF
+bits as set : 007744000000000000007800000000300000000000000123456789
 values      : 0000000123456789 fffffffff0000000 0000000000000078 44 77
 align/size  : 1 27
 
diff --git a/tests/tests2/96_nodata_wanted.c b/tests/tests2/96_nodata_wanted.c
new file mode 100644
index 00000000..6f7f3c22
--- /dev/null
+++ b/tests/tests2/96_nodata_wanted.c
@@ -0,0 +1,74 @@
+/*****************************************************************************/
+/* test 'nodata_wanted' data output suppression */
+
+/*-* test 1: initializer not computable 1 */
+void foo() {
+    if (1) {
+	static short w = (int)&foo; /* error */
+    }
+}
+
+/*-* test 2: initializer not computable 2 */
+void foo() {
+    if (0) {
+	static short w = (int)&foo; /* error */
+    }
+}
+
+/*-* test 3: initializer not computable 3 */
+void foo();
+static short w = (int)&foo; /* error */
+
+
+/*-* test 4: 2 cast warnings */
+void foo() {
+    short w = &foo; /* no error */
+}
+
+/*-* test 5; nodata_wanted test */
+#include <stdio.h>
+
+#define DATA_LBL(s) \
+    __asm__(".global d"#s",t"#s"\n.data\nd"#s":\n.text\nt"#s":\n"); \
+    extern char d##s[],t##s[];
+
+#define PROG \
+        static void *p = (void*)&main;\
+        static char cc[] = "static string";\
+        static double d = 8.0;\
+        static struct __attribute__((packed)) {\
+            unsigned x : 12;\
+            unsigned char y : 7;\
+            unsigned z : 28, a: 4, b: 5;\
+        } s = { 0x333,0x44,0x555555,6,7 };\
+        printf("  static data: %d - %.1f - %.1f - %s - %s\n",\
+            sizeof 8.0, 8.0, d, __FUNCTION__, cc);\
+        printf("  static bitfields: %x %x %x %x %x\n", s.x, s.y, s.z, s.a, s.b);
+
+int main()
+{
+    printf("suppression off\n");
+    DATA_LBL(s1);
+    if (1) {
+        PROG
+    }
+    DATA_LBL(e1);
+    printf("  data length is %s\n", de1 - ds1 ? "not 0":"0");
+    //printf("  text length is %s\n", te1 - ts1 ? "not 0":"0");
+
+    printf("suppression on\n");
+    DATA_LBL(s2);
+    if (0) {
+        PROG
+    }
+    DATA_LBL(e2);
+    printf("  data length is %x\n", de2 - ds2);
+    //printf("  text length is %X\n", te2 - ts2);
+    return 0;
+}
+
+/*-* test 6: some test */
+int main()
+{
+    return 34;
+}
diff --git a/tests/tests2/96_nodata_wanted.expect b/tests/tests2/96_nodata_wanted.expect
new file mode 100644
index 00000000..0db4ba2d
--- /dev/null
+++ b/tests/tests2/96_nodata_wanted.expect
@@ -0,0 +1,24 @@
+/*-* test 1: initializer not computable 1 */
+test 1:3: error: initializer element is not computable at load time
+
+/*-* test 2: initializer not computable 2 */
+test 2:3: error: initializer element is not computable at load time
+
+/*-* test 3: initializer not computable 3 */
+test 3:2: error: initializer element is not computable at load time
+
+/*-* test 4: 2 cast warnings */
+test 4:2: warning: assignment makes integer from pointer without a cast
+test 4:2: warning: nonportable conversion from pointer to char/short
+
+/*-* test 5; nodata_wanted test */
+suppression off
+  static data: 8 - 8.0 - 8.0 - main - static string
+  static bitfields: 333 44 555555 6 7
+  data length is not 0
+suppression on
+  data length is 0
+returns 0
+
+/*-* test 6: some test */
+returns 34
diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile
index 44f20f72..832aa498 100644
--- a/tests/tests2/Makefile
+++ b/tests/tests2/Makefile
@@ -5,29 +5,6 @@ VPATH = $(SRC)
 
 TESTS = $(patsubst %.c,%.test,$(sort $(notdir $(wildcard $(SRC)/*.c))))
 
-# Some tests might need arguments
-ARGS =
-31_args.test : ARGS = arg1 arg2 arg3 arg4 arg5
-46_grep.test : ARGS = '[^* ]*[:a:d: ]+\:\*-/: $$' $(SRC)/46_grep.c
-
-# And some tests don't test the right thing with -run
-NORUN =
-42_function_pointer.test : NORUN = true
-
-# Some tests might need different flags
-FLAGS =
-76_dollars_in_identifiers.test : FLAGS += -fdollars-in-identifiers
-
-# Always generate certain .expects (don't put these in the GIT),
-GEN-ALWAYS = 95_bitfields.expect
-
-# Filter source directory in warnings/errors (out-of-tree builds)
-FILTER = 2>&1 | sed 's,$(SRC)/,,g'
-# Filter some always-warning
-ifeq (-$(findstring arm,$(ARCH))-,-arm-)
-FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported'
-endif
-
 # some tests do not pass on all platforms, remove them for now
 SKIP = 34_array_assignment.test # array assignment is not in C standard
 ifeq ($(CONFIG_arm_eabi),yes) # not ARM soft-float
@@ -50,46 +27,80 @@ ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-)
  SKIP += 95_bitfields_ms.test # type_align is differnt on 32bit-non-windows
 endif
 
+# Some tests might need arguments
+ARGS =
+31_args.test : ARGS = arg1 arg2 arg3 arg4 arg5
+46_grep.test : ARGS = '[^* ]*[:a:d: ]+\:\*-/: $$' $(SRC)/46_grep.c
+
+# And some tests don't test the right thing with -run
+NORUN =
+42_function_pointer.test : NORUN = true
+
+# Some tests might need different flags
+FLAGS =
+76_dollars_in_identifiers.test : FLAGS += -fdollars-in-identifiers
+
+# run the source file cut into snippets
+96_nodata_wanted.test : FLAGS = -dT
+
+# Always generate certain .expects (don't put these in the GIT),
+GEN-ALWAYS =
+GEN-ALWAYS += 95_bitfields.expect
+
+# using the ms compiler for the really ms-compatible bitfields
+95_bitfields_ms.test : GEN = $(GEN-MSC)
+
+# Filter source directory in warnings/errors (out-of-tree builds)
+FILTER = 2>&1 | sed 's,$(SRC)/,,g'
+# Filter some always-warning
+ifeq (-$(findstring arm,$(ARCH))-,-arm-)
+FILTER += 2>&1 | grep -v 'warning: soft float ABI currently not supported'
+endif
+
 all test tests2.all: $(filter-out $(SKIP),$(TESTS)) ;
 
 %.test: %.c %.expect
 	@echo Test: $*...
-	@$(if $(NORUN),\
-	    ($(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS)),\
-	    $(TCC) $(FLAGS) -run $< $(ARGS)\
-	   ) $(FILTER) >$*.output 2>&1 || true
-	@diff -Nbu $(filter %.expect,$^) $*.output \
-	    && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS))
+	@$(if $(NORUN),$(T1),$(T2)) $(if $(NODIFF),,$(T3))
 
-F1 = $(or $(filter $1_%,$(TESTS)),$1_???.test)
-F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)"
+T1 = $(TCC) $(FLAGS) $< -o a.exe && ./a.exe $(ARGS)
+T2 = $(TCC) $(FLAGS) -run $< $(ARGS)
+T3 = $(FILTER) >$*.output 2>&1 || true \
+     && diff -Nbu $(filter %.expect,$^) $*.output \
+     && rm -f $*.output $(filter $*.expect,$(GEN-ALWAYS))
 
 # run single test and update .expect file, e.g. "make tests2.37+"
 tests2.%+:
 	@$(MAKE) $(call F2,$(call F1,$*)) --no-print-directory
 
+# just run tcc to see the output, e.g. "make tests2.37-"
+tests2.%-:
+	@$(MAKE) $(call F1,$*) NODIFF=true --no-print-directory
+
 # run single test, e.g. "make tests2.37"
 tests2.%:
 	@$(MAKE) $(call F1,$*) --no-print-directory
 
+F1 = $(or $(filter $1_%,$(TESTS)),$1_???.test)
+F2 = $1 UPDATE="$(patsubst %.test,%.expect,$1)"
+
 # automatically generate .expect files with gcc:
 %.expect :
 	@echo Generating: $@
-	@$(CC) -w -std=gnu99 $(FLAGS) $(SRC)/$*.c -o a.exe
-	@./a.exe $(ARGS) $(FILTER) >$@ 2>&1
-	@rm -f a.exe
-
-# using the ms compiler for the really ms-compatible bitfields
-MS-CC = cl
-95_bitfields_ms.expect :
-	@echo Generating: $@
-	@$(MS-CC) $(basename $@).c
-	@./$(basename $@).exe >$@ 2>&1
+	@$(call GEN,$(SRC)/$*.c) $(FILTER) >$@ 2>&1
 	@rm -f *.exe *.obj *.pdb
 
+# using TCC for .expect if -dT in FLAGS
+GEN = $(if $(findstring -dT,$(FLAGS)),$(GEN-TCC),$(GEN-CC))
+GEN-CC = $(CC) -w -std=gnu99 $(FLAGS) $1 -o a.exe && ./a.exe $(ARGS)
+GEN-TCC = $(TCC) $(FLAGS) -run $1 $(ARGS)
+GEN-MSC = $(MS-CC) $1 && ./$(basename $@).exe
+MS-CC = cl
+
 # tell make not to delete
 .PRECIOUS: %.expect
 
+# force .expect generation for these files
 $(sort $(GEN-ALWAYS) $(UPDATE)) : force
 force: