Browse Source

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.
Michael Forney 4 years ago
parent
commit
6d9ee13895
2 changed files with 20 additions and 2 deletions
  1. 3 2
      amd64/isel.c
  2. 17 0
      test/cmp1.ssa

+ 3 - 2
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;

+ 17 - 0
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); }
+# <<<