authorgravatar for daniele.cocca@gmail.comDaniele Cocca <daniele.cocca@gmail.com> 2022-03-15 00:02:17+00:00
committergravatar for daniele.cocca@gmail.comDaniele Cocca <daniele.cocca@gmail.com> 2022-03-18 16:50:34+00:00
log6fdca525dec95ea9ed96946188af41d3d0c29f47
treecbf3fe487335722c726da2c052943f5bfebdce2e
parent085e122e296b30de7ef83d10564115a5991bbb2a

CBE: add support for tuples

Also promote tests that are now passing.

3 files changed, 81 insertions(+), 9 deletions(-)

src/codegen/c.zig+80-5
......@@ -1000,6 +1000,46 @@ pub const DeclGen = struct {
10001000 return name;
10011001 }
10021002
1003 fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1004 const tuple = t.tupleFields();
1005
1006 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1007 defer buffer.deinit();
1008 const writer = buffer.writer();
1009
1010 try buffer.appendSlice("typedef struct {\n");
1011 {
1012 for (tuple.types) |field_ty, i| {
1013 const val = tuple.values[i];
1014 if (val.tag() != .unreachable_value) continue;
1015
1016 var name = std.ArrayList(u8).init(dg.gpa);
1017 defer name.deinit();
1018 try name.writer().print("field_{d}", .{i});
1019
1020 try buffer.append(' ');
1021 try dg.renderTypeAndName(writer, field_ty, .{ .bytes = name.items }, .Mut, Value.initTag(.abi_align_default));
1022 try buffer.appendSlice(";\n");
1023 }
1024 }
1025 try buffer.appendSlice("} ");
1026
1027 const name_start = buffer.items.len;
1028 try writer.print("zig_T_{};\n", .{typeToCIdentifier(t)});
1029
1030 const rendered = buffer.toOwnedSlice();
1031 errdefer dg.typedefs.allocator.free(rendered);
1032 const name = rendered[name_start .. rendered.len - 2];
1033
1034 try dg.typedefs.ensureUnusedCapacity(1);
1035 dg.typedefs.putAssumeCapacityNoClobber(
1036 try t.copy(dg.typedefs_arena),
1037 .{ .name = name, .rendered = rendered },
1038 );
1039
1040 return name;
1041 }
1042
10031043 fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
10041044 const union_ty = t.cast(Type.Payload.Union).?.data;
10051045 const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator);
......@@ -1276,7 +1316,9 @@ pub const DeclGen = struct {
12761316 return w.writeAll(name);
12771317 },
12781318 .Struct => {
1279 const name = dg.getTypedefName(t) orelse
1319 const name = dg.getTypedefName(t) orelse if (t.isTuple())
1320 try dg.renderTupleTypedef(t)
1321 else
12801322 try dg.renderStructTypedef(t);
12811323
12821324 return w.writeAll(name);
......@@ -3116,6 +3158,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
31163158 var field_name: []const u8 = undefined;
31173159 var field_val_ty: Type = undefined;
31183160
3161 var buf = std.ArrayList(u8).init(f.object.dg.gpa);
3162 defer buf.deinit();
31193163 switch (struct_ty.tag()) {
31203164 .@"struct" => {
31213165 const fields = struct_ty.structFields();
......@@ -3127,6 +3171,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
31273171 field_name = fields.keys()[index];
31283172 field_val_ty = fields.values()[index].ty;
31293173 },
3174 .tuple => {
3175 const tuple = struct_ty.tupleFields();
3176 if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
3177
3178 try buf.writer().print("field_{d}", .{index});
3179 field_name = buf.items;
3180 field_val_ty = tuple.types[index];
3181 },
31303182 else => unreachable,
31313183 }
31323184 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
......@@ -3149,9 +3201,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
31493201 const writer = f.object.writer();
31503202 const struct_byval = try f.resolveInst(extra.struct_operand);
31513203 const struct_ty = f.air.typeOf(extra.struct_operand);
3204 var buf = std.ArrayList(u8).init(f.object.dg.gpa);
3205 defer buf.deinit();
31523206 const field_name = switch (struct_ty.tag()) {
31533207 .@"struct" => struct_ty.structFields().keys()[extra.field_index],
31543208 .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index],
3209 .tuple => blk: {
3210 const tuple = struct_ty.tupleFields();
3211 if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;
3212
3213 try buf.writer().print("field_{d}", .{extra.field_index});
3214 break :blk buf.items;
3215 },
31553216 else => unreachable,
31563217 };
31573218 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
......@@ -3652,11 +3713,25 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
36523713
36533714 const writer = f.object.writer();
36543715 const local = try f.allocLocal(inst_ty, .Const);
3655 try writer.writeAll(" = ");
3716 try writer.writeAll(" = {");
3717 switch (vector_ty.zigTypeTag()) {
3718 .Struct => {
3719 const tuple = vector_ty.tupleFields();
3720 var i: usize = 0;
3721 for (elements) |elem, elem_index| {
3722 if (tuple.values[elem_index].tag() != .unreachable_value) continue;
3723
3724 const value = try f.resolveInst(elem);
3725 if (i != 0) try writer.writeAll(", ");
3726 try f.writeCValue(writer, value);
3727 i += 1;
3728 }
3729 },
3730 else => |tag| return f.fail("TODO: C backend: implement airAggregateInit for type {s}", .{@tagName(tag)}),
3731 }
3732 try writer.writeAll("};\n");
36563733
3657 _ = elements;
3658 _ = local;
3659 return f.fail("TODO: C backend: implement airAggregateInit", .{});
3734 return local;
36603735}
36613736
36623737fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
test/behavior.zig+1-1
......@@ -145,6 +145,7 @@ test {
145145 {
146146 // Tests that pass for stage1, llvm backend, C backend
147147 _ = @import("behavior/bugs/421.zig");
148 _ = @import("behavior/bugs/3779.zig");
148149 _ = @import("behavior/bugs/9584.zig");
149150 _ = @import("behavior/cast_int.zig");
150151 _ = @import("behavior/eval.zig");
......@@ -161,7 +162,6 @@ test {
161162 _ = @import("behavior/saturating_arithmetic.zig");
162163 _ = @import("behavior/widening.zig");
163164 _ = @import("behavior/bugs/2114.zig");
164 _ = @import("behavior/bugs/3779.zig");
165165 _ = @import("behavior/bugs/10147.zig");
166166 _ = @import("behavior/shuffle.zig");
167167
test/behavior/tuple.zig-3
......@@ -5,7 +5,6 @@ const expect = testing.expect;
55
66test "tuple concatenation" {
77 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -50,7 +49,6 @@ test "tuple multiplication" {
5049
5150test "more tuple concatenation" {
5251 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
5452 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5553 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -128,7 +126,6 @@ test "tuple initializer for var" {
128126}
129127
130128test "array-like initializer for tuple types" {
131 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
132129 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
133130 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
134131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO