| ... | @@ -23,6 +23,7 @@ pub const Inst = struct { | ... | @@ -23,6 +23,7 @@ pub const Inst = struct { |
| 23 | unreach, | 23 | unreach, |
| 24 | constant, | 24 | constant, |
| 25 | assembly, | 25 | assembly, |
| | 26 | ptrtoint, |
| 26 | }; | 27 | }; |
| 27 | | 28 | |
| 28 | pub fn cast(base: *Inst, comptime T: type) ?*T { | 29 | pub fn cast(base: *Inst, comptime T: type) ?*T { |
| ... | @@ -32,12 +33,19 @@ pub const Inst = struct { | ... | @@ -32,12 +33,19 @@ pub const Inst = struct { |
| 32 | return @fieldParentPtr(T, "base", base); | 33 | return @fieldParentPtr(T, "base", base); |
| 33 | } | 34 | } |
| 34 | | 35 | |
| | 36 | pub fn Args(comptime T: type) type { |
| | 37 | return std.meta.fieldInfo(T, "args").field_type; |
| | 38 | } |
| | 39 | |
| 35 | /// Returns `null` if runtime-known. | 40 | /// Returns `null` if runtime-known. |
| 36 | pub fn value(base: *Inst) ?Value { | 41 | pub fn value(base: *Inst) ?Value { |
| 37 | return switch (base.tag) { | 42 | return switch (base.tag) { |
| 38 | .unreach => Value.initTag(.noreturn_value), | 43 | .unreach => Value.initTag(.noreturn_value), |
| 39 | .constant => base.cast(Constant).?.val, | 44 | .constant => base.cast(Constant).?.val, |
| 40 | .assembly => null, | 45 | |
| | 46 | .assembly, |
| | 47 | .ptrtoint, |
| | 48 | => null, |
| 41 | }; | 49 | }; |
| 42 | } | 50 | } |
| 43 | | 51 | |
| ... | @@ -52,12 +60,23 @@ pub const Inst = struct { | ... | @@ -52,12 +60,23 @@ pub const Inst = struct { |
| 52 | pub const base_tag = Tag.assembly; | 60 | pub const base_tag = Tag.assembly; |
| 53 | base: Inst, | 61 | base: Inst, |
| 54 | | 62 | |
| 55 | asm_source: []const u8, | 63 | args: struct { |
| 56 | is_volatile: bool, | 64 | asm_source: []const u8, |
| 57 | output: []const u8, | 65 | is_volatile: bool, |
| 58 | inputs: []const []const u8, | 66 | output: []const u8, |
| 59 | clobbers: []const []const u8, | 67 | inputs: []const []const u8, |
| 60 | args: []const []const u8, | 68 | clobbers: []const []const u8, |
| | 69 | args: []const *Inst, |
| | 70 | }, |
| | 71 | }; |
| | 72 | |
| | 73 | pub const PtrToInt = struct { |
| | 74 | pub const base_tag = Tag.ptrtoint; |
| | 75 | |
| | 76 | base: Inst, |
| | 77 | args: struct { |
| | 78 | ptr: *Inst, |
| | 79 | }, |
| 61 | }; | 80 | }; |
| 62 | }; | 81 | }; |
| 63 | | 82 | |
| ... | @@ -190,6 +209,10 @@ const Analyze = struct { | ... | @@ -190,6 +209,10 @@ const Analyze = struct { |
| 190 | } | 209 | } |
| 191 | } | 210 | } |
| 192 | | 211 | |
| | 212 | fn requireFunctionBody(self: *Analyze, func: ?*Fn, src: usize) !*Fn { |
| | 213 | return func orelse return self.fail(src, "instruction illegal outside function body", .{}); |
| | 214 | } |
| | 215 | |
| 193 | fn resolveInstConst(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) InnerError!TypedValue { | 216 | fn resolveInstConst(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) InnerError!TypedValue { |
| 194 | const new_inst = try self.resolveInst(func, old_inst); | 217 | const new_inst = try self.resolveInst(func, old_inst); |
| 195 | const val = try self.resolveConstValue(new_inst); | 218 | const val = try self.resolveConstValue(new_inst); |
| ... | @@ -237,6 +260,33 @@ const Analyze = struct { | ... | @@ -237,6 +260,33 @@ const Analyze = struct { |
| 237 | }); | 260 | }); |
| 238 | } | 261 | } |
| 239 | | 262 | |
| | 263 | fn addNewInstArgs( |
| | 264 | self: *Analyze, |
| | 265 | func: *Fn, |
| | 266 | src: usize, |
| | 267 | ty: Type, |
| | 268 | comptime T: type, |
| | 269 | args: Inst.Args(T), |
| | 270 | ) !*Inst { |
| | 271 | const inst = try self.addNewInst(func, src, ty, T); |
| | 272 | inst.args = args; |
| | 273 | return &inst.base; |
| | 274 | } |
| | 275 | |
| | 276 | fn addNewInst(self: *Analyze, func: *Fn, src: usize, ty: Type, comptime T: type) !*T { |
| | 277 | const inst = try self.arena.allocator.create(T); |
| | 278 | inst.* = .{ |
| | 279 | .base = .{ |
| | 280 | .tag = T.base_tag, |
| | 281 | .ty = ty, |
| | 282 | .src = src, |
| | 283 | }, |
| | 284 | .args = undefined, |
| | 285 | }; |
| | 286 | try func.body.append(&inst.base); |
| | 287 | return inst; |
| | 288 | } |
| | 289 | |
| 240 | fn constInst(self: *Analyze, src: usize, typed_value: TypedValue) !*Inst { | 290 | fn constInst(self: *Analyze, src: usize, typed_value: TypedValue) !*Inst { |
| 241 | const const_inst = try self.arena.allocator.create(Inst.Constant); | 291 | const const_inst = try self.arena.allocator.create(Inst.Constant); |
| 242 | const_inst.* = .{ | 292 | const_inst.* = .{ |
| ... | @@ -331,7 +381,7 @@ const Analyze = struct { | ... | @@ -331,7 +381,7 @@ const Analyze = struct { |
| 331 | const big_int = old_inst.cast(text.Inst.Int).?.positionals.int; | 381 | const big_int = old_inst.cast(text.Inst.Int).?.positionals.int; |
| 332 | return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int); | 382 | return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int); |
| 333 | }, | 383 | }, |
| 334 | .ptrtoint => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 384 | .ptrtoint => return self.analyzeInstPtrToInt(func, old_inst.cast(text.Inst.PtrToInt).?), |
| 335 | .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 385 | .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 336 | .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), | 386 | .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 337 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), | 387 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), |
| ... | @@ -408,6 +458,18 @@ const Analyze = struct { | ... | @@ -408,6 +458,18 @@ const Analyze = struct { |
| 408 | return self.coerce(dest_type, new_inst); | 458 | return self.coerce(dest_type, new_inst); |
| 409 | } | 459 | } |
| 410 | | 460 | |
| | 461 | fn analyzeInstPtrToInt(self: *Analyze, func: ?*Fn, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst { |
| | 462 | const ptr = try self.resolveInst(func, ptrtoint.positionals.ptr); |
| | 463 | if (ptr.ty.zigTypeTag() != .Pointer) { |
| | 464 | return self.fail(ptrtoint.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty}); |
| | 465 | } |
| | 466 | // TODO handle known-pointer-address |
| | 467 | const f = try self.requireFunctionBody(func, ptrtoint.base.src); |
| | 468 | const ty = Type.initTag(.usize); |
| | 469 | // TODO should not need the cast on the last parameter |
| | 470 | return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr }); |
| | 471 | } |
| | 472 | |
| 411 | fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst { | 473 | fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst { |
| 412 | const dest_type = try self.resolveType(func, intcast.positionals.dest_type); | 474 | const dest_type = try self.resolveType(func, intcast.positionals.dest_type); |
| 413 | const new_inst = try self.resolveInst(func, intcast.positionals.value); | 475 | const new_inst = try self.resolveInst(func, intcast.positionals.value); |