Files
ww/cmd/w6c/6.out.h
Hojun-Cho fa136d0b88 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.
2026-05-25 12:44:56 +09:00

120 lines
2.7 KiB
C

/*
* 6.out.h — amd64 instruction enum + register names. Mirrors the
* Plan 9 6c shape (cmd/6c/6.out.h) but trimmed to the subset that
* w6c emits and w6a consumes in this bootstrap. Each new opcode added
* here must also gain encoding support in cmd/w6a/asm.c.
*/
#ifndef SIX_OUT_H
#define SIX_OUT_H
/* registers — Plan 9 names; lowercase = 8-bit, etc. We use 64-bit. */
enum {
D_NONE = 0,
/* general purpose 64-bit */
D_AX, D_CX, D_DX, D_BX,
D_SP, D_BP, D_SI, D_DI,
D_R8, D_R9, D_R10, D_R11,
D_R12, D_R13, D_R14, D_R15,
/* SSE/XMM 64-bit float regs */
D_X0, D_X1, D_X2, D_X3,
D_X4, D_X5, D_X6, D_X7,
D_X8, D_X9, D_X10, D_X11,
D_X12, D_X13, D_X14, D_X15,
/* pseudo regs (Plan 9) */
D_PSP, /* SP pseudo (frame-relative) */
D_PFP, /* FP pseudo (incoming args) */
D_PSB, /* SB pseudo (static base) */
/* operand kinds; not registers but share the slot */
D_CONST, /* $N immediate */
D_BRANCH, /* label reference */
D_EXTERN, /* external symbol */
D_INDIR /* offset(reg) memory */
};
/* opcodes — the small set we currently emit & encode */
enum {
A_NOP = 0,
A_TEXT,
A_DATA,
A_DATAW, /* writable DATA: lands in .data (RW) instead of .text */
A_DATAR, /* reloc-only: patch a 64-bit slot in .data with a
* symbol's runtime VA. Pairs with a prior DATAW
* that left zero placeholder bytes. */
A_GLOBL,
A_END,
A_MOVQ,
A_MOVL,
A_MOVW,
A_MOVB,
A_MOVZBQ, /* movzx r64, r/m8 — byte zero-extended */
A_MOVZWQ, /* movzx r64, r/m16 — word zero-extended */
A_MOVSXD, /* movsxd r64, r/m32 — i32 sign-extended */
A_MOVSWQ, /* movsx r64, r/m16 — i16 sign-extended */
A_MOVSBQ, /* movsx r64, r/m8 — i8 sign-extended */
/* SSE2 scalar double-precision float */
A_MOVSD, /* xmm/m → xmm and xmm → m */
A_ADDSD,
A_SUBSD,
A_MULSD,
A_DIVSD,
A_UCOMISD,
A_CVTTSD2SI, /* truncate f64 → i64 */
A_CVTSI2SD, /* convert i64 → f64 */
/* SSE scalar single-precision float (f32). Same xmm regs. */
A_MOVSS,
A_ADDSS,
A_SUBSS,
A_MULSS,
A_DIVSS,
A_UCOMISS,
A_CVTTSS2SI,
A_CVTSI2SS,
A_CVTSD2SS, /* f64 → f32 truncate */
A_CVTSS2SD, /* f32 → f64 widen */
A_ADDQ,
A_SUBQ,
A_IMULQ,
A_IDIVQ,
A_DIVQ, /* unsigned 64-bit divide; sibling of IDIVQ */
A_CQO, /* sign-extend RAX into RDX:RAX; the signed-division
* prep that pairs with IDIVQ (DIVQ pairs with a
* MOVQ $0, DX zero-fill). */
A_NEGQ,
A_NOTQ,
A_ANDQ,
A_ORQ,
A_XORQ,
A_SHLQ,
A_SHRQ,
A_CMPQ,
A_PUSHQ,
A_POPQ,
A_LEAQ,
A_CALL,
A_RET,
A_JMP,
A_JE, A_JNE,
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,
A_LAST
};
const char *anames(int); /* opcode -> mnemonic */
const char *rnames(int); /* register -> name */
#endif