w6c: float-aware unary minus (fix -1.0 emitting +1.0 bit pattern)
This commit is contained in:
@@ -622,7 +622,29 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
case N_UN:
|
||||
cgexpr(c, n->lhs, locals);
|
||||
switch (n->op) {
|
||||
case TK_MINUS: ins1(c, A_NEGQ, areg(D_AX)); break;
|
||||
case TK_MINUS:
|
||||
if (node_isfloat(n->lhs)) {
|
||||
/* Float negate: X0 = 0 - X0. cgexpr left the
|
||||
* value in X0; AX-only NEGQ wouldn't touch it. */
|
||||
int isf32 = node_isf32(n->lhs);
|
||||
int mov = isf32 ? A_MOVSS : A_MOVSD;
|
||||
int sub = isf32 ? A_SUBSS : A_SUBSD;
|
||||
/* save orig X0 → stack */
|
||||
ins2(c, A_SUBQ, aimm(8), areg(D_SP));
|
||||
ins2(c, mov, areg(D_X0), amem(D_SP, 0));
|
||||
/* load 0.0 into X0 (zero bit pattern == 0.0) */
|
||||
ins2(c, A_MOVQ, aimm(0), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
ins2(c, mov, amem(D_SP, 0), areg(D_X0));
|
||||
ins2(c, A_ADDQ, aimm(8), areg(D_SP));
|
||||
/* X1 = orig; X0 = X0 - X1 = -orig */
|
||||
ins2(c, mov, amem(D_SP, 0), areg(D_X1));
|
||||
ins2(c, A_ADDQ, aimm(8), areg(D_SP));
|
||||
ins2(c, sub, areg(D_X1), areg(D_X0));
|
||||
} else {
|
||||
ins1(c, A_NEGQ, areg(D_AX));
|
||||
}
|
||||
break;
|
||||
case TK_TILDE: ins1(c, A_NOTQ, areg(D_AX)); break;
|
||||
case TK_NOT: {
|
||||
ins2(c, A_CMPQ, aimm(0), areg(D_AX));
|
||||
|
||||
Reference in New Issue
Block a user