mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge pull request #11217 from jmc-88/cbe-tuples
CBE: add support for tuples
This commit is contained in:
commit
e60c0468aa
4 changed files with 97 additions and 26 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,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");
|
||||||
|
|
@ -162,7 +163,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");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ const ptr_tag_name: [*:0]const u8 = tag_name;
|
||||||
|
|
||||||
test "@tagName() returns a string literal" {
|
test "@tagName() returns a string literal" {
|
||||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
|
||||||
try std.testing.expectEqual(*const [13:0]u8, @TypeOf(tag_name));
|
try std.testing.expect(*const [13:0]u8 == @TypeOf(tag_name));
|
||||||
try std.testing.expectEqualStrings("TestEnumValue", tag_name);
|
try std.testing.expect(std.mem.eql(u8, "TestEnumValue", tag_name));
|
||||||
try std.testing.expectEqualStrings("TestEnumValue", ptr_tag_name[0..tag_name.len]);
|
try std.testing.expect(std.mem.eql(u8, "TestEnumValue", ptr_tag_name[0..tag_name.len]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const TestError = error{TestErrorCode};
|
const TestError = error{TestErrorCode};
|
||||||
|
|
@ -18,9 +18,9 @@ const ptr_error_name: [*:0]const u8 = error_name;
|
||||||
|
|
||||||
test "@errorName() returns a string literal" {
|
test "@errorName() returns a string literal" {
|
||||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
|
||||||
try std.testing.expectEqual(*const [13:0]u8, @TypeOf(error_name));
|
try std.testing.expect(*const [13:0]u8 == @TypeOf(error_name));
|
||||||
try std.testing.expectEqualStrings("TestErrorCode", error_name);
|
try std.testing.expect(std.mem.eql(u8, "TestErrorCode", error_name));
|
||||||
try std.testing.expectEqualStrings("TestErrorCode", ptr_error_name[0..error_name.len]);
|
try std.testing.expect(std.mem.eql(u8, "TestErrorCode", ptr_error_name[0..error_name.len]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const TestType = struct {};
|
const TestType = struct {};
|
||||||
|
|
@ -29,9 +29,9 @@ const ptr_type_name: [*:0]const u8 = type_name;
|
||||||
|
|
||||||
test "@typeName() returns a string literal" {
|
test "@typeName() returns a string literal" {
|
||||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong
|
||||||
try std.testing.expectEqual(*const [type_name.len:0]u8, @TypeOf(type_name));
|
try std.testing.expect(*const [type_name.len:0]u8 == @TypeOf(type_name));
|
||||||
try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", type_name);
|
try std.testing.expect(std.mem.eql(u8, "behavior.bugs.3779.TestType", type_name));
|
||||||
try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]);
|
try std.testing.expect(std.mem.eql(u8, "behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const actual_contents = @embedFile("3779_file_to_embed.txt");
|
const actual_contents = @embedFile("3779_file_to_embed.txt");
|
||||||
|
|
@ -39,10 +39,10 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents;
|
||||||
const expected_contents = "hello zig\n";
|
const expected_contents = "hello zig\n";
|
||||||
|
|
||||||
test "@embedFile() returns a string literal" {
|
test "@embedFile() returns a string literal" {
|
||||||
try std.testing.expectEqual(*const [expected_contents.len:0]u8, @TypeOf(actual_contents));
|
try std.testing.expect(*const [expected_contents.len:0]u8 == @TypeOf(actual_contents));
|
||||||
try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents));
|
try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents));
|
||||||
try std.testing.expectEqualStrings(expected_contents, actual_contents);
|
try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents));
|
||||||
try std.testing.expectEqualStrings(expected_contents, ptr_actual_contents[0..actual_contents.len]);
|
try std.testing.expect(std.mem.eql(u8, expected_contents, ptr_actual_contents[0..actual_contents.len]));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testFnForSrc() std.builtin.SourceLocation {
|
fn testFnForSrc() std.builtin.SourceLocation {
|
||||||
|
|
@ -51,9 +51,9 @@ fn testFnForSrc() std.builtin.SourceLocation {
|
||||||
|
|
||||||
test "@src() returns a struct containing 0-terminated string slices" {
|
test "@src() returns a struct containing 0-terminated string slices" {
|
||||||
const src = testFnForSrc();
|
const src = testFnForSrc();
|
||||||
try std.testing.expectEqual([:0]const u8, @TypeOf(src.file));
|
try std.testing.expect([:0]const u8 == @TypeOf(src.file));
|
||||||
try std.testing.expect(std.mem.endsWith(u8, src.file, "3779.zig"));
|
try std.testing.expect(std.mem.endsWith(u8, src.file, "3779.zig"));
|
||||||
try std.testing.expectEqual([:0]const u8, @TypeOf(src.fn_name));
|
try std.testing.expect([:0]const u8 == @TypeOf(src.fn_name));
|
||||||
try std.testing.expect(std.mem.endsWith(u8, src.fn_name, "testFnForSrc"));
|
try std.testing.expect(std.mem.endsWith(u8, src.fn_name, "testFnForSrc"));
|
||||||
|
|
||||||
const ptr_src_file: [*:0]const u8 = src.file;
|
const ptr_src_file: [*:0]const u8 = src.file;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,9 @@ const builtin = @import("builtin");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const expect = testing.expect;
|
const expect = testing.expect;
|
||||||
const expectEqual = testing.expectEqual;
|
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -18,8 +16,8 @@ test "tuple concatenation" {
|
||||||
var x = .{a};
|
var x = .{a};
|
||||||
var y = .{b};
|
var y = .{b};
|
||||||
var c = x ++ y;
|
var c = x ++ y;
|
||||||
try expectEqual(@as(i32, 1), c[0]);
|
try expect(@as(i32, 1) == c[0]);
|
||||||
try expectEqual(@as(i32, 2), c[1]);
|
try expect(@as(i32, 2) == c[1]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try S.doTheTest();
|
try S.doTheTest();
|
||||||
|
|
@ -51,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
|
||||||
|
|
@ -129,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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue