authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-12 15:35:48+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-30 15:58:12+02:00
log11998d2972bf1f7253351fc756c4f1766a412f1d
tree0dc85f1256f937ecc23df204f1fc38c4ccaeea90
parent2c12f4a993343abb65ebb881f095c38ba0310306
signaturelock-open Commit is signed but in an unrecognized format.

stage2: basic switch analysis


5 files changed, 102 insertions(+), 1 deletions(-)

src/astgen.zig+4
......@@ -1584,6 +1584,10 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
15841584 const case = uncasted_case.castTag(.SwitchCase).?;
15851585 const case_src = tree.token_locs[case.firstToken()].start;
15861586
1587 if (case.payload != null) {
1588 return mod.fail(scope, case_src, "TODO switch case payload capture", .{});
1589 }
1590
15871591 if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) {
15881592 if (else_src) |src| {
15891593 return mod.fail(scope, case_src, "multiple else prongs in switch expression", .{});
src/codegen.zig+7
......@@ -786,6 +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").?),
789790 }
790791 }
791792
......@@ -1989,6 +1990,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19891990 return @bitCast(MCValue, inst.codegen.mcv);
19901991 }
19911992
1993 fn genSwitch(self: *Self, inst: *ir.Inst.Switch) !MCValue {
1994 switch (arch) {
1995 else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}),
1996 }
1997 }
1998
19921999 fn performReloc(self: *Self, src: usize, reloc: Reloc) !void {
19932000 switch (reloc) {
19942001 .rel32 => |pos| {
src/ir.zig+24
......@@ -91,6 +91,7 @@ pub const Inst = struct {
9191 intcast,
9292 unwrap_optional,
9393 wrap_optional,
94 @"switch",
9495
9596 pub fn Type(tag: Tag) type {
9697 return switch (tag) {
......@@ -137,6 +138,7 @@ pub const Inst = struct {
137138 .constant => Constant,
138139 .loop => Loop,
139140 .varptr => VarPtr,
141 .@"switch" => Switch,
140142 };
141143 }
142144
......@@ -458,6 +460,28 @@ pub const Inst = struct {
458460 return null;
459461 }
460462 };
463
464 pub const Switch = struct {
465 pub const base_tag = Tag.@"switch";
466
467 base: Inst,
468 target_ptr: *Inst,
469 cases: []Case,
470 @"else": ?Body,
471
472 pub const Case = struct {
473 items: []Value,
474 body: Body,
475 };
476
477 pub fn operandCount(self: *const Switch) usize {
478 return 1;
479 }
480 pub fn getOperand(self: *const Switch, index: usize) ?*Inst {
481 return self.target_ptr;
482 }
483 // TODO case body deaths
484 };
461485};
462486
463487pub const Body = struct {
src/zir.zig+3
......@@ -2549,6 +2549,9 @@ const EmitZIR = struct {
25492549 },
25502550
25512551 .varptr => @panic("TODO"),
2552 .@"switch" => {
2553 @panic("TODO");
2554 },
25522555 };
25532556 try self.metadata.put(new_inst, .{
25542557 .deaths = inst.deaths,
src/zir_sema.zig+64-1
......@@ -1233,7 +1233,70 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE
12331233 const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src);
12341234 try validateSwitch(mod, scope, target, inst);
12351235
1236 return mod.fail(scope, inst.base.src, "TODO analyzeInstSwitch", .{});
1236 // TODO comptime execution
1237
1238 // excludes else and '_' cases
1239 const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none);
1240
1241 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 };
1253
1254 var case_block: Scope.Block = .{
1255 .parent = parent_block,
1256 .func = parent_block.func,
1257 .decl = parent_block.decl,
1258 .instructions = .{},
1259 .arena = parent_block.arena,
1260 .is_comptime = parent_block.is_comptime,
1261 };
1262 defer case_block.instructions.deinit(mod.gpa);
1263
1264 var items_tmp = std.ArrayList(Value).init(mod.gpa);
1265 defer items_tmp.deinit();
1266
1267 for (inst.positionals.cases[0..case_count]) |case, i| {
1268 // Reset without freeing.
1269 case_block.instructions.items.len = 0;
1270 items_tmp.items.len = 0;
1271
1272 for (case.items) |item| {
1273 if (item.castTag(.switch_range)) |range| {
1274 return mod.fail(scope, item.src, "genSwitch expand range", .{});
1275 }
1276 const resolved = try resolveInst(mod, scope, item);
1277 const casted = try mod.coerce(scope, target.ty, resolved);
1278 const val = try mod.resolveConstValue(scope, casted);
1279 try items_tmp.append(val);
1280 }
1281
1282 try analyzeBody(mod, &case_block.base, case.body);
1283
1284 switch_inst.cases[i] = .{
1285 .items = try parent_block.arena.dupe(Value, items_tmp.items),
1286 .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
1287 };
1288 }
1289
1290 if (inst.kw_args.special_case != .none) {
1291 case_block.instructions.items.len = 0;
1292
1293 try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body);
1294 switch_inst.@"else" = .{
1295 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
1296 };
1297 }
1298
1299 return &switch_inst.base;
12371300}
12381301
12391302fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Switch) InnerError!void {