authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-29 19:11:40-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-01 06:47:20-04:00
log751903ba8fba467411942317c8da0e6bc22a0ff6
tree44074425b691cf0d03635d714db1dfaed5fdf7a7
parentf89dbe6c4ebe3fa1ffe3eb455ed96fe615e2c903

zir: add breakpoint() instruction and object file ability


4 files changed, 114 insertions(+), 62 deletions(-)

src-self-hosted/codegen.zig+1
......@@ -77,6 +77,7 @@ const Function = struct {
7777
7878 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
7979 switch (inst.tag) {
80 .breakpoint => return self.genBreakpoint(inst.src),
8081 .unreach => return MCValue{ .unreach = {} },
8182 .constant => unreachable, // excluded from function bodies
8283 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?),
src-self-hosted/ir.zig+74-38
......@@ -21,16 +21,17 @@ pub const Inst = struct {
2121 src: usize,
2222
2323 pub const Tag = enum {
24 unreach,
25 ret,
26 constant,
2724 assembly,
28 ptrtoint,
2925 bitcast,
26 breakpoint,
3027 cmp,
3128 condbr,
32 isnull,
29 constant,
3330 isnonnull,
31 isnull,
32 ptrtoint,
33 ret,
34 unreach,
3435 };
3536
3637 pub fn cast(base: *Inst, comptime T: type) ?*T {
......@@ -53,25 +54,6 @@ pub const Inst = struct {
5354 return inst.val;
5455 }
5556
56 pub const Unreach = struct {
57 pub const base_tag = Tag.unreach;
58 base: Inst,
59 args: void,
60 };
61
62 pub const Ret = struct {
63 pub const base_tag = Tag.ret;
64 base: Inst,
65 args: void,
66 };
67
68 pub const Constant = struct {
69 pub const base_tag = Tag.constant;
70 base: Inst,
71
72 val: Value,
73 };
74
7557 pub const Assembly = struct {
7658 pub const base_tag = Tag.assembly;
7759 base: Inst,
......@@ -86,15 +68,6 @@ pub const Inst = struct {
8668 },
8769 };
8870
89 pub const PtrToInt = struct {
90 pub const base_tag = Tag.ptrtoint;
91
92 base: Inst,
93 args: struct {
94 ptr: *Inst,
95 },
96 };
97
9871 pub const BitCast = struct {
9972 pub const base_tag = Tag.bitcast;
10073
......@@ -104,6 +77,12 @@ pub const Inst = struct {
10477 },
10578 };
10679
80 pub const Breakpoint = struct {
81 pub const base_tag = Tag.breakpoint;
82 base: Inst,
83 args: void,
84 };
85
10786 pub const Cmp = struct {
10887 pub const base_tag = Tag.cmp;
10988
......@@ -126,6 +105,22 @@ pub const Inst = struct {
126105 },
127106 };
128107
108 pub const Constant = struct {
109 pub const base_tag = Tag.constant;
110 base: Inst,
111
112 val: Value,
113 };
114
115 pub const IsNonNull = struct {
116 pub const base_tag = Tag.isnonnull;
117
118 base: Inst,
119 args: struct {
120 operand: *Inst,
121 },
122 };
123
129124 pub const IsNull = struct {
130125 pub const base_tag = Tag.isnull;
131126
......@@ -135,14 +130,26 @@ pub const Inst = struct {
135130 },
136131 };
137132
138 pub const IsNonNull = struct {
139 pub const base_tag = Tag.isnonnull;
133 pub const PtrToInt = struct {
134 pub const base_tag = Tag.ptrtoint;
140135
141136 base: Inst,
142137 args: struct {
143 operand: *Inst,
138 ptr: *Inst,
144139 },
145140 };
141
142 pub const Ret = struct {
143 pub const base_tag = Tag.ret;
144 base: Inst,
145 args: void,
146 };
147
148 pub const Unreach = struct {
149 pub const base_tag = Tag.unreach;
150 base: Inst,
151 args: void,
152 };
146153};
147154
148155pub const TypedValue = struct {
......@@ -159,6 +166,7 @@ pub const Module = struct {
159166 link_mode: std.builtin.LinkMode,
160167 output_mode: std.builtin.OutputMode,
161168 object_format: std.Target.ObjectFormat,
169 optimize_mode: std.builtin.Mode,
162170
163171 pub const Export = struct {
164172 name: []const u8,
......@@ -198,6 +206,7 @@ pub const AnalyzeOptions = struct {
198206 output_mode: std.builtin.OutputMode,
199207 link_mode: std.builtin.LinkMode,
200208 object_format: ?std.Target.ObjectFormat = null,
209 optimize_mode: std.builtin.Mode,
201210};
202211
203212pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeOptions) !Module {
......@@ -210,6 +219,9 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeO
210219 .exports = std.ArrayList(Module.Export).init(allocator),
211220 .fns = std.ArrayList(Module.Fn).init(allocator),
212221 .target = options.target,
222 .optimize_mode = options.optimize_mode,
223 .link_mode = options.link_mode,
224 .output_mode = options.output_mode,
213225 };
214226 defer ctx.errors.deinit();
215227 defer ctx.decl_table.deinit();
......@@ -229,9 +241,10 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeO
229241 .fns = ctx.fns.toOwnedSlice(),
230242 .arena = ctx.arena,
231243 .target = ctx.target,
232 .link_mode = options.link_mode,
233 .output_mode = options.output_mode,
244 .link_mode = ctx.link_mode,
245 .output_mode = ctx.output_mode,
234246 .object_format = options.object_format orelse ctx.target.getObjectFormat(),
247 .optimize_mode = ctx.optimize_mode,
235248 };
236249}
237250
......@@ -244,6 +257,9 @@ const Analyze = struct {
244257 exports: std.ArrayList(Module.Export),
245258 fns: std.ArrayList(Module.Fn),
246259 target: Target,
260 link_mode: std.builtin.LinkMode,
261 optimize_mode: std.builtin.Mode,
262 output_mode: std.builtin.OutputMode,
247263
248264 const NewDecl = struct {
249265 /// null means a semantic analysis error happened
......@@ -495,6 +511,7 @@ const Analyze = struct {
495511
496512 fn analyzeInst(self: *Analyze, block: ?*Block, old_inst: *text.Inst) InnerError!*Inst {
497513 switch (old_inst.tag) {
514 .breakpoint => return self.analyzeInstBreakpoint(block, old_inst.cast(text.Inst.Breakpoint).?),
498515 .str => {
499516 // We can use this reference because Inst.Const's Value is arena-allocated.
500517 // The value would get copied to a MemoryCell before the `text.Inst.Str` lifetime ends.
......@@ -530,6 +547,11 @@ const Analyze = struct {
530547 }
531548 }
532549
550 fn analyzeInstBreakpoint(self: *Analyze, block: ?*Block, inst: *text.Inst.Breakpoint) InnerError!*Inst {
551 const b = try self.requireRuntimeBlock(block, inst.base.src);
552 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});
553 }
554
533555 fn analyzeInstFn(self: *Analyze, block: ?*Block, fn_inst: *text.Inst.Fn) InnerError!*Inst {
534556 const fn_type = try self.resolveType(block, fn_inst.positionals.fn_type);
535557
......@@ -909,8 +931,21 @@ const Analyze = struct {
909931 });
910932 }
911933
934 fn wantSafety(self: *Analyze, block: ?*Block) bool {
935 return switch (self.optimize_mode) {
936 .Debug => true,
937 .ReleaseSafe => true,
938 .ReleaseFast => false,
939 .ReleaseSmall => false,
940 };
941 }
942
912943 fn analyzeInstUnreachable(self: *Analyze, block: ?*Block, unreach: *text.Inst.Unreachable) InnerError!*Inst {
913944 const b = try self.requireRuntimeBlock(block, unreach.base.src);
945 if (self.wantSafety(block)) {
946 // TODO Once we have a panic function to call, call it here instead of this.
947 _ = try self.addNewInstArgs(b, unreach.base.src, Type.initTag(.void), Inst.Breakpoint, {});
948 }
914949 return self.addNewInstArgs(b, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {});
915950 }
916951
......@@ -1258,6 +1293,7 @@ pub fn main() anyerror!void {
12581293 .target = native_info.target,
12591294 .output_mode = .Obj,
12601295 .link_mode = .Static,
1296 .optimize_mode = .Debug,
12611297 });
12621298 defer analyzed_module.deinit(allocator);
12631299
src-self-hosted/ir/text.zig+24-18
......@@ -18,6 +18,7 @@ pub const Inst = struct {
1818
1919 /// These names are used directly as the instruction names in the text format.
2020 pub const Tag = enum {
21 breakpoint,
2122 str,
2223 int,
2324 ptrtoint,
......@@ -43,6 +44,7 @@ pub const Inst = struct {
4344
4445 pub fn TagToType(tag: Tag) type {
4546 return switch (tag) {
47 .breakpoint => Breakpoint,
4648 .str => Str,
4749 .int => Int,
4850 .ptrtoint => PtrToInt,
......@@ -74,6 +76,14 @@ pub const Inst = struct {
7476 return @fieldParentPtr(T, "base", base);
7577 }
7678
79 pub const Breakpoint = struct {
80 pub const base_tag = Tag.breakpoint;
81 base: Inst,
82
83 positionals: struct {},
84 kw_args: struct {},
85 };
86
7787 pub const Str = struct {
7888 pub const base_tag = Tag.str;
7989 base: Inst,
......@@ -419,6 +429,7 @@ pub const Module = struct {
419429 ) @TypeOf(stream).Error!void {
420430 // TODO I tried implementing this with an inline for loop and hit a compiler bug
421431 switch (decl.tag) {
432 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table),
422433 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
423434 .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),
424435 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),
......@@ -1030,6 +1041,16 @@ const EmitZIR = struct {
10301041 }
10311042 }
10321043
1044 fn emitTrivial(self: *EmitZIR, src: usize, comptime T: type) Allocator.Error!*Inst {
1045 const new_inst = try self.arena.allocator.create(T);
1046 new_inst.* = .{
1047 .base = .{ .src = src, .tag = T.base_tag },
1048 .positionals = .{},
1049 .kw_args = .{},
1050 };
1051 return &new_inst.base;
1052 }
1053
10331054 fn emitBody(
10341055 self: *EmitZIR,
10351056 body: ir.Module.Body,
......@@ -1038,24 +1059,9 @@ const EmitZIR = struct {
10381059 ) Allocator.Error!void {
10391060 for (body.instructions) |inst| {
10401061 const new_inst = switch (inst.tag) {
1041 .unreach => blk: {
1042 const unreach_inst = try self.arena.allocator.create(Inst.Unreachable);
1043 unreach_inst.* = .{
1044 .base = .{ .src = inst.src, .tag = Inst.Unreachable.base_tag },
1045 .positionals = .{},
1046 .kw_args = .{},
1047 };
1048 break :blk &unreach_inst.base;
1049 },
1050 .ret => blk: {
1051 const ret_inst = try self.arena.allocator.create(Inst.Return);
1052 ret_inst.* = .{
1053 .base = .{ .src = inst.src, .tag = Inst.Return.base_tag },
1054 .positionals = .{},
1055 .kw_args = .{},
1056 };
1057 break :blk &ret_inst.base;
1058 },
1062 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
1063 .unreach => try self.emitTrivial(inst.src, Inst.Unreachable),
1064 .ret => try self.emitTrivial(inst.src, Inst.Return),
10591065 .constant => unreachable, // excluded from function bodies
10601066 .assembly => blk: {
10611067 const old_inst = inst.cast(ir.Inst.Assembly).?;
src-self-hosted/link.zig+15-6
......@@ -431,7 +431,7 @@ const Update = struct {
431431 },
432432 }
433433 }
434 if (self.entry_addr == null) {
434 if (self.entry_addr == null and self.module.output_mode == .Exe) {
435435 const msg = try std.fmt.allocPrint(self.errors.allocator, "no entry point found", .{});
436436 errdefer self.errors.allocator.free(msg);
437437 try self.errors.append(.{
......@@ -480,7 +480,15 @@ const Update = struct {
480480
481481 assert(index == 16);
482482
483 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf.ET.EXEC), endian);
483 const elf_type = switch (self.module.output_mode) {
484 .Exe => elf.ET.EXEC,
485 .Obj => elf.ET.REL,
486 .Lib => switch (self.module.link_mode) {
487 .Static => elf.ET.REL,
488 .Dynamic => elf.ET.DYN,
489 },
490 };
491 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian);
484492 index += 2;
485493
486494 const machine = self.module.target.cpu.arch.toElfMachine();
......@@ -491,10 +499,11 @@ const Update = struct {
491499 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
492500 index += 4;
493501
502 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
503
494504 switch (ptr_width) {
495505 .p32 => {
496 // e_entry
497 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.entry_addr.?), endian);
506 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);
498507 index += 4;
499508
500509 // e_phoff
......@@ -507,7 +516,7 @@ const Update = struct {
507516 },
508517 .p64 => {
509518 // e_entry
510 mem.writeInt(u64, hdr_buf[index..][0..8], self.entry_addr.?, endian);
519 mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian);
511520 index += 8;
512521
513522 // e_phoff
......@@ -748,7 +757,7 @@ const Update = struct {
748757pub fn writeFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {
749758 switch (module.output_mode) {
750759 .Exe => {},
751 .Obj => return error.TODOImplementWritingObjectFiles,
760 .Obj => {},
752761 .Lib => return error.TODOImplementWritingLibFiles,
753762 }
754763 switch (module.object_format) {