diff options
author | Michael Forney <mforney@mforney.org> | 2021-06-16 20:27:49 -0700 |
---|---|---|
committer | Quentin Carbonneaux <quentin@c9x.me> | 2021-06-17 22:16:42 +0200 |
commit | 6d9ee1389572ae985f6a39bb99dbd10cdf42c123 (patch) | |
tree | 18d0ad17085f2fd6702d168d676a7716eafafae2 | |
parent | e0b94a3d6ade2f99ded481318e9e6d9f16953662 (diff) | |
download | roux-6d9ee1389572ae985f6a39bb99dbd10cdf42c123.tar.gz |
amd64: fix conditional jump when compare is swapped and used elsewhere
selcmp may potentially swap the arguments and return 1 indicating that the opposite operation should be used. However, if the compare result is used for a conditional jump as well as elsewhere, the original compare op is used instead of the opposite. To fix this, add a check to see whether the opposite compare should be used, regardless of whether selcmp() is done now, or later on during sel(). Bug report and test case from Charlie Stanton.
-rw-r--r-- | amd64/isel.c | 5 | ||||
-rw-r--r-- | test/cmp1.ssa | 17 |
2 files changed, 20 insertions, 2 deletions
diff --git a/amd64/isel.c b/amd64/isel.c index 56e4cf3..5f84561 100644 --- a/amd64/isel.c +++ b/amd64/isel.c @@ -383,9 +383,10 @@ seljmp(Blk *b, Fn *fn) b->jmp.type = Jjf + Cine; } else if (iscmp(fi->op, &k, &c)) { + if (rtype(fi->arg[0]) == RCon) + c = cmpop(c); if (t->nuse == 1) { - if (selcmp(fi->arg, k, fn)) - c = cmpop(c); + selcmp(fi->arg, k, fn); *fi = (Ins){.op = Onop}; } b->jmp.type = Jjf + c; diff --git a/test/cmp1.ssa b/test/cmp1.ssa new file mode 100644 index 0000000..dd5bfa1 --- /dev/null +++ b/test/cmp1.ssa @@ -0,0 +1,17 @@ +# test cmp used in jnz as well as its result value + +export +function w $test(w %c) { +@start + %cmp =w cultw 1, %c + jnz %cmp, @yes, @no +@yes + %cmp =w copy 1 +@no + ret %cmp +} + +# >>> driver +# int test(int); +# int main(void) { return test(0); } +# <<< |