wcc/cgen: #154 str==-global ident operand — name(SB) base in cbinop, not (BP) garbage (cstage)
The str==/!= arm of cbinop had an N_IDENT fast-path that assumed the operand was a local: localfind returns 0 for a module-global str, so it loaded (BP)/8(BP) — saved-BP/retaddr garbage — into rt_streq. `p == sepstr` silently compared garbage (returned wrong). Mirror #148's global branch at both sub-sites (rhs/lhs): off==0 && let_islet -> LEAQ name(SB) base, load ptr/len. Distinct per-site fast-path, not a shared choke (the by-value-global-arg family #148/#150/#151 closes separately). cstage-only; the wwstage str== twin is #146 (-> #125 batch). Pin test/wcc/989_strglobeq (table-driven: const+let globals, rhs+lhs ident, ==/!=, unequal + len>1 rows; teeth-proven). Surfaced by the lib/path c3 buffer-ops gate-1 oracle.
This commit is contained in:
@@ -4568,10 +4568,23 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
/* Push rhs (len, then ptr top) */
|
||||
if (n->rhs->kind == N_IDENT) {
|
||||
int off = localfind(locals, n->rhs->str);
|
||||
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, off), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
/* #154: localfind→0 for a module global, but the
|
||||
* str header lives at name(SB), not BP+0. Mirror
|
||||
* #148's slice global branch (cgen.c:9082): LEAQ
|
||||
* the symbol into a base reg, push len then ptr. */
|
||||
if (off == 0 && let_islet(n->rhs->str)) {
|
||||
ins2(c, A_LEAQ, masym(c, n->rhs->str),
|
||||
areg(D_BX));
|
||||
ins2(c, A_MOVQ, amem(D_BX, 8), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
} else {
|
||||
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, off), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
}
|
||||
} else {
|
||||
cgexpr(c, n->rhs, locals); /* AX=ptr, BX=len */
|
||||
ins1(c, A_PUSHQ, areg(D_BX));
|
||||
@@ -4580,10 +4593,21 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
/* Push lhs */
|
||||
if (n->lhs->kind == N_IDENT) {
|
||||
int off = localfind(locals, n->lhs->str);
|
||||
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, off), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
/* #154: see the rhs branch above — a module-global
|
||||
* str ident lives at name(SB), not BP+0. */
|
||||
if (off == 0 && let_islet(n->lhs->str)) {
|
||||
ins2(c, A_LEAQ, masym(c, n->lhs->str),
|
||||
areg(D_BX));
|
||||
ins2(c, A_MOVQ, amem(D_BX, 8), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
} else {
|
||||
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
ins2(c, A_MOVQ, amem(D_BP, off), areg(D_AX));
|
||||
ins1(c, A_PUSHQ, areg(D_AX));
|
||||
}
|
||||
} else {
|
||||
cgexpr(c, n->lhs, locals);
|
||||
ins1(c, A_PUSHQ, areg(D_BX));
|
||||
|
||||
Reference in New Issue
Block a user