mirror of
git://c9x.me/qbe.git
synced 2026-05-26 15:34:41 +00:00
negated conditions rework
Floating point comparisons are subtle due to
unordered operands (i.e., when one or two of
the operands are nans).
In amd64 we arrange post isel to make sure we
only have comparisons that will return false
on unordered operands and for which we have a
negated version (returning true on unordered
operands). I made this situation a bit more
explicit by marking unexpected comparisons
with "?" in amd64/emit.c.
In arm64, the instruction set is rich enough
to have a negated version for all operators
that returns true on unordered inputs. So we
build a backend specific table.
I made sure to remove cmpneg() from utils.c;
it is a footgun as it does not work well for
floating point ops because of the 'unordered'
edge case.
I found the ARM docs about condition codes
pretty bad; the following C program is a
good substitute:
#include <stdio.h>
int
flags(float a, float b)
{
int z, c, n, v, le;
__asm__(
"fcmpe %s5, %s6\n"
"\tcset %0, eq\n"
"\tcset %1, mi\n"
"\tcset %2, cs\n"
"\tcset %3, vs\n"
"\tcset %4, le\n"
: "=r"(z),"=r"(n),"=r"(c),"=r"(v),"=r"(le)
: "x"(a), "x"(b)
: "cc");
printf(
"cmp(%g,%g): z=%d n=%d c=%d v=%d le=%d\n",
a, b, z, n, c, v, le);
}
int
main()
{
flags(1.0, 1.0);
flags(0.0, 1.0);
flags(1.0, 0.0);
flags(0.0, 0.0/0.0);
flags(0.0/0.0, 0.0);
}
Compile & run with:
aarch64-linux-gnu-gcc -static -no-pie flags.c
qemu-aarch64 ./a.out
This commit is contained in:
parent
bef981e9a1
commit
577b4667db
1
all.h
1
all.h
@ -500,7 +500,6 @@ void emiti(Ins);
|
||||
void idup(Blk *, Ins *, ulong);
|
||||
Ins *icpy(Ins *, Ins *, ulong);
|
||||
int cmpop(int);
|
||||
int cmpneg(int);
|
||||
int cmpwlneg(int);
|
||||
int clsmerge(short *, short);
|
||||
int phicls(int, Tmp *);
|
||||
|
||||
26
amd64/emit.c
26
amd64/emit.c
@ -22,8 +22,8 @@ struct E {
|
||||
X(Ciuge, "ae", "b") \
|
||||
X(Cieq, "z", "nz") \
|
||||
X(Cine, "nz", "z") \
|
||||
X(NCmpI+Cfle, "be", "a") \
|
||||
X(NCmpI+Cflt, "b", "ae") \
|
||||
X(NCmpI+Cfle, "?" , "?") \
|
||||
X(NCmpI+Cflt, "?", "?") \
|
||||
X(NCmpI+Cfgt, "a", "be") \
|
||||
X(NCmpI+Cfge, "ae", "b") \
|
||||
X(NCmpI+Cfo, "np", "p") \
|
||||
@ -627,8 +627,8 @@ sysv_framesz(E *e)
|
||||
void
|
||||
amd64_sysv_emitfn(Fn *fn, FILE *f)
|
||||
{
|
||||
static char *ctoa[] = {
|
||||
#define X(c, s, _) [c] = s,
|
||||
static char *ctoa[][2] = {
|
||||
#define X(c, s, n) [c] = {s, n},
|
||||
CMP(X)
|
||||
#undef X
|
||||
};
|
||||
@ -710,13 +710,14 @@ amd64_sysv_emitfn(Fn *fn, FILE *f)
|
||||
default:
|
||||
c = b->jmp.type - Jjf;
|
||||
if (0 <= c && c <= NCmp) {
|
||||
if (b->link == b->s2 || c >= NCmpI) {
|
||||
if (b->link == b->s2) {
|
||||
s = b->s1;
|
||||
b->s1 = b->s2;
|
||||
b->s2 = s;
|
||||
n = 0;
|
||||
} else
|
||||
c = cmpneg(c);
|
||||
fprintf(f, "\tj%s %sbb%d\n", ctoa[c],
|
||||
n = 1;
|
||||
fprintf(f, "\tj%s %sbb%d\n", ctoa[c][n],
|
||||
T.asloc, id0+b->s2->id);
|
||||
goto Jmp;
|
||||
}
|
||||
@ -752,15 +753,15 @@ winabi_framesz(E *e)
|
||||
void
|
||||
amd64_winabi_emitfn(Fn *fn, FILE *f)
|
||||
{
|
||||
static char *ctoa[] = {
|
||||
#define X(c, s, _) [c] = s,
|
||||
static char *ctoa[][2] = {
|
||||
#define X(c, s, n) [c] = {s, n},
|
||||
CMP(X)
|
||||
#undef X
|
||||
};
|
||||
static int id0;
|
||||
Blk *b, *s;
|
||||
Ins *i, itmp;
|
||||
int *r, c, lbl;
|
||||
int *r, c, n, lbl;
|
||||
E *e;
|
||||
|
||||
e = &(E){.f = f, .fn = fn};
|
||||
@ -831,9 +832,10 @@ amd64_winabi_emitfn(Fn *fn, FILE *f)
|
||||
s = b->s1;
|
||||
b->s1 = b->s2;
|
||||
b->s2 = s;
|
||||
n = 0;
|
||||
} else
|
||||
c = cmpneg(c);
|
||||
fprintf(f, "\tj%s %sbb%d\n", ctoa[c],
|
||||
n = 1;
|
||||
fprintf(f, "\tj%s %sbb%d\n", ctoa[c][n],
|
||||
T.asloc, id0+b->s2->id);
|
||||
goto Jmp;
|
||||
}
|
||||
|
||||
49
arm64/emit.c
49
arm64/emit.c
@ -10,24 +10,24 @@ struct E {
|
||||
};
|
||||
|
||||
#define CMP(X) \
|
||||
X(Cieq, "eq") \
|
||||
X(Cine, "ne") \
|
||||
X(Cisge, "ge") \
|
||||
X(Cisgt, "gt") \
|
||||
X(Cisle, "le") \
|
||||
X(Cislt, "lt") \
|
||||
X(Ciuge, "cs") \
|
||||
X(Ciugt, "hi") \
|
||||
X(Ciule, "ls") \
|
||||
X(Ciult, "cc") \
|
||||
X(NCmpI+Cfeq, "eq") \
|
||||
X(NCmpI+Cfge, "ge") \
|
||||
X(NCmpI+Cfgt, "gt") \
|
||||
X(NCmpI+Cfle, "ls") \
|
||||
X(NCmpI+Cflt, "mi") \
|
||||
X(NCmpI+Cfne, "ne") \
|
||||
X(NCmpI+Cfo, "vc") \
|
||||
X(NCmpI+Cfuo, "vs")
|
||||
X(Cieq, "eq", "ne") \
|
||||
X(Cine, "ne", "eq") \
|
||||
X(Cisge, "ge", "lt") \
|
||||
X(Cisgt, "gt", "le") \
|
||||
X(Cisle, "le", "gt") \
|
||||
X(Cislt, "lt", "ge") \
|
||||
X(Ciuge, "cs", "cc") \
|
||||
X(Ciugt, "hi", "ls") \
|
||||
X(Ciule, "ls", "hi") \
|
||||
X(Ciult, "cc", "cs") \
|
||||
X(NCmpI+Cfeq, "eq", "ne") \
|
||||
X(NCmpI+Cfge, "ge", "lt") \
|
||||
X(NCmpI+Cfgt, "gt", "le") \
|
||||
X(NCmpI+Cfle, "ls", "hi") \
|
||||
X(NCmpI+Cflt, "mi", "pl") \
|
||||
X(NCmpI+Cfne, "ne", "eq") \
|
||||
X(NCmpI+Cfo, "vc", "vs") \
|
||||
X(NCmpI+Cfuo, "vs", "vc")
|
||||
|
||||
enum {
|
||||
Ki = -1, /* matches Kw and Kl */
|
||||
@ -102,7 +102,7 @@ static struct {
|
||||
{ Oacmn, Ki, "cmn %0, %1" },
|
||||
{ Oafcmp, Ka, "fcmpe %0, %1" },
|
||||
|
||||
#define X(c, str) \
|
||||
#define X(c, str, _) \
|
||||
{ Oflag+c, Ki, "cset %=, " str },
|
||||
CMP(X)
|
||||
#undef X
|
||||
@ -532,8 +532,8 @@ framelayout(E *e)
|
||||
void
|
||||
arm64_emitfn(Fn *fn, FILE *out)
|
||||
{
|
||||
static char *ctoa[] = {
|
||||
#define X(c, s) [c] = s,
|
||||
static char *ctoa[][2] = {
|
||||
#define X(c, s, n) [c] = {s, n},
|
||||
CMP(X)
|
||||
#undef X
|
||||
};
|
||||
@ -660,15 +660,16 @@ arm64_emitfn(Fn *fn, FILE *out)
|
||||
c = b->jmp.type - Jjf;
|
||||
if (c < 0 || c > NCmp)
|
||||
die("unhandled jump %d", b->jmp.type);
|
||||
if (b->link == b->s2 || c >= NCmpI) {
|
||||
if (b->link == b->s2) {
|
||||
t = b->s1;
|
||||
b->s1 = b->s2;
|
||||
b->s2 = t;
|
||||
n = 0;
|
||||
} else
|
||||
c = cmpneg(c);
|
||||
n = 1;
|
||||
fprintf(e->f,
|
||||
"\tb%s\t%s%d\n",
|
||||
ctoa[c], T.asloc, id0+b->s2->id
|
||||
ctoa[c][n], T.asloc, id0+b->s2->id
|
||||
);
|
||||
goto Jmp;
|
||||
}
|
||||
|
||||
11
util.c
11
util.c
@ -364,13 +364,6 @@ static int cmptab[][2] ={
|
||||
[NCmpI+Cfuo] = {-1, NCmpI+Cfuo},
|
||||
};
|
||||
|
||||
int
|
||||
cmpneg(int c)
|
||||
{
|
||||
assert(0 <= c && c < NCmpI);
|
||||
return cmptab[c][0];
|
||||
}
|
||||
|
||||
int
|
||||
cmpop(int c)
|
||||
{
|
||||
@ -382,9 +375,9 @@ int
|
||||
cmpwlneg(int op)
|
||||
{
|
||||
if (INRANGE(op, Ocmpw, Ocmpw1))
|
||||
return cmpneg(op - Ocmpw) + Ocmpw;
|
||||
return cmptab[op - Ocmpw][0] + Ocmpw;
|
||||
if (INRANGE(op, Ocmpl, Ocmpl1))
|
||||
return cmpneg(op - Ocmpl) + Ocmpl;
|
||||
return cmptab[op - Ocmpl][0] + Ocmpl;
|
||||
die("not a wl comparison");
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user