authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-13 18:08:15+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-30 15:58:12+02:00
log2020ca640e8db50f1cb5a1ceaa42c28a25483bad
tree1e539fd2e9b3cb16f166519f2f8da6ef2c935490
parent11998d2972bf1f7253351fc756c4f1766a412f1d
signature Commit is signed but in an unrecognized format.

stage2: switch emit zir


6 files changed, 127 insertions(+), 48 deletions(-)

src/Module.zig+23
......@@ -2098,6 +2098,29 @@ pub fn addCall(
20982098 return &inst.base;
20992099}
21002100
2101pub fn addSwitchBr(
2102 self: *Module,
2103 block: *Scope.Block,
2104 src: usize,
2105 target_ptr: *Inst,
2106 cases: []Inst.SwitchBr.Case,
2107 else_body: ?Module.Body,
2108) !*Inst {
2109 const inst = try block.arena.create(Inst.SwitchBr);
2110 inst.* = .{
2111 .base = .{
2112 .tag = .switchbr,
2113 .ty = Type.initTag(.noreturn),
2114 .src = src,
2115 },
2116 .target_ptr = target_ptr,
2117 .cases = cases,
2118 .@"else" = else_body,
2119 };
2120 try block.instructions.append(self.gpa, &inst.base);
2121 return &inst.base;
2122}
2123
21012124pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
21022125 const const_inst = try scope.arena().create(Inst.Constant);
21032126 const_inst.* = .{
src/astgen.zig+3-3
......@@ -1573,8 +1573,8 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
15731573 const tree = scope.tree();
15741574 const switch_src = tree.token_locs[switch_node.switch_token].start;
15751575 const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr);
1576 const cases = try scope.arena().alloc(zir.Inst.Switch.Case, switch_node.cases_len);
1577 var kw_args: std.meta.fieldInfo(zir.Inst.Switch, "kw_args").field_type = .{};
1576 const cases = try scope.arena().alloc(zir.Inst.SwitchBr.Case, switch_node.cases_len);
1577 var kw_args: std.meta.fieldInfo(zir.Inst.SwitchBr, "kw_args").field_type = .{};
15781578
15791579 // first we gather all the switch items and check else/'_' prongs
15801580 var case_index: usize = 0;
......@@ -1643,7 +1643,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
16431643 }
16441644
16451645 // Then we add the switch instruction to finish the block.
1646 _ = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.Switch, .{
1646 _ = try addZIRInst(mod, &block_scope.base, switch_src, zir.Inst.SwitchBr, .{
16471647 .target_ptr = target_ptr,
16481648 .cases = cases,
16491649 }, kw_args);
src/codegen.zig+2-2
......@@ -786,7 +786,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
786786 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
787787 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
788788 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),
789 .@"switch" => return self.genSwitch(inst.castTag(.@"switch").?),
789 .switchbr => return self.genSwitch(inst.castTag(.switchbr).?),
790790 }
791791 }
792792
......@@ -1990,7 +1990,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19901990 return @bitCast(MCValue, inst.codegen.mcv);
19911991 }
19921992
1993 fn genSwitch(self: *Self, inst: *ir.Inst.Switch) !MCValue {
1993 fn genSwitch(self: *Self, inst: *ir.Inst.SwitchBr) !MCValue {
19941994 switch (arch) {
19951995 else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}),
19961996 }
src/ir.zig+27-8
......@@ -91,7 +91,7 @@ pub const Inst = struct {
9191 intcast,
9292 unwrap_optional,
9393 wrap_optional,
94 @"switch",
94 switchbr,
9595
9696 pub fn Type(tag: Tag) type {
9797 return switch (tag) {
......@@ -138,7 +138,7 @@ pub const Inst = struct {
138138 .constant => Constant,
139139 .loop => Loop,
140140 .varptr => VarPtr,
141 .@"switch" => Switch,
141 .switchbr => SwitchBr,
142142 };
143143 }
144144
......@@ -461,26 +461,45 @@ pub const Inst = struct {
461461 }
462462 };
463463
464 pub const Switch = struct {
465 pub const base_tag = Tag.@"switch";
464 pub const SwitchBr = struct {
465 pub const base_tag = Tag.switchbr;
466466
467467 base: Inst,
468468 target_ptr: *Inst,
469469 cases: []Case,
470470 @"else": ?Body,
471 /// Set of instructions whose lifetimes end at the start of one of the cases.
472 /// In same order as cases, deaths[0..case_0_count, case_0_count .. case_1_count, ... , case_n_count ... else_count].
473 deaths: [*]*Inst = undefined,
474 else_index: u32 = 0,
475 else_deaths: u32 = 0,
471476
472477 pub const Case = struct {
473478 items: []Value,
474479 body: Body,
480 index: u32 = 0,
481 deaths: u32 = 0,
475482 };
476483
477 pub fn operandCount(self: *const Switch) usize {
484 pub fn operandCount(self: *const SwitchBr) usize {
478485 return 1;
479486 }
480 pub fn getOperand(self: *const Switch, index: usize) ?*Inst {
481 return self.target_ptr;
487 pub fn getOperand(self: *const SwitchBr, index: usize) ?*Inst {
488 var i = index;
489
490 if (i < 1)
491 return self.target_ptr;
492 i -= 1;
493
494 return null;
495 }
496 pub fn caseDeaths(self: *const SwitchBr, case_index: usize) []*Inst {
497 const case = self.cases[case_index];
498 return (self.deaths + case.index)[0..case.deaths];
499 }
500 pub fn elseDeaths(self: *const SwitchBr) []*Inst {
501 return (self.deaths + self.else_deaths)[0..self.else_deaths];
482502 }
483 // TODO case body deaths
484503 };
485504};
486505
src/zir.zig+63-16
......@@ -273,7 +273,7 @@ pub const Inst = struct {
273273 /// Enum literal
274274 enum_literal,
275275 /// A switch expression.
276 @"switch",
276 switchbr,
277277 /// A range in a switch case, `lhs...rhs`.
278278 /// Only checks that `lhs >= rhs` if they are ints or floats, everything else is
279279 /// validated by the .switch instruction.
......@@ -396,7 +396,7 @@ pub const Inst = struct {
396396 .enum_literal => EnumLiteral,
397397 .error_set => ErrorSet,
398398 .slice => Slice,
399 .@"switch" => Switch,
399 .switchbr => SwitchBr,
400400 };
401401 }
402402
......@@ -513,7 +513,7 @@ pub const Inst = struct {
513513 .unreach_nocheck,
514514 .@"unreachable",
515515 .loop,
516 .@"switch",
516 .switchbr,
517517 => true,
518518 };
519519 }
......@@ -998,8 +998,8 @@ pub const Inst = struct {
998998 },
999999 };
10001000
1001 pub const Switch = struct {
1002 pub const base_tag = Tag.@"switch";
1001 pub const SwitchBr = struct {
1002 pub const base_tag = Tag.switchbr;
10031003 base: Inst,
10041004
10051005 positionals: struct {
......@@ -1275,24 +1275,24 @@ const Writer = struct {
12751275 }
12761276 try stream.writeByte(']');
12771277 },
1278 []Inst.Switch.Case => {
1278 []Inst.SwitchBr.Case => {
12791279 if (param.len == 0) {
12801280 return stream.writeAll("{}");
12811281 }
12821282 try stream.writeAll("{\n");
1283 self.indent += 2;
12841283 for (param) |*case, i| {
12851284 if (i != 0) {
12861285 try stream.writeAll(",\n");
12871286 }
12881287 try stream.writeByteNTimes(' ', self.indent);
1288 self.indent += 2;
12891289 try self.writeParamToStream(stream, &case.items);
12901290 try stream.writeAll(" => ");
12911291 try self.writeParamToStream(stream, &case.body);
1292 self.indent -= 2;
12921293 }
12931294 try stream.writeByte('\n');
1294 self.indent -= 2;
1295 try stream.writeByteNTimes(' ', self.indent);
1295 try stream.writeByteNTimes(' ', self.indent - 2);
12961296 try stream.writeByte('}');
12971297 },
12981298 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
......@@ -1707,12 +1707,12 @@ const Parser = struct {
17071707 try requireEatBytes(self, "]");
17081708 return strings.toOwnedSlice();
17091709 },
1710 []Inst.Switch.Case => {
1710 []Inst.SwitchBr.Case => {
17111711 try requireEatBytes(self, "{");
17121712 skipSpace(self);
1713 if (eatByte(self, '}')) return &[0]Inst.Switch.Case{};
1713 if (eatByte(self, '}')) return &[0]Inst.SwitchBr.Case{};
17141714
1715 var cases = std.ArrayList(Inst.Switch.Case).init(&self.arena.allocator);
1715 var cases = std.ArrayList(Inst.SwitchBr.Case).init(&self.arena.allocator);
17161716 while (true) {
17171717 const cur = try cases.addOne();
17181718 skipSpace(self);
......@@ -1824,7 +1824,7 @@ pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {
18241824 .arena = std.heap.ArenaAllocator.init(allocator),
18251825 .old_module = &old_module,
18261826 .next_auto_name = 0,
1827 .names = std.StringHashMap(void).init(allocator),
1827 .names = std.StringArrayHashMap(void).init(allocator),
18281828 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
18291829 .indent = 0,
18301830 .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator),
......@@ -2547,11 +2547,58 @@ const EmitZIR = struct {
25472547 };
25482548 break :blk &new_inst.base;
25492549 },
2550 .switchbr => blk: {
2551 const old_inst = inst.castTag(.switchbr).?;
2552 const case_count = old_inst.cases.len + @boolToInt(old_inst.@"else" != null);
2553 const cases = try self.arena.allocator.alloc(Inst.SwitchBr.Case, case_count);
2554 const new_inst = try self.arena.allocator.create(Inst.SwitchBr);
2555 new_inst.* = .{
2556 .base = .{
2557 .src = inst.src,
2558 .tag = Inst.SwitchBr.base_tag,
2559 },
2560 .positionals = .{
2561 .target_ptr = try self.resolveInst(new_body, old_inst.target_ptr),
2562 .cases = cases,
2563 },
2564 .kw_args = .{
2565 .special_case = if (old_inst.@"else" != null) .@"else" else .none,
2566 .support_range = null,
2567 },
2568 };
25502569
2551 .varptr => @panic("TODO"),
2552 .@"switch" => {
2553 @panic("TODO");
2570 var body_tmp = std.ArrayList(*Inst).init(self.allocator);
2571 defer body_tmp.deinit();
2572
2573 for (old_inst.cases) |case, i| {
2574 body_tmp.items.len = 0;
2575
2576 try self.emitBody(case.body, inst_table, &body_tmp);
2577 const items = try self.arena.allocator.alloc(*Inst, case.items.len);
2578 for (case.items) |item, j| {
2579 items[j] = (try self.emitTypedValue(inst.src, .{
2580 .ty = old_inst.target_ptr.ty.elemType(),
2581 .val = item,
2582 })).inst;
2583 }
2584
2585 cases[i] = .{
2586 .items = items,
2587 .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
2588 };
2589 }
2590 if (old_inst.@"else") |some| {
2591 body_tmp.items.len = 0;
2592
2593 try self.emitBody(some, inst_table, &body_tmp);
2594 cases[cases.len - 1] = .{
2595 .items = &[0]*Inst{},
2596 .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
2597 };
2598 }
2599 break :blk &new_inst.base;
25542600 },
2601 .varptr => @panic("TODO"),
25552602 };
25562603 try self.metadata.put(new_inst, .{
25572604 .deaths = inst.deaths,
src/zir_sema.zig+9-19
......@@ -135,7 +135,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
135135 .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),
136136 .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
137137 .import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?),
138 .@"switch" => return analyzeInstSwitch(mod, scope, old_inst.castTag(.@"switch").?),
138 .switchbr => return analyzeInstSwitchBr(mod, scope, old_inst.castTag(.switchbr).?),
139139 .switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
140140 }
141141}
......@@ -1228,7 +1228,7 @@ fn analyzeInstSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In
12281228 return mod.constVoid(scope, inst.base.src);
12291229}
12301230
1231fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerError!*Inst {
1231fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) InnerError!*Inst {
12321232 const target_ptr = try resolveInst(mod, scope, inst.positionals.target_ptr);
12331233 const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src);
12341234 try validateSwitch(mod, scope, target, inst);
......@@ -1239,17 +1239,7 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE
12391239 const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none);
12401240
12411241 const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);
1242 const switch_inst = try parent_block.arena.create(Inst.Switch);
1243 switch_inst.* = .{
1244 .base = .{
1245 .tag = Inst.Switch.base_tag,
1246 .ty = Type.initTag(.noreturn),
1247 .src = inst.base.src,
1248 },
1249 .target_ptr = target_ptr,
1250 .@"else" = null,
1251 .cases = try parent_block.arena.alloc(Inst.Switch.Case, case_count),
1252 };
1242 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, case_count);
12531243
12541244 var case_block: Scope.Block = .{
12551245 .parent = parent_block,
......@@ -1281,25 +1271,25 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE
12811271
12821272 try analyzeBody(mod, &case_block.base, case.body);
12831273
1284 switch_inst.cases[i] = .{
1274 cases[i] = .{
12851275 .items = try parent_block.arena.dupe(Value, items_tmp.items),
12861276 .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
12871277 };
12881278 }
12891279
1290 if (inst.kw_args.special_case != .none) {
1280 const else_body = if (inst.kw_args.special_case != .none) blk: {
12911281 case_block.instructions.items.len = 0;
12921282
12931283 try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body);
1294 switch_inst.@"else" = .{
1284 break: blk Body{
12951285 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
12961286 };
1297 }
1287 } else null;
12981288
1299 return &switch_inst.base;
1289 return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases, else_body);
13001290}
13011291
1302fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Switch) InnerError!void {
1292fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.SwitchBr) InnerError!void {
13031293 // validate usage of '_' prongs
13041294 if (inst.kw_args.special_case == .underscore and target.ty.zigTypeTag() != .Enum) {
13051295 return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});