aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.zig
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2022-05-23 18:24:03 +0200
committerAndrew Kelley <andrew@ziglang.org>2022-05-24 15:34:52 -0700
commitc90a97f9be9ffef858b0e450de5006f61a12fafd (patch)
treec8ba955be7b7cd81230a2e0da39f2c36e73a681e /src/codegen.zig
parent3264abe3d8f658e1b7275d2be80e43eddfc098dc (diff)
downloadzig-c90a97f9be9ffef858b0e450de5006f61a12fafd.tar.gz
zig-c90a97f9be9ffef858b0e450de5006f61a12fafd.zip
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.
Diffstat (limited to 'src/codegen.zig')
-rw-r--r--src/codegen.zig48
1 files changed, 41 insertions, 7 deletions
diff --git a/src/codegen.zig b/src/codegen.zig
index bd556baa5e..81b303ab82 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -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);
+ // 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 = 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 error_val = if (!is_payload) typed_value.val else Value.initTag(.zero);
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 = error_ty,
- .val = error_val,
+ .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| {