| ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); | ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); |
| 3 | const mem = std.mem; | 3 | const mem = std.mem; |
| 4 | const math = std.math; | 4 | const math = std.math; |
| 5 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| | 6 | const codegen = @import("../../codegen.zig"); |
| 6 | const Air = @import("../../Air.zig"); | 7 | const Air = @import("../../Air.zig"); |
| 7 | const Mir = @import("Mir.zig"); | 8 | const Mir = @import("Mir.zig"); |
| 8 | const Emit = @import("Emit.zig"); | 9 | const Emit = @import("Emit.zig"); |
| ... | @@ -22,12 +23,14 @@ const leb128 = std.leb; | ... | @@ -22,12 +23,14 @@ const leb128 = std.leb; |
| 22 | const log = std.log.scoped(.codegen); | 23 | const log = std.log.scoped(.codegen); |
| 23 | const build_options = @import("build_options"); | 24 | const build_options = @import("build_options"); |
| 24 | | 25 | |
| 25 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; | 26 | const GenerateSymbolError = codegen.GenerateSymbolError; |
| 26 | const FnResult = @import("../../codegen.zig").FnResult; | 27 | const FnResult = codegen.FnResult; |
| 27 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | 28 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 28 | | 29 | |
| 29 | const bits = @import("bits.zig"); | 30 | const bits = @import("bits.zig"); |
| 30 | const abi = @import("abi.zig"); | 31 | const abi = @import("abi.zig"); |
| | 32 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| | 33 | const errUnionErrOffset = codegen.errUnionErrOffset; |
| 31 | const RegisterManager = abi.RegisterManager; | 34 | const RegisterManager = abi.RegisterManager; |
| 32 | const RegisterLock = RegisterManager.RegisterLock; | 35 | const RegisterLock = RegisterManager.RegisterLock; |
| 33 | const Register = bits.Register; | 36 | const 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. |
| 3272 | | 3275 | |
| 3273 | fn ret(self: *Self, mcv: MCValue) !void { | 3276 | fn 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 later | 3286 | // 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(); |
| 3603 | | 3613 | |
| 3604 | if (!error_type.hasRuntimeBits()) { | 3614 | if (error_type.errorSetCardinality() == .zero) { |
| 3605 | return MCValue{ .immediate = 0 }; // always false | 3615 | 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 | }; | | |
| 3612 | | 3617 | |
| | 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 | }); |
| 3620 | | 3630 | }, |
| 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 | } |
| 3629 | | 3648 | |
| 3630 | fn isNonErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 3649 | fn 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 { |
| 4491 | | 4510 | |
| 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 = {} }; |
| 4496 | | 4515 | |
| 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(); |
| 4686 | | 4713 | |
| 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 | } | | |
| 4692 | | 4718 | |
| 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 | } | | |
| 4700 | | 4720 | |
| 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 { |
| 4796 | | 4821 | |
| 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", .{}); |