diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index f2977977c5..1e79119997 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2884,6 +2884,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { break :blk dst_mcv; } }; + dst_mcv.freezeIfRegister(&self.register_manager); + defer dst_mcv.unfreezeIfRegister(&self.register_manager); // Shift by struct_field_offset. const shift = @intCast(u8, struct_field_offset * @sizeOf(usize)); @@ -2893,7 +2895,25 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { const max_reg_bit_width = Register.rax.size(); const mask_shift = @intCast(u6, (max_reg_bit_width - struct_field_ty.bitSize(self.target.*))); const mask = (~@as(u64, 0)) >> mask_shift; - try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .immediate = mask }); + + const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask }); + try self.genBinMathOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg }); + + const signedness: std.builtin.Signedness = blk: { + if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned; + break :blk struct_field_ty.intInfo(self.target.*).signedness; + }; + const field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); + if (signedness == .signed and field_size < 8) { + _ = try self.addInst(.{ + .tag = .mov_sign_extend, + .ops = (Mir.Ops{ + .reg1 = dst_mcv.register, + .reg2 = registerAlias(dst_mcv.register, field_size), + }).encode(), + .data = undefined, + }); + } break :result dst_mcv; }, @@ -5671,13 +5691,42 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { } fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { - const vector_ty = self.air.typeOfIndex(inst); - const len = vector_ty.vectorLen(); + const result_ty = self.air.typeOfIndex(inst); + const len = @intCast(usize, result_ty.arrayLen()); const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const elements = @bitCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); + const abi_size = @intCast(u32, result_ty.abiSize(self.target.*)); + const abi_align = result_ty.abiAlignment(self.target.*); const result: MCValue = res: { if (self.liveness.isUnused(inst)) break :res MCValue.dead; - return self.fail("TODO implement airAggregateInit for x86_64", .{}); + switch (result_ty.zigTypeTag()) { + .Struct => { + const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); + for (elements) |elem, elem_i| { + if (result_ty.structFieldValueComptime(elem_i) != null) continue; // comptime elem + + const elem_ty = result_ty.structFieldType(elem_i); + const elem_off = result_ty.structFieldOffset(elem_i, self.target.*); + const elem_mcv = try self.resolveInst(elem); + try self.genSetStack(elem_ty, stack_offset - @intCast(i32, elem_off), elem_mcv, .{}); + } + break :res MCValue{ .stack_offset = stack_offset }; + }, + .Array => { + const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); + const elem_ty = result_ty.childType(); + const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); + + for (elements) |elem, elem_i| { + const elem_mcv = try self.resolveInst(elem); + const elem_off = @intCast(i32, elem_size * elem_i); + try self.genSetStack(elem_ty, stack_offset - elem_off, elem_mcv, .{}); + } + break :res MCValue{ .stack_offset = stack_offset }; + }, + .Vector => return self.fail("TODO implement aggregate_init for vectors", .{}), + else => unreachable, + } }; if (elements.len <= Liveness.bpi - 1) { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 7643fe55c4..5e1af101de 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -881,45 +881,63 @@ fn addDbgInfoType( } }, .Struct => blk: { - if (ty.tag() == .tuple) { - log.debug("TODO implement .debug_info for type '{}'", .{ty.fmtDebug()}); - try dbg_info_buffer.append(abbrev_pad1); - break :blk; - } - // try dbg_info_buffer.ensureUnusedCapacity(23); // DW.AT.structure_type try dbg_info_buffer.append(abbrev_struct_type); // DW.AT.byte_size, DW.FORM.sdata const abi_size = ty.abiSize(target); try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); - // DW.AT.name, DW.FORM.string - const struct_name = try ty.nameAllocArena(arena, target); - try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); - dbg_info_buffer.appendSliceAssumeCapacity(struct_name); - dbg_info_buffer.appendAssumeCapacity(0); - const struct_obj = ty.castTag(.@"struct").?.data; - if (struct_obj.layout == .Packed) { - log.debug("TODO implement .debug_info for packed structs", .{}); - break :blk; - } + switch (ty.tag()) { + .tuple, .anon_struct => { + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)}); - const fields = ty.structFields(); - for (fields.keys()) |field_name, field_index| { - const field = fields.get(field_name).?; - // DW.AT.member - try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); - dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); - // DW.AT.name, DW.FORM.string - dbg_info_buffer.appendSliceAssumeCapacity(field_name); - dbg_info_buffer.appendAssumeCapacity(0); - // DW.AT.type, DW.FORM.ref4 - var index = dbg_info_buffer.items.len; - try dbg_info_buffer.resize(index + 4); - try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) }); - // DW.AT.data_member_location, DW.FORM.sdata - const field_off = ty.structFieldOffset(field_index, target); - try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); + const fields = ty.tupleFields(); + for (fields.types) |field, field_index| { + // DW.AT.member + try dbg_info_buffer.append(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + try dbg_info_buffer.writer().print("{d}\x00", .{field_index}); + // DW.AT.type, DW.FORM.ref4 + var index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try relocs.append(.{ .ty = field, .reloc = @intCast(u32, index) }); + // DW.AT.data_member_location, DW.FORM.sdata + const field_off = ty.structFieldOffset(field_index, target); + try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); + } + }, + else => { + // DW.AT.name, DW.FORM.string + const struct_name = try ty.nameAllocArena(arena, target); + try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); + dbg_info_buffer.appendSliceAssumeCapacity(struct_name); + dbg_info_buffer.appendAssumeCapacity(0); + + const struct_obj = ty.castTag(.@"struct").?.data; + if (struct_obj.layout == .Packed) { + log.debug("TODO implement .debug_info for packed structs", .{}); + break :blk; + } + + const fields = ty.structFields(); + for (fields.keys()) |field_name, field_index| { + const field = fields.get(field_name).?; + // DW.AT.member + try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); + dbg_info_buffer.appendAssumeCapacity(abbrev_struct_member); + // DW.AT.name, DW.FORM.string + dbg_info_buffer.appendSliceAssumeCapacity(field_name); + dbg_info_buffer.appendAssumeCapacity(0); + // DW.AT.type, DW.FORM.ref4 + var index = dbg_info_buffer.items.len; + try dbg_info_buffer.resize(index + 4); + try relocs.append(.{ .ty = field.ty, .reloc = @intCast(u32, index) }); + // DW.AT.data_member_location, DW.FORM.sdata + const field_off = ty.structFieldOffset(field_index, target); + try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); + } + }, } // DW.AT.structure_type delimit children diff --git a/test/behavior/array.zig b/test/behavior/array.zig index d7a87bed9c..13a4763a91 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -501,7 +501,6 @@ test "type coercion of anon struct literal to array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const S = struct { const U = union { diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index f9a039208f..4bed1f56cc 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -301,7 +301,6 @@ test "void struct fields" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const foo = VoidStructFieldsFoo{ .a = void{}, @@ -1019,7 +1018,6 @@ test "struct with union field" { } test "type coercion of anon struct literal to struct" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index a51aa466d9..80eaea5072 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -4,7 +4,6 @@ const testing = std.testing; const expect = testing.expect; test "tuple concatenation" { - 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_aarch64) return error.SkipZigTest; // TODO @@ -47,7 +46,6 @@ test "tuple multiplication" { } test "more tuple concatenation" { - 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_arm) return error.SkipZigTest; // TODO