CBE: renderValue pays attention to Type, not Tag

This commit is contained in:
Noam Preil 2020-08-12 22:15:09 -04:00 committed by Andrew Kelley
parent 5a166cead8
commit 1eb5aaa4b5
2 changed files with 116 additions and 39 deletions

View File

@ -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);

View File

@ -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,