diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 17e9e04da7..b8723c56ee 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -240,7 +240,7 @@ comptime { _ = @import("compiler_rt/udivmodti4.zig"); // extra - if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/os_version_check.zig"); + _ = @import("compiler_rt/os_version_check.zig"); _ = @import("compiler_rt/emutls.zig"); _ = @import("compiler_rt/arm.zig"); _ = @import("compiler_rt/aulldiv.zig"); diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index 6ceb3f3a59..f84088624a 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -584,7 +584,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { air_body_index += 1; }, - .@"try", .try_cold, .try_ptr, .try_ptr_cold => { + .@"try", .try_cold => { const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; const extra = isel.air.extraData(Air.Try, pl_op.payload); @@ -596,6 +596,18 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { air_inst_index = air_body[air_body_index]; continue :air_tag air_tags[@intFromEnum(air_inst_index)]; }, + .try_ptr, .try_ptr_cold => { + const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; + const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload); + + try isel.analyzeUse(extra.data.ptr); + try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + try isel.def_order.putNoClobber(gpa, air_inst_index, {}); + + air_body_index += 1; + air_inst_index = air_body[air_body_index]; + continue :air_tag air_tags[@intFromEnum(air_inst_index)]; + }, .ret, .ret_safe, .ret_load => { const un_op = air_data[@intFromEnum(air_inst_index)].un_op; isel.returns = true; @@ -4760,17 +4772,62 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, const error_set_part_vi = try error_set_part_it.only(isel); const error_set_part_mat = try error_set_part_vi.?.matReg(isel); try isel.emit(.cbz( - switch (error_set_part_vi.?.size(isel)) { - else => unreachable, - 1...4 => error_set_part_mat.ra.w(), - 5...8 => error_set_part_mat.ra.x(), - }, + error_set_part_mat.ra.w(), @intCast((isel.instructions.items.len + 1 - cont_label) << 2), )); try error_set_part_mat.finish(isel); if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .try_ptr, .try_ptr_cold => { + const ty_pl = air.data(air.inst_index).ty_pl; + const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload); + const error_union_ty = isel.air.typeOf(extra.data.ptr, ip).childType(zcu); + const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; + const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); + + const error_union_ptr_vi = try isel.use(extra.data.ptr); + const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel); + if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: { + defer payload_ptr_vi.value.deref(isel); + switch (codegen.errUnionPayloadOffset(ty_pl.ty.toType().childType(zcu), zcu)) { + 0 => try payload_ptr_vi.value.move(isel, extra.data.ptr), + else => |payload_offset| { + const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused; + const lo12: u12 = @truncate(payload_offset >> 0); + const hi12: u12 = @intCast(payload_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + payload_ptr_ra.x(), + if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 })); + }, + } + } + + const cont_label = isel.instructions.items.len; + const cont_live_registers = isel.live_registers; + try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); + try isel.merge(&cont_live_registers, .{}); + + const error_set_ra = try isel.allocIntReg(); + defer isel.freeReg(error_set_ra); + try isel.loadReg( + error_set_ra, + ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu), + .unsigned, + error_union_ptr_mat.ra, + codegen.errUnionErrorOffset(payload_ty, zcu), + ); + try error_union_ptr_mat.finish(isel); + try isel.emit(.cbz( + error_set_ra.w(), + @intCast((isel.instructions.items.len + 1 - cont_label) << 2), + )); + + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .dbg_stmt => { if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -5403,14 +5460,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .optional_payload_ptr => { - if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| { - defer dst_vi.value.deref(isel); - const ty_op = air.data(air.inst_index).ty_op; - try dst_vi.value.move(isel, ty_op.operand); - } - if (air.next()) |next_air_tag| continue :air_tag next_air_tag; - }, .optional_payload => { if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: { defer payload_vi.value.deref(isel); @@ -5429,6 +5478,37 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .optional_payload_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| { + defer payload_ptr_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + try payload_ptr_vi.value.move(isel, ty_op.operand); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .optional_payload_ptr_set => { + if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| { + defer payload_ptr_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + const opt_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu); + if (!opt_ty.optionalReprIsPayload(zcu)) { + const opt_ptr_vi = try isel.use(ty_op.operand); + const opt_ptr_mat = try opt_ptr_vi.matReg(isel); + const has_value_ra = try isel.allocIntReg(); + defer isel.freeReg(has_value_ra); + try isel.storeReg( + has_value_ra, + 1, + opt_ptr_mat.ra, + opt_ty.optionalChild(zcu).abiSize(zcu), + ); + try opt_ptr_mat.finish(isel); + try isel.emit(.movz(has_value_ra.w(), 1, .{ .lsl = .@"0" })); + } + try payload_ptr_vi.value.move(isel, ty_op.operand); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .wrap_optional => { if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: { defer opt_vi.value.deref(isel); @@ -5486,6 +5566,93 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .unwrap_errunion_payload_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: { + defer payload_ptr_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + switch (codegen.errUnionPayloadOffset(ty_op.ty.toType().childType(zcu), zcu)) { + 0 => try payload_ptr_vi.value.move(isel, ty_op.operand), + else => |payload_offset| { + const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused; + const error_union_ptr_vi = try isel.use(ty_op.operand); + const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel); + const lo12: u12 = @truncate(payload_offset >> 0); + const hi12: u12 = @intCast(payload_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + payload_ptr_ra.x(), + if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 })); + try error_union_ptr_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .unwrap_errunion_err_ptr => { + if (isel.live_values.fetchRemove(air.inst_index)) |error_ptr_vi| unused: { + defer error_ptr_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + switch (codegen.errUnionErrorOffset( + isel.air.typeOf(ty_op.operand, ip).childType(zcu).errorUnionPayload(zcu), + zcu, + )) { + 0 => try error_ptr_vi.value.move(isel, ty_op.operand), + else => |error_offset| { + const error_ptr_ra = try error_ptr_vi.value.defReg(isel) orelse break :unused; + const error_union_ptr_vi = try isel.use(ty_op.operand); + const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel); + const lo12: u12 = @truncate(error_offset >> 0); + const hi12: u12 = @intCast(error_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + error_ptr_ra.x(), + if (lo12 > 0) error_ptr_ra.x() else error_union_ptr_mat.ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0) try isel.emit(.add(error_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 })); + try error_union_ptr_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .errunion_payload_ptr_set => { + if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: { + defer payload_ptr_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + const payload_ty = ty_op.ty.toType().childType(zcu); + const error_union_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu); + const error_set_size = error_union_ty.errorUnionSet(zcu).abiSize(zcu); + const error_union_ptr_vi = try isel.use(ty_op.operand); + const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel); + if (error_set_size > 0) try isel.storeReg( + .zr, + error_set_size, + error_union_ptr_mat.ra, + codegen.errUnionErrorOffset(payload_ty, zcu), + ); + switch (codegen.errUnionPayloadOffset(payload_ty, zcu)) { + 0 => { + try error_union_ptr_mat.finish(isel); + try payload_ptr_vi.value.move(isel, ty_op.operand); + }, + else => |payload_offset| { + const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused; + const lo12: u12 = @truncate(payload_offset >> 0); + const hi12: u12 = @intCast(payload_offset >> 12); + if (hi12 > 0) try isel.emit(.add( + payload_ptr_ra.x(), + if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(), + .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, + )); + if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 })); + try error_union_ptr_mat.finish(isel); + }, + } + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .wrap_errunion_payload => { if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| { defer error_union_vi.value.deref(isel); @@ -5672,6 +5839,32 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, + .set_union_tag => { + const bin_op = air.data(air.inst_index).bin_op; + const union_ty = isel.air.typeOf(bin_op.lhs, ip).childType(zcu); + const union_layout = union_ty.unionGetLayout(zcu); + const tag_vi = try isel.use(bin_op.rhs); + const union_ptr_vi = try isel.use(bin_op.lhs); + const union_ptr_mat = try union_ptr_vi.matReg(isel); + try tag_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), union_ptr_mat.ra, .{ + .offset = union_layout.tagOffset(), + }); + try union_ptr_mat.finish(isel); + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, + .get_union_tag => { + if (isel.live_values.fetchRemove(air.inst_index)) |tag_vi| { + defer tag_vi.value.deref(isel); + const ty_op = air.data(air.inst_index).ty_op; + const union_ty = isel.air.typeOf(ty_op.operand, ip); + const union_layout = union_ty.unionGetLayout(zcu); + const union_vi = try isel.use(ty_op.operand); + var tag_part_it = union_vi.field(union_ty, union_layout.tagOffset(), union_layout.tag_size); + const tag_part_vi = try tag_part_it.only(isel); + try tag_vi.value.copy(isel, ty_op.ty.toType(), tag_part_vi.?); + } + if (air.next()) |next_air_tag| continue :air_tag next_air_tag; + }, .slice => { if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| { defer slice_vi.value.deref(isel); @@ -6541,8 +6734,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, if (ptr_part_ra == null and len_part_ra == null) break :unused; const un_op = air.data(air.inst_index).un_op; - const err_vi = try isel.use(un_op); - const err_mat = try err_vi.matReg(isel); + const error_vi = try isel.use(un_op); + const error_mat = try error_vi.matReg(isel); const ptr_ra = try isel.allocIntReg(); defer isel.freeReg(ptr_ra); const start_ra, const end_ra = range_ras: { @@ -6573,7 +6766,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, if (len_part_ra) |_| try isel.emit(.sub(end_ra.w(), end_ra.w(), .{ .immediate = 1 })); try isel.emit(.ldp(start_ra.w(), end_ra.w(), .{ .base = start_ra.x() })); try isel.emit(.add(start_ra.x(), ptr_ra.x(), .{ .extended_register = .{ - .register = err_mat.ra.w(), + .register = error_mat.ra.w(), .extend = switch (zcu.errorSetBits()) { else => unreachable, 1...8 => .{ .uxtb = 2 }, @@ -6591,7 +6784,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.adrp(ptr_ra.x(), 0)); - try err_mat.finish(isel); + try error_mat.finish(isel); } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -6893,11 +7086,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(.ls))); const un_op = air.data(air.inst_index).un_op; - const err_vi = try isel.use(un_op); - const err_mat = try err_vi.matReg(isel); + const error_vi = try isel.use(un_op); + const error_mat = try error_vi.matReg(isel); const ptr_ra = try isel.allocIntReg(); defer isel.freeReg(ptr_ra); - try isel.emit(.subs(.wzr, err_mat.ra.w(), .{ .register = ptr_ra.w() })); + try isel.emit(.subs(.wzr, error_mat.ra.w(), .{ .register = ptr_ra.w() })); try isel.lazy_relocs.append(gpa, .{ .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, @@ -6908,7 +7101,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, .reloc = .{ .label = @intCast(isel.instructions.items.len) }, }); try isel.emit(.adrp(ptr_ra.x(), 0)); - try err_mat.finish(isel); + try error_mat.finish(isel); } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, @@ -9529,8 +9722,14 @@ pub const Value = struct { } }, }, .struct_type => { - const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; const loaded_struct = ip.loadStructType(ty.toIntern()); + switch (loaded_struct.layout) { + .auto, .@"extern" => {}, + .@"packed" => continue :type_key .{ + .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type, + }, + } + const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; if (loaded_struct.field_types.len > Value.max_parts and (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); @@ -9638,6 +9837,77 @@ pub const Value = struct { if (part.is_vector) subpart_vi.setIsVector(isel); } }, + .union_type => { + const loaded_union = ip.loadUnionType(ty.toIntern()); + switch (loaded_union.flagsUnordered(ip).layout) { + .auto, .@"extern" => {}, + .@"packed" => continue :type_key .{ .int_type = .{ + .signedness = .unsigned, + .bits = @intCast(ty.bitSize(zcu)), + } }, + } + const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; + if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) + return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); + const union_layout = ZigType.getUnionLayout(loaded_union, zcu); + const alignment = vi.alignment(isel); + const tag_offset = union_layout.tagOffset(); + const payload_offset = union_layout.payloadOffset(); + const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness }; + var parts: [2]Part = undefined; + var parts_len: Value.PartsLen = 0; + var field_end: u64 = 0; + for (0..2) |field_index| { + const field: enum { tag, payload } = switch (field_index) { + 0 => if (tag_offset < payload_offset) .tag else .payload, + 1 => if (tag_offset < payload_offset) .payload else .tag, + else => unreachable, + }; + const field_size, const field_begin = switch (field) { + .tag => .{ union_layout.tag_size, tag_offset }, + .payload => .{ union_layout.payload_size, payload_offset }, + }; + if (field_begin >= offset + size) break; + if (field_size == 0) continue; + field_end = field_begin + field_size; + if (field_end <= offset) continue; + const field_signedness = field_signedness: switch (field) { + .tag => { + if (offset >= field_begin and offset + size <= field_begin + field_size) { + ty = .fromInterned(loaded_union.enum_tag_ty); + ty_size = field_size; + offset -= field_begin; + continue :type_key ip.indexToKey(loaded_union.enum_tag_ty); + } + break :field_signedness ip.indexToKey(loaded_union.loadTagType(ip).tag_ty).int_type.signedness; + }, + .payload => null, + }; + if (parts_len > 0) combine: { + const prev_part = &parts[parts_len - 1]; + const combined_size = field_end - prev_part.offset; + if (combined_size > @as(u64, 1) << @min( + min_part_log2_stride, + alignment.toLog2Units(), + @ctz(prev_part.offset), + )) break :combine; + prev_part.size = combined_size; + prev_part.signedness = null; + continue; + } + parts[parts_len] = .{ + .offset = field_begin, + .size = field_size, + .signedness = field_signedness, + }; + parts_len += 1; + } + vi.setParts(isel, parts_len); + for (parts[0..parts_len]) |part| { + const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); + if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness); + } + }, .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque }, .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty), .error_set_type, @@ -10075,7 +10345,11 @@ pub const Value = struct { }; }, .slice => |slice| switch (offset) { - 0 => continue :constant_key .{ .ptr = ip.indexToKey(slice.ptr).ptr }, + 0 => continue :constant_key switch (ip.indexToKey(slice.ptr)) { + else => unreachable, + .undef => |undef| .{ .undef = undef }, + .ptr => |ptr| .{ .ptr = ptr }, + }, else => { assert(offset == @divExact(isel.target.ptrBitWidth(), 8)); offset = 0; @@ -11128,16 +11402,14 @@ pub const CallAbiIterator = struct { { const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type); const offset = codegen.errUnionErrorOffset(payload_ty, zcu); - const size = error_set_ty.abiSize(zcu); - const end = offset % 8 + size; + const end = offset % 8 + error_set_ty.abiSize(zcu); const part_index: usize = @intCast(offset / 8); sizes[part_index] = @max(sizes[part_index], @min(end, 8)); if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); } { const offset = codegen.errUnionPayloadOffset(payload_ty, zcu); - const size = payload_ty.abiSize(zcu); - const end = offset % 8 + size; + const end = offset % 8 + payload_ty.abiSize(zcu); const part_index: usize = @intCast(offset / 8); sizes[part_index] = @max(sizes[part_index], @min(end, 8)); if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); @@ -11181,8 +11453,14 @@ pub const CallAbiIterator = struct { => unreachable, }, .struct_type => { - const size = wip_vi.size(isel); const loaded_struct = ip.loadStructType(ty.toIntern()); + switch (loaded_struct.layout) { + .auto, .@"extern" => {}, + .@"packed" => continue :type_key .{ + .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type, + }, + } + const size = wip_vi.size(isel); if (size <= 16 * 4) homogeneous_aggregate: { const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate; const parts_len = @shrExact(size, fdt.log2Size()); @@ -11267,6 +11545,40 @@ pub const CallAbiIterator = struct { else => it.indirect(isel, wip_vi), } }, + .union_type => { + const loaded_union = ip.loadUnionType(ty.toIntern()); + switch (loaded_union.flagsUnordered(ip).layout) { + .auto, .@"extern" => {}, + .@"packed" => continue :type_key .{ .int_type = .{ + .signedness = .unsigned, + .bits = @intCast(ty.bitSize(zcu)), + } }, + } + switch (wip_vi.size(isel)) { + 0 => unreachable, + 1...8 => it.integer(isel, wip_vi), + 9...16 => { + const union_layout = ZigType.getUnionLayout(loaded_union, zcu); + var sizes: [2]u64 = @splat(0); + { + const offset = union_layout.tagOffset(); + const end = offset % 8 + union_layout.tag_size; + const part_index: usize = @intCast(offset / 8); + sizes[part_index] = @max(sizes[part_index], @min(end, 8)); + if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); + } + { + const offset = union_layout.payloadOffset(); + const end = offset % 8 + union_layout.payload_size; + const part_index: usize = @intCast(offset / 8); + sizes[part_index] = @max(sizes[part_index], @min(end, 8)); + if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); + } + it.integers(isel, wip_vi, sizes); + }, + else => it.indirect(isel, wip_vi), + } + }, .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque }, .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty), .error_set_type, diff --git a/test/behavior/decl_literals.zig b/test/behavior/decl_literals.zig index 169c705a6b..f96f461771 100644 --- a/test/behavior/decl_literals.zig +++ b/test/behavior/decl_literals.zig @@ -33,7 +33,6 @@ test "decl literal with pointer" { } test "call decl literal with optional" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -74,7 +73,6 @@ test "call decl literal" { } test "call decl literal with error union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO const S = struct { diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 4665178808..ae99c0a7e8 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -943,7 +943,6 @@ test "optional error set function parameter" { } test "returning an error union containing a type with no runtime bits" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/field_parent_ptr.zig b/test/behavior/field_parent_ptr.zig index 59742cf3f6..742b306059 100644 --- a/test/behavior/field_parent_ptr.zig +++ b/test/behavior/field_parent_ptr.zig @@ -587,7 +587,6 @@ test "@fieldParentPtr extern struct last zero-bit field" { } test "@fieldParentPtr unaligned packed struct" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -726,7 +725,6 @@ test "@fieldParentPtr unaligned packed struct" { } test "@fieldParentPtr aligned packed struct" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/inline_switch.zig b/test/behavior/inline_switch.zig index 57444d22a4..a1efe7ab02 100644 --- a/test/behavior/inline_switch.zig +++ b/test/behavior/inline_switch.zig @@ -43,7 +43,6 @@ test "inline switch enums" { const U = union(E) { a: void, b: u2, c: u3, d: u4 }; test "inline switch unions" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 3a63dfb1ac..11d4ee0537 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -319,7 +319,6 @@ test "assigning to an unwrapped optional field in an inline loop" { } test "coerce an anon struct literal to optional struct" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -447,7 +446,6 @@ test "optional pointer to zero bit optional payload" { } test "optional pointer to zero bit error union payload" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index ba69ae0990..3c4c4d7f80 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -797,7 +797,6 @@ test "fn with C calling convention returns struct by value" { } test "non-packed struct with u128 entry in union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1026,7 +1025,6 @@ test "packed struct with undefined initializers" { } test "for loop over pointers to struct, getting field from struct pointer" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1093,7 +1091,6 @@ test "anon init through error unions and optionals" { } test "anon init through optional" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1113,7 +1110,6 @@ test "anon init through optional" { } test "anon init through error union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -1398,7 +1394,6 @@ test "struct has only one reference" { } test "no dependency loop on pointer to optional struct" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index a7173be1ed..77b3321ba3 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -299,7 +299,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void { } test "switch on enum using pointer capture" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -360,7 +359,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 { } test "switch on union with some prongs capturing" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -975,8 +973,6 @@ test "switch prong captures range" { } test "prong with inline call to unreachable" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - const U = union(enum) { void: void, bool: bool, diff --git a/test/behavior/switch_on_captured_error.zig b/test/behavior/switch_on_captured_error.zig index 75a4280d62..9aae1c7fbe 100644 --- a/test/behavior/switch_on_captured_error.zig +++ b/test/behavior/switch_on_captured_error.zig @@ -6,7 +6,6 @@ const expectEqual = std.testing.expectEqual; const builtin = @import("builtin"); test "switch on error union catch capture" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/union.zig b/test/behavior/union.zig index bbace0f706..fb05b9edbb 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -160,7 +160,6 @@ test "unions embedded in aggregate types" { } test "constant tagged union with payload" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -263,7 +262,6 @@ fn testComparison() !void { } test "comparison between union and enum literal" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -279,7 +277,6 @@ const TheUnion = union(TheTag) { C: i32, }; test "cast union to tag type of union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -300,7 +297,6 @@ test "union field access gives the enum values" { } test "cast tag type of union to union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -316,7 +312,6 @@ const Value2 = union(Letter2) { }; test "implicit cast union to its tag type" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -495,7 +490,6 @@ test "initialize global array of union" { } test "update the tag value for zero-sized unions" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -734,7 +728,6 @@ test "union with only 1 field casted to its enum type which has enum value speci } test "@intFromEnum works on unions" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -848,7 +841,6 @@ test "@unionInit stored to a const" { } test "@unionInit can modify a union type" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -871,7 +863,6 @@ test "@unionInit can modify a union type" { } test "@unionInit can modify a pointer value" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -990,7 +981,6 @@ test "function call result coerces from tagged union to the tag" { } test "switching on non exhaustive union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1176,7 +1166,6 @@ test "comptime equality of extern unions with same tag" { } test "union tag is set when initiated as a temporary value at runtime" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1216,7 +1205,6 @@ test "extern union most-aligned field is smaller" { } test "return an extern union from C calling convention" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; @@ -1248,7 +1236,6 @@ test "return an extern union from C calling convention" { } test "noreturn field in union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1481,8 +1468,6 @@ test "reinterpreting enum value inside packed union" { } test "access the tag of a global tagged union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - const U = union(enum) { a, b: u8, @@ -2111,7 +2096,6 @@ test "runtime union init, most-aligned field != largest" { } test "copied union field doesn't alias source" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -2334,8 +2318,6 @@ test "assign global tagged union" { } test "set mutable union by switching on same union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - const U = union(enum) { foo, bar: usize, diff --git a/test/behavior/union_with_members.zig b/test/behavior/union_with_members.zig index 288d47d9cb..9303ac14da 100644 --- a/test/behavior/union_with_members.zig +++ b/test/behavior/union_with_members.zig @@ -17,7 +17,6 @@ const ET = union(enum) { }; test "enum with members" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/while.zig b/test/behavior/while.zig index db3d299b55..d6323babf5 100644 --- a/test/behavior/while.zig +++ b/test/behavior/while.zig @@ -344,7 +344,6 @@ test "else continue outer while" { } test "try terminating an infinite loop" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;