cgen: materialise str-def operands in streq pushes
A str `def` has no name(SB) header; the streq push arms read a frame slot that does not exist. Load the literal through cgexpr (AX=ptr, BX=len) instead. Both stages.
This commit is contained in:
@@ -4925,6 +4925,12 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins1(c, A_PUSHQ, areg(D_AX));
|
ins1(c, A_PUSHQ, areg(D_AX));
|
||||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
||||||
ins1(c, A_PUSHQ, areg(D_AX));
|
ins1(c, A_PUSHQ, areg(D_AX));
|
||||||
|
} else if (off == 0 && def_isanydef(n->rhs->str)) {
|
||||||
|
/* A str `def` has no name(SB) header: cgexpr
|
||||||
|
* materialises its literal as AX=ptr, BX=len. */
|
||||||
|
cgexpr(c, n->rhs, locals);
|
||||||
|
ins1(c, A_PUSHQ, areg(D_BX));
|
||||||
|
ins1(c, A_PUSHQ, areg(D_AX));
|
||||||
} else {
|
} else {
|
||||||
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
||||||
ins1(c, A_PUSHQ, areg(D_AX));
|
ins1(c, A_PUSHQ, areg(D_AX));
|
||||||
@@ -4948,6 +4954,10 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
|||||||
ins1(c, A_PUSHQ, areg(D_AX));
|
ins1(c, A_PUSHQ, areg(D_AX));
|
||||||
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
ins2(c, A_MOVQ, amem(D_BX, 0), areg(D_AX));
|
||||||
ins1(c, A_PUSHQ, areg(D_AX));
|
ins1(c, A_PUSHQ, areg(D_AX));
|
||||||
|
} else if (off == 0 && def_isanydef(n->lhs->str)) {
|
||||||
|
cgexpr(c, n->lhs, locals);
|
||||||
|
ins1(c, A_PUSHQ, areg(D_BX));
|
||||||
|
ins1(c, A_PUSHQ, areg(D_AX));
|
||||||
} else {
|
} else {
|
||||||
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
ins2(c, A_MOVQ, amem(D_BP, off + 8), areg(D_AX));
|
||||||
ins1(c, A_PUSHQ, areg(D_AX));
|
ins1(c, A_PUSHQ, areg(D_AX));
|
||||||
|
|||||||
@@ -5808,6 +5808,14 @@ fn cgstreqpush(c: *cgen, op: *syntax.node) void = {
|
|||||||
emitline("\tPUSHQ\tAX\n");
|
emitline("\tPUSHQ\tAX\n");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
if (lc == nil && deflookup(c, nm)) {
|
||||||
|
// A str def has no name(SB) header. Its ordinary expression
|
||||||
|
// load materialises the literal as AX=ptr, BX=len.
|
||||||
|
cgexpr(c, op);
|
||||||
|
emitline("\tPUSHQ\tBX\n");
|
||||||
|
emitline("\tPUSHQ\tAX\n");
|
||||||
|
return;
|
||||||
|
};
|
||||||
let off: i32 = 0;
|
let off: i32 = 0;
|
||||||
if (lc != nil) { off = lc.off; };
|
if (lc != nil) { off = lc.off; };
|
||||||
emitline("\tMOVQ\t");
|
emitline("\tMOVQ\t");
|
||||||
|
|||||||
20
test/lang/str_def_equality_test.ww
Normal file
20
test/lang/str_def_equality_test.ww
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// String equality must materialise a module def literal instead of treating
|
||||||
|
// its name as a frame-local string header. Use a duplicated local so pointer
|
||||||
|
// equality cannot accidentally satisfy the content comparison.
|
||||||
|
|
||||||
|
package str_def_equality_test;
|
||||||
|
|
||||||
|
import strings;
|
||||||
|
|
||||||
|
def expected: str = "dynamic string versus def";
|
||||||
|
|
||||||
|
@test fn dynamic_string_and_def_compare_by_content() void = {
|
||||||
|
let observed: str = strings.dup(expected);
|
||||||
|
assert(observed == expected);
|
||||||
|
assert(expected == observed);
|
||||||
|
assert(!(observed != expected));
|
||||||
|
assert(!(expected != observed));
|
||||||
|
let different: str = strings.concat(observed, "!");
|
||||||
|
assert(different != expected);
|
||||||
|
assert(expected != different);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user