Skip to content

Commit

Permalink
Handle NaN
Browse files Browse the repository at this point in the history
Keep lhs and rhs for comparing flonums.

Fix #161
  • Loading branch information
tyfkda committed Jul 10, 2024
1 parent 2e0a99c commit d661b5c
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/as/arch/aarch64/aarch64_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
#define FSUB(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1e203800U | ((sz) << 22) | ((rm) << 16) | ((rn) << 5) | (rd))
#define FMUL(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1e200800U | ((sz) << 22) | ((rm) << 16) | ((rn) << 5) | (rd))
#define FDIV(sz, rd, rn, rm) MAKE_CODE32(inst, code, 0x1e201800U | ((sz) << 22) | ((rm) << 16) | ((rn) << 5) | (rd))
#define FCMP(sz, rd, rn) MAKE_CODE32(inst, code, 0x1e602000U | ((sz) << 22) | ((rn) << 16) | ((rd) << 5))
#define FCMP(sz, rd, rn) MAKE_CODE32(inst, code, 0x1e202000U | ((sz) << 22) | ((rn) << 16) | ((rd) << 5))
#define FNEG(sz, rd, rn) MAKE_CODE32(inst, code, 0x1e214000U | ((sz) << 22) | ((rn) << 5) | (rd))
#define FSQRT(sz, rd, rn) MAKE_CODE32(inst, code, 0x1e21c000U | ((sz) << 22) | ((rn) << 5) | (rd))

Expand Down
29 changes: 13 additions & 16 deletions src/as/arch/x64/asm_code.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ static unsigned char *asm_xorpd_xx(Inst *inst, Code *code) {
}
#define asm_xorps_xx asm_xorpd_xx

static unsigned char *assemble_ucomisd(Inst *inst, Code *code, bool single) {
static unsigned char *assemble_ucomisd(Inst *inst, Code *code, unsigned char opc, bool single) {
unsigned char *p = code->buf;
if (inst->opr[0].type == REG_XMM && inst->opr[1].type == REG_XMM) {
unsigned char sno = inst->opr[0].regxmm - XMM0;
Expand All @@ -589,15 +589,17 @@ static unsigned char *assemble_ucomisd(Inst *inst, Code *code, bool single) {
single ? -1 : 0x66,
sno >= 8 || dno >= 8 ? (unsigned char)0x40 | ((sno & 8) >> 3) | ((dno & 8) >> 1) : -1,
0x0f,
0x2e,
opc,
(unsigned char)0xc0 | ((dno & 7) << 3) | (sno & 7),
};
p = put_code_filtered(p, buf, ARRAY_SIZE(buf));
}
return p;
}
static unsigned char *asm_ucomisd_xx(Inst *inst, Code *code) { return assemble_ucomisd(inst, code, false); }
static unsigned char *asm_ucomiss_xx(Inst *inst, Code *code) { return assemble_ucomisd(inst, code, true); }
static unsigned char *asm_comisd_xx(Inst *inst, Code *code) { return assemble_ucomisd(inst, code, 0x2f, false); }
static unsigned char *asm_comiss_xx(Inst *inst, Code *code) { return assemble_ucomisd(inst, code, 0x2f, true); }
static unsigned char *asm_ucomisd_xx(Inst *inst, Code *code) { return assemble_ucomisd(inst, code, 0x2e, false); }
static unsigned char *asm_ucomiss_xx(Inst *inst, Code *code) { return assemble_ucomisd(inst, code, 0x2e, true); }

static unsigned char *assemble_cvtsi2sd(Inst *inst, Code *code, bool single) {
unsigned char *p = code->buf;
Expand Down Expand Up @@ -1587,18 +1589,13 @@ static const AsmInstFunc table[] = {
[MOVSS_XX] = asm_movss_xx,
[MOVSS_IX] = asm_movss_ix,
[MOVSS_XI] = asm_movss_xi,
[ADDSD] = asm_addsd_xx,
[ADDSS] = asm_addss_xx,
[SUBSD] = asm_subsd_xx,
[SUBSS] = asm_subss_xx,
[MULSD] = asm_mulsd_xx,
[MULSS] = asm_mulss_xx,
[DIVSD] = asm_divsd_xx,
[DIVSS] = asm_divss_xx,
[XORPD] = asm_xorpd_xx,
[XORPS] = asm_xorps_xx,
[UCOMISD] = asm_ucomisd_xx,
[UCOMISS] = asm_ucomiss_xx,
[ADDSD] = asm_addsd_xx, [ADDSS] = asm_addss_xx,
[SUBSD] = asm_subsd_xx, [SUBSS] = asm_subss_xx,
[MULSD] = asm_mulsd_xx, [MULSS] = asm_mulss_xx,
[DIVSD] = asm_divsd_xx, [DIVSS] = asm_divss_xx,
[XORPD] = asm_xorpd_xx, [XORPS] = asm_xorps_xx,
[COMISD] = asm_comisd_xx, [UCOMISD] = asm_ucomisd_xx,
[COMISS] = asm_comiss_xx, [UCOMISS] = asm_ucomiss_xx,
[CVTSI2SD] = asm_cvtsi2sd_rx,
[CVTSI2SS] = asm_cvtsi2ss_rx,
[CVTTSD2SI] = asm_cvttsd2si_xr,
Expand Down
4 changes: 2 additions & 2 deletions src/as/arch/x64/inst.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ enum Opcode {

MOVSD_XX, MOVSD_IX, MOVSD_XI,
ADDSD, SUBSD, MULSD, DIVSD, XORPD,
UCOMISD,
COMISD, UCOMISD,
CVTSI2SD, CVTTSD2SI,
SQRTSD,

MOVSS_XX, MOVSS_IX, MOVSS_XI,
ADDSS, SUBSS, MULSS, DIVSS, XORPS,
UCOMISS,
COMISS, UCOMISS,
CVTSI2SS, CVTTSS2SI,
CVTSD2SS, CVTSS2SD,
};
Expand Down
10 changes: 6 additions & 4 deletions src/as/arch/x64/parse_x64.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ enum RawOpcode {
R_INT, R_SYSCALL,

R_MOVSD, R_ADDSD, R_SUBSD, R_MULSD, R_DIVSD, R_XORPD,
R_UCOMISD,
R_COMISD, R_UCOMISD,
R_CVTSI2SD, R_CVTTSD2SI,
R_SQRTSD,

R_MOVSS, R_ADDSS, R_SUBSS, R_MULSS, R_DIVSS, R_XORPS,
R_UCOMISS,
R_COMISS, R_UCOMISS,
R_CVTSI2SS, R_CVTTSS2SI,

R_CVTSD2SS, R_CVTSS2SD,
Expand Down Expand Up @@ -85,12 +85,12 @@ const char *kRawOpTable[] = {
"int", "syscall",

"movsd", "addsd", "subsd", "mulsd", "divsd", "xorpd",
"ucomisd",
"comisd", "ucomisd",
"cvtsi2sd", "cvttsd2si",
"sqrtsd",

"movss", "addss", "subss", "mulss", "divss", "xorps",
"ucomiss",
"comiss", "ucomiss",
"cvtsi2ss", "cvttss2si",
"cvtsd2ss", "cvtss2sd",
NULL,
Expand Down Expand Up @@ -674,7 +674,9 @@ const ParseInstTable kParseInstTable[] = {
[R_DIVSS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){DIVSS, {XMM, XMM}}, } },
[R_XORPD] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){XORPD, {XMM, XMM}}, } },
[R_XORPS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){XORPS, {XMM, XMM}}, } },
[R_COMISD] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){COMISD, {XMM, XMM}}, } },
[R_UCOMISD] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UCOMISD, {XMM, XMM}}, } },
[R_COMISS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){COMISS, {XMM, XMM}}, } },
[R_UCOMISS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){UCOMISS, {XMM, XMM}}, } },
[R_CVTSI2SD] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){CVTSI2SD, {R32 | R64, XMM}}, } },
[R_CVTSI2SS] = { 1, (const ParseOpArray*[]){ &(ParseOpArray){CVTSI2SS, {R32 | R64, XMM}}, } },
Expand Down
16 changes: 11 additions & 5 deletions src/cc/arch/aarch64/aarch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,20 @@
// Condition
#define CEQ "eq"
#define CNE "ne"
#define CLT "lt"
#define CGT "gt"
#define CLE "le"
#define CGE "ge"
#define CHS "hs"
#define CLO "lo"
#define CMI "mi"
#define CPL "pl"
#define CVS "vs"
#define CVC "vc"
#define CHI "hi"
#define CLS "ls"
#define CHS "hs"
#define CGE "ge"
#define CLT "lt"
#define CGT "gt"
#define CLE "le"
#define CAL "al"
#define CNV "nv"

#define MOV(o1, o2) EMIT_ASM("mov", o1, o2)
#define MOVK(o1, o2, o3) EMIT_ASM("movk", o1, o2, o3)
Expand Down
23 changes: 21 additions & 2 deletions src/cc/arch/aarch64/ir_aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,18 @@ static void ei_cond(IR *ir) {

assert(!(ir->dst->flag & VRF_CONST));
const char *dst = kReg32s[ir->dst->phys]; // Assume bool is 4 byte.
int cond = ir->cond.kind;
// On aarch64, flag for comparing flonum is signed.
switch (ir->cond.kind & (COND_MASK | COND_UNSIGNED)) {
if (cond & COND_FLONUM) {
cond &= COND_MASK;
switch (cond) {
case COND_LT: CSET(dst, CMI); return;
case COND_LE: CSET(dst, CLS); return;
default: break;
}
}

switch (cond) {
case COND_EQ | COND_UNSIGNED: // Fallthrough
case COND_EQ: CSET(dst, CEQ); break;

Expand All @@ -586,14 +596,23 @@ static void ei_cond(IR *ir) {

static void ei_jmp(IR *ir) {
const char *label = fmt_name(ir->jmp.bb->label);
int cond = ir->jmp.cond & (COND_MASK | COND_UNSIGNED);
int cond = ir->jmp.cond;
if (cond == COND_ANY) {
BRANCH(label);
return;
}

cmp_vregs(ir->opr1, ir->opr2);

if (cond & COND_FLONUM) {
cond &= COND_MASK;
switch (cond) {
case COND_LT: Bcc(CMI, label); return;
case COND_LE: Bcc(CLS, label); return;
default: break;
}
}

// On aarch64, flag for comparing flonum is signed.
switch (cond) {
case COND_EQ | COND_UNSIGNED: // Fallthrough
Expand Down
94 changes: 83 additions & 11 deletions src/cc/arch/x64/ir_x64.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,13 +464,21 @@ static void ei_rshift(IR *ir) {
#undef RSHIFT_INST
}

static void cmp_vregs(VReg *opr1, VReg *opr2) {
static void cmp_vregs(VReg *opr1, VReg *opr2, int cond) {
if (opr1->flag & VRF_FLONUM) {
assert(opr2->flag & VRF_FLONUM);
switch (opr1->vsize) {
case SZ_FLOAT: UCOMISS(kFReg64s[opr2->phys], kFReg64s[opr1->phys]); break;
case SZ_DOUBLE: UCOMISD(kFReg64s[opr2->phys], kFReg64s[opr1->phys]); break;
default: assert(false); break;
if ((cond & COND_MASK) <= COND_NE) {
switch (opr1->vsize) {
case SZ_FLOAT: UCOMISS(kFReg64s[opr2->phys], kFReg64s[opr1->phys]); break;
case SZ_DOUBLE: UCOMISD(kFReg64s[opr2->phys], kFReg64s[opr1->phys]); break;
default: assert(false); break;
}
} else {
switch (opr1->vsize) {
case SZ_FLOAT: COMISS(kFReg64s[opr2->phys], kFReg64s[opr1->phys]); break;
case SZ_DOUBLE: COMISD(kFReg64s[opr2->phys], kFReg64s[opr1->phys]); break;
default: assert(false); break;
}
}
} else {
assert(!(opr1->flag & VRF_CONST));
Expand Down Expand Up @@ -544,14 +552,46 @@ static void ei_bitnot(IR *ir) {
}

static void ei_cond(IR *ir) {
cmp_vregs(ir->opr1, ir->opr2);
VReg *opr1 = ir->opr1, *opr2 = ir->opr2;

assert(!(ir->dst->flag & VRF_CONST));
const char *dst = kReg8s[ir->dst->phys];
int cond = ir->cond.kind;
// On x64, flag for comparing flonum is same as unsigned.
if (cond & COND_FLONUM)
cond ^= COND_FLONUM | COND_UNSIGNED; // Turn off flonum, and turn on unsigned
if (cond & COND_FLONUM) {
cond &= COND_MASK;
if (cond == COND_LT || cond == COND_LE) {
VReg *tmp = opr1;
opr1 = opr2;
opr2 = tmp;
cond = swap_cond(cond);
}
switch (cond) {
case COND_EQ:
case COND_NE:
{
cmp_vregs(opr1, opr2, cond);
if (cond == COND_EQ) SETNP(dst);
else SETP(dst);

const Name *skip_label = alloc_label();
cmp_vregs(opr1, opr2, cond);
JE(fmt_name(skip_label));
MOV(IM(cond != COND_EQ ? 1 : 0), dst);
EMIT_LABEL(fmt_name(skip_label));

MOVSX(dst, kReg32s[ir->dst->phys]); // Assume bool is 4 byte.
}
return;

default: break;
}

cond |= COND_UNSIGNED; // Turn on unsigned
}

cmp_vregs(opr1, opr2, cond);

switch (cond) {
case COND_EQ | COND_UNSIGNED: // Fallthrough
case COND_EQ: SETE(dst); break;
Expand All @@ -575,17 +615,49 @@ static void ei_cond(IR *ir) {

static void ei_jmp(IR *ir) {
const char *label = fmt_name(ir->jmp.bb->label);
VReg *opr1 = ir->opr1, *opr2 = ir->opr2;
int cond = ir->jmp.cond;
// On x64, flag for comparing flonum is same as unsigned.
if (cond & COND_FLONUM)
cond ^= COND_FLONUM | COND_UNSIGNED; // Turn off flonum, and turn on unsigned
if (cond & COND_FLONUM) {
cond &= COND_MASK;
// Special handling required for `==` and `!=`.
switch (cond) {
case COND_EQ:
{
const Name *skip_label = alloc_label();
cmp_vregs(ir->opr1, ir->opr2, cond);
JP(fmt_name(skip_label));
JE(label);
EMIT_LABEL(fmt_name(skip_label));
}
return;
case COND_NE:
cmp_vregs(ir->opr1, ir->opr2, cond);
JP(label);
JNE(label);
return;

case COND_LT: case COND_LE:
{
VReg *tmp = opr1;
opr1 = opr2;
opr2 = tmp;
cond = swap_cond(cond);
}
break;

default: break;
}

cond |= COND_UNSIGNED; // Turn on unsigned
}

if (cond == COND_ANY) {
JMP(label);
return;
}

cmp_vregs(ir->opr1, ir->opr2);
cmp_vregs(opr1, opr2, cond);

switch (cond) {
case COND_EQ | COND_UNSIGNED: // Fallthrough
Expand Down
6 changes: 6 additions & 0 deletions src/cc/arch/x64/x64.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@
#define JA(o1) EMIT_ASM("ja", o1)
#define JBE(o1) EMIT_ASM("jbe", o1)
#define JAE(o1) EMIT_ASM("jae", o1)
#define JP(o1) EMIT_ASM("jp", o1)
#define JNP(o1) EMIT_ASM("jnp", o1)
#define JS(o1) EMIT_ASM("js", o1)
#define CALL(o1) EMIT_ASM("call", o1)
#define RET() EMIT_ASM("ret")
Expand All @@ -170,6 +172,8 @@
#define SETA(o1) EMIT_ASM("seta", o1)
#define SETBE(o1) EMIT_ASM("setbe", o1)
#define SETAE(o1) EMIT_ASM("setae", o1)
#define SETP(o1) EMIT_ASM("setp", o1)
#define SETNP(o1) EMIT_ASM("setnp", o1)
#define CWTL() EMIT_ASM("cwtl")
#define CLTD() EMIT_ASM("cltd")
#define CQTO() EMIT_ASM("cqto")
Expand All @@ -182,6 +186,7 @@
#define MULSD(o1, o2) EMIT_ASM("mulsd", o1, o2)
#define DIVSD(o1, o2) EMIT_ASM("divsd", o1, o2)
#define XORPD(o1, o2) EMIT_ASM("xorpd", o1, o2)
#define COMISD(o1, o2) EMIT_ASM("comisd", o1, o2)
#define UCOMISD(o1, o2) EMIT_ASM("ucomisd", o1, o2)
#define CVTSI2SD(o1, o2) EMIT_ASM("cvtsi2sd", o1, o2)
#define CVTTSD2SI(o1, o2) EMIT_ASM("cvttsd2si", o1, o2)
Expand All @@ -192,6 +197,7 @@
#define MULSS(o1, o2) EMIT_ASM("mulss", o1, o2)
#define DIVSS(o1, o2) EMIT_ASM("divss", o1, o2)
#define XORPS(o1, o2) EMIT_ASM("xorps", o1, o2)
#define COMISS(o1, o2) EMIT_ASM("comiss", o1, o2)
#define UCOMISS(o1, o2) EMIT_ASM("ucomiss", o1, o2)
#define CVTSI2SS(o1, o2) EMIT_ASM("cvtsi2ss", o1, o2)
#define CVTTSS2SI(o1, o2) EMIT_ASM("cvttss2si", o1, o2)
Expand Down
Loading

0 comments on commit d661b5c

Please sign in to comment.