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 {...@@ -10414,11 +10414,12 @@ pub const Value = struct {
10414 } },10414 } },
10415 .error_union => |error_union| {10415 .error_union => |error_union| {
10416 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;10416 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);
10417 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);10418 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
10418 if (!ip.isNoReturn(error_union_type.error_set_type) and10419 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
10419 offset == codegen.errUnionErrorOffset(payload_ty, zcu))10420 const error_set_size = error_set_ty.abiSize(zcu);
10420 {10421 if (offset >= error_set_offset and offset + size <= error_set_offset + error_set_size) {
10421 offset = 0;10422 offset -= error_set_offset;
10422 continue :constant_key switch (error_union.val) {10423 continue :constant_key switch (error_union.val) {
10423 .err_name => |err_name| .{ .err = .{10424 .err_name => |err_name| .{ .err = .{
10424 .ty = error_union_type.error_set_type,10425 .ty = error_union_type.error_set_type,
...@@ -10430,15 +10431,18 @@ pub const Value = struct {...@@ -10430,15 +10431,18 @@ pub const Value = struct {
10430 } },10431 } },
10431 };10432 };
10432 }10433 }
10433 assert(payload_ty.hasRuntimeBitsIgnoreComptime(zcu));10434 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
10434 offset -= @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));10435 const payload_size = payload_ty.abiSize(zcu);
10435 switch (error_union.val) {10436 if (offset >= payload_offset and offset + size <= payload_offset + payload_size) {
10436 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },10437 offset -= payload_offset;
10437 .payload => |payload| {10438 switch (error_union.val) {
10438 constant = payload;10439 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
10439 constant_key = ip.indexToKey(payload);10440 .payload => |payload| {
10440 continue :constant_key constant_key;10441 constant = payload;
10441 },10442 constant_key = ip.indexToKey(payload);
10443 continue :constant_key constant_key;
10444 },
10445 }
10442 }10446 }
10443 },10447 },
10444 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },10448 .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...@@ -10975,7 +10979,17 @@ fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8
10975fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {10979fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {
10976 const zcu = isel.pt.zcu;10980 const zcu = isel.pt.zcu;
10977 const ip = &zcu.intern_pool;10981 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) {
10979 .int_type,10993 .int_type,
10980 .ptr_type,10994 .ptr_type,
10981 .array_type,10995 .array_type,
...@@ -10997,6 +11011,37 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -10997,6 +11011,37 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
10997 .empty_enum_value,11011 .empty_enum_value,
10998 .memoized_call,11012 .memoized_call,
10999 => unreachable, // not a runtime value11013 => 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 },
11000 .opt => |opt| {11045 .opt => |opt| {
11001 const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));11046 const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));
11002 switch (opt.val) {11047 switch (opt.val) {
...@@ -11008,7 +11053,6 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -11008,7 +11053,6 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
11008 if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);11053 if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);
11009 },11054 },
11010 }11055 }
11011 return true;
11012 },11056 },
11013 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {11057 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
11014 else => unreachable,11058 else => unreachable,
...@@ -11027,9 +11071,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -11027,9 +11071,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
11027 elem_offset += elem_size;11071 elem_offset += elem_size;
11028 },11072 },
11029 }11073 }
11030 return true;
11031 },11074 },
11032 .vector_type => {},11075 .vector_type => return false,
11033 .struct_type => {11076 .struct_type => {
11034 const loaded_struct = ip.loadStructType(aggregate.ty);11077 const loaded_struct = ip.loadStructType(aggregate.ty);
11035 switch (loaded_struct.layout) {11078 switch (loaded_struct.layout) {
...@@ -11052,9 +11095,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -11052,9 +11095,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
11052 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;11095 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
11053 field_offset += field_size;11096 field_offset += field_size;
11054 }11097 }
11055 return true;
11056 },11098 },
11057 .@"extern", .@"packed" => {},11099 .@"extern", .@"packed" => return false,
11058 }11100 }
11059 },11101 },
11060 .tuple_type => |tuple_type| {11102 .tuple_type => |tuple_type| {
...@@ -11071,15 +11113,10 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -11071,15 +11113,10 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
11071 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;11113 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
11072 field_offset += field_size;11114 field_offset += field_size;
11073 }11115 }
11074 return true;
11075 },11116 },
11076 },11117 },
11077 else => {},11118 else => return false,
11078 }11119 }
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 };
11083 return true;11120 return true;
11084}11121}
1108511122
test/behavior/enum.zig-1
...@@ -926,7 +926,6 @@ test "enum literal casting to tagged union" {...@@ -926,7 +926,6 @@ test "enum literal casting to tagged union" {
926const Bar = enum { A, B, C, D };926const Bar = enum { A, B, C, D };
927927
928test "enum literal casting to error union with payload enum" {928test "enum literal casting to error union with payload enum" {
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
931930
932 var bar: error{B}!Bar = undefined;931 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" {...@@ -145,14 +145,11 @@ test "implicit cast to optional to error union to return result loc" {
145}145}
146146
147test "fn returning empty error set can be passed as fn returning any error" {147test "fn returning empty error set can be passed as fn returning any error" {
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149
150 entry();148 entry();
151 comptime entry();149 comptime entry();
152}150}
153151
154test "fn returning empty error set can be passed as fn returning any error - pointer" {152test "fn returning empty error set can be passed as fn returning any error - pointer" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
157154
158 entryPtr();155 entryPtr();
...@@ -404,7 +401,6 @@ fn intLiteral(str: []const u8) !?i64 {...@@ -404,7 +401,6 @@ fn intLiteral(str: []const u8) !?i64 {
404}401}
405402
406test "nested error union function call in optional unwrap" {403test "nested error union function call in optional unwrap" {
407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
408 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO405 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" {...@@ -482,7 +478,6 @@ test "optional error set is the same size as error set" {
482}478}
483479
484test "nested catch" {480test "nested catch" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO481 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
487482
488 const S = struct {483 const S = struct {
...@@ -698,7 +693,6 @@ test "coerce error set to the current inferred error set" {...@@ -698,7 +693,6 @@ test "coerce error set to the current inferred error set" {
698}693}
699694
700test "error union payload is properly aligned" {695test "error union payload is properly aligned" {
701 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
702 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO696 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
703 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO697 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;698 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -757,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {...@@ -757,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {
757}751}
758752
759test "pointer to error union payload" {753test "pointer to error union payload" {
760 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
761 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
762 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
763 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;756 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -845,7 +838,6 @@ test "alignment of wrapping an error union payload" {...@@ -845,7 +838,6 @@ test "alignment of wrapping an error union payload" {
845}838}
846839
847test "compare error union and error set" {840test "compare error union and error set" {
848 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
849 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO841 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
850842
851 var a: anyerror = error.Foo;843 var a: anyerror = error.Foo;
...@@ -1034,8 +1026,6 @@ test "errorCast to adhoc inferred error set" {...@@ -1034,8 +1026,6 @@ test "errorCast to adhoc inferred error set" {
1034}1026}
10351027
1036test "@errorCast from error set to error union" {1028test "@errorCast from error set to error union" {
1037 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1038
1039 const S = struct {1029 const S = struct {
1040 fn doTheTest(set: error{ A, B }) error{A}!i32 {1030 fn doTheTest(set: error{ A, B }) error{A}!i32 {
1041 return @errorCast(set);1031 return @errorCast(set);
...@@ -1046,8 +1036,6 @@ test "@errorCast from error set to error union" {...@@ -1046,8 +1036,6 @@ test "@errorCast from error set to error union" {
1046}1036}
10471037
1048test "@errorCast from error union to error union" {1038test "@errorCast from error union to error union" {
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1050
1051 const S = struct {1039 const S = struct {
1052 fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {1040 fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {
1053 return @errorCast(set);1041 return @errorCast(set);
test/behavior/while.zig-2
...@@ -174,7 +174,6 @@ test "while with optional as condition with else" {...@@ -174,7 +174,6 @@ test "while with optional as condition with else" {
174}174}
175175
176test "while with error union condition" {176test "while with error union condition" {
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
178 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
179 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
180 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;179 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -306,7 +305,6 @@ test "while optional 2 break statements and an else" {...@@ -306,7 +305,6 @@ test "while optional 2 break statements and an else" {
306}305}
307306
308test "while error 2 break statements and an else" {307test "while error 2 break statements and an else" {
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO309 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312310