w6c+selfhost: cgen && and || short-circuit
Both stages were eagerly evaluating RHS regardless of LHS (eager ANDQ/ORQ on the two results). Now: eval LHS into AX, CMPQ $0 + JE/JNE to a per-call-site label, eval RHS into AX, fall through. AX holds the LHS sentinel on the skipped path — typechecker already enforces bool operands. Surfaced by lib/getopt's nil-argv guard segfault. Six new rows in test/wcc/700_e2e.c, three of which segfault pre-fix. lib/getopt test comment relaxed; nested-if kept as regression marker.
This commit is contained in:
@@ -1887,6 +1887,26 @@ fn cgun(c: *cgen, n: *node) void = {
|
||||
};
|
||||
|
||||
fn cgbin(c: *cgen, n: *node) void = {
|
||||
// Short-circuit `&&` / `||`. Operands are bool (0/1); the type
|
||||
// checker enforces it. Eval LHS into AX, branch over RHS on the
|
||||
// short-circuit polarity, otherwise eval RHS into AX. The
|
||||
// surviving AX is the result. Must precede any eager-eval path
|
||||
// below — `if (p != nil && p.x > 0)` would segfault on a nil
|
||||
// deref otherwise. Byte-identical to cmd/w6c/cgen.c N_BIN.
|
||||
if (n.op == tkind.TK_AND || n.op == tkind.TK_OR) {
|
||||
let prefix: str = "andend";
|
||||
let jshrt: str = "JE";
|
||||
if (n.op == tkind.TK_OR) { prefix = "orend"; jshrt = "JNE"; };
|
||||
let end: str = mklabel(c, prefix);
|
||||
cgexpr(c, n.lhs);
|
||||
emitline("\tCMPQ\t$0, AX\n");
|
||||
emitline("\t"); emitline(jshrt); emitline("\t");
|
||||
emitline(end); emitline("\n");
|
||||
cgexpr(c, n.rhs);
|
||||
emitlabel(end);
|
||||
return;
|
||||
};
|
||||
|
||||
let unsignd: bool = nodeisunsigned(c, n.lhs);
|
||||
if (!unsignd) { unsignd = nodeisunsigned(c, n.rhs); };
|
||||
|
||||
@@ -1992,8 +2012,8 @@ fn cgbin(c: *cgen, n: *node) void = {
|
||||
emitline("\tSHRQ\tCX, AX\n");
|
||||
return;
|
||||
};
|
||||
if (n.op == tkind.TK_AND) { emitline("\tANDQ\tBX, AX\n"); return; };
|
||||
if (n.op == tkind.TK_OR) { emitline("\tORQ\tBX, AX\n"); return; };
|
||||
// TK_AND / TK_OR handled with short-circuit codegen at the top of
|
||||
// cgbin — they never reach this eager-eval tail.
|
||||
|
||||
// Comparison: emit CMPQ, jump on signed/unsigned variant,
|
||||
// materialise 0/1 in AX. Same shape as the C cgen.
|
||||
|
||||
Reference in New Issue
Block a user