authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-10-12 05:40:59-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-12 12:40:59+03:00
log562ac8be48e4a08358da73e556e331e3618f8b4b
tree3495e59a81924c3a8ff12b8948fe069f01f104cc
parentb47e54ed3f6e5d93fff8a2327c88c903cc0a194c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

codegen: add support for lowering .field_ptr on a slice

Closes #13068

7 files changed, 83 insertions(+), 18 deletions(-)

src/arch/wasm/CodeGen.zig+8
...@@ -2289,6 +2289,14 @@ fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WV...@@ -2289,6 +2289,14 @@ fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WV
2289 const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));2289 const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
2290 break :blk offset;2290 break :blk offset;
2291 },2291 },
2292 .Pointer => switch (parent_ty.ptrSize()) {
2293 .Slice => switch (field_ptr.field_index) {
2294 0 => 0,
2295 1 => self.ptrSize(),
2296 else => unreachable,
2297 },
2298 else => unreachable,
2299 },
2292 else => unreachable,2300 else => unreachable,
2293 };2301 };
22942302
src/codegen.zig+12-2
...@@ -363,11 +363,21 @@ pub fn generateSymbol(...@@ -363,11 +363,21 @@ pub fn generateSymbol(
363 const mod = bin_file.options.module.?;363 const mod = bin_file.options.module.?;
364 const decl = mod.declPtr(decl_index);364 const decl = mod.declPtr(decl_index);
365 const addend = blk: {365 const addend = blk: {
366 switch (decl.ty.tag()) {366 switch (decl.ty.zigTypeTag()) {
367 .@"struct" => {367 .Struct => {
368 const addend = decl.ty.structFieldOffset(field_ptr.field_index, target);368 const addend = decl.ty.structFieldOffset(field_ptr.field_index, target);
369 break :blk @intCast(u32, addend);369 break :blk @intCast(u32, addend);
370 },370 },
371 .Pointer => {
372 assert(decl.ty.isSlice());
373 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
374 const addend = switch (field_ptr.field_index) {
375 0 => 0,
376 1 => decl.ty.slicePtrFieldType(&buf).abiSize(target),
377 else => unreachable,
378 };
379 break :blk @intCast(u32, addend);
380 },
371 else => return Result{381 else => return Result{
372 .fail = try ErrorMsg.create(382 .fail = try ErrorMsg.create(
373 bin_file.allocator,383 bin_file.allocator,
src/codegen/c.zig+22-12
...@@ -485,14 +485,24 @@ pub const DeclGen = struct {...@@ -485,14 +485,24 @@ pub const DeclGen = struct {
485 const field_ptr = ptr_val.castTag(.field_ptr).?.data;485 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
486 const container_ty = field_ptr.container_ty;486 const container_ty = field_ptr.container_ty;
487 const index = field_ptr.field_index;487 const index = field_ptr.field_index;
488 const field_name = switch (container_ty.zigTypeTag()) {488 const FieldInfo = struct { name: []const u8, ty: Type };
489 .Struct => container_ty.structFields().keys()[index],489 const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {
490 .Union => container_ty.unionFields().keys()[index],490 .Struct => .{
491 else => unreachable,491 .name = container_ty.structFields().keys()[index],
492 };492 .ty = container_ty.structFields().values()[index].ty,
493 const field_ty = switch (container_ty.zigTypeTag()) {493 },
494 .Struct => container_ty.structFields().values()[index].ty,494 .Union => .{
495 .Union => container_ty.unionFields().values()[index].ty,495 .name = container_ty.unionFields().keys()[index],
496 .ty = container_ty.unionFields().values()[index].ty,
497 },
498 .Pointer => switch (container_ty.ptrSize()) {
499 .Slice => switch (index) {
500 0 => FieldInfo{ .name = "ptr", .ty = container_ty.childType() },
501 1 => FieldInfo{ .name = "len", .ty = Type.usize },
502 else => unreachable,
503 },
504 else => unreachable,
505 },
496 else => unreachable,506 else => unreachable,
497 };507 };
498 var container_ptr_ty_pl: Type.Payload.ElemType = .{508 var container_ptr_ty_pl: Type.Payload.ElemType = .{
...@@ -501,16 +511,16 @@ pub const DeclGen = struct {...@@ -501,16 +511,16 @@ pub const DeclGen = struct {
501 };511 };
502 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);512 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
503513
504 if (field_ty.hasRuntimeBitsIgnoreComptime()) {514 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {
505 try writer.writeAll("&(");515 try writer.writeAll("&(");
506 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);516 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
507 if (field_ptr.container_ty.tag() == .union_tagged or field_ptr.container_ty.tag() == .union_safety_tagged) {517 if (field_ptr.container_ty.tag() == .union_tagged or field_ptr.container_ty.tag() == .union_safety_tagged) {
508 try writer.print(")->payload.{ }", .{fmtIdent(field_name)});518 try writer.print(")->payload.{ }", .{fmtIdent(field_info.name)});
509 } else {519 } else {
510 try writer.print(")->{ }", .{fmtIdent(field_name)});520 try writer.print(")->{ }", .{fmtIdent(field_info.name)});
511 }521 }
512 } else {522 } else {
513 try dg.renderParentPtr(writer, field_ptr.container_ptr, field_ty);523 try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty);
514 }524 }
515 },525 },
516 .elem_ptr => {526 .elem_ptr => {
src/codegen/llvm.zig+9
...@@ -3938,6 +3938,15 @@ pub const DeclGen = struct {...@@ -3938,6 +3938,15 @@ pub const DeclGen = struct {
3938 const parent_llvm_ty = try dg.lowerType(parent_ty);3938 const parent_llvm_ty = try dg.lowerType(parent_ty);
3939 break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);3939 break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
3940 },3940 },
3941 .Pointer => {
3942 assert(parent_ty.isSlice());
3943 const indices: [2]*llvm.Value = .{
3944 llvm_u32.constInt(0, .False),
3945 llvm_u32.constInt(field_index, .False),
3946 };
3947 const parent_llvm_ty = try dg.lowerType(parent_ty);
3948 break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
3949 },
3941 else => unreachable,3950 else => unreachable,
3942 }3951 }
3943 },3952 },
test/behavior.zig+1
...@@ -100,6 +100,7 @@ test {...@@ -100,6 +100,7 @@ test {
100 _ = @import("behavior/bugs/12928.zig");100 _ = @import("behavior/bugs/12928.zig");
101 _ = @import("behavior/bugs/12945.zig");101 _ = @import("behavior/bugs/12945.zig");
102 _ = @import("behavior/bugs/12984.zig");102 _ = @import("behavior/bugs/12984.zig");
103 _ = @import("behavior/bugs/13068.zig");
103 _ = @import("behavior/bugs/13128.zig");104 _ = @import("behavior/bugs/13128.zig");
104 _ = @import("behavior/byteswap.zig");105 _ = @import("behavior/byteswap.zig");
105 _ = @import("behavior/byval_arg_var.zig");106 _ = @import("behavior/byval_arg_var.zig");
test/behavior/bugs/13068.zig created+15
...@@ -0,0 +1,15 @@
1const std = @import("std");
2const builtin = @import("builtin");
3
4pub const allocator = std.heap.page_allocator;
5var list = std.ArrayList(u32).init(allocator);
6
7test {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
13
14 list.items.len = 0;
15}
test/behavior/slice.zig+16-4
...@@ -2,6 +2,7 @@ const builtin = @import("builtin");...@@ -2,6 +2,7 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const expectEqualSlices = std.testing.expectEqualSlices;4const expectEqualSlices = std.testing.expectEqualSlices;
5const expectEqualStrings = std.testing.expectEqualStrings;
5const expectEqual = std.testing.expectEqual;6const expectEqual = std.testing.expectEqual;
6const mem = std.mem;7const mem = std.mem;
78
...@@ -686,8 +687,6 @@ test "slice len modification at comptime" {...@@ -686,8 +687,6 @@ test "slice len modification at comptime" {
686}687}
687688
688test "slice field ptr const" {689test "slice field ptr const" {
689 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
690
691 const const_slice: []const u8 = "string";690 const const_slice: []const u8 = "string";
692691
693 const const_ptr_const_slice = &const_slice;692 const const_ptr_const_slice = &const_slice;
...@@ -700,8 +699,6 @@ test "slice field ptr const" {...@@ -700,8 +699,6 @@ test "slice field ptr const" {
700}699}
701700
702test "slice field ptr var" {701test "slice field ptr var" {
703 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
704
705 var var_slice: []const u8 = "string";702 var var_slice: []const u8 = "string";
706703
707 var var_ptr_var_slice = &var_slice;704 var var_ptr_var_slice = &var_slice;
...@@ -712,3 +709,18 @@ test "slice field ptr var" {...@@ -712,3 +709,18 @@ test "slice field ptr var" {
712 try expectEqual(*[]const u8, @TypeOf(&const_ptr_var_slice.*));709 try expectEqual(*[]const u8, @TypeOf(&const_ptr_var_slice.*));
713 try expectEqual(*[*]const u8, @TypeOf(&const_ptr_var_slice.ptr));710 try expectEqual(*[*]const u8, @TypeOf(&const_ptr_var_slice.ptr));
714}711}
712
713test "global slice field access" {
714 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
715 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
716 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
717 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
718
719 const S = struct {
720 var slice: []const u8 = undefined;
721 };
722 S.slice = "string";
723 S.slice.ptr += 1;
724 S.slice.len -= 2;
725 try expectEqualStrings("trin", S.slice);
726}