Commit c12bc8652e

Andrew Kelley <andrew@ziglang.org>
2020-04-22 02:34:40
ir: analyze ptrtoint
1 parent 2cdbb5f
Changed files (1)
src-self-hosted
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);