Commit 1eb5aaa4b5

Noam Preil <noam@pixelhero.dev>
2020-08-13 04:15:09
CBE: renderValue pays attention to Type, not Tag
1 parent 5a166ce
Changed files (2)
src-self-hosted
src-self-hosted/codegen/c.zig
@@ -17,41 +17,43 @@ fn map(allocator: *std.mem.Allocator, name: []const u8) ![]const u8 {
     return allocator.dupe(u8, name);
 }
 
-fn renderType(file: *C, writer: std.ArrayList(u8).Writer, T: Type, src: usize) !void {
-    if (T.tag() == .usize) {
-        file.need_stddef = true;
-        try writer.writeAll("size_t");
-    } else {
-        switch (T.zigTypeTag()) {
-            .NoReturn => {
-                try writer.writeAll("zig_noreturn void");
-            },
-            .Void => try writer.writeAll("void"),
-            .Int => {
-                if (T.tag() == .u8) {
-                    file.need_stdint = true;
-                    try writer.writeAll("uint8_t");
-                } else {
-                    return file.fail(src, "TODO implement int types", .{});
-                }
-            },
-            else => |e| return file.fail(src, "TODO implement type {}", .{e}),
-        }
+fn renderType(ctx: *Context, writer: std.ArrayList(u8).Writer, T: Type) !void {
+    switch (T.zigTypeTag()) {
+        .NoReturn => {
+            try writer.writeAll("zig_noreturn void");
+        },
+        .Void => try writer.writeAll("void"),
+        .Int => {
+            if (T.tag() == .u8) {
+                ctx.file.need_stdint = true;
+                try writer.writeAll("uint8_t");
+            } else if (T.tag() == .usize) {
+                ctx.file.need_stddef = true;
+                try writer.writeAll("size_t");
+            } else {
+                return ctx.file.fail(ctx.decl.src(), "TODO implement int types", .{});
+            }
+        },
+        else => |e| return ctx.file.fail(ctx.decl.src(), "TODO implement type {}", .{e}),
     }
 }
 
-fn renderValue(file: *C, writer: std.ArrayList(u8).Writer, val: Value, src: usize) !void {
-    switch (val.tag()) {
-        .int_u64 => return writer.print("{}", .{val.toUnsignedInt()}),
-        else => |e| return file.fail(src, "TODO implement value {}", .{e}),
+fn renderValue(ctx: *Context, writer: std.ArrayList(u8).Writer, T: Type, val: Value) !void {
+    switch (T.zigTypeTag()) {
+        .Int => {
+            if (T.isSignedInt())
+                return writer.print("{}", .{val.toSignedInt()});
+            return writer.print("{}", .{val.toUnsignedInt()});
+        },
+        else => |e| return ctx.file.fail(ctx.decl.src(), "TODO implement value {}", .{e}),
     }
 }
 
-fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *Decl) !void {
+fn renderFunctionSignature(ctx: *Context, writer: std.ArrayList(u8).Writer, decl: *Decl) !void {
     const tv = decl.typed_value.most_recent.typed_value;
-    try renderType(file, writer, tv.ty.fnReturnType(), decl.src());
-    const name = try map(file.base.allocator, mem.spanZ(decl.name));
-    defer file.base.allocator.free(name);
+    try renderType(ctx, writer, tv.ty.fnReturnType());
+    const name = try map(ctx.file.base.allocator, mem.spanZ(decl.name));
+    defer ctx.file.base.allocator.free(name);
     try writer.print(" {}(", .{name});
     var param_len = tv.ty.fnParamLen();
     if (param_len == 0)
@@ -62,7 +64,7 @@ fn renderFunctionSignature(file: *C, writer: std.ArrayList(u8).Writer, decl: *De
             if (index > 0) {
                 try writer.writeAll(", ");
             }
-            try renderType(file, writer, tv.ty.fnParamType(index), decl.src());
+            try renderType(ctx, writer, tv.ty.fnParamType(index));
             try writer.print(" arg{}", .{index});
         }
     }
@@ -120,10 +122,6 @@ fn genFn(file: *C, decl: *Decl) !void {
     const writer = file.main.writer();
     const tv = decl.typed_value.most_recent.typed_value;
 
-    try renderFunctionSignature(file, writer, decl);
-
-    try writer.writeAll(" {");
-
     var ctx = Context{
         .file = file,
         .decl = decl,
@@ -131,6 +129,10 @@ fn genFn(file: *C, decl: *Decl) !void {
     };
     defer ctx.deinit();
 
+    try renderFunctionSignature(&ctx, writer, decl);
+
+    try writer.writeAll(" {");
+
     const func: *Module.Fn = tv.val.cast(Value.Payload.Function).?.func;
     const instructions = func.analysis.success.instructions;
     if (instructions.len > 0) {
@@ -180,9 +182,9 @@ fn genIntCast(ctx: *Context, inst: *Inst.UnOp) !?[]u8 {
     const from = ctx.inst_map.get(op) orelse
         return ctx.file.fail(ctx.decl.src(), "Internal error in C backend: intCast argument not found in inst_map", .{});
     try writer.writeAll("    const ");
-    try renderType(ctx.file, writer, inst.base.ty, ctx.decl.src());
+    try renderType(ctx, writer, inst.base.ty);
     try writer.print(" {} = (", .{name});
-    try renderType(ctx.file, writer, inst.base.ty, ctx.decl.src());
+    try renderType(ctx, writer, inst.base.ty);
     try writer.print("){};\n", .{from});
     return name;
 }
@@ -202,7 +204,7 @@ fn genCall(ctx: *Context, inst: *Inst.Call) !?[]u8 {
             const tname = mem.spanZ(target.name);
             if (ctx.file.called.get(tname) == null) {
                 try ctx.file.called.put(tname, void{});
-                try renderFunctionSignature(ctx.file, header, target);
+                try renderFunctionSignature(ctx, header, target);
                 try header.writeAll(";\n");
             }
             try writer.print("{}(", .{tname});
@@ -212,7 +214,7 @@ fn genCall(ctx: *Context, inst: *Inst.Call) !?[]u8 {
                         try writer.writeAll(", ");
                     }
                     if (arg.cast(Inst.Constant)) |con| {
-                        try renderValue(ctx.file, writer, con.val, ctx.decl.src());
+                        try renderValue(ctx, writer, arg.ty, con.val);
                     } else {
                         return ctx.file.fail(ctx.decl.src(), "TODO call pass arg {}", .{arg});
                     }
@@ -251,11 +253,11 @@ fn genAsm(ctx: *Context, as: *Inst.Assembly) !?[]u8 {
             const reg = i[1 .. i.len - 1];
             const arg = as.args[index];
             try writer.writeAll("register ");
-            try renderType(ctx.file, writer, arg.ty, ctx.decl.src());
+            try renderType(ctx, writer, arg.ty);
             try writer.print(" {}_constant __asm__(\"{}\") = ", .{ reg, reg });
             // TODO merge constant handling into inst_map as well
             if (arg.castTag(.constant)) |c| {
-                try renderValue(ctx.file, writer, c.val, ctx.decl.src());
+                try renderValue(ctx, writer, arg.ty, c.val);
                 try writer.writeAll(";\n    ");
             } else {
                 const gop = try ctx.inst_map.getOrPut(arg);
src-self-hosted/value.zig
@@ -568,6 +568,81 @@ pub const Value = extern union {
         }
     }
 
+    /// Asserts the value is an integer and it fits in a i64
+    pub fn toSignedInt(self: Value) i64 {
+        switch (self.tag()) {
+            .ty,
+            .int_type,
+            .u8_type,
+            .i8_type,
+            .u16_type,
+            .i16_type,
+            .u32_type,
+            .i32_type,
+            .u64_type,
+            .i64_type,
+            .usize_type,
+            .isize_type,
+            .c_short_type,
+            .c_ushort_type,
+            .c_int_type,
+            .c_uint_type,
+            .c_long_type,
+            .c_ulong_type,
+            .c_longlong_type,
+            .c_ulonglong_type,
+            .c_longdouble_type,
+            .f16_type,
+            .f32_type,
+            .f64_type,
+            .f128_type,
+            .c_void_type,
+            .bool_type,
+            .void_type,
+            .type_type,
+            .anyerror_type,
+            .comptime_int_type,
+            .comptime_float_type,
+            .noreturn_type,
+            .null_type,
+            .undefined_type,
+            .fn_noreturn_no_args_type,
+            .fn_void_no_args_type,
+            .fn_naked_noreturn_no_args_type,
+            .fn_ccc_void_no_args_type,
+            .single_const_pointer_to_comptime_int_type,
+            .const_slice_u8_type,
+            .null_value,
+            .function,
+            .ref_val,
+            .decl_ref,
+            .elem_ptr,
+            .bytes,
+            .repeated,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
+            .void_value,
+            .unreachable_value,
+            .empty_array,
+            => unreachable,
+
+            .undef => unreachable,
+
+            .zero,
+            .bool_false,
+            => return 0,
+
+            .bool_true => return 1,
+
+            .int_u64 => return @intCast(i64, self.cast(Payload.Int_i64).?.int),
+            .int_i64 => return self.cast(Payload.Int_i64).?.int,
+            .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(i64) catch unreachable,
+            .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(i64) catch unreachable,
+        }
+    }
+
     pub fn toBool(self: Value) bool {
         return switch (self.tag()) {
             .bool_true => true,