summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-06-16 20:27:49 -0700
committerQuentin Carbonneaux <quentin@c9x.me>2021-06-17 22:16:42 +0200
commit6d9ee1389572ae985f6a39bb99dbd10cdf42c123 (patch)
tree18d0ad17085f2fd6702d168d676a7716eafafae2
parente0b94a3d6ade2f99ded481318e9e6d9f16953662 (diff)
downloadroux-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.c5
-rw-r--r--test/cmp1.ssa17
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); }
+# <<<