cgen: f64 compare consults parity flag for NaN, 4 relops (both stages, #97)
UCOMISD/UCOMISS set PF=ZF=CF=1 on unordered (a NaN operand). The old arms keyed on ZF/CF only, so 4 of the 6 relops mishandled NaN: `nan != nan` was false (JNE keys on ZF=0), `nan == nan` was true, and `<`/`<=` (JB/JBE) fired on the unordered CF=1. IEEE-754: any relop with a NaN operand is unordered — `!=` true, the rest false. `!=` now jumps to true on JNE OR JP; `==`/`<`/`<=` jump to false on JP before the ordered Jcc. `>`/`>=` (JA/JAE) are LEFT UNCHANGED: they require CF=0, which an unordered UCOMISD never produces, so they already reject NaN correctly. Adding a PF guard there would only churn their .s (an extra JP on every >/>= float compare) for no correctness gain, so their arm stays byte-identical to the pre-#97 single template. Bundles the cgen fix with JP-mnemonic support in both assemblers (w6c enum/printer + w6a/w6a_ww parse+encode, 0F 8A). They can't split: the cgen emits JP, which has no encoding without the assembler change, so a cgen-only commit would not build. JP is the only PF-sensitive jump on amd64 — there is no alternative instruction.
This commit is contained in:
@@ -811,7 +811,8 @@ a_encode(Asm *a)
|
||||
break;
|
||||
case A_JE: case A_JNE: case A_JL: case A_JLE:
|
||||
case A_JG: case A_JGE: case A_JB: case A_JBE:
|
||||
case A_JA: case A_JAE: case A_JZ: case A_JNZ: {
|
||||
case A_JA: case A_JAE: case A_JZ: case A_JNZ:
|
||||
case A_JP: {
|
||||
u8 cc = 0;
|
||||
switch (p->as) {
|
||||
case A_JE: case A_JZ: cc = 0x84; break;
|
||||
@@ -824,6 +825,7 @@ a_encode(Asm *a)
|
||||
case A_JBE: cc = 0x86; break;
|
||||
case A_JA: cc = 0x87; break;
|
||||
case A_JAE: cc = 0x83; break;
|
||||
case A_JP: cc = 0x8A; break;
|
||||
default: break;
|
||||
}
|
||||
a_emit_byte(a, 0x0F);
|
||||
|
||||
@@ -119,6 +119,7 @@ opcode_lookup(const char *m)
|
||||
{ "JB", A_JB },{ "JBE", A_JBE },
|
||||
{ "JA", A_JA },{ "JAE", A_JAE },
|
||||
{ "JZ", A_JZ },{ "JNZ", A_JNZ },
|
||||
{ "JP", A_JP },
|
||||
{ "SYSCALL", A_SYSCALL },
|
||||
{ "TEXT", A_TEXT },
|
||||
{ "DATA", A_DATA },
|
||||
|
||||
@@ -106,6 +106,7 @@ enum {
|
||||
A_JL, A_JLE, A_JG, A_JGE,
|
||||
A_JB, A_JBE, A_JA, A_JAE,
|
||||
A_JZ, A_JNZ,
|
||||
A_JP, /* jump on parity (PF=1): UCOMISD unordered, #97 */
|
||||
|
||||
A_SYSCALL,
|
||||
|
||||
|
||||
@@ -2358,8 +2358,14 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
* unsigned compare, so the JA family is the right Jcc set
|
||||
* regardless of how the operand types are signed. Plan 9's
|
||||
* own w6c picks the same pattern (txt.c around AUCOMISD).
|
||||
* NaN handling: UCOMI sets PF on unordered; we ignore it,
|
||||
* which means NaN compares behave like Hare's default. */
|
||||
* NaN handling: UCOMI sets PF=ZF=CF=1 on unordered (a NaN
|
||||
* operand). IEEE-754: any relop with a NaN operand is
|
||||
* unordered — `!=` true, the other five false. PF must steer
|
||||
* `!=`/`==`/`<`/`<=` (#97): JNE keys on ZF=0 so `nan != nan`
|
||||
* came out false; JE/JB/JBE all fire on the unordered ZF/CF.
|
||||
* `>`/`>=` (JA/JAE) need CF=0, which unordered never gives,
|
||||
* so they are ALREADY NaN-correct and stay byte-identical to
|
||||
* the pre-#97 single-template arm — no redundant PF guard. */
|
||||
if (n->lhs && node_isfloat(n->lhs) &&
|
||||
(n->op == TK_EQ || n->op == TK_NEQ
|
||||
|| n->op == TK_LT || n->op == TK_LE
|
||||
@@ -2374,16 +2380,39 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, mov, amem(D_SP, 0), areg(D_X1));
|
||||
ins2(c, A_ADDQ, aimm(8), areg(D_SP));
|
||||
ins2(c, ucomi, areg(D_X1), areg(D_X0));
|
||||
int op = A_JE;
|
||||
switch (n->op) {
|
||||
case TK_EQ: op = A_JE; break;
|
||||
case TK_NEQ: op = A_JNE; break;
|
||||
case TK_LT: op = A_JB; break;
|
||||
case TK_LE: op = A_JBE; break;
|
||||
case TK_GT: op = A_JA; break;
|
||||
case TK_GE: op = A_JAE; break;
|
||||
default: break;
|
||||
if (n->op == TK_NEQ) {
|
||||
/* not-equal OR unordered -> true */
|
||||
char *t = mklabel(c, "ct");
|
||||
char *e = mklabel(c, "ce");
|
||||
ins1(c, A_JNE, abranch(t));
|
||||
ins1(c, A_JP, abranch(t));
|
||||
ins2(c, A_MOVQ, aimm(0), areg(D_AX));
|
||||
ins1(c, A_JMP, abranch(e));
|
||||
label(c, t);
|
||||
ins2(c, A_MOVQ, aimm(1), areg(D_AX));
|
||||
label(c, e);
|
||||
break;
|
||||
}
|
||||
if (n->op == TK_EQ || n->op == TK_LT || n->op == TK_LE) {
|
||||
/* unordered -> false; otherwise the ordered Jcc decides */
|
||||
int op = (n->op == TK_EQ) ? A_JE
|
||||
: (n->op == TK_LT) ? A_JB : A_JBE;
|
||||
char *fl = mklabel(c, "cf");
|
||||
char *t = mklabel(c, "ct");
|
||||
char *e = mklabel(c, "ce");
|
||||
ins1(c, A_JP, abranch(fl));
|
||||
ins1(c, op, abranch(t));
|
||||
label(c, fl);
|
||||
ins2(c, A_MOVQ, aimm(0), areg(D_AX));
|
||||
ins1(c, A_JMP, abranch(e));
|
||||
label(c, t);
|
||||
ins2(c, A_MOVQ, aimm(1), areg(D_AX));
|
||||
label(c, e);
|
||||
break;
|
||||
}
|
||||
/* `>`/`>=`: JA/JAE already reject unordered (CF=1), so
|
||||
* keep the pre-#97 single-template shape verbatim. */
|
||||
int op = (n->op == TK_GT) ? A_JA : A_JAE;
|
||||
char *t = mklabel(c, "ct");
|
||||
char *e = mklabel(c, "ce");
|
||||
ins1(c, op, abranch(t));
|
||||
|
||||
@@ -88,6 +88,7 @@ anames(int op)
|
||||
case A_JAE: return "JAE";
|
||||
case A_JZ: return "JZ";
|
||||
case A_JNZ: return "JNZ";
|
||||
case A_JP: return "JP";
|
||||
case A_SYSCALL: return "SYSCALL";
|
||||
}
|
||||
return "??";
|
||||
@@ -184,6 +185,7 @@ txt_emit(FILE *f, Prog *head)
|
||||
case A_JL: case A_JLE: case A_JG: case A_JGE:
|
||||
case A_JB: case A_JBE: case A_JA: case A_JAE:
|
||||
case A_JZ: case A_JNZ:
|
||||
case A_JP:
|
||||
fprintf(f, "\t%s\t", anames(p->as));
|
||||
prAdr(f, p->to);
|
||||
fputc('\n', f);
|
||||
|
||||
@@ -813,7 +813,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
else { if (op == A_JBE) { cc = 134u8; }
|
||||
else { if (op == A_JA) { cc = 135u8; }
|
||||
else { if (op == A_JAE) { cc = 131u8; }
|
||||
else { isjcc = false; };};};};};};};};};};};};
|
||||
else { if (op == A_JP) { cc = 138u8; } // 0x8A, UCOMISD unordered (#97)
|
||||
else { isjcc = false; };};};};};};};};};};};};};
|
||||
if (isjcc) {
|
||||
emitbyte(a, 15u8);
|
||||
emitbyte(a, cc);
|
||||
|
||||
@@ -2805,6 +2805,10 @@ def A_JA: i32 = 55;
|
||||
def A_JAE: i32 = 56;
|
||||
def A_JZ: i32 = 57;
|
||||
def A_JNZ: i32 = 58;
|
||||
// 67 (next free above A_CQO=66): appended so the existing A_MOV*/
|
||||
// A_SYSCALL/A_DATAW/A_DATAR/A_CQO numbers stay put. Jump on
|
||||
// parity (PF=1): UCOMISD unordered (#97).
|
||||
def A_JP: i32 = 67;
|
||||
|
||||
def A_SYSCALL: i32 = 59;
|
||||
|
||||
@@ -3060,6 +3064,7 @@ fn opcodelookup(p: *u8, n: u64) i32 = {
|
||||
if (streqlit(p, n, "JAE")) { return A_JAE; };
|
||||
if (streqlit(p, n, "JZ")) { return A_JZ; };
|
||||
if (streqlit(p, n, "JNZ")) { return A_JNZ; };
|
||||
if (streqlit(p, n, "JP")) { return A_JP; };
|
||||
if (streqlit(p, n, "SYSCALL")) { return A_SYSCALL; };
|
||||
if (streqlit(p, n, "TEXT")) { return A_TEXT; };
|
||||
if (streqlit(p, n, "DATA")) { return A_DATA; };
|
||||
@@ -4370,7 +4375,8 @@ export fn encode(a: *asm_) i32 = {
|
||||
else { if (op == A_JBE) { cc = 134u8; }
|
||||
else { if (op == A_JA) { cc = 135u8; }
|
||||
else { if (op == A_JAE) { cc = 131u8; }
|
||||
else { isjcc = false; };};};};};};};};};};};};
|
||||
else { if (op == A_JP) { cc = 138u8; } // 0x8A, UCOMISD unordered (#97)
|
||||
else { isjcc = false; };};};};};};};};};};};};};
|
||||
if (isjcc) {
|
||||
emitbyte(a, 15u8);
|
||||
emitbyte(a, cc);
|
||||
|
||||
@@ -122,6 +122,10 @@ def A_JA: i32 = 55;
|
||||
def A_JAE: i32 = 56;
|
||||
def A_JZ: i32 = 57;
|
||||
def A_JNZ: i32 = 58;
|
||||
// 67 (next free above A_CQO=66): appended so the existing A_MOV*/
|
||||
// A_SYSCALL/A_DATAW/A_DATAR/A_CQO numbers stay put. Jump on
|
||||
// parity (PF=1): UCOMISD unordered (#97).
|
||||
def A_JP: i32 = 67;
|
||||
|
||||
def A_SYSCALL: i32 = 59;
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ fn opcodelookup(p: *u8, n: u64) i32 = {
|
||||
if (streqlit(p, n, "JAE")) { return A_JAE; };
|
||||
if (streqlit(p, n, "JZ")) { return A_JZ; };
|
||||
if (streqlit(p, n, "JNZ")) { return A_JNZ; };
|
||||
if (streqlit(p, n, "JP")) { return A_JP; };
|
||||
if (streqlit(p, n, "SYSCALL")) { return A_SYSCALL; };
|
||||
if (streqlit(p, n, "TEXT")) { return A_TEXT; };
|
||||
if (streqlit(p, n, "DATA")) { return A_DATA; };
|
||||
|
||||
@@ -16848,16 +16848,12 @@ fn cgbin(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
let isfcmp: bool = false;
|
||||
let jcc: str = "";
|
||||
// UCOMISD/SS sets ZF/PF/CF; unordered (NaN) propagates as
|
||||
// "not equal / not less". JA/JAE/JB/JBE keys off CF which
|
||||
// matches the ordered comparisons we need.
|
||||
if (n.op == tkind.TK_EQ) { isfcmp = true; jcc = "JE"; };
|
||||
if (n.op == tkind.TK_NEQ) { isfcmp = true; jcc = "JNE"; };
|
||||
if (n.op == tkind.TK_LT) { isfcmp = true; jcc = "JB"; };
|
||||
if (n.op == tkind.TK_LE) { isfcmp = true; jcc = "JBE"; };
|
||||
if (n.op == tkind.TK_GT) { isfcmp = true; jcc = "JA"; };
|
||||
if (n.op == tkind.TK_GE) { isfcmp = true; jcc = "JAE"; };
|
||||
if (n.op == tkind.TK_EQ) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_NEQ) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_LT) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_LE) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_GT) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_GE) { isfcmp = true; };
|
||||
if (isfcmp) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
@@ -16868,6 +16864,51 @@ fn cgbin(c: *cgen, n: *node) void = {
|
||||
let ucomi: str = "UCOMISD";
|
||||
if (fk == 1) { ucomi = "UCOMISS"; };
|
||||
emitline("\t"); emitline(ucomi); emitline("\tX1, X0\n");
|
||||
// IEEE-754: UCOMISD/SS sets PF=ZF=CF=1 on unordered (a
|
||||
// NaN operand). Any relop with a NaN operand is
|
||||
// unordered -> `!=` true, the other five false. PF must
|
||||
// steer `!=`/`==`/`<`/`<=` (#97): JNE keys on ZF=0 so
|
||||
// `nan != nan` came out false; JE/JB/JBE fire on the
|
||||
// unordered ZF/CF. `>`/`>=` (JA/JAE) need CF=0, which
|
||||
// unordered never gives, so they are ALREADY NaN-correct
|
||||
// and stay byte-identical to the pre-#97 single-template
|
||||
// arm — no redundant PF guard.
|
||||
if (n.op == tkind.TK_NEQ) {
|
||||
// not-equal OR unordered -> true
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\tJNE\t"); emitline(t); emitline("\n");
|
||||
emitline("\tJP\t"); emitline(t); emitline("\n");
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
emitline("\tJMP\t"); emitline(e); emitline("\n");
|
||||
emitlabel(t);
|
||||
emitline("\tMOVQ\t$1, AX\n");
|
||||
emitlabel(e);
|
||||
return;
|
||||
};
|
||||
if (n.op == tkind.TK_EQ || n.op == tkind.TK_LT ||
|
||||
n.op == tkind.TK_LE) {
|
||||
// unordered -> false; otherwise the ordered Jcc decides.
|
||||
let jcc: str = "JE";
|
||||
if (n.op == tkind.TK_LT) { jcc = "JB"; };
|
||||
if (n.op == tkind.TK_LE) { jcc = "JBE"; };
|
||||
let fl: str = mklabel(c, "cf");
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\tJP\t"); emitline(fl); emitline("\n");
|
||||
emitline("\t"); emitline(jcc); emitline("\t"); emitline(t); emitline("\n");
|
||||
emitlabel(fl);
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
emitline("\tJMP\t"); emitline(e); emitline("\n");
|
||||
emitlabel(t);
|
||||
emitline("\tMOVQ\t$1, AX\n");
|
||||
emitlabel(e);
|
||||
return;
|
||||
};
|
||||
// `>`/`>=`: JA/JAE already reject unordered (CF=1), so
|
||||
// keep the pre-#97 single-template shape verbatim.
|
||||
let jcc: str = "JA";
|
||||
if (n.op == tkind.TK_GE) { jcc = "JAE"; };
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\t"); emitline(jcc); emitline("\t"); emitline(t); emitline("\n");
|
||||
|
||||
@@ -2825,16 +2825,12 @@ fn cgbin(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
let isfcmp: bool = false;
|
||||
let jcc: str = "";
|
||||
// UCOMISD/SS sets ZF/PF/CF; unordered (NaN) propagates as
|
||||
// "not equal / not less". JA/JAE/JB/JBE keys off CF which
|
||||
// matches the ordered comparisons we need.
|
||||
if (n.op == tkind.TK_EQ) { isfcmp = true; jcc = "JE"; };
|
||||
if (n.op == tkind.TK_NEQ) { isfcmp = true; jcc = "JNE"; };
|
||||
if (n.op == tkind.TK_LT) { isfcmp = true; jcc = "JB"; };
|
||||
if (n.op == tkind.TK_LE) { isfcmp = true; jcc = "JBE"; };
|
||||
if (n.op == tkind.TK_GT) { isfcmp = true; jcc = "JA"; };
|
||||
if (n.op == tkind.TK_GE) { isfcmp = true; jcc = "JAE"; };
|
||||
if (n.op == tkind.TK_EQ) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_NEQ) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_LT) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_LE) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_GT) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_GE) { isfcmp = true; };
|
||||
if (isfcmp) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
@@ -2845,6 +2841,51 @@ fn cgbin(c: *cgen, n: *node) void = {
|
||||
let ucomi: str = "UCOMISD";
|
||||
if (fk == 1) { ucomi = "UCOMISS"; };
|
||||
emitline("\t"); emitline(ucomi); emitline("\tX1, X0\n");
|
||||
// IEEE-754: UCOMISD/SS sets PF=ZF=CF=1 on unordered (a
|
||||
// NaN operand). Any relop with a NaN operand is
|
||||
// unordered -> `!=` true, the other five false. PF must
|
||||
// steer `!=`/`==`/`<`/`<=` (#97): JNE keys on ZF=0 so
|
||||
// `nan != nan` came out false; JE/JB/JBE fire on the
|
||||
// unordered ZF/CF. `>`/`>=` (JA/JAE) need CF=0, which
|
||||
// unordered never gives, so they are ALREADY NaN-correct
|
||||
// and stay byte-identical to the pre-#97 single-template
|
||||
// arm — no redundant PF guard.
|
||||
if (n.op == tkind.TK_NEQ) {
|
||||
// not-equal OR unordered -> true
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\tJNE\t"); emitline(t); emitline("\n");
|
||||
emitline("\tJP\t"); emitline(t); emitline("\n");
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
emitline("\tJMP\t"); emitline(e); emitline("\n");
|
||||
emitlabel(t);
|
||||
emitline("\tMOVQ\t$1, AX\n");
|
||||
emitlabel(e);
|
||||
return;
|
||||
};
|
||||
if (n.op == tkind.TK_EQ || n.op == tkind.TK_LT ||
|
||||
n.op == tkind.TK_LE) {
|
||||
// unordered -> false; otherwise the ordered Jcc decides.
|
||||
let jcc: str = "JE";
|
||||
if (n.op == tkind.TK_LT) { jcc = "JB"; };
|
||||
if (n.op == tkind.TK_LE) { jcc = "JBE"; };
|
||||
let fl: str = mklabel(c, "cf");
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\tJP\t"); emitline(fl); emitline("\n");
|
||||
emitline("\t"); emitline(jcc); emitline("\t"); emitline(t); emitline("\n");
|
||||
emitlabel(fl);
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
emitline("\tJMP\t"); emitline(e); emitline("\n");
|
||||
emitlabel(t);
|
||||
emitline("\tMOVQ\t$1, AX\n");
|
||||
emitlabel(e);
|
||||
return;
|
||||
};
|
||||
// `>`/`>=`: JA/JAE already reject unordered (CF=1), so
|
||||
// keep the pre-#97 single-template shape verbatim.
|
||||
let jcc: str = "JA";
|
||||
if (n.op == tkind.TK_GE) { jcc = "JAE"; };
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\t"); emitline(jcc); emitline("\t"); emitline(t); emitline("\n");
|
||||
|
||||
@@ -16848,16 +16848,12 @@ fn cgbin(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
let isfcmp: bool = false;
|
||||
let jcc: str = "";
|
||||
// UCOMISD/SS sets ZF/PF/CF; unordered (NaN) propagates as
|
||||
// "not equal / not less". JA/JAE/JB/JBE keys off CF which
|
||||
// matches the ordered comparisons we need.
|
||||
if (n.op == tkind.TK_EQ) { isfcmp = true; jcc = "JE"; };
|
||||
if (n.op == tkind.TK_NEQ) { isfcmp = true; jcc = "JNE"; };
|
||||
if (n.op == tkind.TK_LT) { isfcmp = true; jcc = "JB"; };
|
||||
if (n.op == tkind.TK_LE) { isfcmp = true; jcc = "JBE"; };
|
||||
if (n.op == tkind.TK_GT) { isfcmp = true; jcc = "JA"; };
|
||||
if (n.op == tkind.TK_GE) { isfcmp = true; jcc = "JAE"; };
|
||||
if (n.op == tkind.TK_EQ) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_NEQ) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_LT) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_LE) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_GT) { isfcmp = true; };
|
||||
if (n.op == tkind.TK_GE) { isfcmp = true; };
|
||||
if (isfcmp) {
|
||||
cgexpr(c, n.rhs);
|
||||
emitline("\tSUBQ\t$8, SP\n");
|
||||
@@ -16868,6 +16864,51 @@ fn cgbin(c: *cgen, n: *node) void = {
|
||||
let ucomi: str = "UCOMISD";
|
||||
if (fk == 1) { ucomi = "UCOMISS"; };
|
||||
emitline("\t"); emitline(ucomi); emitline("\tX1, X0\n");
|
||||
// IEEE-754: UCOMISD/SS sets PF=ZF=CF=1 on unordered (a
|
||||
// NaN operand). Any relop with a NaN operand is
|
||||
// unordered -> `!=` true, the other five false. PF must
|
||||
// steer `!=`/`==`/`<`/`<=` (#97): JNE keys on ZF=0 so
|
||||
// `nan != nan` came out false; JE/JB/JBE fire on the
|
||||
// unordered ZF/CF. `>`/`>=` (JA/JAE) need CF=0, which
|
||||
// unordered never gives, so they are ALREADY NaN-correct
|
||||
// and stay byte-identical to the pre-#97 single-template
|
||||
// arm — no redundant PF guard.
|
||||
if (n.op == tkind.TK_NEQ) {
|
||||
// not-equal OR unordered -> true
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\tJNE\t"); emitline(t); emitline("\n");
|
||||
emitline("\tJP\t"); emitline(t); emitline("\n");
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
emitline("\tJMP\t"); emitline(e); emitline("\n");
|
||||
emitlabel(t);
|
||||
emitline("\tMOVQ\t$1, AX\n");
|
||||
emitlabel(e);
|
||||
return;
|
||||
};
|
||||
if (n.op == tkind.TK_EQ || n.op == tkind.TK_LT ||
|
||||
n.op == tkind.TK_LE) {
|
||||
// unordered -> false; otherwise the ordered Jcc decides.
|
||||
let jcc: str = "JE";
|
||||
if (n.op == tkind.TK_LT) { jcc = "JB"; };
|
||||
if (n.op == tkind.TK_LE) { jcc = "JBE"; };
|
||||
let fl: str = mklabel(c, "cf");
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\tJP\t"); emitline(fl); emitline("\n");
|
||||
emitline("\t"); emitline(jcc); emitline("\t"); emitline(t); emitline("\n");
|
||||
emitlabel(fl);
|
||||
emitline("\tMOVQ\t$0, AX\n");
|
||||
emitline("\tJMP\t"); emitline(e); emitline("\n");
|
||||
emitlabel(t);
|
||||
emitline("\tMOVQ\t$1, AX\n");
|
||||
emitlabel(e);
|
||||
return;
|
||||
};
|
||||
// `>`/`>=`: JA/JAE already reject unordered (CF=1), so
|
||||
// keep the pre-#97 single-template shape verbatim.
|
||||
let jcc: str = "JA";
|
||||
if (n.op == tkind.TK_GE) { jcc = "JAE"; };
|
||||
let t: str = mklabel(c, "ct");
|
||||
let e: str = mklabel(c, "ce");
|
||||
emitline("\t"); emitline(jcc); emitline("\t"); emitline(t); emitline("\n");
|
||||
|
||||
Reference in New Issue
Block a user