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
22892289 const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align));
22902290 break :blk offset;
22912291 },
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 },
22922300 else => unreachable,
22932301 };
22942302
src/codegen.zig+12-2
......@@ -363,11 +363,21 @@ pub fn generateSymbol(
363363 const mod = bin_file.options.module.?;
364364 const decl = mod.declPtr(decl_index);
365365 const addend = blk: {
366 switch (decl.ty.tag()) {
367 .@"struct" => {
366 switch (decl.ty.zigTypeTag()) {
367 .Struct => {
368368 const addend = decl.ty.structFieldOffset(field_ptr.field_index, target);
369369 break :blk @intCast(u32, addend);
370370 },
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 },
371381 else => return Result{
372382 .fail = try ErrorMsg.create(
373383 bin_file.allocator,
src/codegen/c.zig+22-12
......@@ -485,14 +485,24 @@ pub const DeclGen = struct {
485485 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
486486 const container_ty = field_ptr.container_ty;
487487 const index = field_ptr.field_index;
488 const field_name = switch (container_ty.zigTypeTag()) {
489 .Struct => container_ty.structFields().keys()[index],
490 .Union => container_ty.unionFields().keys()[index],
491 else => unreachable,
492 };
493 const field_ty = switch (container_ty.zigTypeTag()) {
494 .Struct => container_ty.structFields().values()[index].ty,
495 .Union => container_ty.unionFields().values()[index].ty,
488 const FieldInfo = struct { name: []const u8, ty: Type };
489 const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {
490 .Struct => .{
491 .name = container_ty.structFields().keys()[index],
492 .ty = container_ty.structFields().values()[index].ty,
493 },
494 .Union => .{
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 },
496506 else => unreachable,
497507 };
498508 var container_ptr_ty_pl: Type.Payload.ElemType = .{
......@@ -501,16 +511,16 @@ pub const DeclGen = struct {
501511 };
502512 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
503513
504 if (field_ty.hasRuntimeBitsIgnoreComptime()) {
514 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {
505515 try writer.writeAll("&(");
506516 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty);
507517 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)});
509519 } else {
510 try writer.print(")->{ }", .{fmtIdent(field_name)});
520 try writer.print(")->{ }", .{fmtIdent(field_info.name)});
511521 }
512522 } else {
513 try dg.renderParentPtr(writer, field_ptr.container_ptr, field_ty);
523 try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty);
514524 }
515525 },
516526 .elem_ptr => {
src/codegen/llvm.zig+9
......@@ -3938,6 +3938,15 @@ pub const DeclGen = struct {
39383938 const parent_llvm_ty = try dg.lowerType(parent_ty);
39393939 break :blk parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
39403940 },
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 },
39413950 else => unreachable,
39423951 }
39433952 },
test/behavior.zig+1
......@@ -100,6 +100,7 @@ test {
100100 _ = @import("behavior/bugs/12928.zig");
101101 _ = @import("behavior/bugs/12945.zig");
102102 _ = @import("behavior/bugs/12984.zig");
103 _ = @import("behavior/bugs/13068.zig");
103104 _ = @import("behavior/bugs/13128.zig");
104105 _ = @import("behavior/byteswap.zig");
105106 _ = @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");
22const std = @import("std");
33const expect = std.testing.expect;
44const expectEqualSlices = std.testing.expectEqualSlices;
5const expectEqualStrings = std.testing.expectEqualStrings;
56const expectEqual = std.testing.expectEqual;
67const mem = std.mem;
78
......@@ -686,8 +687,6 @@ test "slice len modification at comptime" {
686687}
687688
688689test "slice field ptr const" {
689 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
690
691690 const const_slice: []const u8 = "string";
692691
693692 const const_ptr_const_slice = &const_slice;
......@@ -700,8 +699,6 @@ test "slice field ptr const" {
700699}
701700
702701test "slice field ptr var" {
703 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
704
705702 var var_slice: []const u8 = "string";
706703
707704 var var_ptr_var_slice = &var_slice;
......@@ -712,3 +709,18 @@ test "slice field ptr var" {
712709 try expectEqual(*[]const u8, @TypeOf(&const_ptr_var_slice.*));
713710 try expectEqual(*[*]const u8, @TypeOf(&const_ptr_var_slice.ptr));
714711}
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}