CBE: add support for tuples

Also promote tests that are now passing.
This commit is contained in:
Daniele Cocca 2022-03-15 00:02:17 +00:00
parent 085e122e29
commit 6fdca525de
3 changed files with 81 additions and 9 deletions

View File

@ -1000,6 +1000,46 @@ pub const DeclGen = struct {
return name; return name;
} }
fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
const tuple = t.tupleFields();
var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
defer buffer.deinit();
const writer = buffer.writer();
try buffer.appendSlice("typedef struct {\n");
{
for (tuple.types) |field_ty, i| {
const val = tuple.values[i];
if (val.tag() != .unreachable_value) continue;
var name = std.ArrayList(u8).init(dg.gpa);
defer name.deinit();
try name.writer().print("field_{d}", .{i});
try buffer.append(' ');
try dg.renderTypeAndName(writer, field_ty, .{ .bytes = name.items }, .Mut, Value.initTag(.abi_align_default));
try buffer.appendSlice(";\n");
}
}
try buffer.appendSlice("} ");
const name_start = buffer.items.len;
try writer.print("zig_T_{};\n", .{typeToCIdentifier(t)});
const rendered = buffer.toOwnedSlice();
errdefer dg.typedefs.allocator.free(rendered);
const name = rendered[name_start .. rendered.len - 2];
try dg.typedefs.ensureUnusedCapacity(1);
dg.typedefs.putAssumeCapacityNoClobber(
try t.copy(dg.typedefs_arena),
.{ .name = name, .rendered = rendered },
);
return name;
}
fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
const union_ty = t.cast(Type.Payload.Union).?.data; const union_ty = t.cast(Type.Payload.Union).?.data;
const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator); const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator);
@ -1276,7 +1316,9 @@ pub const DeclGen = struct {
return w.writeAll(name); return w.writeAll(name);
}, },
.Struct => { .Struct => {
const name = dg.getTypedefName(t) orelse const name = dg.getTypedefName(t) orelse if (t.isTuple())
try dg.renderTupleTypedef(t)
else
try dg.renderStructTypedef(t); try dg.renderStructTypedef(t);
return w.writeAll(name); return w.writeAll(name);
@ -3116,6 +3158,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
var field_name: []const u8 = undefined; var field_name: []const u8 = undefined;
var field_val_ty: Type = undefined; var field_val_ty: Type = undefined;
var buf = std.ArrayList(u8).init(f.object.dg.gpa);
defer buf.deinit();
switch (struct_ty.tag()) { switch (struct_ty.tag()) {
.@"struct" => { .@"struct" => {
const fields = struct_ty.structFields(); const fields = struct_ty.structFields();
@ -3127,6 +3171,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
field_name = fields.keys()[index]; field_name = fields.keys()[index];
field_val_ty = fields.values()[index].ty; field_val_ty = fields.values()[index].ty;
}, },
.tuple => {
const tuple = struct_ty.tupleFields();
if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
try buf.writer().print("field_{d}", .{index});
field_name = buf.items;
field_val_ty = tuple.types[index];
},
else => unreachable, else => unreachable,
} }
const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
@ -3149,9 +3201,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer(); const writer = f.object.writer();
const struct_byval = try f.resolveInst(extra.struct_operand); const struct_byval = try f.resolveInst(extra.struct_operand);
const struct_ty = f.air.typeOf(extra.struct_operand); const struct_ty = f.air.typeOf(extra.struct_operand);
var buf = std.ArrayList(u8).init(f.object.dg.gpa);
defer buf.deinit();
const field_name = switch (struct_ty.tag()) { const field_name = switch (struct_ty.tag()) {
.@"struct" => struct_ty.structFields().keys()[extra.field_index], .@"struct" => struct_ty.structFields().keys()[extra.field_index],
.@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index], .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index],
.tuple => blk: {
const tuple = struct_ty.tupleFields();
if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;
try buf.writer().print("field_{d}", .{extra.field_index});
break :blk buf.items;
},
else => unreachable, else => unreachable,
}; };
const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
@ -3652,11 +3713,25 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer(); const writer = f.object.writer();
const local = try f.allocLocal(inst_ty, .Const); const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = "); try writer.writeAll(" = {");
switch (vector_ty.zigTypeTag()) {
.Struct => {
const tuple = vector_ty.tupleFields();
var i: usize = 0;
for (elements) |elem, elem_index| {
if (tuple.values[elem_index].tag() != .unreachable_value) continue;
_ = elements; const value = try f.resolveInst(elem);
_ = local; if (i != 0) try writer.writeAll(", ");
return f.fail("TODO: C backend: implement airAggregateInit", .{}); try f.writeCValue(writer, value);
i += 1;
}
},
else => |tag| return f.fail("TODO: C backend: implement airAggregateInit for type {s}", .{@tagName(tag)}),
}
try writer.writeAll("};\n");
return local;
} }
fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {

View File

@ -145,6 +145,7 @@ test {
{ {
// Tests that pass for stage1, llvm backend, C backend // Tests that pass for stage1, llvm backend, C backend
_ = @import("behavior/bugs/421.zig"); _ = @import("behavior/bugs/421.zig");
_ = @import("behavior/bugs/3779.zig");
_ = @import("behavior/bugs/9584.zig"); _ = @import("behavior/bugs/9584.zig");
_ = @import("behavior/cast_int.zig"); _ = @import("behavior/cast_int.zig");
_ = @import("behavior/eval.zig"); _ = @import("behavior/eval.zig");
@ -161,7 +162,6 @@ test {
_ = @import("behavior/saturating_arithmetic.zig"); _ = @import("behavior/saturating_arithmetic.zig");
_ = @import("behavior/widening.zig"); _ = @import("behavior/widening.zig");
_ = @import("behavior/bugs/2114.zig"); _ = @import("behavior/bugs/2114.zig");
_ = @import("behavior/bugs/3779.zig");
_ = @import("behavior/bugs/10147.zig"); _ = @import("behavior/bugs/10147.zig");
_ = @import("behavior/shuffle.zig"); _ = @import("behavior/shuffle.zig");

View File

@ -5,7 +5,6 @@ const expect = testing.expect;
test "tuple concatenation" { test "tuple concatenation" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
@ -50,7 +49,6 @@ test "tuple multiplication" {
test "more tuple concatenation" { test "more tuple concatenation" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
@ -128,7 +126,6 @@ test "tuple initializer for var" {
} }
test "array-like initializer for tuple types" { test "array-like initializer for tuple types" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO