authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-18 15:23:40-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-18 15:23:40-04:00
loge60c0468aaed9bae19ff40bcc163927e98aa2dd9
tree8b8fcb9b7fbc5554aebb1bb223d463fd039dd91d
parent338bf55e84abcb4f5fb595266135d6fc074ecf3c
parent6fdca525dec95ea9ed96946188af41d3d0c29f47
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11217 from jmc-88/cbe-tuples

CBE: add support for tuples

4 files changed, 97 insertions(+), 26 deletions(-)

src/codegen/c.zig+80-5
...@@ -1000,6 +1000,46 @@ pub const DeclGen = struct {...@@ -1000,6 +1000,46 @@ pub const DeclGen = struct {
1000 return name;1000 return name;
1001 }1001 }
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
1003 fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {1043 fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1004 const union_ty = t.cast(Type.Payload.Union).?.data;1044 const union_ty = t.cast(Type.Payload.Union).?.data;
1005 const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator);1045 const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator);
...@@ -1276,7 +1316,9 @@ pub const DeclGen = struct {...@@ -1276,7 +1316,9 @@ pub const DeclGen = struct {
1276 return w.writeAll(name);1316 return w.writeAll(name);
1277 },1317 },
1278 .Struct => {1318 .Struct => {
1279 const name = dg.getTypedefName(t) orelse1319 const name = dg.getTypedefName(t) orelse if (t.isTuple())
1320 try dg.renderTupleTypedef(t)
1321 else
1280 try dg.renderStructTypedef(t);1322 try dg.renderStructTypedef(t);
12811323
1282 return w.writeAll(name);1324 return w.writeAll(name);
...@@ -3116,6 +3158,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -3116,6 +3158,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
3116 var field_name: []const u8 = undefined;3158 var field_name: []const u8 = undefined;
3117 var field_val_ty: Type = undefined;3159 var field_val_ty: Type = undefined;
31183160
3161 var buf = std.ArrayList(u8).init(f.object.dg.gpa);
3162 defer buf.deinit();
3119 switch (struct_ty.tag()) {3163 switch (struct_ty.tag()) {
3120 .@"struct" => {3164 .@"struct" => {
3121 const fields = struct_ty.structFields();3165 const fields = struct_ty.structFields();
...@@ -3127,6 +3171,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -3127,6 +3171,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
3127 field_name = fields.keys()[index];3171 field_name = fields.keys()[index];
3128 field_val_ty = fields.values()[index].ty;3172 field_val_ty = fields.values()[index].ty;
3129 },3173 },
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 },
3130 else => unreachable,3182 else => unreachable,
3131 }3183 }
3132 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";3184 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
...@@ -3149,9 +3201,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3149,9 +3201,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
3149 const writer = f.object.writer();3201 const writer = f.object.writer();
3150 const struct_byval = try f.resolveInst(extra.struct_operand);3202 const struct_byval = try f.resolveInst(extra.struct_operand);
3151 const struct_ty = f.air.typeOf(extra.struct_operand);3203 const struct_ty = f.air.typeOf(extra.struct_operand);
3204 var buf = std.ArrayList(u8).init(f.object.dg.gpa);
3205 defer buf.deinit();
3152 const field_name = switch (struct_ty.tag()) {3206 const field_name = switch (struct_ty.tag()) {
3153 .@"struct" => struct_ty.structFields().keys()[extra.field_index],3207 .@"struct" => struct_ty.structFields().keys()[extra.field_index],
3154 .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index],3208 .@"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 },
3155 else => unreachable,3216 else => unreachable,
3156 };3217 };
3157 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";3218 const payload = if (struct_ty.tag() == .union_tagged) "payload." else "";
...@@ -3652,11 +3713,25 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3652,11 +3713,25 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
36523713
3653 const writer = f.object.writer();3714 const writer = f.object.writer();
3654 const local = try f.allocLocal(inst_ty, .Const);3715 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;3734 return local;
3658 _ = local;
3659 return f.fail("TODO: C backend: implement airAggregateInit", .{});
3660}3735}
36613736
3662fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {3737fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
test/behavior.zig+1-1
...@@ -146,6 +146,7 @@ test {...@@ -146,6 +146,7 @@ test {
146 {146 {
147 // Tests that pass for stage1, llvm backend, C backend147 // Tests that pass for stage1, llvm backend, C backend
148 _ = @import("behavior/bugs/421.zig");148 _ = @import("behavior/bugs/421.zig");
149 _ = @import("behavior/bugs/3779.zig");
149 _ = @import("behavior/bugs/9584.zig");150 _ = @import("behavior/bugs/9584.zig");
150 _ = @import("behavior/cast_int.zig");151 _ = @import("behavior/cast_int.zig");
151 _ = @import("behavior/eval.zig");152 _ = @import("behavior/eval.zig");
...@@ -162,7 +163,6 @@ test {...@@ -162,7 +163,6 @@ test {
162 _ = @import("behavior/saturating_arithmetic.zig");163 _ = @import("behavior/saturating_arithmetic.zig");
163 _ = @import("behavior/widening.zig");164 _ = @import("behavior/widening.zig");
164 _ = @import("behavior/bugs/2114.zig");165 _ = @import("behavior/bugs/2114.zig");
165 _ = @import("behavior/bugs/3779.zig");
166 _ = @import("behavior/bugs/10147.zig");166 _ = @import("behavior/bugs/10147.zig");
167 _ = @import("behavior/shuffle.zig");167 _ = @import("behavior/shuffle.zig");
168168
test/behavior/bugs/3779.zig+14-14
...@@ -7,9 +7,9 @@ const ptr_tag_name: [*:0]const u8 = tag_name;...@@ -7,9 +7,9 @@ const ptr_tag_name: [*:0]const u8 = tag_name;
77
8test "@tagName() returns a string literal" {8test "@tagName() returns a string literal" {
9 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong9 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
10 try std.testing.expectEqual(*const [13:0]u8, @TypeOf(tag_name));10 try std.testing.expect(*const [13:0]u8 == @TypeOf(tag_name));
11 try std.testing.expectEqualStrings("TestEnumValue", tag_name);11 try std.testing.expect(std.mem.eql(u8, "TestEnumValue", tag_name));
12 try std.testing.expectEqualStrings("TestEnumValue", ptr_tag_name[0..tag_name.len]);12 try std.testing.expect(std.mem.eql(u8, "TestEnumValue", ptr_tag_name[0..tag_name.len]));
13}13}
1414
15const TestError = error{TestErrorCode};15const TestError = error{TestErrorCode};
...@@ -18,9 +18,9 @@ const ptr_error_name: [*:0]const u8 = error_name;...@@ -18,9 +18,9 @@ const ptr_error_name: [*:0]const u8 = error_name;
1818
19test "@errorName() returns a string literal" {19test "@errorName() returns a string literal" {
20 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong20 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
21 try std.testing.expectEqual(*const [13:0]u8, @TypeOf(error_name));21 try std.testing.expect(*const [13:0]u8 == @TypeOf(error_name));
22 try std.testing.expectEqualStrings("TestErrorCode", error_name);22 try std.testing.expect(std.mem.eql(u8, "TestErrorCode", error_name));
23 try std.testing.expectEqualStrings("TestErrorCode", ptr_error_name[0..error_name.len]);23 try std.testing.expect(std.mem.eql(u8, "TestErrorCode", ptr_error_name[0..error_name.len]));
24}24}
2525
26const TestType = struct {};26const TestType = struct {};
...@@ -29,9 +29,9 @@ const ptr_type_name: [*:0]const u8 = type_name;...@@ -29,9 +29,9 @@ const ptr_type_name: [*:0]const u8 = type_name;
2929
30test "@typeName() returns a string literal" {30test "@typeName() returns a string literal" {
31 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong31 if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
32 try std.testing.expectEqual(*const [type_name.len:0]u8, @TypeOf(type_name));32 try std.testing.expect(*const [type_name.len:0]u8 == @TypeOf(type_name));
33 try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", type_name);33 try std.testing.expect(std.mem.eql(u8, "behavior.bugs.3779.TestType", type_name));
34 try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]);34 try std.testing.expect(std.mem.eql(u8, "behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]));
35}35}
3636
37const actual_contents = @embedFile("3779_file_to_embed.txt");37const actual_contents = @embedFile("3779_file_to_embed.txt");
...@@ -39,10 +39,10 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents;...@@ -39,10 +39,10 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents;
39const expected_contents = "hello zig\n";39const expected_contents = "hello zig\n";
4040
41test "@embedFile() returns a string literal" {41test "@embedFile() returns a string literal" {
42 try std.testing.expectEqual(*const [expected_contents.len:0]u8, @TypeOf(actual_contents));42 try std.testing.expect(*const [expected_contents.len:0]u8 == @TypeOf(actual_contents));
43 try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents));43 try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents));
44 try std.testing.expectEqualStrings(expected_contents, actual_contents);44 try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents));
45 try std.testing.expectEqualStrings(expected_contents, ptr_actual_contents[0..actual_contents.len]);45 try std.testing.expect(std.mem.eql(u8, expected_contents, ptr_actual_contents[0..actual_contents.len]));
46}46}
4747
48fn testFnForSrc() std.builtin.SourceLocation {48fn testFnForSrc() std.builtin.SourceLocation {
...@@ -51,9 +51,9 @@ fn testFnForSrc() std.builtin.SourceLocation {...@@ -51,9 +51,9 @@ fn testFnForSrc() std.builtin.SourceLocation {
5151
52test "@src() returns a struct containing 0-terminated string slices" {52test "@src() returns a struct containing 0-terminated string slices" {
53 const src = testFnForSrc();53 const src = testFnForSrc();
54 try std.testing.expectEqual([:0]const u8, @TypeOf(src.file));54 try std.testing.expect([:0]const u8 == @TypeOf(src.file));
55 try std.testing.expect(std.mem.endsWith(u8, src.file, "3779.zig"));55 try std.testing.expect(std.mem.endsWith(u8, src.file, "3779.zig"));
56 try std.testing.expectEqual([:0]const u8, @TypeOf(src.fn_name));56 try std.testing.expect([:0]const u8 == @TypeOf(src.fn_name));
57 try std.testing.expect(std.mem.endsWith(u8, src.fn_name, "testFnForSrc"));57 try std.testing.expect(std.mem.endsWith(u8, src.fn_name, "testFnForSrc"));
5858
59 const ptr_src_file: [*:0]const u8 = src.file;59 const ptr_src_file: [*:0]const u8 = src.file;
test/behavior/tuple.zig+2-6
...@@ -2,11 +2,9 @@ const builtin = @import("builtin");...@@ -2,11 +2,9 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const testing = std.testing;3const testing = std.testing;
4const expect = testing.expect;4const expect = testing.expect;
5const expectEqual = testing.expectEqual;
65
7test "tuple concatenation" {6test "tuple concatenation" {
8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -18,8 +16,8 @@ test "tuple concatenation" {...@@ -18,8 +16,8 @@ test "tuple concatenation" {
18 var x = .{a};16 var x = .{a};
19 var y = .{b};17 var y = .{b};
20 var c = x ++ y;18 var c = x ++ y;
21 try expectEqual(@as(i32, 1), c[0]);19 try expect(@as(i32, 1) == c[0]);
22 try expectEqual(@as(i32, 2), c[1]);20 try expect(@as(i32, 2) == c[1]);
23 }21 }
24 };22 };
25 try S.doTheTest();23 try S.doTheTest();
...@@ -51,7 +49,6 @@ test "tuple multiplication" {...@@ -51,7 +49,6 @@ test "tuple multiplication" {
5149
52test "more tuple concatenation" {50test "more tuple concatenation" {
53 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -129,7 +126,6 @@ test "tuple initializer for var" {...@@ -129,7 +126,6 @@ test "tuple initializer for var" {
129}126}
130127
131test "array-like initializer for tuple types" {128test "array-like initializer for tuple types" {
132 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO129 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO130 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO