Some more subtle issues with code suppression: - outputting asms but not their operand setup is broken - but global asms must always be output - statement expressions are transparent to code suppression - vtop can't be transformed from VT_CMP/VT_JMP when nocode_wanted Also remove .exe files from tests2 if they don't fail.
Showing the changes to tests (6 of 8 files). Show all
Unified · Split
| @@ -1404,6 +1404,15 @@ void optimize_out(void) · 1403 unmodified lines | ||
| 1404 | 1404 | if (defined_function() && 0) |
| 1405 | 1405 | refer_to_undefined(); |
| 1406 | 1406 | |
| 1407 | + if (0) { | |
| 1408 | + (void)sizeof( ({ | |
| 1409 | + do { } while (0); | |
| 1410 | + 0; | |
| 1411 | + }) ); | |
| 1412 | + undefined_function(); | |
| 1413 | + } | |
| 1414 | + | |
| 1415 | + /* Leave the "if(1)return; printf()" in this order and last in the function */ | |
| 1407 | 1416 | if (1) |
| 1408 | 1417 | return; |
| 1409 | 1418 | printf ("oor:%d\n", undefined_function()); |
| @@ -3251,6 +3260,28 @@ void trace_console(long len, long len2) · 1841 unmodified lines | ||
| 3251 | 3260 | } |
| 3252 | 3261 | #endif |
| 3253 | 3262 | } |
| 3263 | + | |
| 3264 | +void test_asm_dead_code(void) | |
| 3265 | +{ | |
| 3266 | + long rdi; | |
| 3267 | + /* Try to make sure that xdi contains a zero, and hence will | |
| 3268 | + lead to a segfault if the next asm is evaluated without | |
| 3269 | + arguments being set up. */ | |
| 3270 | + asm volatile ("" : "=D" (rdi) : "0" (0)); | |
| 3271 | + (void)sizeof (({ | |
| 3272 | + int var; | |
| 3273 | + /* This shouldn't trigger a segfault, either the argument | |
| 3274 | + registers need to be set up and the asm emitted despite | |
| 3275 | + this being in an unevaluated context, or both the argument | |
| 3276 | + setup _and_ the asm emission need to be suppressed. The latter | |
| 3277 | + is better. Disabling asm code gen when suppression is on | |
| 3278 | + also fixes the above trace_console bug, but that came earlier | |
| 3279 | + than asm suppression. */ | |
| 3280 | + asm volatile ("movl $0,(%0)" : : "D" (&var) : "memory"); | |
| 3281 | + var; | |
| 3282 | + })); | |
| 3283 | +} | |
| 3284 | + | |
| 3254 | 3285 | void asm_test(void) |
| 3255 | 3286 | { |
| 3256 | 3287 | char buf[128]; |
| @@ -3334,6 +3365,7 @@ void asm_test(void) · 77 unmodified lines | ||
| 3334 | 3365 | printf ("regvar=%x\n", regvar); |
| 3335 | 3366 | test_high_clobbers(); |
| 3336 | 3367 | trace_console(8, 8); |
| 3368 | + test_asm_dead_code(); | |
| 3337 | 3369 | return; |
| 3338 | 3370 | label1: |
| 3339 | 3371 | goto label2; |
| @@ -1,7 +1,9 @@ | ||
| 1 | +extern int printf (const char *, ...); | |
| 1 | 2 | extern void vide(void); |
| 2 | 3 | __asm__("vide: ret"); |
| 3 | 4 | |
| 4 | 5 | int main() { |
| 5 | 6 | vide(); |
| 7 | + printf ("okay\n"); | |
| 6 | 8 | return 0; |
| 7 | 9 | } |
| @@ -0,0 +1 @@ | ||
| 1 | +okay | |
| @@ -0,0 +1,68 @@ | ||
| 1 | +/* Check some way in where code suppression caused various | |
| 2 | + miscompilations. */ | |
| 3 | +extern int printf (const char *, ...); | |
| 4 | +typedef unsigned long size_t; | |
| 5 | + | |
| 6 | +size_t _brk_start, _brk_end; | |
| 7 | +void * extend_brk(size_t size, size_t align) | |
| 8 | +{ | |
| 9 | + size_t mask = align - 1; | |
| 10 | + void *ret = 0; | |
| 11 | + | |
| 12 | + do { | |
| 13 | + if (__builtin_expect(!!(_brk_start == 0), 0)) | |
| 14 | + do { | |
| 15 | + printf("wrong1\n"); | |
| 16 | + } while (0); | |
| 17 | + } while (0); | |
| 18 | + _brk_end = (_brk_end + mask) & ~mask; | |
| 19 | + ret = (void *)_brk_end; | |
| 20 | + _brk_end += size; | |
| 21 | + | |
| 22 | + return ret; | |
| 23 | +} | |
| 24 | + | |
| 25 | +static void get_args (int a, int b) | |
| 26 | +{ | |
| 27 | + if (a != 1) | |
| 28 | + printf("wrong2\n"); | |
| 29 | + else | |
| 30 | + printf("okay\n"); | |
| 31 | +} | |
| 32 | + | |
| 33 | +void bla(void) | |
| 34 | +{ | |
| 35 | + int __ret = 42; | |
| 36 | + ({ | |
| 37 | + if (__builtin_expect(!!(0), 0)) { | |
| 38 | + if (__builtin_expect(!!__ret, 0)) | |
| 39 | + printf("wrong3\n"); | |
| 40 | + int x = !!(__ret); | |
| 41 | + } | |
| 42 | + __ret; | |
| 43 | + }); | |
| 44 | + get_args(!!__ret, sizeof(__ret)); | |
| 45 | +} | |
| 46 | + | |
| 47 | +_Bool chk(unsigned long addr, unsigned long limit, unsigned long size) | |
| 48 | +{ | |
| 49 | + _Bool ret; | |
| 50 | + /* This just needs to compile, no runtime test. (And it doesn't compile | |
| 51 | + only with certain internal checking added that's not committed). */ | |
| 52 | + if (0) | |
| 53 | + ret = 0 != (!!(addr > limit - size)); | |
| 54 | +} | |
| 55 | + | |
| 56 | +int main() | |
| 57 | +{ | |
| 58 | + void *r; | |
| 59 | + _brk_start = 1024; | |
| 60 | + _brk_end = 1024; | |
| 61 | + r = extend_brk (4096, 16); | |
| 62 | + if (!r) | |
| 63 | + printf("wrong4\n"); | |
| 64 | + else | |
| 65 | + printf("okay\n"); | |
| 66 | + bla(); | |
| 67 | + return 0; | |
| 68 | +} | |
| @@ -0,0 +1,2 @@ | ||
| 1 | +okay | |
| 2 | +okay | |
| @@ -59,7 +59,7 @@ all test: $(filter-out $(SKIP),$(TESTS)) · 58 unmodified lines | ||
| 59 | 59 | $(TCC) $< -o ./$*.exe $(FILTER) 2>&1 && \ |
| 60 | 60 | ./$*.exe $(ARGS) >$*.output 2>&1 || true; \ |
| 61 | 61 | fi |
| 62 | − @diff -Nbu $(SRC)/$*.expect $*.output && rm -f $*.output | |
| 62 | + @diff -Nbu $(SRC)/$*.expect $*.output && rm -f $*.output $*.exe | |
| 63 | 63 | |
| 64 | 64 | # automatically generate .expect files with gcc: |
| 65 | 65 | %.expect : %.c |