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.
This commit is contained in:
Michael Matz 2012-04-16 02:52:15 +02:00
parent 718fd591fa
commit 9ca9c82ff8
2 changed files with 38 additions and 0 deletions

View File

@ -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;

View File

@ -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;
}