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
signaturelock-open 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(...@@ -2098,6 +2098,29 @@ pub fn addCall(
2098 return &inst.base;2098 return &inst.base;
2099}2099}
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
2101pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {2124pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
2102 const const_inst = try scope.arena().create(Inst.Constant);2125 const const_inst = try scope.arena().create(Inst.Constant);
2103 const_inst.* = .{2126 const_inst.* = .{
src/astgen.zig+3-3
...@@ -1573,8 +1573,8 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -1573,8 +1573,8 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
1573 const tree = scope.tree();1573 const tree = scope.tree();
1574 const switch_src = tree.token_locs[switch_node.switch_token].start;1574 const switch_src = tree.token_locs[switch_node.switch_token].start;
1575 const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr);1575 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);1576 const cases = try scope.arena().alloc(zir.Inst.SwitchBr.Case, switch_node.cases_len);
1577 var kw_args: std.meta.fieldInfo(zir.Inst.Switch, "kw_args").field_type = .{};1577 var kw_args: std.meta.fieldInfo(zir.Inst.SwitchBr, "kw_args").field_type = .{};
15781578
1579 // first we gather all the switch items and check else/'_' prongs1579 // first we gather all the switch items and check else/'_' prongs
1580 var case_index: usize = 0;1580 var case_index: usize = 0;
...@@ -1643,7 +1643,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -1643,7 +1643,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
1643 }1643 }
16441644
1645 // Then we add the switch instruction to finish the block.1645 // 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, .{
1647 .target_ptr = target_ptr,1647 .target_ptr = target_ptr,
1648 .cases = cases,1648 .cases = cases,
1649 }, kw_args);1649 }, kw_args);
src/codegen.zig+2-2
...@@ -786,7 +786,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -786,7 +786,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
786 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),786 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
787 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),787 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
788 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),788 .varptr => return self.genVarPtr(inst.castTag(.varptr).?),
789 .@"switch" => return self.genSwitch(inst.castTag(.@"switch").?),789 .switchbr => return self.genSwitch(inst.castTag(.switchbr).?),
790 }790 }
791 }791 }
792792
...@@ -1990,7 +1990,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1990,7 +1990,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1990 return @bitCast(MCValue, inst.codegen.mcv);1990 return @bitCast(MCValue, inst.codegen.mcv);
1991 }1991 }
19921992
1993 fn genSwitch(self: *Self, inst: *ir.Inst.Switch) !MCValue {1993 fn genSwitch(self: *Self, inst: *ir.Inst.SwitchBr) !MCValue {
1994 switch (arch) {1994 switch (arch) {
1995 else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}),1995 else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}),
1996 }1996 }
src/ir.zig+27-8
...@@ -91,7 +91,7 @@ pub const Inst = struct {...@@ -91,7 +91,7 @@ pub const Inst = struct {
91 intcast,91 intcast,
92 unwrap_optional,92 unwrap_optional,
93 wrap_optional,93 wrap_optional,
94 @"switch",94 switchbr,
9595
96 pub fn Type(tag: Tag) type {96 pub fn Type(tag: Tag) type {
97 return switch (tag) {97 return switch (tag) {
...@@ -138,7 +138,7 @@ pub const Inst = struct {...@@ -138,7 +138,7 @@ pub const Inst = struct {
138 .constant => Constant,138 .constant => Constant,
139 .loop => Loop,139 .loop => Loop,
140 .varptr => VarPtr,140 .varptr => VarPtr,
141 .@"switch" => Switch,141 .switchbr => SwitchBr,
142 };142 };
143 }143 }
144144
...@@ -461,26 +461,45 @@ pub const Inst = struct {...@@ -461,26 +461,45 @@ pub const Inst = struct {
461 }461 }
462 };462 };
463463
464 pub const Switch = struct {464 pub const SwitchBr = struct {
465 pub const base_tag = Tag.@"switch";465 pub const base_tag = Tag.switchbr;
466466
467 base: Inst,467 base: Inst,
468 target_ptr: *Inst,468 target_ptr: *Inst,
469 cases: []Case,469 cases: []Case,
470 @"else": ?Body,470 @"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
472 pub const Case = struct {477 pub const Case = struct {
473 items: []Value,478 items: []Value,
474 body: Body,479 body: Body,
480 index: u32 = 0,
481 deaths: u32 = 0,
475 };482 };
476483
477 pub fn operandCount(self: *const Switch) usize {484 pub fn operandCount(self: *const SwitchBr) usize {
478 return 1;485 return 1;
479 }486 }
480 pub fn getOperand(self: *const Switch, index: usize) ?*Inst {487 pub fn getOperand(self: *const SwitchBr, index: usize) ?*Inst {
481 return self.target_ptr;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];
482 }502 }
483 // TODO case body deaths
484 };503 };
485};504};
486505
src/zir.zig+63-16
...@@ -273,7 +273,7 @@ pub const Inst = struct {...@@ -273,7 +273,7 @@ pub const Inst = struct {
273 /// Enum literal273 /// Enum literal
274 enum_literal,274 enum_literal,
275 /// A switch expression.275 /// A switch expression.
276 @"switch",276 switchbr,
277 /// A range in a switch case, `lhs...rhs`.277 /// A range in a switch case, `lhs...rhs`.
278 /// Only checks that `lhs >= rhs` if they are ints or floats, everything else is278 /// Only checks that `lhs >= rhs` if they are ints or floats, everything else is
279 /// validated by the .switch instruction.279 /// validated by the .switch instruction.
...@@ -396,7 +396,7 @@ pub const Inst = struct {...@@ -396,7 +396,7 @@ pub const Inst = struct {
396 .enum_literal => EnumLiteral,396 .enum_literal => EnumLiteral,
397 .error_set => ErrorSet,397 .error_set => ErrorSet,
398 .slice => Slice,398 .slice => Slice,
399 .@"switch" => Switch,399 .switchbr => SwitchBr,
400 };400 };
401 }401 }
402402
...@@ -513,7 +513,7 @@ pub const Inst = struct {...@@ -513,7 +513,7 @@ pub const Inst = struct {
513 .unreach_nocheck,513 .unreach_nocheck,
514 .@"unreachable",514 .@"unreachable",
515 .loop,515 .loop,
516 .@"switch",516 .switchbr,
517 => true,517 => true,
518 };518 };
519 }519 }
...@@ -998,8 +998,8 @@ pub const Inst = struct {...@@ -998,8 +998,8 @@ pub const Inst = struct {
998 },998 },
999 };999 };
10001000
1001 pub const Switch = struct {1001 pub const SwitchBr = struct {
1002 pub const base_tag = Tag.@"switch";1002 pub const base_tag = Tag.switchbr;
1003 base: Inst,1003 base: Inst,
10041004
1005 positionals: struct {1005 positionals: struct {
...@@ -1275,24 +1275,24 @@ const Writer = struct {...@@ -1275,24 +1275,24 @@ const Writer = struct {
1275 }1275 }
1276 try stream.writeByte(']');1276 try stream.writeByte(']');
1277 },1277 },
1278 []Inst.Switch.Case => {1278 []Inst.SwitchBr.Case => {
1279 if (param.len == 0) {1279 if (param.len == 0) {
1280 return stream.writeAll("{}");1280 return stream.writeAll("{}");
1281 }1281 }
1282 try stream.writeAll("{\n");1282 try stream.writeAll("{\n");
1283 self.indent += 2;
1284 for (param) |*case, i| {1283 for (param) |*case, i| {
1285 if (i != 0) {1284 if (i != 0) {
1286 try stream.writeAll(",\n");1285 try stream.writeAll(",\n");
1287 }1286 }
1288 try stream.writeByteNTimes(' ', self.indent);1287 try stream.writeByteNTimes(' ', self.indent);
1288 self.indent += 2;
1289 try self.writeParamToStream(stream, &case.items);1289 try self.writeParamToStream(stream, &case.items);
1290 try stream.writeAll(" => ");1290 try stream.writeAll(" => ");
1291 try self.writeParamToStream(stream, &case.body);1291 try self.writeParamToStream(stream, &case.body);
1292 self.indent -= 2;
1292 }1293 }
1293 try stream.writeByte('\n');1294 try stream.writeByte('\n');
1294 self.indent -= 2;1295 try stream.writeByteNTimes(' ', self.indent - 2);
1295 try stream.writeByteNTimes(' ', self.indent);
1296 try stream.writeByte('}');1296 try stream.writeByte('}');
1297 },1297 },
1298 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),1298 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
...@@ -1707,12 +1707,12 @@ const Parser = struct {...@@ -1707,12 +1707,12 @@ const Parser = struct {
1707 try requireEatBytes(self, "]");1707 try requireEatBytes(self, "]");
1708 return strings.toOwnedSlice();1708 return strings.toOwnedSlice();
1709 },1709 },
1710 []Inst.Switch.Case => {1710 []Inst.SwitchBr.Case => {
1711 try requireEatBytes(self, "{");1711 try requireEatBytes(self, "{");
1712 skipSpace(self);1712 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);
1716 while (true) {1716 while (true) {
1717 const cur = try cases.addOne();1717 const cur = try cases.addOne();
1718 skipSpace(self);1718 skipSpace(self);
...@@ -1824,7 +1824,7 @@ pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {...@@ -1824,7 +1824,7 @@ pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {
1824 .arena = std.heap.ArenaAllocator.init(allocator),1824 .arena = std.heap.ArenaAllocator.init(allocator),
1825 .old_module = &old_module,1825 .old_module = &old_module,
1826 .next_auto_name = 0,1826 .next_auto_name = 0,
1827 .names = std.StringHashMap(void).init(allocator),1827 .names = std.StringArrayHashMap(void).init(allocator),
1828 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),1828 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
1829 .indent = 0,1829 .indent = 0,
1830 .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator),1830 .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator),
...@@ -2547,11 +2547,58 @@ const EmitZIR = struct {...@@ -2547,11 +2547,58 @@ const EmitZIR = struct {
2547 };2547 };
2548 break :blk &new_inst.base;2548 break :blk &new_inst.base;
2549 },2549 },
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"),2570 var body_tmp = std.ArrayList(*Inst).init(self.allocator);
2552 .@"switch" => {2571 defer body_tmp.deinit();
2553 @panic("TODO");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;
2554 },2600 },
2601 .varptr => @panic("TODO"),
2555 };2602 };
2556 try self.metadata.put(new_inst, .{2603 try self.metadata.put(new_inst, .{
2557 .deaths = inst.deaths,2604 .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!...@@ -135,7 +135,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
135 .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),135 .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),
136 .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),136 .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
137 .import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?),137 .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).?),
139 .switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),139 .switch_range => return analyzeInstSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
140 }140 }
141}141}
...@@ -1228,7 +1228,7 @@ fn analyzeInstSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In...@@ -1228,7 +1228,7 @@ fn analyzeInstSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) In
1228 return mod.constVoid(scope, inst.base.src);1228 return mod.constVoid(scope, inst.base.src);
1229}1229}
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 {
1232 const target_ptr = try resolveInst(mod, scope, inst.positionals.target_ptr);1232 const target_ptr = try resolveInst(mod, scope, inst.positionals.target_ptr);
1233 const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src);1233 const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src);
1234 try validateSwitch(mod, scope, target, inst);1234 try validateSwitch(mod, scope, target, inst);
...@@ -1239,17 +1239,7 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE...@@ -1239,17 +1239,7 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE
1239 const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none);1239 const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none);
12401240
1241 const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);1241 const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);
1242 const switch_inst = try parent_block.arena.create(Inst.Switch);1242 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, case_count);
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 };
12531243
1254 var case_block: Scope.Block = .{1244 var case_block: Scope.Block = .{
1255 .parent = parent_block,1245 .parent = parent_block,
...@@ -1281,25 +1271,25 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE...@@ -1281,25 +1271,25 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE
12811271
1282 try analyzeBody(mod, &case_block.base, case.body);1272 try analyzeBody(mod, &case_block.base, case.body);
12831273
1284 switch_inst.cases[i] = .{1274 cases[i] = .{
1285 .items = try parent_block.arena.dupe(Value, items_tmp.items),1275 .items = try parent_block.arena.dupe(Value, items_tmp.items),
1286 .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },1276 .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
1287 };1277 };
1288 }1278 }
12891279
1290 if (inst.kw_args.special_case != .none) {1280 const else_body = if (inst.kw_args.special_case != .none) blk: {
1291 case_block.instructions.items.len = 0;1281 case_block.instructions.items.len = 0;
12921282
1293 try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body);1283 try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body);
1294 switch_inst.@"else" = .{1284 break: blk Body{
1295 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),1285 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
1296 };1286 };
1297 }1287 } else null;
1298 1288
1299 return &switch_inst.base;1289 return mod.addSwitchBr(parent_block, inst.base.src, target_ptr, cases, else_body);
1300}1290}
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 {
1303 // validate usage of '_' prongs1293 // validate usage of '_' prongs
1304 if (inst.kw_args.special_case == .underscore and target.ty.zigTypeTag() != .Enum) {1294 if (inst.kw_args.special_case == .underscore and target.ty.zigTypeTag() != .Enum) {
1305 return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});1295 return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});