From 1eb5aaa4b5bee902bed354ef6ebfbb643a624440 Mon Sep 17 00:00:00 2001 From: Noam Preil Date: Wed, 12 Aug 2020 22:15:09 -0400 Subject: [PATCH] CBE: renderValue pays attention to Type, not Tag --- src-self-hosted/codegen/c.zig | 80 ++++++++++++++++++----------------- src-self-hosted/value.zig | 75 ++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 39 deletions(-) diff --git a/src-self-hosted/codegen/c.zig b/src-self-hosted/codegen/c.zig index 76585a6dfb..f0d3d8367a 100644 --- a/src-self-hosted/codegen/c.zig +++ b/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); diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index e71805dc5b..b2fad9207d 100644 --- a/src-self-hosted/value.zig +++ b/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,