| ... | ... | @@ -23,6 +23,7 @@ pub const Inst = struct { |
| 23 | 23 | unreach, |
| 24 | 24 | constant, |
| 25 | 25 | assembly, |
| 26 | ptrtoint, |
| 26 | 27 | }; |
| 27 | 28 | |
| 28 | 29 | pub fn cast(base: *Inst, comptime T: type) ?*T { |
| ... | ... | @@ -32,12 +33,19 @@ pub const Inst = struct { |
| 32 | 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 | 40 | /// Returns `null` if runtime-known. |
| 36 | 41 | pub fn value(base: *Inst) ?Value { |
| 37 | 42 | return switch (base.tag) { |
| 38 | 43 | .unreach => Value.initTag(.noreturn_value), |
| 39 | 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 | 60 | pub const base_tag = Tag.assembly; |
| 53 | 61 | base: Inst, |
| 54 | 62 | |
| 55 | | asm_source: []const u8, |
| 56 | | is_volatile: bool, |
| 57 | | output: []const u8, |
| 58 | | inputs: []const []const u8, |
| 59 | | clobbers: []const []const u8, |
| 60 | | args: []const []const u8, |
| 63 | args: struct { |
| 64 | asm_source: []const u8, |
| 65 | is_volatile: bool, |
| 66 | output: []const u8, |
| 67 | inputs: []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 | 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 | 216 | fn resolveInstConst(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) InnerError!TypedValue { |
| 194 | 217 | const new_inst = try self.resolveInst(func, old_inst); |
| 195 | 218 | const val = try self.resolveConstValue(new_inst); |
| ... | ... | @@ -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 | 290 | fn constInst(self: *Analyze, src: usize, typed_value: TypedValue) !*Inst { |
| 241 | 291 | const const_inst = try self.arena.allocator.create(Inst.Constant); |
| 242 | 292 | const_inst.* = .{ |
| ... | ... | @@ -331,7 +381,7 @@ const Analyze = struct { |
| 331 | 381 | const big_int = old_inst.cast(text.Inst.Int).?.positionals.int; |
| 332 | 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 | 385 | .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 336 | 386 | .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), |
| 337 | 387 | .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), |
| ... | ... | @@ -408,6 +458,18 @@ const Analyze = struct { |
| 408 | 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 | 473 | fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst { |
| 412 | 474 | const dest_type = try self.resolveType(func, intcast.positionals.dest_type); |
| 413 | 475 | const new_inst = try self.resolveInst(func, intcast.positionals.value); |