feat: code generation for switch statements
This commit is contained in:
parent
e5e2b7c559
commit
fac5a968e3
3 changed files with 195 additions and 14 deletions
59
src/Sema.zig
59
src/Sema.zig
|
|
@ -174,6 +174,59 @@ fn irBlock(sema: *Sema, chunk: *Chunk, inst: Ir.Inst.Index) InnerError!void {
|
|||
return blockBodyInner(sema, chunk, body);
|
||||
}
|
||||
|
||||
fn irSwitchBr(sema: *Sema, chunk: *Chunk, inst: Ir.Inst.Index) InnerError!void {
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = sema.ir.extraData(Ir.Inst.SwitchBr, data.payload_index);
|
||||
const cases_slice = sema.ir.bodySlice(extra.end, extra.data.cases_len);
|
||||
|
||||
var case_labels: std.ArrayListUnmanaged(usize) = .empty;
|
||||
try case_labels.ensureUnusedCapacity(sema.gpa, cases_slice.len + 1);
|
||||
defer case_labels.deinit(sema.gpa);
|
||||
|
||||
// TODO: Do something with this value?
|
||||
//const condition = chunk.resolveInst(extra.data.operand);
|
||||
const exit_label = try chunk.addLabel();
|
||||
|
||||
const cmp_var = chunk.knot.stack_size;
|
||||
chunk.knot.stack_size += 1;
|
||||
_ = try chunk.addConstOp(.store, @intCast(cmp_var));
|
||||
|
||||
for (cases_slice) |case_index| {
|
||||
const case_extra = sema.ir.extraData(Ir.Inst.SwitchBr.Case, @intFromEnum(case_index));
|
||||
const case_expr = chunk.resolveInst(case_extra.data.operand);
|
||||
const case_label_index = try chunk.addLabel();
|
||||
case_labels.appendAssumeCapacity(case_label_index);
|
||||
|
||||
_ = try chunk.addConstOp(.load, @intCast(cmp_var));
|
||||
_ = try chunk.doLoad(case_expr);
|
||||
_ = try chunk.addByteOp(.cmp_eq);
|
||||
_ = try chunk.addFixup(.jmp_t, case_label_index);
|
||||
_ = try chunk.addByteOp(.pop);
|
||||
}
|
||||
|
||||
const else_label = try chunk.addLabel();
|
||||
try chunk.addFixup(.jmp, else_label);
|
||||
|
||||
for (cases_slice, case_labels.items) |case_index, label_index| {
|
||||
const case_extra = sema.ir.extraData(Ir.Inst.SwitchBr.Case, @intFromEnum(case_index));
|
||||
const case_body = sema.ir.bodySlice(case_extra.end, case_extra.data.body_len);
|
||||
|
||||
chunk.setLabel(label_index);
|
||||
_ = try chunk.addByteOp(.pop);
|
||||
try blockBodyInner(sema, chunk, case_body);
|
||||
try chunk.addFixup(.jmp, exit_label);
|
||||
}
|
||||
|
||||
const else_body = sema.ir.bodySlice(
|
||||
extra.end + extra.data.cases_len,
|
||||
extra.data.else_body_len,
|
||||
);
|
||||
|
||||
chunk.setLabel(else_label);
|
||||
try blockBodyInner(sema, chunk, else_body);
|
||||
chunk.setLabel(exit_label);
|
||||
}
|
||||
|
||||
fn irContentPush(sema: *Sema, chunk: *Chunk, inst: Ir.Inst.Index) InnerError!Ref {
|
||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.un;
|
||||
const lhs = chunk.resolveInst(data.lhs);
|
||||
|
|
@ -264,6 +317,10 @@ fn blockBodyInner(sema: *Sema, chunk: *Chunk, body: []const Ir.Inst.Index) Inner
|
|||
},
|
||||
.decl_var => unreachable, // handled in declaration()
|
||||
.decl_knot => unreachable, // handled in declaration()
|
||||
.switch_br => {
|
||||
try irSwitchBr(sema, chunk, inst);
|
||||
continue;
|
||||
},
|
||||
.alloc => try irAlloc(sema, chunk, inst),
|
||||
.store => {
|
||||
try irStore(sema, chunk, inst);
|
||||
|
|
@ -534,7 +591,7 @@ pub fn compile(gpa: std.mem.Allocator, ir: *const Ir) !CompiledStory {
|
|||
};
|
||||
defer sema.deinit();
|
||||
|
||||
try file(&sema, @enumFromInt(0));
|
||||
try file(&sema, .file_inst);
|
||||
return .{
|
||||
.constants = try sema.constants.toOwnedSlice(gpa),
|
||||
.globals = try sema.globals.toOwnedSlice(gpa),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue