w6c+selfhost: cgen N_CAST signed narrow + peel !T on unsigned narrow
TY_RUNE excluded — wwstage primsize skips it; task #5 will collapse both gates back to symmetric once type_isunsigned recurses TY_ENUM.
This commit is contained in:
@@ -494,11 +494,41 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
if (isgpr(ft)) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(ft), 1);
|
||||
emitbyte(a, 15u8);
|
||||
emitbyte(a, 191u8); // 0xBF
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSWQ shape\n".ptr, 29u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
|
||||
if (op == A_MOVSBQ) {
|
||||
// MOVSX r64, r/m8 — 0F BE /r with REX.W.
|
||||
let ft: i32 = p.from.atype;
|
||||
let tt: i32 = p.to.atype;
|
||||
if (ft == D_INDIR) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(p.from.reg), 1);
|
||||
emitbyte(a, 15u8);
|
||||
emitbyte(a, 190u8); // 0xBE
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
if (isgpr(ft)) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(ft), 1);
|
||||
emitbyte(a, 15u8);
|
||||
emitbyte(a, 190u8); // 0xBE
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSBQ shape\n".ptr, 29u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
|
||||
if (op == A_MOVZBQ) {
|
||||
let ft: i32 = p.from.atype;
|
||||
let tt: i32 = p.to.atype;
|
||||
@@ -549,6 +579,12 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
if (isgpr(ft)) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(ft), 1);
|
||||
emitbyte(a, 99u8); // 0x63
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSXD shape\n".ptr, 29u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
|
||||
@@ -421,6 +421,7 @@ def A_MOVSXD: i32 = 9;
|
||||
def A_MOVW: i32 = 62;
|
||||
def A_MOVZWQ: i32 = 63;
|
||||
def A_MOVSWQ: i32 = 64;
|
||||
def A_MOVSBQ: i32 = 65;
|
||||
|
||||
def A_MOVSD: i32 = 10;
|
||||
def A_ADDSD: i32 = 11;
|
||||
@@ -673,6 +674,7 @@ fn opcodelookup(p: *u8, n: u64) i32 = {
|
||||
if (streqlit(p, n, "MOVZWQ")) { return A_MOVZWQ; };
|
||||
if (streqlit(p, n, "MOVSXD")) { return A_MOVSXD; };
|
||||
if (streqlit(p, n, "MOVSWQ")) { return A_MOVSWQ; };
|
||||
if (streqlit(p, n, "MOVSBQ")) { return A_MOVSBQ; };
|
||||
if (streqlit(p, n, "MOVSD")) { return A_MOVSD; };
|
||||
if (streqlit(p, n, "ADDSD")) { return A_ADDSD; };
|
||||
if (streqlit(p, n, "SUBSD")) { return A_SUBSD; };
|
||||
@@ -1720,11 +1722,41 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
if (isgpr(ft)) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(ft), 1);
|
||||
emitbyte(a, 15u8);
|
||||
emitbyte(a, 191u8); // 0xBF
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSWQ shape\n".ptr, 29u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
|
||||
if (op == A_MOVSBQ) {
|
||||
// MOVSX r64, r/m8 — 0F BE /r with REX.W.
|
||||
let ft: i32 = p.from.atype;
|
||||
let tt: i32 = p.to.atype;
|
||||
if (ft == D_INDIR) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(p.from.reg), 1);
|
||||
emitbyte(a, 15u8);
|
||||
emitbyte(a, 190u8); // 0xBE
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
if (isgpr(ft)) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(ft), 1);
|
||||
emitbyte(a, 15u8);
|
||||
emitbyte(a, 190u8); // 0xBE
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSBQ shape\n".ptr, 29u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
};
|
||||
|
||||
if (op == A_MOVZBQ) {
|
||||
let ft: i32 = p.from.atype;
|
||||
let tt: i32 = p.to.atype;
|
||||
@@ -1775,6 +1807,12 @@ export fn encode(a: *asm_) i32 = {
|
||||
emitmodrmmem(a, rcode(tt), p.from.reg, p.from.offset);
|
||||
p = p.link; continue;
|
||||
};};
|
||||
if (isgpr(ft)) { if (isgpr(tt)) {
|
||||
emitrex(a, rhi(tt), rhi(ft), 1);
|
||||
emitbyte(a, 99u8); // 0x63
|
||||
emitbyte(a, modrmbyte(3, rcode(tt), rcode(ft)));
|
||||
p = p.link; continue;
|
||||
};};
|
||||
os.write(2, "w6a: unsupported MOVSXD shape\n".ptr, 29u64);
|
||||
a.errs += 1;
|
||||
p = p.link; continue;
|
||||
|
||||
@@ -37,6 +37,7 @@ fn opcodelookup(p: *u8, n: u64) i32 = {
|
||||
if (streqlit(p, n, "MOVZWQ")) { return A_MOVZWQ; };
|
||||
if (streqlit(p, n, "MOVSXD")) { return A_MOVSXD; };
|
||||
if (streqlit(p, n, "MOVSWQ")) { return A_MOVSWQ; };
|
||||
if (streqlit(p, n, "MOVSBQ")) { return A_MOVSBQ; };
|
||||
if (streqlit(p, n, "MOVSD")) { return A_MOVSD; };
|
||||
if (streqlit(p, n, "ADDSD")) { return A_ADDSD; };
|
||||
if (streqlit(p, n, "SUBSD")) { return A_SUBSD; };
|
||||
|
||||
@@ -67,6 +67,7 @@ def A_MOVSXD: i32 = 9;
|
||||
def A_MOVW: i32 = 62;
|
||||
def A_MOVZWQ: i32 = 63;
|
||||
def A_MOVSWQ: i32 = 64;
|
||||
def A_MOVSBQ: i32 = 65;
|
||||
|
||||
def A_MOVSD: i32 = 10;
|
||||
def A_ADDSD: i32 = 11;
|
||||
|
||||
@@ -8159,21 +8159,25 @@ fn cgcast(c: *cgen, n: *node) void = {
|
||||
// int↔int casts narrow via an explicit clamp before the early
|
||||
// return so `(big_u64): u32` doesn't leak the upper 32 bits.
|
||||
// Hare semantics: `expr: T` truncates to T's bit width (mod 2^n).
|
||||
// Mirrors cmd/w6c/cgen.c's N_CAST clamp; signed-narrow targets
|
||||
// (i8/i16/i32) stay no-ops until the assembler grows MOVSBQ /
|
||||
// MOVSWQ / MOVSXD reg-reg forms.
|
||||
// Mirrors cmd/w6c/cgen.c's N_CAST clamp. Unsigned narrow clears
|
||||
// the upper bits via MOVL/ANDQ; signed narrow sign-extends via
|
||||
// MOVSBQ/MOVSWQ/MOVSXD reg-reg so the sign bit propagates.
|
||||
if (srcfk == 0 && dstfk == 0) {
|
||||
let tn: *node = n.rhs;
|
||||
// Walk through alias chains (`type random = u64`).
|
||||
// Walk through alias chains (`type random = u64`) and the
|
||||
// `!T` error-flag wrapper (`type invalid = !i32`) — the
|
||||
// bang is a tagged-union marker, not a representational
|
||||
// change, so it must not block the narrow-cast clamp.
|
||||
for (tn != nil) {
|
||||
if (tn.kind != nkind.N_TNAME) { tn = nil; }
|
||||
if (tn.kind == nkind.N_TBANG) { tn = tn.lhs; }
|
||||
else { if (tn.kind != nkind.N_TNAME) { tn = nil; }
|
||||
else {
|
||||
let nm: str = tn.str;
|
||||
if (primsize(nm) > 0) { break; };
|
||||
let alias: *node = aliaslookup(c, nm);
|
||||
if (alias == nil) { tn = nil; }
|
||||
else { tn = alias; };
|
||||
};
|
||||
}; };
|
||||
};
|
||||
if (tn != nil) {
|
||||
let nm: str = tn.str;
|
||||
@@ -8193,7 +8197,13 @@ fn cgcast(c: *cgen, n: *node) void = {
|
||||
};
|
||||
} else { if (is_bool) {
|
||||
emitline("\tANDQ\t$255, AX\n");
|
||||
}; };
|
||||
} else { if (streq(nm, "i8")) {
|
||||
emitline("\tMOVSBQ\tAX, AX\n");
|
||||
} else { if (streq(nm, "i16")) {
|
||||
emitline("\tMOVSWQ\tAX, AX\n");
|
||||
} else { if (streq(nm, "i32")) {
|
||||
emitline("\tMOVSXD\tAX, AX\n");
|
||||
}; }; }; }; };
|
||||
}; };
|
||||
};
|
||||
return;
|
||||
|
||||
@@ -378,21 +378,25 @@ fn cgcast(c: *cgen, n: *node) void = {
|
||||
// int↔int casts narrow via an explicit clamp before the early
|
||||
// return so `(big_u64): u32` doesn't leak the upper 32 bits.
|
||||
// Hare semantics: `expr: T` truncates to T's bit width (mod 2^n).
|
||||
// Mirrors cmd/w6c/cgen.c's N_CAST clamp; signed-narrow targets
|
||||
// (i8/i16/i32) stay no-ops until the assembler grows MOVSBQ /
|
||||
// MOVSWQ / MOVSXD reg-reg forms.
|
||||
// Mirrors cmd/w6c/cgen.c's N_CAST clamp. Unsigned narrow clears
|
||||
// the upper bits via MOVL/ANDQ; signed narrow sign-extends via
|
||||
// MOVSBQ/MOVSWQ/MOVSXD reg-reg so the sign bit propagates.
|
||||
if (srcfk == 0 && dstfk == 0) {
|
||||
let tn: *node = n.rhs;
|
||||
// Walk through alias chains (`type random = u64`).
|
||||
// Walk through alias chains (`type random = u64`) and the
|
||||
// `!T` error-flag wrapper (`type invalid = !i32`) — the
|
||||
// bang is a tagged-union marker, not a representational
|
||||
// change, so it must not block the narrow-cast clamp.
|
||||
for (tn != nil) {
|
||||
if (tn.kind != nkind.N_TNAME) { tn = nil; }
|
||||
if (tn.kind == nkind.N_TBANG) { tn = tn.lhs; }
|
||||
else { if (tn.kind != nkind.N_TNAME) { tn = nil; }
|
||||
else {
|
||||
let nm: str = tn.str;
|
||||
if (primsize(nm) > 0) { break; };
|
||||
let alias: *node = aliaslookup(c, nm);
|
||||
if (alias == nil) { tn = nil; }
|
||||
else { tn = alias; };
|
||||
};
|
||||
}; };
|
||||
};
|
||||
if (tn != nil) {
|
||||
let nm: str = tn.str;
|
||||
@@ -412,7 +416,13 @@ fn cgcast(c: *cgen, n: *node) void = {
|
||||
};
|
||||
} else { if (is_bool) {
|
||||
emitline("\tANDQ\t$255, AX\n");
|
||||
}; };
|
||||
} else { if (streq(nm, "i8")) {
|
||||
emitline("\tMOVSBQ\tAX, AX\n");
|
||||
} else { if (streq(nm, "i16")) {
|
||||
emitline("\tMOVSWQ\tAX, AX\n");
|
||||
} else { if (streq(nm, "i32")) {
|
||||
emitline("\tMOVSXD\tAX, AX\n");
|
||||
}; }; }; }; };
|
||||
}; };
|
||||
};
|
||||
return;
|
||||
|
||||
@@ -8159,21 +8159,25 @@ fn cgcast(c: *cgen, n: *node) void = {
|
||||
// int↔int casts narrow via an explicit clamp before the early
|
||||
// return so `(big_u64): u32` doesn't leak the upper 32 bits.
|
||||
// Hare semantics: `expr: T` truncates to T's bit width (mod 2^n).
|
||||
// Mirrors cmd/w6c/cgen.c's N_CAST clamp; signed-narrow targets
|
||||
// (i8/i16/i32) stay no-ops until the assembler grows MOVSBQ /
|
||||
// MOVSWQ / MOVSXD reg-reg forms.
|
||||
// Mirrors cmd/w6c/cgen.c's N_CAST clamp. Unsigned narrow clears
|
||||
// the upper bits via MOVL/ANDQ; signed narrow sign-extends via
|
||||
// MOVSBQ/MOVSWQ/MOVSXD reg-reg so the sign bit propagates.
|
||||
if (srcfk == 0 && dstfk == 0) {
|
||||
let tn: *node = n.rhs;
|
||||
// Walk through alias chains (`type random = u64`).
|
||||
// Walk through alias chains (`type random = u64`) and the
|
||||
// `!T` error-flag wrapper (`type invalid = !i32`) — the
|
||||
// bang is a tagged-union marker, not a representational
|
||||
// change, so it must not block the narrow-cast clamp.
|
||||
for (tn != nil) {
|
||||
if (tn.kind != nkind.N_TNAME) { tn = nil; }
|
||||
if (tn.kind == nkind.N_TBANG) { tn = tn.lhs; }
|
||||
else { if (tn.kind != nkind.N_TNAME) { tn = nil; }
|
||||
else {
|
||||
let nm: str = tn.str;
|
||||
if (primsize(nm) > 0) { break; };
|
||||
let alias: *node = aliaslookup(c, nm);
|
||||
if (alias == nil) { tn = nil; }
|
||||
else { tn = alias; };
|
||||
};
|
||||
}; };
|
||||
};
|
||||
if (tn != nil) {
|
||||
let nm: str = tn.str;
|
||||
@@ -8193,7 +8197,13 @@ fn cgcast(c: *cgen, n: *node) void = {
|
||||
};
|
||||
} else { if (is_bool) {
|
||||
emitline("\tANDQ\t$255, AX\n");
|
||||
}; };
|
||||
} else { if (streq(nm, "i8")) {
|
||||
emitline("\tMOVSBQ\tAX, AX\n");
|
||||
} else { if (streq(nm, "i16")) {
|
||||
emitline("\tMOVSWQ\tAX, AX\n");
|
||||
} else { if (streq(nm, "i32")) {
|
||||
emitline("\tMOVSXD\tAX, AX\n");
|
||||
}; }; }; }; };
|
||||
}; };
|
||||
};
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user