Commit 7894703ee7
Changed files (13)
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");
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,
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 {
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;
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;
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
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;
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;
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,
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;
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,
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;
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;