diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index eeba732f6d..24db3b035a 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -23,6 +23,7 @@ pub const Inst = struct { unreach, constant, assembly, + ptrtoint, }; pub fn cast(base: *Inst, comptime T: type) ?*T { @@ -32,12 +33,19 @@ pub const Inst = struct { return @fieldParentPtr(T, "base", base); } + pub fn Args(comptime T: type) type { + return std.meta.fieldInfo(T, "args").field_type; + } + /// Returns `null` if runtime-known. pub fn value(base: *Inst) ?Value { return switch (base.tag) { .unreach => Value.initTag(.noreturn_value), .constant => base.cast(Constant).?.val, - .assembly => null, + + .assembly, + .ptrtoint, + => null, }; } @@ -52,12 +60,23 @@ pub const Inst = struct { pub const base_tag = Tag.assembly; base: Inst, - asm_source: []const u8, - is_volatile: bool, - output: []const u8, - inputs: []const []const u8, - clobbers: []const []const u8, - args: []const []const u8, + args: struct { + asm_source: []const u8, + is_volatile: bool, + output: []const u8, + inputs: []const []const u8, + clobbers: []const []const u8, + args: []const *Inst, + }, + }; + + pub const PtrToInt = struct { + pub const base_tag = Tag.ptrtoint; + + base: Inst, + args: struct { + ptr: *Inst, + }, }; }; @@ -190,6 +209,10 @@ const Analyze = struct { } } + fn requireFunctionBody(self: *Analyze, func: ?*Fn, src: usize) !*Fn { + return func orelse return self.fail(src, "instruction illegal outside function body", .{}); + } + fn resolveInstConst(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) InnerError!TypedValue { const new_inst = try self.resolveInst(func, old_inst); const val = try self.resolveConstValue(new_inst); @@ -237,6 +260,33 @@ const Analyze = struct { }); } + fn addNewInstArgs( + self: *Analyze, + func: *Fn, + src: usize, + ty: Type, + comptime T: type, + args: Inst.Args(T), + ) !*Inst { + const inst = try self.addNewInst(func, src, ty, T); + inst.args = args; + return &inst.base; + } + + fn addNewInst(self: *Analyze, func: *Fn, src: usize, ty: Type, comptime T: type) !*T { + const inst = try self.arena.allocator.create(T); + inst.* = .{ + .base = .{ + .tag = T.base_tag, + .ty = ty, + .src = src, + }, + .args = undefined, + }; + try func.body.append(&inst.base); + return inst; + } + fn constInst(self: *Analyze, src: usize, typed_value: TypedValue) !*Inst { const const_inst = try self.arena.allocator.create(Inst.Constant); const_inst.* = .{ @@ -331,7 +381,7 @@ const Analyze = struct { const big_int = old_inst.cast(text.Inst.Int).?.positionals.int; return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int); }, - .ptrtoint => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), + .ptrtoint => return self.analyzeInstPtrToInt(func, old_inst.cast(text.Inst.PtrToInt).?), .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), .deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}), .as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?), @@ -408,6 +458,18 @@ const Analyze = struct { return self.coerce(dest_type, new_inst); } + fn analyzeInstPtrToInt(self: *Analyze, func: ?*Fn, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst { + const ptr = try self.resolveInst(func, ptrtoint.positionals.ptr); + if (ptr.ty.zigTypeTag() != .Pointer) { + return self.fail(ptrtoint.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty}); + } + // TODO handle known-pointer-address + const f = try self.requireFunctionBody(func, ptrtoint.base.src); + const ty = Type.initTag(.usize); + // TODO should not need the cast on the last parameter + return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr }); + } + fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst { const dest_type = try self.resolveType(func, intcast.positionals.dest_type); const new_inst = try self.resolveInst(func, intcast.positionals.value);