| author | |
| committer | |
| log | b55d0193e41311532e7b3603b9386863626afcd2 |
| tree | 99e727cfd24fb359a6ed2b2fdd698c3d11888a88 |
| parent | 4d01385e147ae36ad96a1c28d2b6fdec69ce69c9 |
4 files changed, 55 insertions(+), 15 deletions(-)
src-self-hosted/Module.zig+6-13| ... | ... | @@ -2545,18 +2545,6 @@ fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerEr |
| 2545 | 2545 | assert(child_block.instructions.items.len != 0); |
| 2546 | 2546 | assert(child_block.instructions.items[child_block.instructions.items.len - 1].tag.isNoReturn()); |
| 2547 | 2547 | |
| 2548 | if (label.results.items.len <= 1) { | |
| 2549 | // No need to add the Block instruction; we can add the instructions to the parent block directly. | |
| 2550 | // Blocks are terminated with a noreturn instruction which we do not want to include. | |
| 2551 | const instrs = child_block.instructions.items; | |
| 2552 | try parent_block.instructions.appendSlice(self.gpa, instrs[0 .. instrs.len - 1]); | |
| 2553 | if (label.results.items.len == 1) { | |
| 2554 | return label.results.items[0]; | |
| 2555 | } else { | |
| 2556 | return self.constNoReturn(scope, inst.base.src); | |
| 2557 | } | |
| 2558 | } | |
| 2559 | ||
| 2560 | 2548 | // Need to set the type and emit the Block instruction. This allows machine code generation |
| 2561 | 2549 | // to emit a jump instruction to after the block when it encounters the break. |
| 2562 | 2550 | try parent_block.instructions.append(self.gpa, &block_inst.base); |
| ... | ... | @@ -2579,7 +2567,10 @@ fn analyzeInstBreakVoid(self: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) |
| 2579 | 2567 | if (block.label) |*label| { |
| 2580 | 2568 | if (mem.eql(u8, label.name, label_name)) { |
| 2581 | 2569 | try label.results.append(self.gpa, void_inst); |
| 2582 | return self.constNoReturn(scope, inst.base.src); | |
| 2570 | const b = try self.requireRuntimeBlock(scope, inst.base.src); | |
| 2571 | return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.BreakVoid, .{ | |
| 2572 | .block = label.block_inst, | |
| 2573 | }); | |
| 2583 | 2574 | } |
| 2584 | 2575 | } |
| 2585 | 2576 | opt_block = block.parent; |
| ... | ... | @@ -3366,6 +3357,8 @@ fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type { |
| 3366 | 3357 | fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type { |
| 3367 | 3358 | if (instructions.len == 0) |
| 3368 | 3359 | return Type.initTag(.noreturn); |
| 3360 | if (instructions.len == 1) | |
| 3361 | return instructions[0].ty; | |
| 3369 | 3362 | return self.fail(scope, instructions[0].src, "TODO peer type resolution", .{}); |
| 3370 | 3363 | } |
| 3371 | 3364 |
src-self-hosted/codegen.zig+19-2| ... | ... | @@ -218,6 +218,11 @@ pub fn generateSymbol( |
| 218 | 218 | } |
| 219 | 219 | } |
| 220 | 220 | |
| 221 | const InnerError = error { | |
| 222 | OutOfMemory, | |
| 223 | CodegenFail, | |
| 224 | }; | |
| 225 | ||
| 221 | 226 | const Function = struct { |
| 222 | 227 | gpa: *Allocator, |
| 223 | 228 | bin_file: *link.ElfFile, |
| ... | ... | @@ -379,8 +384,12 @@ const Function = struct { |
| 379 | 384 | } |
| 380 | 385 | |
| 381 | 386 | fn genArch(self: *Function, comptime arch: std.Target.Cpu.Arch) !void { |
| 387 | return self.genBody(self.mod_fn.analysis.success, arch); | |
| 388 | } | |
| 389 | ||
| 390 | fn genBody(self: *Function, body: ir.Body, comptime arch: std.Target.Cpu.Arch) InnerError!void { | |
| 382 | 391 | const inst_table = &self.branch_stack.items[0].inst_table; |
| 383 | for (self.mod_fn.analysis.success.instructions) |inst| { | |
| 392 | for (body.instructions) |inst| { | |
| 384 | 393 | const new_inst = try self.genFuncInst(inst, arch); |
| 385 | 394 | try inst_table.putNoClobber(self.gpa, inst, new_inst); |
| 386 | 395 | } |
| ... | ... | @@ -394,6 +403,7 @@ const Function = struct { |
| 394 | 403 | .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?), |
| 395 | 404 | .block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch), |
| 396 | 405 | .breakpoint => return self.genBreakpoint(inst.src, arch), |
| 406 | .breakvoid => return self.genBreakVoid(inst.cast(ir.Inst.BreakVoid).?, arch), | |
| 397 | 407 | .call => return self.genCall(inst.cast(ir.Inst.Call).?, arch), |
| 398 | 408 | .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch), |
| 399 | 409 | .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch), |
| ... | ... | @@ -686,9 +696,16 @@ const Function = struct { |
| 686 | 696 | } |
| 687 | 697 | |
| 688 | 698 | fn genBlock(self: *Function, inst: *ir.Inst.Block, comptime arch: std.Target.Cpu.Arch) !MCValue { |
| 699 | // A block is nothing but a setup to be able to jump to the end. | |
| 700 | try self.genBody(inst.args.body, arch); | |
| 701 | return self.fail(inst.base.src, "TODO process jump relocs after block end", .{}); | |
| 702 | } | |
| 703 | ||
| 704 | fn genBreakVoid(self: *Function, inst: *ir.Inst.BreakVoid, comptime arch: std.Target.Cpu.Arch) !MCValue { | |
| 689 | 705 | switch (arch) { |
| 690 | else => return self.fail(inst.base.src, "TODO implement codegen Block for {}", .{self.target.cpu.arch}), | |
| 706 | else => return self.fail(inst.base.src, "TODO implement breakvoid for {}", .{self.target.cpu.arch}), | |
| 691 | 707 | } |
| 708 | return .none; | |
| 692 | 709 | } |
| 693 | 710 | |
| 694 | 711 | fn genAsm(self: *Function, inst: *ir.Inst.Assembly, comptime arch: Target.Cpu.Arch) !MCValue { |
src-self-hosted/ir.zig+14| ... | ... | @@ -35,6 +35,10 @@ pub const Inst = struct { |
| 35 | 35 | return @truncate(u1, self.deaths << index) != 0; |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | pub fn specialOperandDeaths(self: Inst) bool { | |
| 39 | return (self.deaths & 0b1000_0000) != 0; | |
| 40 | } | |
| 41 | ||
| 38 | 42 | pub const Tag = enum { |
| 39 | 43 | add, |
| 40 | 44 | arg, |
| ... | ... | @@ -42,6 +46,7 @@ pub const Inst = struct { |
| 42 | 46 | bitcast, |
| 43 | 47 | block, |
| 44 | 48 | breakpoint, |
| 49 | breakvoid, | |
| 45 | 50 | call, |
| 46 | 51 | cmp, |
| 47 | 52 | condbr, |
| ... | ... | @@ -74,6 +79,7 @@ pub const Inst = struct { |
| 74 | 79 | .sub, |
| 75 | 80 | => false, |
| 76 | 81 | |
| 82 | .breakvoid, | |
| 77 | 83 | .condbr, |
| 78 | 84 | .ret, |
| 79 | 85 | .retvoid, |
| ... | ... | @@ -159,6 +165,14 @@ pub const Inst = struct { |
| 159 | 165 | args: void, |
| 160 | 166 | }; |
| 161 | 167 | |
| 168 | pub const BreakVoid = struct { | |
| 169 | pub const base_tag = Tag.breakvoid; | |
| 170 | base: Inst, | |
| 171 | args: struct { | |
| 172 | block: *Block, | |
| 173 | }, | |
| 174 | }; | |
| 175 | ||
| 162 | 176 | pub const Call = struct { |
| 163 | 177 | pub const base_tag = Tag.call; |
| 164 | 178 | base: Inst, |
src-self-hosted/zir.zig+16| ... | ... | @@ -1608,6 +1608,22 @@ const EmitZIR = struct { |
| 1608 | 1608 | break :blk &new_inst.base; |
| 1609 | 1609 | }, |
| 1610 | 1610 | .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint), |
| 1611 | .breakvoid => blk: { | |
| 1612 | const old_inst = inst.cast(ir.Inst.BreakVoid).?; | |
| 1613 | const new_block = inst_table.get(&old_inst.args.block.base).?; | |
| 1614 | const new_inst = try self.arena.allocator.create(Inst.BreakVoid); | |
| 1615 | new_inst.* = .{ | |
| 1616 | .base = .{ | |
| 1617 | .src = inst.src, | |
| 1618 | .tag = Inst.BreakVoid.base_tag, | |
| 1619 | }, | |
| 1620 | .positionals = .{ | |
| 1621 | .label = new_block.cast(Inst.Block).?.positionals.label, | |
| 1622 | }, | |
| 1623 | .kw_args = .{}, | |
| 1624 | }; | |
| 1625 | break :blk &new_inst.base; | |
| 1626 | }, | |
| 1611 | 1627 | .call => blk: { |
| 1612 | 1628 | const old_inst = inst.cast(ir.Inst.Call).?; |
| 1613 | 1629 | const new_inst = try self.arena.allocator.create(Inst.Call); |