authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-24 19:23:33+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-24 15:34:52-07:00
log8c49420928b29271429cc09b5d5f1447a942f8d6
treea6dfcb22fb8d86ba4159ed12491a67cc065e9b61
parentc043d57cabdc4db20a55a9877ec607c81d15442f

aarch64: update for new error union layout


4 files changed, 93 insertions(+), 60 deletions(-)

src/arch/aarch64/CodeGen.zig+69-41
...@@ -3,6 +3,7 @@ const builtin = @import("builtin");...@@ -3,6 +3,7 @@ const builtin = @import("builtin");
3const mem = std.mem;3const mem = std.mem;
4const math = std.math;4const math = std.math;
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const codegen = @import("../../codegen.zig");
6const Air = @import("../../Air.zig");7const Air = @import("../../Air.zig");
7const Mir = @import("Mir.zig");8const Mir = @import("Mir.zig");
8const Emit = @import("Emit.zig");9const Emit = @import("Emit.zig");
...@@ -22,12 +23,14 @@ const leb128 = std.leb;...@@ -22,12 +23,14 @@ const leb128 = std.leb;
22const log = std.log.scoped(.codegen);23const log = std.log.scoped(.codegen);
23const build_options = @import("build_options");24const build_options = @import("build_options");
2425
25const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;26const GenerateSymbolError = codegen.GenerateSymbolError;
26const FnResult = @import("../../codegen.zig").FnResult;27const FnResult = codegen.FnResult;
27const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;28const DebugInfoOutput = codegen.DebugInfoOutput;
2829
29const bits = @import("bits.zig");30const bits = @import("bits.zig");
30const abi = @import("abi.zig");31const abi = @import("abi.zig");
32const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
33const errUnionErrOffset = codegen.errUnionErrOffset;
31const RegisterManager = abi.RegisterManager;34const RegisterManager = abi.RegisterManager;
32const RegisterLock = RegisterManager.RegisterLock;35const RegisterLock = RegisterManager.RegisterLock;
33const Register = bits.Register;36const Register = bits.Register;
...@@ -3272,7 +3275,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3272,7 +3275,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
32723275
3273fn ret(self: *Self, mcv: MCValue) !void {3276fn ret(self: *Self, mcv: MCValue) !void {
3274 const ret_ty = self.fn_type.fnReturnType();3277 const ret_ty = self.fn_type.fnReturnType();
3275 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);3278 switch (self.ret_mcv) {
3279 .immediate => {
3280 assert(ret_ty.isError());
3281 },
3282 else => {
3283 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
3284 },
3285 }
3276 // Just add space for an instruction, patch this later3286 // Just add space for an instruction, patch this later
3277 const index = try self.addInst(.{3287 const index = try self.addInst(.{
3278 .tag = .nop,3288 .tag = .nop,
...@@ -3601,30 +3611,39 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -3601,30 +3611,39 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3601 const error_type = ty.errorUnionSet();3611 const error_type = ty.errorUnionSet();
3602 const payload_type = ty.errorUnionPayload();3612 const payload_type = ty.errorUnionPayload();
36033613
3604 if (!error_type.hasRuntimeBits()) {3614 if (error_type.errorSetCardinality() == .zero) {
3605 return MCValue{ .immediate = 0 }; // always false3615 return MCValue{ .immediate = 0 }; // always false
3606 } else if (!payload_type.hasRuntimeBits()) {3616 }
3607 if (error_type.abiSize(self.target.*) <= 8) {
3608 const reg_mcv: MCValue = switch (operand) {
3609 .register => operand,
3610 else => .{ .register = try self.copyToTmpRegister(error_type, operand) },
3611 };
36123617
3618 const err_off = errUnionErrOffset(ty, self.target.*);
3619 switch (operand) {
3620 .stack_offset => |off| {
3621 const offset = off - @intCast(u32, err_off);
3622 const tmp_reg = try self.copyToTmpRegister(Type.anyerror, .{ .stack_offset = offset });
3613 _ = try self.addInst(.{3623 _ = try self.addInst(.{
3614 .tag = .cmp_immediate,3624 .tag = .cmp_immediate,
3615 .data = .{ .r_imm12_sh = .{3625 .data = .{ .r_imm12_sh = .{
3616 .rn = reg_mcv.register,3626 .rn = tmp_reg,
3617 .imm12 = 0,3627 .imm12 = 0,
3618 } },3628 } },
3619 });3629 });
36203630 },
3621 return MCValue{ .compare_flags_unsigned = .gt };3631 .register => |reg| {
3622 } else {3632 if (err_off > 0 or payload_type.hasRuntimeBitsIgnoreComptime()) {
3623 return self.fail("TODO isErr for errors with size > 8", .{});3633 return self.fail("TODO implement isErr for register operand with payload bits", .{});
3624 }3634 }
3625 } else {3635 _ = try self.addInst(.{
3626 return self.fail("TODO isErr for non-empty payloads", .{});3636 .tag = .cmp_immediate,
3637 .data = .{ .r_imm12_sh = .{
3638 .rn = reg,
3639 .imm12 = 0,
3640 } },
3641 });
3642 },
3643 else => return self.fail("TODO implement isErr for {}", .{operand}),
3627 }3644 }
3645
3646 return MCValue{ .compare_flags_unsigned = .gt };
3628}3647}
36293648
3630fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {3649fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
...@@ -4483,7 +4502,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -4483,7 +4502,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
4483 const ref_int = @enumToInt(inst);4502 const ref_int = @enumToInt(inst);
4484 if (ref_int < Air.Inst.Ref.typed_value_map.len) {4503 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
4485 const tv = Air.Inst.Ref.typed_value_map[ref_int];4504 const tv = Air.Inst.Ref.typed_value_map[ref_int];
4486 if (!tv.ty.hasRuntimeBits()) {4505 if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) {
4487 return MCValue{ .none = {} };4506 return MCValue{ .none = {} };
4488 }4507 }
4489 return self.genTypedValue(tv);4508 return self.genTypedValue(tv);
...@@ -4491,7 +4510,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -4491,7 +4510,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
44914510
4492 // If the type has no codegen bits, no need to store it.4511 // If the type has no codegen bits, no need to store it.
4493 const inst_ty = self.air.typeOf(inst);4512 const inst_ty = self.air.typeOf(inst);
4494 if (!inst_ty.hasRuntimeBits())4513 if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError())
4495 return MCValue{ .none = {} };4514 return MCValue{ .none = {} };
44964515
4497 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);4516 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
...@@ -4674,32 +4693,38 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -4674,32 +4693,38 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
4674 }4693 }
4675 },4694 },
4676 .ErrorSet => {4695 .ErrorSet => {
4677 const err_name = typed_value.val.castTag(.@"error").?.data.name;4696 switch (typed_value.val.tag()) {
4678 const module = self.bin_file.options.module.?;4697 .@"error" => {
4679 const global_error_set = module.global_error_set;4698 const err_name = typed_value.val.castTag(.@"error").?.data.name;
4680 const error_index = global_error_set.get(err_name).?;4699 const module = self.bin_file.options.module.?;
4681 return MCValue{ .immediate = error_index };4700 const global_error_set = module.global_error_set;
4701 const error_index = global_error_set.get(err_name).?;
4702 return MCValue{ .immediate = error_index };
4703 },
4704 else => {
4705 // In this case we are rendering an error union which has a 0 bits payload.
4706 return MCValue{ .immediate = 0 };
4707 },
4708 }
4682 },4709 },
4683 .ErrorUnion => {4710 .ErrorUnion => {
4684 const error_type = typed_value.ty.errorUnionSet();4711 const error_type = typed_value.ty.errorUnionSet();
4685 const payload_type = typed_value.ty.errorUnionPayload();4712 const payload_type = typed_value.ty.errorUnionPayload();
46864713
4687 if (typed_value.val.castTag(.eu_payload)) |pl| {4714 if (error_type.errorSetCardinality() == .zero) {
4688 if (!payload_type.hasRuntimeBits()) {4715 const payload_val = typed_value.val.castTag(.eu_payload).?.data;
4689 // We use the error type directly as the type.4716 return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
4690 return MCValue{ .immediate = 0 };4717 }
4691 }
46924718
4693 _ = pl;4719 const is_pl = typed_value.val.errorUnionIsPayload();
4694 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty.fmtDebug()});
4695 } else {
4696 if (!payload_type.hasRuntimeBits()) {
4697 // We use the error type directly as the type.
4698 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
4699 }
47004720
4701 return self.fail("TODO implement error union const of type '{}' (error)", .{typed_value.ty.fmtDebug()});4721 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
4722 // We use the error type directly as the type.
4723 const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero);
4724 return self.genTypedValue(.{ .ty = error_type, .val = err_val });
4702 }4725 }
4726
4727 return self.lowerUnnamedConst(typed_value);
4703 },4728 },
4704 .Struct => {4729 .Struct => {
4705 return self.lowerUnnamedConst(typed_value);4730 return self.lowerUnnamedConst(typed_value);
...@@ -4796,13 +4821,16 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4796,13 +4821,16 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
47964821
4797 if (ret_ty.zigTypeTag() == .NoReturn) {4822 if (ret_ty.zigTypeTag() == .NoReturn) {
4798 result.return_value = .{ .unreach = {} };4823 result.return_value = .{ .unreach = {} };
4799 } else if (!ret_ty.hasRuntimeBits()) {4824 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
4800 result.return_value = .{ .none = {} };4825 result.return_value = .{ .none = {} };
4801 } else switch (cc) {4826 } else switch (cc) {
4802 .Naked => unreachable,4827 .Naked => unreachable,
4803 .Unspecified, .C => {4828 .Unspecified, .C => {
4804 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));4829 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
4805 if (ret_ty_size <= 8) {4830 if (ret_ty_size == 0) {
4831 assert(ret_ty.isError());
4832 result.return_value = .{ .immediate = 0 };
4833 } else if (ret_ty_size <= 8) {
4806 result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) };4834 result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) };
4807 } else {4835 } else {
4808 return self.fail("TODO support more return types for ARM backend", .{});4836 return self.fail("TODO support more return types for ARM backend", .{});
src/arch/x86_64/CodeGen.zig+6-19
...@@ -2,6 +2,7 @@ const std = @import("std");...@@ -2,6 +2,7 @@ const std = @import("std");
2const build_options = @import("build_options");2const build_options = @import("build_options");
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const codegen = @import("../../codegen.zig");
5const leb128 = std.leb;6const leb128 = std.leb;
6const link = @import("../../link.zig");7const link = @import("../../link.zig");
7const log = std.log.scoped(.codegen);8const log = std.log.scoped(.codegen);
...@@ -12,11 +13,11 @@ const trace = @import("../../tracy.zig").trace;...@@ -12,11 +13,11 @@ const trace = @import("../../tracy.zig").trace;
12const Air = @import("../../Air.zig");13const Air = @import("../../Air.zig");
13const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
14const Compilation = @import("../../Compilation.zig");15const Compilation = @import("../../Compilation.zig");
15const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;16const DebugInfoOutput = codegen.DebugInfoOutput;
16const DW = std.dwarf;17const DW = std.dwarf;
17const ErrorMsg = Module.ErrorMsg;18const ErrorMsg = Module.ErrorMsg;
18const FnResult = @import("../../codegen.zig").FnResult;19const FnResult = codegen.FnResult;
19const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;20const GenerateSymbolError = codegen.GenerateSymbolError;
20const Emit = @import("Emit.zig");21const Emit = @import("Emit.zig");
21const Liveness = @import("../../Liveness.zig");22const Liveness = @import("../../Liveness.zig");
22const Mir = @import("Mir.zig");23const Mir = @import("Mir.zig");
...@@ -28,6 +29,8 @@ const Value = @import("../../value.zig").Value;...@@ -28,6 +29,8 @@ const Value = @import("../../value.zig").Value;
2829
29const bits = @import("bits.zig");30const bits = @import("bits.zig");
30const abi = @import("abi.zig");31const abi = @import("abi.zig");
32const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
33const errUnionErrOffset = codegen.errUnionErrOffset;
3134
32const callee_preserved_regs = abi.callee_preserved_regs;35const callee_preserved_regs = abi.callee_preserved_regs;
33const caller_preserved_regs = abi.caller_preserved_regs;36const caller_preserved_regs = abi.caller_preserved_regs;
...@@ -7183,19 +7186,3 @@ fn intrinsicsAllowed(target: Target, ty: Type) bool {...@@ -7183,19 +7186,3 @@ fn intrinsicsAllowed(target: Target, ty: Type) bool {
7183fn hasAvxSupport(target: Target) bool {7186fn hasAvxSupport(target: Target) bool {
7184 return Target.x86.featureSetHasAny(target.cpu.features, .{ .avx, .avx2 });7187 return Target.x86.featureSetHasAny(target.cpu.features, .{ .avx, .avx2 });
7185}7188}
7186
7187fn errUnionPayloadOffset(ty: Type, target: std.Target) u64 {
7188 const payload_ty = ty.errorUnionPayload();
7189 return if (Type.anyerror.abiAlignment(target) >= payload_ty.abiAlignment(target))
7190 Type.anyerror.abiSize(target)
7191 else
7192 0;
7193}
7194
7195fn errUnionErrOffset(ty: Type, target: std.Target) u64 {
7196 const payload_ty = ty.errorUnionPayload();
7197 return if (Type.anyerror.abiAlignment(target) >= payload_ty.abiAlignment(target))
7198 0
7199 else
7200 payload_ty.abiSize(target);
7201}
src/codegen.zig+16
...@@ -890,3 +890,19 @@ fn lowerDeclRef(...@@ -890,3 +890,19 @@ fn lowerDeclRef(
890890
891 return Result{ .appended = {} };891 return Result{ .appended = {} };
892}892}
893
894pub fn errUnionPayloadOffset(ty: Type, target: std.Target) u64 {
895 const payload_ty = ty.errorUnionPayload();
896 return if (Type.anyerror.abiAlignment(target) >= payload_ty.abiAlignment(target))
897 Type.anyerror.abiSize(target)
898 else
899 0;
900}
901
902pub fn errUnionErrOffset(ty: Type, target: std.Target) u64 {
903 const payload_ty = ty.errorUnionPayload();
904 return if (Type.anyerror.abiAlignment(target) >= payload_ty.abiAlignment(target))
905 0
906 else
907 payload_ty.abiSize(target);
908}
test/behavior/error.zig+2
...@@ -440,6 +440,8 @@ test "return function call to error set from error union function" {...@@ -440,6 +440,8 @@ test "return function call to error set from error union function" {
440}440}
441441
442test "optional error set is the same size as error set" {442test "optional error set is the same size as error set" {
443 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
444
443 comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror));445 comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror));
444 comptime try expect(@alignOf(?anyerror) == @alignOf(anyerror));446 comptime try expect(@alignOf(?anyerror) == @alignOf(anyerror));
445 const S = struct {447 const S = struct {