| 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,18 +2545,6 @@ fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerEr |
| 2545 | assert(child_block.instructions.items.len != 0); | 2545 | assert(child_block.instructions.items.len != 0); |
| 2546 | assert(child_block.instructions.items[child_block.instructions.items.len - 1].tag.isNoReturn()); | 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 | // Need to set the type and emit the Block instruction. This allows machine code generation | 2548 | // Need to set the type and emit the Block instruction. This allows machine code generation |
| 2561 | // to emit a jump instruction to after the block when it encounters the break. | 2549 | // to emit a jump instruction to after the block when it encounters the break. |
| 2562 | try parent_block.instructions.append(self.gpa, &block_inst.base); | 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,7 +2567,10 @@ fn analyzeInstBreakVoid(self: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) |
| 2579 | if (block.label) |*label| { | 2567 | if (block.label) |*label| { |
| 2580 | if (mem.eql(u8, label.name, label_name)) { | 2568 | if (mem.eql(u8, label.name, label_name)) { |
| 2581 | try label.results.append(self.gpa, void_inst); | 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 | opt_block = block.parent; | 2576 | opt_block = block.parent; |
| ... | @@ -3366,6 +3357,8 @@ fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type { | ... | @@ -3366,6 +3357,8 @@ fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type { |
| 3366 | fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type { | 3357 | fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type { |
| 3367 | if (instructions.len == 0) | 3358 | if (instructions.len == 0) |
| 3368 | return Type.initTag(.noreturn); | 3359 | return Type.initTag(.noreturn); |
| 3360 | if (instructions.len == 1) | ||
| 3361 | return instructions[0].ty; | ||
| 3369 | return self.fail(scope, instructions[0].src, "TODO peer type resolution", .{}); | 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,6 +218,11 @@ pub fn generateSymbol( |
| 218 | } | 218 | } |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | const InnerError = error { | ||
| 222 | OutOfMemory, | ||
| 223 | CodegenFail, | ||
| 224 | }; | ||
| 225 | |||
| 221 | const Function = struct { | 226 | const Function = struct { |
| 222 | gpa: *Allocator, | 227 | gpa: *Allocator, |
| 223 | bin_file: *link.ElfFile, | 228 | bin_file: *link.ElfFile, |
| ... | @@ -379,8 +384,12 @@ const Function = struct { | ... | @@ -379,8 +384,12 @@ const Function = struct { |
| 379 | } | 384 | } |
| 380 | 385 | ||
| 381 | fn genArch(self: *Function, comptime arch: std.Target.Cpu.Arch) !void { | 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 | const inst_table = &self.branch_stack.items[0].inst_table; | 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 | const new_inst = try self.genFuncInst(inst, arch); | 393 | const new_inst = try self.genFuncInst(inst, arch); |
| 385 | try inst_table.putNoClobber(self.gpa, inst, new_inst); | 394 | try inst_table.putNoClobber(self.gpa, inst, new_inst); |
| 386 | } | 395 | } |
| ... | @@ -394,6 +403,7 @@ const Function = struct { | ... | @@ -394,6 +403,7 @@ const Function = struct { |
| 394 | .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?), | 403 | .bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?), |
| 395 | .block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch), | 404 | .block => return self.genBlock(inst.cast(ir.Inst.Block).?, arch), |
| 396 | .breakpoint => return self.genBreakpoint(inst.src, arch), | 405 | .breakpoint => return self.genBreakpoint(inst.src, arch), |
| 406 | .breakvoid => return self.genBreakVoid(inst.cast(ir.Inst.BreakVoid).?, arch), | ||
| 397 | .call => return self.genCall(inst.cast(ir.Inst.Call).?, arch), | 407 | .call => return self.genCall(inst.cast(ir.Inst.Call).?, arch), |
| 398 | .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch), | 408 | .cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?, arch), |
| 399 | .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch), | 409 | .condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?, arch), |
| ... | @@ -686,9 +696,16 @@ const Function = struct { | ... | @@ -686,9 +696,16 @@ const Function = struct { |
| 686 | } | 696 | } |
| 687 | 697 | ||
| 688 | fn genBlock(self: *Function, inst: *ir.Inst.Block, comptime arch: std.Target.Cpu.Arch) !MCValue { | 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 | switch (arch) { | 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 | fn genAsm(self: *Function, inst: *ir.Inst.Assembly, comptime arch: Target.Cpu.Arch) !MCValue { | 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,6 +35,10 @@ pub const Inst = struct { |
| 35 | return @truncate(u1, self.deaths << index) != 0; | 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 | pub const Tag = enum { | 42 | pub const Tag = enum { |
| 39 | add, | 43 | add, |
| 40 | arg, | 44 | arg, |
| ... | @@ -42,6 +46,7 @@ pub const Inst = struct { | ... | @@ -42,6 +46,7 @@ pub const Inst = struct { |
| 42 | bitcast, | 46 | bitcast, |
| 43 | block, | 47 | block, |
| 44 | breakpoint, | 48 | breakpoint, |
| 49 | breakvoid, | ||
| 45 | call, | 50 | call, |
| 46 | cmp, | 51 | cmp, |
| 47 | condbr, | 52 | condbr, |
| ... | @@ -74,6 +79,7 @@ pub const Inst = struct { | ... | @@ -74,6 +79,7 @@ pub const Inst = struct { |
| 74 | .sub, | 79 | .sub, |
| 75 | => false, | 80 | => false, |
| 76 | 81 | ||
| 82 | .breakvoid, | ||
| 77 | .condbr, | 83 | .condbr, |
| 78 | .ret, | 84 | .ret, |
| 79 | .retvoid, | 85 | .retvoid, |
| ... | @@ -159,6 +165,14 @@ pub const Inst = struct { | ... | @@ -159,6 +165,14 @@ pub const Inst = struct { |
| 159 | args: void, | 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 | pub const Call = struct { | 176 | pub const Call = struct { |
| 163 | pub const base_tag = Tag.call; | 177 | pub const base_tag = Tag.call; |
| 164 | base: Inst, | 178 | base: Inst, |
src-self-hosted/zir.zig+16| ... | @@ -1608,6 +1608,22 @@ const EmitZIR = struct { | ... | @@ -1608,6 +1608,22 @@ const EmitZIR = struct { |
| 1608 | break :blk &new_inst.base; | 1608 | break :blk &new_inst.base; |
| 1609 | }, | 1609 | }, |
| 1610 | .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint), | 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 | .call => blk: { | 1627 | .call => blk: { |
| 1612 | const old_inst = inst.cast(ir.Inst.Call).?; | 1628 | const old_inst = inst.cast(ir.Inst.Call).?; |
| 1613 | const new_inst = try self.arena.allocator.create(Inst.Call); | 1629 | const new_inst = try self.arena.allocator.create(Inst.Call); |