From 9ca9c82ff8a4001299a4b9666d85352f5806d565 Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Mon, 16 Apr 2012 02:52:15 +0200 Subject: [PATCH 9/9] Fix comparing comparisons Sometimes the result of a comparison is not directly used in a jump, but in arithmetic or further comparisons. If those further things do a vswap() with the VT_CMP as current top, and then generate instructions for the new top, this most probably destroys the flags (e.g. if it's a bitfield load like in the example). vswap() must do the same like vsetc() and not allow VT_CMP vtops to be moved down. --- tccgen.c | 8 ++++++++ tests/tcctest.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 0 deletions(-) diff --git a/tccgen.c b/tccgen.c index 36a1879..9339b5f 100644 --- a/tccgen.c +++ b/tccgen.c @@ -452,6 +452,14 @@ ST_FUNC void vswap(void) { SValue tmp; + /* cannot let cpu flags if other instruction are generated. Also + avoid leaving VT_JMP anywhere except on the top of the stack + because it would complicate the code generator. */ + if (vtop >= vstack) { + int v = vtop->r & VT_VALMASK; + if (v == VT_CMP || (v & ~1) == VT_JMP) + gv(RC_INT); + } tmp = vtop[0]; vtop[0] = vtop[-1]; vtop[-1] = tmp; diff --git a/tests/tcctest.c b/tests/tcctest.c index 9598fa4..7772f89 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -86,6 +86,7 @@ void asm_test(void); void builtin_test(void); void weak_test(void); void global_data_test(void); +void cmp_comparison_test(void); int fib(int n); void num(int n); @@ -592,6 +593,7 @@ int main(int argc, char **argv) builtin_test(); weak_test(); global_data_test(); + cmp_comparison_test(); return 0; } @@ -2562,3 +2564,31 @@ void global_data_test (void) global_data_callit (0); printf ("%d\n", global_data.a[0]); } + +struct cmpcmpS +{ + unsigned char fill : 3; + unsigned char b1 : 1; + unsigned char b2 : 1; + unsigned char fill2 : 3; +}; + +int glob1, glob2, glob3; + +void compare_comparisons (struct cmpcmpS *s) +{ + if (s->b1 != (glob1 == glob2) + || (s->b2 != (glob1 == glob3))) + printf ("comparing comparisons broken\n"); +} + +void cmp_comparison_test(void) +{ + struct cmpcmpS s; + s.b1 = 1; + glob1 = 42; glob2 = 42; + s.b2 = 0; + glob3 = 43; + compare_comparisons (&s); + return 0; +} -- 1.7.3.4