| author | |
| committer | |
| log | 20cc560c2dba4834e683692dabd43162a5ce8d22 |
| tree | cf11423a3e228a20b1f78d24f74030c1a47ae20d |
| parent | b09280b48452be8b57b87bbf4eaacd430e6e3537 |
| parent | 04523db6ae214e92f9c842436e66d5618d73d48f |
| signature |
stage2: add debug info for tuples (and anon structs), and implement aggregate_init for structs and arrays5 files changed, 103 insertions(+), 41 deletions(-)
src/arch/x86_64/CodeGen.zig+53-4| ... | ... | @@ -2884,6 +2884,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2884 | 2884 | break :blk dst_mcv; |
| 2885 | 2885 | } |
| 2886 | 2886 | }; |
| 2887 | dst_mcv.freezeIfRegister(&self.register_manager); | |
| 2888 | defer dst_mcv.unfreezeIfRegister(&self.register_manager); | |
| 2887 | 2889 | |
| 2888 | 2890 | // Shift by struct_field_offset. |
| 2889 | 2891 | const shift = @intCast(u8, struct_field_offset * @sizeOf(usize)); |
| ... | ... | @@ -2893,7 +2895,25 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2893 | 2895 | const max_reg_bit_width = Register.rax.size(); |
| 2894 | 2896 | const mask_shift = @intCast(u6, (max_reg_bit_width - struct_field_ty.bitSize(self.target.*))); |
| 2895 | 2897 | const mask = (~@as(u64, 0)) >> mask_shift; |
| 2896 | try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .immediate = mask }); | |
| 2898 | ||
| 2899 | const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); | |
| 2900 | try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg }); | |
| 2901 | ||
| 2902 | const signedness: std.builtin.Signedness = blk: { | |
| 2903 | if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned; | |
| 2904 | break :blk struct_field_ty.intInfo(self.target.*).signedness; | |
| 2905 | }; | |
| 2906 | const field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); | |
| 2907 | if (signedness == .signed and field_size < 8) { | |
| 2908 | _ = try self.addInst(.{ | |
| 2909 | .tag = .mov_sign_extend, | |
| 2910 | .ops = (Mir.Ops{ | |
| 2911 | .reg1 = dst_mcv.register, | |
| 2912 | .reg2 = registerAlias(dst_mcv.register, field_size), | |
| 2913 | }).encode(), | |
| 2914 | .data = undefined, | |
| 2915 | }); | |
| 2916 | } | |
| 2897 | 2917 | |
| 2898 | 2918 | break :result dst_mcv; |
| 2899 | 2919 | }, |
| ... | ... | @@ -5671,13 +5691,42 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| 5671 | 5691 | } |
| 5672 | 5692 | |
| 5673 | 5693 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 5674 | const vector_ty = self.air.typeOfIndex(inst); | |
| 5675 | const len = vector_ty.vectorLen(); | |
| 5694 | const result_ty = self.air.typeOfIndex(inst); | |
| 5695 | const len = @intCast(usize, result_ty.arrayLen()); | |
| 5676 | 5696 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5677 | 5697 | const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 5698 | const abi_size = @intCast(u32, result_ty.abiSize(self.target.*)); | |
| 5699 | const abi_align = result_ty.abiAlignment(self.target.*); | |
| 5678 | 5700 | const result: MCValue = res: { |
| 5679 | 5701 | if (self.liveness.isUnused(inst)) break :res MCValue.dead; |
| 5680 | return self.fail("TODO implement airAggregateInit for x86_64", .{}); | |
| 5702 | switch (result_ty.zigTypeTag()) { | |
| 5703 | .Struct => { | |
| 5704 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); | |
| 5705 | for (elements) |elem, elem_i| { | |
| 5706 | if (result_ty.structFieldValueComptime(elem_i) != null) continue; // comptime elem | |
| 5707 | ||
| 5708 | const elem_ty = result_ty.structFieldType(elem_i); | |
| 5709 | const elem_off = result_ty.structFieldOffset(elem_i, self.target.*); | |
| 5710 | const elem_mcv = try self.resolveInst(elem); | |
| 5711 | try self.genSetStack(elem_ty, stack_offset - @intCast(i32, elem_off), elem_mcv, .{}); | |
| 5712 | } | |
| 5713 | break :res MCValue{ .stack_offset = stack_offset }; | |
| 5714 | }, | |
| 5715 | .Array => { | |
| 5716 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); | |
| 5717 | const elem_ty = result_ty.childType(); | |
| 5718 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | |
| 5719 | ||
| 5720 | for (elements) |elem, elem_i| { | |
| 5721 | const elem_mcv = try self.resolveInst(elem); | |
| 5722 | const elem_off = @intCast(i32, elem_size * elem_i); | |
| 5723 | try self.genSetStack(elem_ty, stack_offset - elem_off, elem_mcv, .{}); | |
| 5724 | } | |
| 5725 | break :res MCValue{ .stack_offset = stack_offset }; | |
| 5726 | }, | |
| 5727 | .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}), | |
| 5728 | else => unreachable, | |
| 5729 | } | |
| 5681 | 5730 | }; |
| 5682 | 5731 | |
| 5683 | 5732 | if (elements.len <= Liveness.bpi - 1) { |
src/link/Dwarf.zig+50-32| ... | ... | @@ -881,45 +881,63 @@ fn addDbgInfoType( |
| 881 | 881 | } |
| 882 | 882 | }, |
| 883 | 883 | .Struct => blk: { |
| 884 | if (ty.tag() == .tuple) { | |
| 885 | log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()}); | |
| 886 | try dbg_info_buffer.append(abbrev_pad1); | |
| 887 | break :blk; | |
| 888 | } | |
| 889 | // try dbg_info_buffer.ensureUnusedCapacity(23); | |
| 890 | 884 | // DW.AT.structure_type |
| 891 | 885 | try dbg_info_buffer.append(abbrev_struct_type); |
| 892 | 886 | // DW.AT.byte_size, DW.FORM.sdata |
| 893 | 887 | const abi_size = ty.abiSize(target); |
| 894 | 888 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); |
| 895 | // DW.AT.name, DW.FORM.string | |
| 896 | const struct_name = try ty.nameAllocArena(arena, target); | |
| 897 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); | |
| 898 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); | |
| 899 | dbg_info_buffer.appendAssumeCapacity(0); | |
| 900 | 889 | |
| 901 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 902 | if (struct_obj.layout == .Packed) { | |
| 903 | log.debug("TODO implement .debug_info for packed structs", .{}); | |
| 904 | break :blk; | |
| 905 | } | |
| 890 | switch (ty.tag()) { | |
| 891 | .tuple, .anon_struct => { | |
| 892 | // DW.AT.name, DW.FORM.string | |
| 893 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); | |
| 894 | ||
| 895 | const fields = ty.tupleFields(); | |
| 896 | for (fields.types) |field, field_index| { | |
| 897 | // DW.AT.member | |
| 898 | try dbg_info_buffer.append(abbrev_struct_member); | |
| 899 | // DW.AT.name, DW.FORM.string | |
| 900 | try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); | |
| 901 | // DW.AT.type, DW.FORM.ref4 | |
| 902 | var index = dbg_info_buffer.items.len; | |
| 903 | try dbg_info_buffer.resize(index + 4); | |
| 904 | try relocs.append(.{ .ty = field, .reloc = @intCast(u32, index) }); | |
| 905 | // DW.AT.data_member_location, DW.FORM.sdata | |
| 906 | const field_off = ty.structFieldOffset(field_index, target); | |
| 907 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | |
| 908 | } | |
| 909 | }, | |
| 910 | else => { | |
| 911 | // DW.AT.name, DW.FORM.string | |
| 912 | const struct_name = try ty.nameAllocArena(arena, target); | |
| 913 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); | |
| 914 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); | |
| 915 | dbg_info_buffer.appendAssumeCapacity(0); | |
| 916 | ||
| 917 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 918 | if (struct_obj.layout == .Packed) { | |
| 919 | log.debug("TODO implement .debug_info for packed structs", .{}); | |
| 920 | break :blk; | |
| 921 | } | |
| 906 | 922 | |
| 907 | const fields = ty.structFields(); | |
| 908 | for (fields.keys()) |field_name, field_index| { | |
| 909 | const field = fields.get(field_name).?; | |
| 910 | // DW.AT.member | |
| 911 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); | |
| 912 | dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); | |
| 913 | // DW.AT.name, DW.FORM.string | |
| 914 | dbg_info_buffer.appendSliceAssumeCapacity(field_name); | |
| 915 | dbg_info_buffer.appendAssumeCapacity(0); | |
| 916 | // DW.AT.type, DW.FORM.ref4 | |
| 917 | var index = dbg_info_buffer.items.len; | |
| 918 | try dbg_info_buffer.resize(index + 4); | |
| 919 | try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) }); | |
| 920 | // DW.AT.data_member_location, DW.FORM.sdata | |
| 921 | const field_off = ty.structFieldOffset(field_index, target); | |
| 922 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | |
| 923 | const fields = ty.structFields(); | |
| 924 | for (fields.keys()) |field_name, field_index| { | |
| 925 | const field = fields.get(field_name).?; | |
| 926 | // DW.AT.member | |
| 927 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); | |
| 928 | dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); | |
| 929 | // DW.AT.name, DW.FORM.string | |
| 930 | dbg_info_buffer.appendSliceAssumeCapacity(field_name); | |
| 931 | dbg_info_buffer.appendAssumeCapacity(0); | |
| 932 | // DW.AT.type, DW.FORM.ref4 | |
| 933 | var index = dbg_info_buffer.items.len; | |
| 934 | try dbg_info_buffer.resize(index + 4); | |
| 935 | try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) }); | |
| 936 | // DW.AT.data_member_location, DW.FORM.sdata | |
| 937 | const field_off = ty.structFieldOffset(field_index, target); | |
| 938 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | |
| 939 | } | |
| 940 | }, | |
| 923 | 941 | } |
| 924 | 942 | |
| 925 | 943 | // DW.AT.structure_type delimit children |
test/behavior/array.zig-1| ... | ... | @@ -501,7 +501,6 @@ test "type coercion of anon struct literal to array" { |
| 501 | 501 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 502 | 502 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 503 | 503 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 504 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 505 | 504 | |
| 506 | 505 | const S = struct { |
| 507 | 506 | const U = union { |
test/behavior/struct.zig-2| ... | ... | @@ -301,7 +301,6 @@ test "void struct fields" { |
| 301 | 301 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 302 | 302 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 303 | 303 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 304 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 305 | 304 | |
| 306 | 305 | const foo = VoidStructFieldsFoo{ |
| 307 | 306 | .a = void{}, |
| ... | ... | @@ -1019,7 +1018,6 @@ test "struct with union field" { |
| 1019 | 1018 | } |
| 1020 | 1019 | |
| 1021 | 1020 | test "type coercion of anon struct literal to struct" { |
| 1022 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 1023 | 1021 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1024 | 1022 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1025 | 1023 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
test/behavior/tuple.zig-2| ... | ... | @@ -4,7 +4,6 @@ const testing = std.testing; |
| 4 | 4 | const expect = testing.expect; |
| 5 | 5 | |
| 6 | 6 | test "tuple concatenation" { |
| 7 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 10 | 9 | |
| ... | ... | @@ -47,7 +46,6 @@ test "tuple multiplication" { |
| 47 | 46 | } |
| 48 | 47 | |
| 49 | 48 | test "more tuple concatenation" { |
| 50 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 51 | 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 52 | 50 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 53 | 51 |