selfhost: port switch — N_SWITCH parser + cgen + scratch slot
This commit is contained in:
@@ -34,6 +34,8 @@ fn cgstmt(c: *cgen, n: *node) void = {
|
||||
|
||||
if (k == nkind.N_FOR) { cgfor(c, n); return; };
|
||||
|
||||
if (k == nkind.N_SWITCH) { cgswitch(c, n); return; };
|
||||
|
||||
if (k == nkind.N_MASSIGN) { cgmassign(c, n); return; };
|
||||
|
||||
if (k == nkind.N_MLET) { cgmlet(c, n); return; };
|
||||
@@ -716,6 +718,65 @@ fn cgmlet(c: *cgen, n: *node) void = {
|
||||
return;
|
||||
};
|
||||
|
||||
// cgswitch — lower `switch (e) { case 1, 2: ...; case: default; }` to
|
||||
// a chain of compares against the scrutinee. Scrutinee lands in a
|
||||
// fresh 8B local slot so case bodies can spill SP without losing it.
|
||||
// Cases are tried top-to-bottom; the `case:` arm with no exprs is the
|
||||
// default and runs after all named arms fail. Mirrors cmd/w6c/cgen.c
|
||||
// N_SWITCH: same labelseq consumption order so labels match byte-for-
|
||||
// byte.
|
||||
fn cgswitch(c: *cgen, n: *node) void = {
|
||||
let swname: str = mkscratchname(c, "sw");
|
||||
let sloff: i32 = localalloc(c, swname, 8, nil);
|
||||
|
||||
if (n.lhs != nil) { cgexpr(c, n.lhs); };
|
||||
emitline("\tMOVQ\tAX, ");
|
||||
emitoff(sloff: i64);
|
||||
emitline("(BP)\n");
|
||||
|
||||
let endl: str = mklabel(c, "swend");
|
||||
let defcase: *node = nil;
|
||||
|
||||
let cs: *node = n.list;
|
||||
for (cs != nil) {
|
||||
if (cs.list == nil) {
|
||||
defcase = cs;
|
||||
cs = cs.next;
|
||||
continue;
|
||||
};
|
||||
let body: str = mklabel(c, "swcase");
|
||||
let nxt: str = mklabel(c, "swnext");
|
||||
let e: *node = cs.list;
|
||||
for (e != nil) {
|
||||
cgexpr(c, e);
|
||||
emitline("\tMOVQ\t");
|
||||
emitoff(sloff: i64);
|
||||
emitline("(BP), BX\n");
|
||||
emitline("\tCMPQ\tBX, AX\n");
|
||||
emitline("\tJE\t");
|
||||
emitline(body);
|
||||
emitline("\n");
|
||||
e = e.next;
|
||||
};
|
||||
emitline("\tJMP\t");
|
||||
emitline(nxt);
|
||||
emitline("\n");
|
||||
emitlabel(body);
|
||||
if (cs.body != nil) { cgstmt(c, cs.body); };
|
||||
emitline("\tJMP\t");
|
||||
emitline(endl);
|
||||
emitline("\n");
|
||||
emitlabel(nxt);
|
||||
cs = cs.next;
|
||||
};
|
||||
if (defcase != nil) {
|
||||
if (defcase.body != nil) { cgstmt(c, defcase.body); };
|
||||
};
|
||||
emitlabel(endl);
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
|
||||
fn cgbreak(c: *cgen, n: *node) void = {
|
||||
if (c.looptop > 0) {
|
||||
let lbl: str = c.loopendbuf[c.looptop - 1];
|
||||
|
||||
Reference in New Issue
Block a user