| ... | @@ -21,16 +21,17 @@ pub const Inst = struct { | ... | @@ -21,16 +21,17 @@ pub const Inst = struct { |
| 21 | src: usize, | 21 | src: usize, |
| 22 | | 22 | |
| 23 | pub const Tag = enum { | 23 | pub const Tag = enum { |
| 24 | unreach, | | |
| 25 | ret, | | |
| 26 | constant, | | |
| 27 | assembly, | 24 | assembly, |
| 28 | ptrtoint, | | |
| 29 | bitcast, | 25 | bitcast, |
| | 26 | breakpoint, |
| 30 | cmp, | 27 | cmp, |
| 31 | condbr, | 28 | condbr, |
| 32 | isnull, | 29 | constant, |
| 33 | isnonnull, | 30 | isnonnull, |
| | 31 | isnull, |
| | 32 | ptrtoint, |
| | 33 | ret, |
| | 34 | unreach, |
| 34 | }; | 35 | }; |
| 35 | | 36 | |
| 36 | pub fn cast(base: *Inst, comptime T: type) ?*T { | 37 | pub fn cast(base: *Inst, comptime T: type) ?*T { |
| ... | @@ -53,25 +54,6 @@ pub const Inst = struct { | ... | @@ -53,25 +54,6 @@ pub const Inst = struct { |
| 53 | return inst.val; | 54 | return inst.val; |
| 54 | } | 55 | } |
| 55 | | 56 | |
| 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 | | | |
| 75 | pub const Assembly = struct { | 57 | pub const Assembly = struct { |
| 76 | pub const base_tag = Tag.assembly; | 58 | pub const base_tag = Tag.assembly; |
| 77 | base: Inst, | 59 | base: Inst, |
| ... | @@ -86,15 +68,6 @@ pub const Inst = struct { | ... | @@ -86,15 +68,6 @@ pub const Inst = struct { |
| 86 | }, | 68 | }, |
| 87 | }; | 69 | }; |
| 88 | | 70 | |
| 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 | | | |
| 98 | pub const BitCast = struct { | 71 | pub const BitCast = struct { |
| 99 | pub const base_tag = Tag.bitcast; | 72 | pub const base_tag = Tag.bitcast; |
| 100 | | 73 | |
| ... | @@ -104,6 +77,12 @@ pub const Inst = struct { | ... | @@ -104,6 +77,12 @@ pub const Inst = struct { |
| 104 | }, | 77 | }, |
| 105 | }; | 78 | }; |
| 106 | | 79 | |
| | 80 | pub const Breakpoint = struct { |
| | 81 | pub const base_tag = Tag.breakpoint; |
| | 82 | base: Inst, |
| | 83 | args: void, |
| | 84 | }; |
| | 85 | |
| 107 | pub const Cmp = struct { | 86 | pub const Cmp = struct { |
| 108 | pub const base_tag = Tag.cmp; | 87 | pub const base_tag = Tag.cmp; |
| 109 | | 88 | |
| ... | @@ -126,6 +105,22 @@ pub const Inst = struct { | ... | @@ -126,6 +105,22 @@ pub const Inst = struct { |
| 126 | }, | 105 | }, |
| 127 | }; | 106 | }; |
| 128 | | 107 | |
| | 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 | |
| 129 | pub const IsNull = struct { | 124 | pub const IsNull = struct { |
| 130 | pub const base_tag = Tag.isnull; | 125 | pub const base_tag = Tag.isnull; |
| 131 | | 126 | |
| ... | @@ -135,14 +130,26 @@ pub const Inst = struct { | ... | @@ -135,14 +130,26 @@ pub const Inst = struct { |
| 135 | }, | 130 | }, |
| 136 | }; | 131 | }; |
| 137 | | 132 | |
| 138 | pub const IsNonNull = struct { | 133 | pub const PtrToInt = struct { |
| 139 | pub const base_tag = Tag.isnonnull; | 134 | pub const base_tag = Tag.ptrtoint; |
| 140 | | 135 | |
| 141 | base: Inst, | 136 | base: Inst, |
| 142 | args: struct { | 137 | args: struct { |
| 143 | operand: *Inst, | 138 | ptr: *Inst, |
| 144 | }, | 139 | }, |
| 145 | }; | 140 | }; |
| | 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 | }; |
| 146 | }; | 153 | }; |
| 147 | | 154 | |
| 148 | pub const TypedValue = struct { | 155 | pub const TypedValue = struct { |
| ... | @@ -159,6 +166,7 @@ pub const Module = struct { | ... | @@ -159,6 +166,7 @@ pub const Module = struct { |
| 159 | link_mode: std.builtin.LinkMode, | 166 | link_mode: std.builtin.LinkMode, |
| 160 | output_mode: std.builtin.OutputMode, | 167 | output_mode: std.builtin.OutputMode, |
| 161 | object_format: std.Target.ObjectFormat, | 168 | object_format: std.Target.ObjectFormat, |
| | 169 | optimize_mode: std.builtin.Mode, |
| 162 | | 170 | |
| 163 | pub const Export = struct { | 171 | pub const Export = struct { |
| 164 | name: []const u8, | 172 | name: []const u8, |
| ... | @@ -198,6 +206,7 @@ pub const AnalyzeOptions = struct { | ... | @@ -198,6 +206,7 @@ pub const AnalyzeOptions = struct { |
| 198 | output_mode: std.builtin.OutputMode, | 206 | output_mode: std.builtin.OutputMode, |
| 199 | link_mode: std.builtin.LinkMode, | 207 | link_mode: std.builtin.LinkMode, |
| 200 | object_format: ?std.Target.ObjectFormat = null, | 208 | object_format: ?std.Target.ObjectFormat = null, |
| | 209 | optimize_mode: std.builtin.Mode, |
| 201 | }; | 210 | }; |
| 202 | | 211 | |
| 203 | pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeOptions) !Module { | 212 | pub 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 | ... | @@ -210,6 +219,9 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeO |
| 210 | .exports = std.ArrayList(Module.Export).init(allocator), | 219 | .exports = std.ArrayList(Module.Export).init(allocator), |
| 211 | .fns = std.ArrayList(Module.Fn).init(allocator), | 220 | .fns = std.ArrayList(Module.Fn).init(allocator), |
| 212 | .target = options.target, | 221 | .target = options.target, |
| | 222 | .optimize_mode = options.optimize_mode, |
| | 223 | .link_mode = options.link_mode, |
| | 224 | .output_mode = options.output_mode, |
| 213 | }; | 225 | }; |
| 214 | defer ctx.errors.deinit(); | 226 | defer ctx.errors.deinit(); |
| 215 | defer ctx.decl_table.deinit(); | 227 | defer ctx.decl_table.deinit(); |
| ... | @@ -229,9 +241,10 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeO | ... | @@ -229,9 +241,10 @@ pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeO |
| 229 | .fns = ctx.fns.toOwnedSlice(), | 241 | .fns = ctx.fns.toOwnedSlice(), |
| 230 | .arena = ctx.arena, | 242 | .arena = ctx.arena, |
| 231 | .target = ctx.target, | 243 | .target = ctx.target, |
| 232 | .link_mode = options.link_mode, | 244 | .link_mode = ctx.link_mode, |
| 233 | .output_mode = options.output_mode, | 245 | .output_mode = ctx.output_mode, |
| 234 | .object_format = options.object_format orelse ctx.target.getObjectFormat(), | 246 | .object_format = options.object_format orelse ctx.target.getObjectFormat(), |
| | 247 | .optimize_mode = ctx.optimize_mode, |
| 235 | }; | 248 | }; |
| 236 | } | 249 | } |
| 237 | | 250 | |
| ... | @@ -244,6 +257,9 @@ const Analyze = struct { | ... | @@ -244,6 +257,9 @@ const Analyze = struct { |
| 244 | exports: std.ArrayList(Module.Export), | 257 | exports: std.ArrayList(Module.Export), |
| 245 | fns: std.ArrayList(Module.Fn), | 258 | fns: std.ArrayList(Module.Fn), |
| 246 | target: Target, | 259 | target: Target, |
| | 260 | link_mode: std.builtin.LinkMode, |
| | 261 | optimize_mode: std.builtin.Mode, |
| | 262 | output_mode: std.builtin.OutputMode, |
| 247 | | 263 | |
| 248 | const NewDecl = struct { | 264 | const NewDecl = struct { |
| 249 | /// null means a semantic analysis error happened | 265 | /// null means a semantic analysis error happened |
| ... | @@ -495,6 +511,7 @@ const Analyze = struct { | ... | @@ -495,6 +511,7 @@ const Analyze = struct { |
| 495 | | 511 | |
| 496 | fn analyzeInst(self: *Analyze, block: ?*Block, old_inst: *text.Inst) InnerError!*Inst { | 512 | fn analyzeInst(self: *Analyze, block: ?*Block, old_inst: *text.Inst) InnerError!*Inst { |
| 497 | switch (old_inst.tag) { | 513 | switch (old_inst.tag) { |
| | 514 | .breakpoint => return self.analyzeInstBreakpoint(block, old_inst.cast(text.Inst.Breakpoint).?), |
| 498 | .str => { | 515 | .str => { |
| 499 | // We can use this reference because Inst.Const's Value is arena-allocated. | 516 | // We can use this reference because Inst.Const's Value is arena-allocated. |
| 500 | // The value would get copied to a MemoryCell before the `text.Inst.Str` lifetime ends. | 517 | // The value would get copied to a MemoryCell before the `text.Inst.Str` lifetime ends. |
| ... | @@ -530,6 +547,11 @@ const Analyze = struct { | ... | @@ -530,6 +547,11 @@ const Analyze = struct { |
| 530 | } | 547 | } |
| 531 | } | 548 | } |
| 532 | | 549 | |
| | 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 | |
| 533 | fn analyzeInstFn(self: *Analyze, block: ?*Block, fn_inst: *text.Inst.Fn) InnerError!*Inst { | 555 | fn analyzeInstFn(self: *Analyze, block: ?*Block, fn_inst: *text.Inst.Fn) InnerError!*Inst { |
| 534 | const fn_type = try self.resolveType(block, fn_inst.positionals.fn_type); | 556 | const fn_type = try self.resolveType(block, fn_inst.positionals.fn_type); |
| 535 | | 557 | |
| ... | @@ -909,8 +931,21 @@ const Analyze = struct { | ... | @@ -909,8 +931,21 @@ const Analyze = struct { |
| 909 | }); | 931 | }); |
| 910 | } | 932 | } |
| 911 | | 933 | |
| | 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 | |
| 912 | fn analyzeInstUnreachable(self: *Analyze, block: ?*Block, unreach: *text.Inst.Unreachable) InnerError!*Inst { | 943 | fn analyzeInstUnreachable(self: *Analyze, block: ?*Block, unreach: *text.Inst.Unreachable) InnerError!*Inst { |
| 913 | const b = try self.requireRuntimeBlock(block, unreach.base.src); | 944 | 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 | } |
| 914 | return self.addNewInstArgs(b, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {}); | 949 | return self.addNewInstArgs(b, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {}); |
| 915 | } | 950 | } |
| 916 | | 951 | |
| ... | @@ -1258,6 +1293,7 @@ pub fn main() anyerror!void { | ... | @@ -1258,6 +1293,7 @@ pub fn main() anyerror!void { |
| 1258 | .target = native_info.target, | 1293 | .target = native_info.target, |
| 1259 | .output_mode = .Obj, | 1294 | .output_mode = .Obj, |
| 1260 | .link_mode = .Static, | 1295 | .link_mode = .Static, |
| | 1296 | .optimize_mode = .Debug, |
| 1261 | }); | 1297 | }); |
| 1262 | defer analyzed_module.deinit(allocator); | 1298 | defer analyzed_module.deinit(allocator); |
| 1263 | | 1299 | |