authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-07-27 08:00:57-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-07-27 08:01:07-04:00
logb26e732bd0a33161b079202e9df9dda4b918b2bb
treea58ca0c2486476a333a2fedcf1458ebe42d77e31
parent771523c67534fc47800608eb720886e9f53da7b4

aarch64: fix error union constants


4 files changed, 62 insertions(+), 40 deletions(-)

src/codegen/aarch64/Select.zig+62-25
......@@ -10414,11 +10414,12 @@ pub const Value = struct {
1041410414 } },
1041510415 .error_union => |error_union| {
1041610416 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
10417 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
1041710418 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
10418 if (!ip.isNoReturn(error_union_type.error_set_type) and
10419 offset == codegen.errUnionErrorOffset(payload_ty, zcu))
10420 {
10421 offset = 0;
10419 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
10420 const error_set_size = error_set_ty.abiSize(zcu);
10421 if (offset >= error_set_offset and offset + size <= error_set_offset + error_set_size) {
10422 offset -= error_set_offset;
1042210423 continue :constant_key switch (error_union.val) {
1042310424 .err_name => |err_name| .{ .err = .{
1042410425 .ty = error_union_type.error_set_type,
......@@ -10430,15 +10431,18 @@ pub const Value = struct {
1043010431 } },
1043110432 };
1043210433 }
10433 assert(payload_ty.hasRuntimeBitsIgnoreComptime(zcu));
10434 offset -= @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));
10435 switch (error_union.val) {
10436 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
10437 .payload => |payload| {
10438 constant = payload;
10439 constant_key = ip.indexToKey(payload);
10440 continue :constant_key constant_key;
10441 },
10434 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
10435 const payload_size = payload_ty.abiSize(zcu);
10436 if (offset >= payload_offset and offset + size <= payload_offset + payload_size) {
10437 offset -= payload_offset;
10438 switch (error_union.val) {
10439 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
10440 .payload => |payload| {
10441 constant = payload;
10442 constant_key = ip.indexToKey(payload);
10443 continue :constant_key constant_key;
10444 },
10445 }
1044210446 }
1044310447 },
1044410448 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },
......@@ -10975,7 +10979,17 @@ fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8
1097510979fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {
1097610980 const zcu = isel.pt.zcu;
1097710981 const ip = &zcu.intern_pool;
10978 switch (ip.indexToKey(constant.toIntern())) {
10982 if (try isel.writeKeyToMemory(ip.indexToKey(constant.toIntern()), buffer)) return true;
10983 constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) {
10984 error.OutOfMemory => return error.OutOfMemory,
10985 error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false,
10986 };
10987 return true;
10988}
10989fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) error{OutOfMemory}!bool {
10990 const zcu = isel.pt.zcu;
10991 const ip = &zcu.intern_pool;
10992 switch (constant_key) {
1097910993 .int_type,
1098010994 .ptr_type,
1098110995 .array_type,
......@@ -10997,6 +11011,37 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
1099711011 .empty_enum_value,
1099811012 .memoized_call,
1099911013 => unreachable, // not a runtime value
11014 .err => |err| {
11015 const error_int = ip.getErrorValueIfExists(err.name).?;
11016 switch (buffer.len) {
11017 else => unreachable,
11018 inline 1...4 => |size| std.mem.writeInt(
11019 @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * size } }),
11020 buffer[0..size],
11021 @intCast(error_int),
11022 isel.target.cpu.arch.endian(),
11023 ),
11024 }
11025 },
11026 .error_union => |error_union| {
11027 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
11028 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
11029 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
11030 const error_set = buffer[@intCast(codegen.errUnionErrorOffset(payload_ty, zcu))..][0..@intCast(error_set_ty.abiSize(zcu))];
11031 switch (error_union.val) {
11032 .err_name => |err_name| if (!try isel.writeKeyToMemory(.{ .err = .{
11033 .ty = error_set_ty.toIntern(),
11034 .name = err_name,
11035 } }, error_set)) return false,
11036 .payload => |payload| {
11037 if (!try isel.writeToMemory(
11038 .fromInterned(payload),
11039 buffer[@intCast(codegen.errUnionPayloadOffset(payload_ty, zcu))..][0..@intCast(payload_ty.abiSize(zcu))],
11040 )) return false;
11041 @memset(error_set, 0);
11042 },
11043 }
11044 },
1100011045 .opt => |opt| {
1100111046 const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));
1100211047 switch (opt.val) {
......@@ -11008,7 +11053,6 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
1100811053 if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);
1100911054 },
1101011055 }
11011 return true;
1101211056 },
1101311057 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
1101411058 else => unreachable,
......@@ -11027,9 +11071,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
1102711071 elem_offset += elem_size;
1102811072 },
1102911073 }
11030 return true;
1103111074 },
11032 .vector_type => {},
11075 .vector_type => return false,
1103311076 .struct_type => {
1103411077 const loaded_struct = ip.loadStructType(aggregate.ty);
1103511078 switch (loaded_struct.layout) {
......@@ -11052,9 +11095,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
1105211095 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
1105311096 field_offset += field_size;
1105411097 }
11055 return true;
1105611098 },
11057 .@"extern", .@"packed" => {},
11099 .@"extern", .@"packed" => return false,
1105811100 }
1105911101 },
1106011102 .tuple_type => |tuple_type| {
......@@ -11071,15 +11113,10 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
1107111113 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
1107211114 field_offset += field_size;
1107311115 }
11074 return true;
1107511116 },
1107611117 },
11077 else => {},
11118 else => return false,
1107811119 }
11079 constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) {
11080 error.OutOfMemory => return error.OutOfMemory,
11081 error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false,
11082 };
1108311120 return true;
1108411121}
1108511122
test/behavior/enum.zig-1
......@@ -926,7 +926,6 @@ test "enum literal casting to tagged union" {
926926const Bar = enum { A, B, C, D };
927927
928928test "enum literal casting to error union with payload enum" {
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
931930
932931 var bar: error{B}!Bar = undefined;
test/behavior/error.zig-12
......@@ -145,14 +145,11 @@ test "implicit cast to optional to error union to return result loc" {
145145}
146146
147147test "fn returning empty error set can be passed as fn returning any error" {
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149
150148 entry();
151149 comptime entry();
152150}
153151
154152test "fn returning empty error set can be passed as fn returning any error - pointer" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
157154
158155 entryPtr();
......@@ -404,7 +401,6 @@ fn intLiteral(str: []const u8) !?i64 {
404401}
405402
406403test "nested error union function call in optional unwrap" {
407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
408404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
409405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
410406
......@@ -482,7 +478,6 @@ test "optional error set is the same size as error set" {
482478}
483479
484480test "nested catch" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
486481 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
487482
488483 const S = struct {
......@@ -698,7 +693,6 @@ test "coerce error set to the current inferred error set" {
698693}
699694
700695test "error union payload is properly aligned" {
701 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
702696 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
703697 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
704698 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -757,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {
757751}
758752
759753test "pointer to error union payload" {
760 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
761754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
762755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
763756 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -845,7 +838,6 @@ test "alignment of wrapping an error union payload" {
845838}
846839
847840test "compare error union and error set" {
848 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
849841 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
850842
851843 var a: anyerror = error.Foo;
......@@ -1034,8 +1026,6 @@ test "errorCast to adhoc inferred error set" {
10341026}
10351027
10361028test "@errorCast from error set to error union" {
1037 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1038
10391029 const S = struct {
10401030 fn doTheTest(set: error{ A, B }) error{A}!i32 {
10411031 return @errorCast(set);
......@@ -1046,8 +1036,6 @@ test "@errorCast from error set to error union" {
10461036}
10471037
10481038test "@errorCast from error union to error union" {
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1050
10511039 const S = struct {
10521040 fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {
10531041 return @errorCast(set);
test/behavior/while.zig-2
......@@ -174,7 +174,6 @@ test "while with optional as condition with else" {
174174}
175175
176176test "while with error union condition" {
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
178177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
179178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
180179 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -306,7 +305,6 @@ test "while optional 2 break statements and an else" {
306305}
307306
308307test "while error 2 break statements and an else" {
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
310308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311309 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312310