codegen: Order error union fields per alignment

Based on the size of the payload the native backends will lower
the error union with its fields (errorset & payload) in the correct order.
e.g. ErrorA!u8 will first lower the error set's value and then the payload.
In the event of ErrorA!u32 will lower the payload first.
This commit is contained in:
Luuk de Gram 2022-05-23 18:24:03 +02:00 committed by Andrew Kelley
parent 3264abe3d8
commit c90a97f9be

View File

@ -702,16 +702,50 @@ pub fn generateSymbol(
.ErrorUnion => {
const error_ty = typed_value.ty.errorUnionSet();
const payload_ty = typed_value.ty.errorUnionPayload();
if (error_ty.errorSetCardinality() == .zero) {
const payload_val = typed_value.val.castTag(.eu_payload).?.data;
return generateSymbol(bin_file, src_loc, .{
.ty = payload_ty,
.val = payload_val,
}, code, debug_output, reloc_info);
}
const is_payload = typed_value.val.errorUnionIsPayload();
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
const err_val = if (!is_payload) typed_value.val else Value.initTag(.zero);
return generateSymbol(bin_file, src_loc, .{
.ty = error_ty,
.val = err_val,
}, code, debug_output, reloc_info);
}
const payload_align = payload_ty.abiAlignment(target);
const error_align = Type.anyerror.abiAlignment(target);
const abi_align = typed_value.ty.abiAlignment(target);
{
const error_val = if (!is_payload) typed_value.val else Value.initTag(.zero);
const begin = code.items.len;
// error value first when its type is larger than the error union's payload
if (error_align > payload_align) {
switch (try generateSymbol(bin_file, src_loc, .{
.ty = error_ty,
.val = error_val,
.val = if (is_payload) Value.initTag(.zero) else typed_value.val,
}, code, debug_output, reloc_info)) {
.appended => {},
.externally_managed => |external_slice| {
code.appendSliceAssumeCapacity(external_slice);
},
.fail => |em| return Result{ .fail = em },
}
}
// emit payload part of the error union
{
const begin = code.items.len;
const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef);
switch (try generateSymbol(bin_file, src_loc, .{
.ty = payload_ty,
.val = payload_val,
}, code, debug_output, reloc_info)) {
.appended => {},
.externally_managed => |external_slice| {
@ -728,12 +762,12 @@ pub fn generateSymbol(
}
}
if (payload_ty.hasRuntimeBits()) {
// Payload size is larger than error set, so emit our error set last
if (error_align < payload_align) {
const begin = code.items.len;
const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef);
switch (try generateSymbol(bin_file, src_loc, .{
.ty = payload_ty,
.val = payload_val,
.ty = error_ty,
.val = if (is_payload) Value.initTag(.zero) else typed_value.val,
}, code, debug_output, reloc_info)) {
.appended => {},
.externally_managed => |external_slice| {