authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-25 03:12:34-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-25 03:12:34-04:00
log83735207850bd526807a39771432be0bc7410414
treede0b8dc27f0824f14134dbece33a088bbffa4001
parenta0775fdaa1e7427dcd6be9b19726d4996344e9fa
parent60af42705d62417c73a13481e60b0861423e77fe
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11699 from ziglang/empty-error-sets

stage2: fixes for error union semantics

14 files changed, 1553 insertions(+), 727 deletions(-)

lib/std/debug.zig+1-1
...@@ -1798,7 +1798,7 @@ fn resetSegfaultHandler() void {...@@ -1798,7 +1798,7 @@ fn resetSegfaultHandler() void {
1798 .mask = os.empty_sigset,1798 .mask = os.empty_sigset,
1799 .flags = 0,1799 .flags = 0,
1800 };1800 };
1801 // do nothing if an error happens to avoid a double-panic1801 // To avoid a double-panic, do nothing if an error happens here.
1802 updateSegfaultHandler(&act) catch {};1802 updateSegfaultHandler(&act) catch {};
1803}1803}
18041804
src/Sema.zig+87-16
...@@ -5899,12 +5899,22 @@ fn zirErrorToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -5899,12 +5899,22 @@ fn zirErrorToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
5899 if (val.isUndef()) {5899 if (val.isUndef()) {
5900 return sema.addConstUndef(result_ty);5900 return sema.addConstUndef(result_ty);
5901 }5901 }
5902 const payload = try sema.arena.create(Value.Payload.U64);5902 switch (val.tag()) {
5903 payload.* = .{5903 .@"error" => {
5904 .base = .{ .tag = .int_u64 },5904 const payload = try sema.arena.create(Value.Payload.U64);
5905 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,5905 payload.* = .{
5906 };5906 .base = .{ .tag = .int_u64 },
5907 return sema.addConstant(result_ty, Value.initPayload(&payload.base));5907 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
5908 };
5909 return sema.addConstant(result_ty, Value.initPayload(&payload.base));
5910 },
5911
5912 // This is not a valid combination with the type `anyerror`.
5913 .the_only_possible_value => unreachable,
5914
5915 // Assume it's already encoded as an integer.
5916 else => return sema.addConstant(result_ty, val),
5917 }
5908 }5918 }
59095919
5910 try sema.requireRuntimeBlock(block, src);5920 try sema.requireRuntimeBlock(block, src);
...@@ -6261,19 +6271,24 @@ fn zirErrUnionPayload(...@@ -6261,19 +6271,24 @@ fn zirErrUnionPayload(
6261 });6271 });
6262 }6272 }
62636273
6274 const result_ty = operand_ty.errorUnionPayload();
6264 if (try sema.resolveDefinedValue(block, src, operand)) |val| {6275 if (try sema.resolveDefinedValue(block, src, operand)) |val| {
6265 if (val.getError()) |name| {6276 if (val.getError()) |name| {
6266 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});6277 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
6267 }6278 }
6268 const data = val.castTag(.eu_payload).?.data;6279 const data = val.castTag(.eu_payload).?.data;
6269 const result_ty = operand_ty.errorUnionPayload();
6270 return sema.addConstant(result_ty, data);6280 return sema.addConstant(result_ty, data);
6271 }6281 }
6282
6272 try sema.requireRuntimeBlock(block, src);6283 try sema.requireRuntimeBlock(block, src);
6273 if (safety_check and block.wantSafety()) {6284
6285 // If the error set has no fields then no safety check is needed.
6286 if (safety_check and block.wantSafety() and
6287 operand_ty.errorUnionSet().errorSetCardinality() != .zero)
6288 {
6274 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);6289 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);
6275 }6290 }
6276 const result_ty = operand_ty.errorUnionPayload();6291
6277 return block.addTyOp(.unwrap_errunion_payload, result_ty, operand);6292 return block.addTyOp(.unwrap_errunion_payload, result_ty, operand);
6278}6293}
62796294
...@@ -6311,7 +6326,8 @@ fn analyzeErrUnionPayloadPtr(...@@ -6311,7 +6326,8 @@ fn analyzeErrUnionPayloadPtr(
6311 });6326 });
6312 }6327 }
63136328
6314 const payload_ty = operand_ty.elemType().errorUnionPayload();6329 const err_union_ty = operand_ty.elemType();
6330 const payload_ty = err_union_ty.errorUnionPayload();
6315 const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{6331 const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{
6316 .pointee_type = payload_ty,6332 .pointee_type = payload_ty,
6317 .mutable = !operand_ty.isConstPtr(),6333 .mutable = !operand_ty.isConstPtr(),
...@@ -6351,9 +6367,14 @@ fn analyzeErrUnionPayloadPtr(...@@ -6351,9 +6367,14 @@ fn analyzeErrUnionPayloadPtr(
6351 }6367 }
63526368
6353 try sema.requireRuntimeBlock(block, src);6369 try sema.requireRuntimeBlock(block, src);
6354 if (safety_check and block.wantSafety()) {6370
6371 // If the error set has no fields then no safety check is needed.
6372 if (safety_check and block.wantSafety() and
6373 err_union_ty.errorUnionSet().errorSetCardinality() != .zero)
6374 {
6355 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);6375 try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
6356 }6376 }
6377
6357 const air_tag: Air.Inst.Tag = if (initializing)6378 const air_tag: Air.Inst.Tag = if (initializing)
6358 .errunion_payload_ptr_set6379 .errunion_payload_ptr_set
6359 else6380 else
...@@ -20929,6 +20950,11 @@ fn analyzeLoad(...@@ -20929,6 +20950,11 @@ fn analyzeLoad(
20929 .Pointer => ptr_ty.childType(),20950 .Pointer => ptr_ty.childType(),
20930 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}),20951 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}),
20931 };20952 };
20953
20954 if (try sema.typeHasOnePossibleValue(block, src, elem_ty)) |opv| {
20955 return sema.addConstant(elem_ty, opv);
20956 }
20957
20932 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {20958 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
20933 if (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) |elem_val| {20959 if (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) |elem_val| {
20934 return sema.addConstant(elem_ty, elem_val);20960 return sema.addConstant(elem_ty, elem_val);
...@@ -23295,16 +23321,11 @@ pub fn typeHasOnePossibleValue(...@@ -23295,16 +23321,11 @@ pub fn typeHasOnePossibleValue(
23295 .const_slice,23321 .const_slice,
23296 .mut_slice,23322 .mut_slice,
23297 .anyopaque,23323 .anyopaque,
23298 .optional,
23299 .optional_single_mut_pointer,23324 .optional_single_mut_pointer,
23300 .optional_single_const_pointer,23325 .optional_single_const_pointer,
23301 .enum_literal,23326 .enum_literal,
23302 .anyerror_void_error_union,23327 .anyerror_void_error_union,
23303 .error_union,
23304 .error_set,
23305 .error_set_single,
23306 .error_set_inferred,23328 .error_set_inferred,
23307 .error_set_merged,
23308 .@"opaque",23329 .@"opaque",
23309 .var_args_param,23330 .var_args_param,
23310 .manyptr_u8,23331 .manyptr_u8,
...@@ -23333,6 +23354,56 @@ pub fn typeHasOnePossibleValue(...@@ -23333,6 +23354,56 @@ pub fn typeHasOnePossibleValue(
23333 .bound_fn,23354 .bound_fn,
23334 => return null,23355 => return null,
2333523356
23357 .optional => {
23358 var buf: Type.Payload.ElemType = undefined;
23359 const child_ty = ty.optionalChild(&buf);
23360 if (child_ty.isNoReturn()) {
23361 return Value.@"null";
23362 } else {
23363 return null;
23364 }
23365 },
23366
23367 .error_union => {
23368 const error_ty = ty.errorUnionSet();
23369 switch (error_ty.errorSetCardinality()) {
23370 .zero => {
23371 const payload_ty = ty.errorUnionPayload();
23372 if (try typeHasOnePossibleValue(sema, block, src, payload_ty)) |payload_val| {
23373 return try Value.Tag.eu_payload.create(sema.arena, payload_val);
23374 } else {
23375 return null;
23376 }
23377 },
23378 .one => {
23379 if (ty.errorUnionPayload().isNoReturn()) {
23380 const error_val = (try typeHasOnePossibleValue(sema, block, src, error_ty)).?;
23381 return error_val;
23382 } else {
23383 return null;
23384 }
23385 },
23386 .many => return null,
23387 }
23388 },
23389
23390 .error_set_single => {
23391 const name = ty.castTag(.error_set_single).?.data;
23392 return try Value.Tag.@"error".create(sema.arena, .{ .name = name });
23393 },
23394 .error_set => {
23395 const err_set_obj = ty.castTag(.error_set).?.data;
23396 const names = err_set_obj.names.keys();
23397 if (names.len > 1) return null;
23398 return try Value.Tag.@"error".create(sema.arena, .{ .name = names[0] });
23399 },
23400 .error_set_merged => {
23401 const name_map = ty.castTag(.error_set_merged).?.data;
23402 const names = name_map.keys();
23403 if (names.len > 1) return null;
23404 return try Value.Tag.@"error".create(sema.arena, .{ .name = names[0] });
23405 },
23406
23336 .@"struct" => {23407 .@"struct" => {
23337 const resolved_ty = try sema.resolveTypeFields(block, src, ty);23408 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
23338 const s = resolved_ty.castTag(.@"struct").?.data;23409 const s = resolved_ty.castTag(.@"struct").?.data;
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 errUnionErrorOffset = codegen.errUnionErrorOffset;
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 = errUnionErrorOffset(payload_type, 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/arm/CodeGen.zig+64-37
...@@ -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 FnResult = @import("../../codegen.zig").FnResult;26const FnResult = codegen.FnResult;
26const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;27const GenerateSymbolError = codegen.GenerateSymbolError;
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 errUnionErrorOffset = codegen.errUnionErrorOffset;
31const RegisterManager = abi.RegisterManager;34const RegisterManager = abi.RegisterManager;
32const RegisterLock = RegisterManager.RegisterLock;35const RegisterLock = RegisterManager.RegisterLock;
33const Register = bits.Register;36const Register = bits.Register;
...@@ -1763,19 +1766,26 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {...@@ -1763,19 +1766,26 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
17631766
1764/// Given an error union, returns the error1767/// Given an error union, returns the error
1765fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {1768fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1769 const err_ty = error_union_ty.errorUnionSet();
1766 const payload_ty = error_union_ty.errorUnionPayload();1770 const payload_ty = error_union_ty.errorUnionPayload();
1767 if (!payload_ty.hasRuntimeBits()) return error_union_mcv;1771 if (err_ty.errorSetCardinality() == .zero) {
1772 return MCValue{ .immediate = 0 };
1773 }
1774 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1775 return error_union_mcv;
1776 }
17681777
1778 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
1769 switch (error_union_mcv) {1779 switch (error_union_mcv) {
1770 .register => return self.fail("TODO errUnionErr for registers", .{}),1780 .register => return self.fail("TODO errUnionErr for registers", .{}),
1771 .stack_argument_offset => |off| {1781 .stack_argument_offset => |off| {
1772 return MCValue{ .stack_argument_offset = off };1782 return MCValue{ .stack_argument_offset = off - err_offset };
1773 },1783 },
1774 .stack_offset => |off| {1784 .stack_offset => |off| {
1775 return MCValue{ .stack_offset = off };1785 return MCValue{ .stack_offset = off - err_offset };
1776 },1786 },
1777 .memory => |addr| {1787 .memory => |addr| {
1778 return MCValue{ .memory = addr };1788 return MCValue{ .memory = addr + err_offset };
1779 },1789 },
1780 else => unreachable, // invalid MCValue for an error union1790 else => unreachable, // invalid MCValue for an error union
1781 }1791 }
...@@ -1793,24 +1803,26 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1793,24 +1803,26 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
17931803
1794/// Given an error union, returns the payload1804/// Given an error union, returns the payload
1795fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {1805fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
1806 const err_ty = error_union_ty.errorUnionSet();
1796 const payload_ty = error_union_ty.errorUnionPayload();1807 const payload_ty = error_union_ty.errorUnionPayload();
1797 if (!payload_ty.hasRuntimeBits()) return MCValue.none;1808 if (err_ty.errorSetCardinality() == .zero) {
17981809 return error_union_mcv;
1799 const error_ty = error_union_ty.errorUnionSet();1810 }
1800 const error_size = @intCast(u32, error_ty.abiSize(self.target.*));1811 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1801 const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*));1812 return MCValue.none;
1802 const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align);1813 }
18031814
1815 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
1804 switch (error_union_mcv) {1816 switch (error_union_mcv) {
1805 .register => return self.fail("TODO errUnionPayload for registers", .{}),1817 .register => return self.fail("TODO errUnionPayload for registers", .{}),
1806 .stack_argument_offset => |off| {1818 .stack_argument_offset => |off| {
1807 return MCValue{ .stack_argument_offset = off - offset };1819 return MCValue{ .stack_argument_offset = off - payload_offset };
1808 },1820 },
1809 .stack_offset => |off| {1821 .stack_offset => |off| {
1810 return MCValue{ .stack_offset = off - offset };1822 return MCValue{ .stack_offset = off - payload_offset };
1811 },1823 },
1812 .memory => |addr| {1824 .memory => |addr| {
1813 return MCValue{ .memory = addr - offset };1825 return MCValue{ .memory = addr + payload_offset };
1814 },1826 },
1815 else => unreachable, // invalid MCValue for an error union1827 else => unreachable, // invalid MCValue for an error union
1816 }1828 }
...@@ -3478,6 +3490,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -3478,6 +3490,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
34783490
3479 switch (self.ret_mcv) {3491 switch (self.ret_mcv) {
3480 .none => {},3492 .none => {},
3493 .immediate => {
3494 assert(ret_ty.isError());
3495 },
3481 .register => |reg| {3496 .register => |reg| {
3482 // Return result by value3497 // Return result by value
3483 try self.genSetReg(ret_ty, reg, operand);3498 try self.genSetReg(ret_ty, reg, operand);
...@@ -3867,7 +3882,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -3867,7 +3882,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3867 const error_type = ty.errorUnionSet();3882 const error_type = ty.errorUnionSet();
3868 const error_int_type = Type.initTag(.u16);3883 const error_int_type = Type.initTag(.u16);
38693884
3870 if (!error_type.hasRuntimeBits()) {3885 if (error_type.errorSetCardinality() == .zero) {
3871 return MCValue{ .immediate = 0 }; // always false3886 return MCValue{ .immediate = 0 }; // always false
3872 }3887 }
38733888
...@@ -4975,7 +4990,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -4975,7 +4990,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
4975 const ref_int = @enumToInt(inst);4990 const ref_int = @enumToInt(inst);
4976 if (ref_int < Air.Inst.Ref.typed_value_map.len) {4991 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
4977 const tv = Air.Inst.Ref.typed_value_map[ref_int];4992 const tv = Air.Inst.Ref.typed_value_map[ref_int];
4978 if (!tv.ty.hasRuntimeBits()) {4993 if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) {
4979 return MCValue{ .none = {} };4994 return MCValue{ .none = {} };
4980 }4995 }
4981 return self.genTypedValue(tv);4996 return self.genTypedValue(tv);
...@@ -4983,7 +4998,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -4983,7 +4998,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
49834998
4984 // If the type has no codegen bits, no need to store it.4999 // If the type has no codegen bits, no need to store it.
4985 const inst_ty = self.air.typeOf(inst);5000 const inst_ty = self.air.typeOf(inst);
4986 if (!inst_ty.hasRuntimeBits())5001 if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError())
4987 return MCValue{ .none = {} };5002 return MCValue{ .none = {} };
49885003
4989 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);5004 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
...@@ -5147,26 +5162,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -5147,26 +5162,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
5147 }5162 }
5148 },5163 },
5149 .ErrorSet => {5164 .ErrorSet => {
5150 const err_name = typed_value.val.castTag(.@"error").?.data.name;5165 switch (typed_value.val.tag()) {
5151 const module = self.bin_file.options.module.?;5166 .@"error" => {
5152 const global_error_set = module.global_error_set;5167 const err_name = typed_value.val.castTag(.@"error").?.data.name;
5153 const error_index = global_error_set.get(err_name).?;5168 const module = self.bin_file.options.module.?;
5154 return MCValue{ .immediate = error_index };5169 const global_error_set = module.global_error_set;
5170 const error_index = global_error_set.get(err_name).?;
5171 return MCValue{ .immediate = error_index };
5172 },
5173 else => {
5174 // In this case we are rendering an error union which has a 0 bits payload.
5175 return MCValue{ .immediate = 0 };
5176 },
5177 }
5155 },5178 },
5156 .ErrorUnion => {5179 .ErrorUnion => {
5157 const error_type = typed_value.ty.errorUnionSet();5180 const error_type = typed_value.ty.errorUnionSet();
5158 const payload_type = typed_value.ty.errorUnionPayload();5181 const payload_type = typed_value.ty.errorUnionPayload();
51595182
5160 if (typed_value.val.castTag(.eu_payload)) |_| {5183 if (error_type.errorSetCardinality() == .zero) {
5161 if (!payload_type.hasRuntimeBits()) {5184 const payload_val = typed_value.val.castTag(.eu_payload).?.data;
5162 // We use the error type directly as the type.5185 return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
5163 return MCValue{ .immediate = 0 };5186 }
5164 }5187
5165 } else {5188 const is_pl = typed_value.val.errorUnionIsPayload();
5166 if (!payload_type.hasRuntimeBits()) {5189
5167 // We use the error type directly as the type.5190 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
5168 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });5191 // We use the error type directly as the type.
5169 }5192 const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero);
5193 return self.genTypedValue(.{ .ty = error_type, .val = err_val });
5170 }5194 }
5171 },5195 },
51725196
...@@ -5231,7 +5255,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -5231,7 +5255,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
52315255
5232 if (ret_ty.zigTypeTag() == .NoReturn) {5256 if (ret_ty.zigTypeTag() == .NoReturn) {
5233 result.return_value = .{ .unreach = {} };5257 result.return_value = .{ .unreach = {} };
5234 } else if (!ret_ty.hasRuntimeBits()) {5258 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
5235 result.return_value = .{ .none = {} };5259 result.return_value = .{ .none = {} };
5236 } else {5260 } else {
5237 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));5261 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
...@@ -5278,11 +5302,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -5278,11 +5302,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
5278 .Unspecified => {5302 .Unspecified => {
5279 if (ret_ty.zigTypeTag() == .NoReturn) {5303 if (ret_ty.zigTypeTag() == .NoReturn) {
5280 result.return_value = .{ .unreach = {} };5304 result.return_value = .{ .unreach = {} };
5281 } else if (!ret_ty.hasRuntimeBits()) {5305 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
5282 result.return_value = .{ .none = {} };5306 result.return_value = .{ .none = {} };
5283 } else {5307 } else {
5284 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));5308 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
5285 if (ret_ty_size <= 4) {5309 if (ret_ty_size == 0) {
5310 assert(ret_ty.isError());
5311 result.return_value = .{ .immediate = 0 };
5312 } else if (ret_ty_size <= 4) {
5286 result.return_value = .{ .register = .r0 };5313 result.return_value = .{ .register = .r0 };
5287 } else {5314 } else {
5288 // The result is returned by reference, not by5315 // The result is returned by reference, not by
src/arch/wasm/CodeGen.zig+110-59
...@@ -22,6 +22,8 @@ const Liveness = @import("../../Liveness.zig");...@@ -22,6 +22,8 @@ const Liveness = @import("../../Liveness.zig");
22const Mir = @import("Mir.zig");22const Mir = @import("Mir.zig");
23const Emit = @import("Emit.zig");23const Emit = @import("Emit.zig");
24const abi = @import("abi.zig");24const abi = @import("abi.zig");
25const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
26const errUnionErrorOffset = codegen.errUnionErrorOffset;
2527
26/// Wasm Value, created when generating an instruction28/// Wasm Value, created when generating an instruction
27const WValue = union(enum) {29const WValue = union(enum) {
...@@ -636,7 +638,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {...@@ -636,7 +638,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
636 // means we must generate it from a constant.638 // means we must generate it from a constant.
637 const val = self.air.value(ref).?;639 const val = self.air.value(ref).?;
638 const ty = self.air.typeOf(ref);640 const ty = self.air.typeOf(ref);
639 if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt()) {641 if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt() and !ty.isError()) {
640 gop.value_ptr.* = WValue{ .none = {} };642 gop.value_ptr.* = WValue{ .none = {} };
641 return gop.value_ptr.*;643 return gop.value_ptr.*;
642 }644 }
...@@ -804,6 +806,8 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std....@@ -804,6 +806,8 @@ fn genFunctype(gpa: Allocator, fn_info: Type.Payload.Function.Data, target: std.
804 } else {806 } else {
805 try returns.append(typeToValtype(fn_info.return_type, target));807 try returns.append(typeToValtype(fn_info.return_type, target));
806 }808 }
809 } else if (fn_info.return_type.isError()) {
810 try returns.append(.i32);
807 }811 }
808812
809 // param types813 // param types
...@@ -1373,13 +1377,18 @@ fn isByRef(ty: Type, target: std.Target) bool {...@@ -1373,13 +1377,18 @@ fn isByRef(ty: Type, target: std.Target) bool {
1373 .Int => return ty.intInfo(target).bits > 64,1377 .Int => return ty.intInfo(target).bits > 64,
1374 .Float => return ty.floatBits(target) > 64,1378 .Float => return ty.floatBits(target) > 64,
1375 .ErrorUnion => {1379 .ErrorUnion => {
1376 const has_tag = ty.errorUnionSet().hasRuntimeBitsIgnoreComptime();1380 const err_ty = ty.errorUnionSet();
1377 const has_pl = ty.errorUnionPayload().hasRuntimeBitsIgnoreComptime();1381 const pl_ty = ty.errorUnionPayload();
1378 if (!has_tag or !has_pl) return false;1382 if (err_ty.errorSetCardinality() == .zero) {
1379 return ty.hasRuntimeBitsIgnoreComptime();1383 return isByRef(pl_ty, target);
1384 }
1385 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
1386 return false;
1387 }
1388 return true;
1380 },1389 },
1381 .Optional => {1390 .Optional => {
1382 if (ty.isPtrLikeOptional()) return false;1391 if (ty.optionalReprIsPayload()) return false;
1383 var buf: Type.Payload.ElemType = undefined;1392 var buf: Type.Payload.ElemType = undefined;
1384 return ty.optionalChild(&buf).hasRuntimeBitsIgnoreComptime();1393 return ty.optionalChild(&buf).hasRuntimeBitsIgnoreComptime();
1385 },1394 },
...@@ -1624,13 +1633,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -1624,13 +1633,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1624fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1633fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1625 const un_op = self.air.instructions.items(.data)[inst].un_op;1634 const un_op = self.air.instructions.items(.data)[inst].un_op;
1626 const operand = try self.resolveInst(un_op);1635 const operand = try self.resolveInst(un_op);
1627 const ret_ty = self.decl.ty.fnReturnType();1636 const fn_info = self.decl.ty.fnInfo();
1637 const ret_ty = fn_info.return_type;
16281638
1629 // result must be stored in the stack and we return a pointer1639 // result must be stored in the stack and we return a pointer
1630 // to the stack instead1640 // to the stack instead
1631 if (self.return_value != .none) {1641 if (self.return_value != .none) {
1632 try self.store(self.return_value, operand, self.decl.ty.fnReturnType(), 0);1642 try self.store(self.return_value, operand, ret_ty, 0);
1633 } else if (self.decl.ty.fnInfo().cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) {1643 } else if (fn_info.cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) {
1634 switch (ret_ty.zigTypeTag()) {1644 switch (ret_ty.zigTypeTag()) {
1635 // Aggregate types can be lowered as a singular value1645 // Aggregate types can be lowered as a singular value
1636 .Struct, .Union => {1646 .Struct, .Union => {
...@@ -1650,7 +1660,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1650,7 +1660,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1650 else => try self.emitWValue(operand),1660 else => try self.emitWValue(operand),
1651 }1661 }
1652 } else {1662 } else {
1653 try self.emitWValue(operand);1663 if (!ret_ty.hasRuntimeBitsIgnoreComptime() and ret_ty.isError()) {
1664 try self.addImm32(0);
1665 } else {
1666 try self.emitWValue(operand);
1667 }
1654 }1668 }
1655 try self.restoreStackPointer();1669 try self.restoreStackPointer();
1656 try self.addTag(.@"return");1670 try self.addTag(.@"return");
...@@ -1675,7 +1689,13 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1675,7 +1689,13 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1675 const un_op = self.air.instructions.items(.data)[inst].un_op;1689 const un_op = self.air.instructions.items(.data)[inst].un_op;
1676 const operand = try self.resolveInst(un_op);1690 const operand = try self.resolveInst(un_op);
1677 const ret_ty = self.air.typeOf(un_op).childType();1691 const ret_ty = self.air.typeOf(un_op).childType();
1678 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) return WValue.none;1692 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
1693 if (ret_ty.isError()) {
1694 try self.addImm32(0);
1695 } else {
1696 return WValue.none;
1697 }
1698 }
16791699
1680 if (!firstParamSRet(self.decl.ty.fnInfo(), self.target)) {1700 if (!firstParamSRet(self.decl.ty.fnInfo(), self.target)) {
1681 const result = try self.load(operand, ret_ty, 0);1701 const result = try self.load(operand, ret_ty, 0);
...@@ -1723,8 +1743,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1723,8 +1743,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
17231743
1724 const sret = if (first_param_sret) blk: {1744 const sret = if (first_param_sret) blk: {
1725 const sret_local = try self.allocStack(ret_ty);1745 const sret_local = try self.allocStack(ret_ty);
1726 const ptr_offset = try self.buildPointerOffset(sret_local, 0, .new);1746 try self.lowerToStack(sret_local);
1727 try self.emitWValue(ptr_offset);
1728 break :blk sret_local;1747 break :blk sret_local;
1729 } else WValue{ .none = {} };1748 } else WValue{ .none = {} };
17301749
...@@ -1754,7 +1773,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1754,7 +1773,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1754 try self.addLabel(.call_indirect, fn_type_index);1773 try self.addLabel(.call_indirect, fn_type_index);
1755 }1774 }
17561775
1757 if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBitsIgnoreComptime()) {1776 if (self.liveness.isUnused(inst) or (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError())) {
1758 return WValue.none;1777 return WValue.none;
1759 } else if (ret_ty.isNoReturn()) {1778 } else if (ret_ty.isNoReturn()) {
1760 try self.addTag(.@"unreachable");1779 try self.addTag(.@"unreachable");
...@@ -1796,8 +1815,11 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1796,8 +1815,11 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1796 .ErrorUnion => {1815 .ErrorUnion => {
1797 const err_ty = ty.errorUnionSet();1816 const err_ty = ty.errorUnionSet();
1798 const pl_ty = ty.errorUnionPayload();1817 const pl_ty = ty.errorUnionPayload();
1818 if (err_ty.errorSetCardinality() == .zero) {
1819 return self.store(lhs, rhs, pl_ty, 0);
1820 }
1799 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {1821 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
1800 return self.store(lhs, rhs, err_ty, 0);1822 return self.store(lhs, rhs, Type.anyerror, 0);
1801 }1823 }
18021824
1803 const len = @intCast(u32, ty.abiSize(self.target));1825 const len = @intCast(u32, ty.abiSize(self.target));
...@@ -1812,6 +1834,9 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1812,6 +1834,9 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1812 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {1834 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
1813 return self.store(lhs, rhs, Type.u8, 0);1835 return self.store(lhs, rhs, Type.u8, 0);
1814 }1836 }
1837 if (pl_ty.zigTypeTag() == .ErrorSet) {
1838 return self.store(lhs, rhs, Type.anyerror, 0);
1839 }
18151840
1816 const len = @intCast(u32, ty.abiSize(self.target));1841 const len = @intCast(u32, ty.abiSize(self.target));
1817 return self.memcpy(lhs, rhs, .{ .imm32 = len });1842 return self.memcpy(lhs, rhs, .{ .imm32 = len });
...@@ -2178,7 +2203,7 @@ fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WV...@@ -2178,7 +2203,7 @@ fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WV
2178 const parent_ptr = try self.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);2203 const parent_ptr = try self.lowerParentPtr(payload_ptr.container_ptr, payload_ptr.container_ty);
2179 var buf: Type.Payload.ElemType = undefined;2204 var buf: Type.Payload.ElemType = undefined;
2180 const payload_ty = payload_ptr.container_ty.optionalChild(&buf);2205 const payload_ty = payload_ptr.container_ty.optionalChild(&buf);
2181 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.isPtrLikeOptional()) {2206 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.optionalReprIsPayload()) {
2182 return parent_ptr;2207 return parent_ptr;
2183 }2208 }
21842209
...@@ -2256,6 +2281,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2256,6 +2281,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2256 const target = self.target;2281 const target = self.target;
22572282
2258 switch (ty.zigTypeTag()) {2283 switch (ty.zigTypeTag()) {
2284 .Void => return WValue{ .none = {} },
2259 .Int => {2285 .Int => {
2260 const int_info = ty.intInfo(self.target);2286 const int_info = ty.intInfo(self.target);
2261 switch (int_info.signedness) {2287 switch (int_info.signedness) {
...@@ -2324,11 +2350,15 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2324,11 +2350,15 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2324 },2350 },
2325 .ErrorUnion => {2351 .ErrorUnion => {
2326 const error_type = ty.errorUnionSet();2352 const error_type = ty.errorUnionSet();
2353 if (error_type.errorSetCardinality() == .zero) {
2354 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
2355 return self.lowerConstant(pl_val, ty.errorUnionPayload());
2356 }
2327 const is_pl = val.errorUnionIsPayload();2357 const is_pl = val.errorUnionIsPayload();
2328 const err_val = if (!is_pl) val else Value.initTag(.zero);2358 const err_val = if (!is_pl) val else Value.initTag(.zero);
2329 return self.lowerConstant(err_val, error_type);2359 return self.lowerConstant(err_val, error_type);
2330 },2360 },
2331 .Optional => if (ty.isPtrLikeOptional()) {2361 .Optional => if (ty.optionalReprIsPayload()) {
2332 var buf: Type.Payload.ElemType = undefined;2362 var buf: Type.Payload.ElemType = undefined;
2333 const pl_ty = ty.optionalChild(&buf);2363 const pl_ty = ty.optionalChild(&buf);
2334 if (val.castTag(.opt_payload)) |payload| {2364 if (val.castTag(.opt_payload)) |payload| {
...@@ -2367,7 +2397,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {...@@ -2367,7 +2397,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
2367 .Optional => {2397 .Optional => {
2368 var buf: Type.Payload.ElemType = undefined;2398 var buf: Type.Payload.ElemType = undefined;
2369 const pl_ty = ty.optionalChild(&buf);2399 const pl_ty = ty.optionalChild(&buf);
2370 if (ty.isPtrLikeOptional()) {2400 if (ty.optionalReprIsPayload()) {
2371 return self.emitUndefined(pl_ty);2401 return self.emitUndefined(pl_ty);
2372 }2402 }
2373 return WValue{ .imm32 = 0xaaaaaaaa };2403 return WValue{ .imm32 = 0xaaaaaaaa };
...@@ -2517,7 +2547,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2517,7 +2547,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2517}2547}
25182548
2519fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {2549fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {
2520 if (ty.zigTypeTag() == .Optional and !ty.isPtrLikeOptional()) {2550 if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) {
2521 var buf: Type.Payload.ElemType = undefined;2551 var buf: Type.Payload.ElemType = undefined;
2522 const payload_ty = ty.optionalChild(&buf);2552 const payload_ty = ty.optionalChild(&buf);
2523 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {2553 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
...@@ -2889,15 +2919,22 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2889,15 +2919,22 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2889fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {2919fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {
2890 const un_op = self.air.instructions.items(.data)[inst].un_op;2920 const un_op = self.air.instructions.items(.data)[inst].un_op;
2891 const operand = try self.resolveInst(un_op);2921 const operand = try self.resolveInst(un_op);
2892 const err_ty = self.air.typeOf(un_op);2922 const err_union_ty = self.air.typeOf(un_op);
2893 const pl_ty = err_ty.errorUnionPayload();2923 const pl_ty = err_union_ty.errorUnionPayload();
2924
2925 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
2926 switch (opcode) {
2927 .i32_ne => return WValue{ .imm32 = 0 },
2928 .i32_eq => return WValue{ .imm32 = 1 },
2929 else => unreachable,
2930 }
2931 }
28942932
2895 // load the error tag value
2896 try self.emitWValue(operand);2933 try self.emitWValue(operand);
2897 if (pl_ty.hasRuntimeBitsIgnoreComptime()) {2934 if (pl_ty.hasRuntimeBitsIgnoreComptime()) {
2898 try self.addMemArg(.i32_load16_u, .{2935 try self.addMemArg(.i32_load16_u, .{
2899 .offset = operand.offset(),2936 .offset = operand.offset() + @intCast(u32, errUnionErrorOffset(pl_ty, self.target)),
2900 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),2937 .alignment = Type.anyerror.abiAlignment(self.target),
2901 });2938 });
2902 }2939 }
29032940
...@@ -2905,7 +2942,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W...@@ -2905,7 +2942,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
2905 try self.addImm32(0);2942 try self.addImm32(0);
2906 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));2943 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
29072944
2908 const is_err_tmp = try self.allocLocal(Type.initTag(.i32)); // result is always an i322945 const is_err_tmp = try self.allocLocal(Type.i32);
2909 try self.addLabel(.local_set, is_err_tmp.local);2946 try self.addLabel(.local_set, is_err_tmp.local);
2910 return is_err_tmp;2947 return is_err_tmp;
2911}2948}
...@@ -2917,14 +2954,18 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)...@@ -2917,14 +2954,18 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)
2917 const op_ty = self.air.typeOf(ty_op.operand);2954 const op_ty = self.air.typeOf(ty_op.operand);
2918 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;2955 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;
2919 const payload_ty = err_ty.errorUnionPayload();2956 const payload_ty = err_ty.errorUnionPayload();
2957
2958 if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
2959 return operand;
2960 }
2961
2920 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };2962 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
2921 const err_align = err_ty.abiAlignment(self.target);2963
2922 const set_size = err_ty.errorUnionSet().abiSize(self.target);2964 const pl_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target));
2923 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
2924 if (op_is_ptr or isByRef(payload_ty, self.target)) {2965 if (op_is_ptr or isByRef(payload_ty, self.target)) {
2925 return self.buildPointerOffset(operand, offset, .new);2966 return self.buildPointerOffset(operand, pl_offset, .new);
2926 }2967 }
2927 return self.load(operand, payload_ty, @intCast(u32, offset));2968 return self.load(operand, payload_ty, pl_offset);
2928}2969}
29292970
2930fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue {2971fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue {
...@@ -2935,11 +2976,16 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In...@@ -2935,11 +2976,16 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In
2935 const op_ty = self.air.typeOf(ty_op.operand);2976 const op_ty = self.air.typeOf(ty_op.operand);
2936 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;2977 const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;
2937 const payload_ty = err_ty.errorUnionPayload();2978 const payload_ty = err_ty.errorUnionPayload();
2979
2980 if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
2981 return WValue{ .imm32 = 0 };
2982 }
2983
2938 if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime()) {2984 if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime()) {
2939 return operand;2985 return operand;
2940 }2986 }
29412987
2942 return self.load(operand, err_ty.errorUnionSet(), 0);2988 return self.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, self.target)));
2943}2989}
29442990
2945fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2991fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -2947,22 +2993,26 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2947,22 +2993,26 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29472993
2948 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2994 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2949 const operand = try self.resolveInst(ty_op.operand);2995 const operand = try self.resolveInst(ty_op.operand);
2996 const err_ty = self.air.typeOfIndex(inst);
29502997
2951 const op_ty = self.air.typeOf(ty_op.operand);2998 if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
2952 if (!op_ty.hasRuntimeBitsIgnoreComptime()) return operand;2999 return operand;
2953 const err_union_ty = self.air.getRefType(ty_op.ty);3000 }
2954 const err_align = err_union_ty.abiAlignment(self.target);
2955 const set_size = err_union_ty.errorUnionSet().abiSize(self.target);
2956 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
29573001
2958 const err_union = try self.allocStack(err_union_ty);3002 const pl_ty = self.air.typeOf(ty_op.operand);
2959 const payload_ptr = try self.buildPointerOffset(err_union, offset, .new);3003 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
2960 try self.store(payload_ptr, operand, op_ty, 0);3004 return operand;
3005 }
3006
3007 const err_union = try self.allocStack(err_ty);
3008 const payload_ptr = try self.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, self.target)), .new);
3009 try self.store(payload_ptr, operand, pl_ty, 0);
29613010
2962 // ensure we also write '0' to the error part, so any present stack value gets overwritten by it.3011 // ensure we also write '0' to the error part, so any present stack value gets overwritten by it.
2963 try self.emitWValue(err_union);3012 try self.emitWValue(err_union);
2964 try self.addImm32(0);3013 try self.addImm32(0);
2965 try self.addMemArg(.i32_store16, .{ .offset = err_union.offset(), .alignment = 2 });3014 const err_val_offset = @intCast(u32, errUnionErrorOffset(pl_ty, self.target));
3015 try self.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 });
29663016
2967 return err_union;3017 return err_union;
2968}3018}
...@@ -2973,17 +3023,18 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2973,17 +3023,18 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2973 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3023 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2974 const operand = try self.resolveInst(ty_op.operand);3024 const operand = try self.resolveInst(ty_op.operand);
2975 const err_ty = self.air.getRefType(ty_op.ty);3025 const err_ty = self.air.getRefType(ty_op.ty);
3026 const pl_ty = err_ty.errorUnionPayload();
29763027
2977 if (!err_ty.errorUnionPayload().hasRuntimeBitsIgnoreComptime()) return operand;3028 if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
3029 return operand;
3030 }
29783031
2979 const err_union = try self.allocStack(err_ty);3032 const err_union = try self.allocStack(err_ty);
2980 try self.store(err_union, operand, err_ty.errorUnionSet(), 0);3033 // store error value
3034 try self.store(err_union, operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(pl_ty, self.target)));
29813035
2982 // write 'undefined' to the payload3036 // write 'undefined' to the payload
2983 const err_align = err_ty.abiAlignment(self.target);3037 const payload_ptr = try self.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, self.target)), .new);
2984 const set_size = err_ty.errorUnionSet().abiSize(self.target);
2985 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
2986 const payload_ptr = try self.buildPointerOffset(err_union, offset, .new);
2987 const len = @intCast(u32, err_ty.errorUnionPayload().abiSize(self.target));3038 const len = @intCast(u32, err_ty.errorUnionPayload().abiSize(self.target));
2988 try self.memset(payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaaaaaaaa });3039 try self.memset(payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaaaaaaaa });
29893040
...@@ -3074,7 +3125,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en...@@ -3074,7 +3125,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en
30743125
3075fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {3126fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
3076 try self.emitWValue(operand);3127 try self.emitWValue(operand);
3077 if (!optional_ty.isPtrLikeOptional()) {3128 if (!optional_ty.optionalReprIsPayload()) {
3078 var buf: Type.Payload.ElemType = undefined;3129 var buf: Type.Payload.ElemType = undefined;
3079 const payload_ty = optional_ty.optionalChild(&buf);3130 const payload_ty = optional_ty.optionalChild(&buf);
3080 // When payload is zero-bits, we can treat operand as a value, rather than3131 // When payload is zero-bits, we can treat operand as a value, rather than
...@@ -3100,7 +3151,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3100,7 +3151,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3100 const opt_ty = self.air.typeOf(ty_op.operand);3151 const opt_ty = self.air.typeOf(ty_op.operand);
3101 const payload_ty = self.air.typeOfIndex(inst);3152 const payload_ty = self.air.typeOfIndex(inst);
3102 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };3153 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
3103 if (opt_ty.isPtrLikeOptional()) return operand;3154 if (opt_ty.optionalReprIsPayload()) return operand;
31043155
3105 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);3156 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
31063157
...@@ -3120,7 +3171,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3120,7 +3171,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31203171
3121 var buf: Type.Payload.ElemType = undefined;3172 var buf: Type.Payload.ElemType = undefined;
3122 const payload_ty = opt_ty.optionalChild(&buf);3173 const payload_ty = opt_ty.optionalChild(&buf);
3123 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or opt_ty.isPtrLikeOptional()) {3174 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or opt_ty.optionalReprIsPayload()) {
3124 return operand;3175 return operand;
3125 }3176 }
31263177
...@@ -3138,7 +3189,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -3138,7 +3189,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
3138 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()});3189 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()});
3139 }3190 }
31403191
3141 if (opt_ty.isPtrLikeOptional()) {3192 if (opt_ty.optionalReprIsPayload()) {
3142 return operand;3193 return operand;
3143 }3194 }
31443195
...@@ -3169,7 +3220,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3169,7 +3220,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31693220
3170 const operand = try self.resolveInst(ty_op.operand);3221 const operand = try self.resolveInst(ty_op.operand);
3171 const op_ty = self.air.typeOfIndex(inst);3222 const op_ty = self.air.typeOfIndex(inst);
3172 if (op_ty.isPtrLikeOptional()) {3223 if (op_ty.optionalReprIsPayload()) {
3173 return operand;3224 return operand;
3174 }3225 }
3175 const offset = std.math.cast(u32, op_ty.abiSize(self.target) - payload_ty.abiSize(self.target)) catch {3226 const offset = std.math.cast(u32, op_ty.abiSize(self.target) - payload_ty.abiSize(self.target)) catch {
...@@ -3927,12 +3978,16 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3927,12 +3978,16 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3927fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3978fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3928 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3979 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3929 const err_set_ty = self.air.typeOf(ty_op.operand).childType();3980 const err_set_ty = self.air.typeOf(ty_op.operand).childType();
3930 const err_ty = err_set_ty.errorUnionSet();
3931 const payload_ty = err_set_ty.errorUnionPayload();3981 const payload_ty = err_set_ty.errorUnionPayload();
3932 const operand = try self.resolveInst(ty_op.operand);3982 const operand = try self.resolveInst(ty_op.operand);
39333983
3934 // set error-tag to '0' to annotate error union is non-error3984 // set error-tag to '0' to annotate error union is non-error
3935 try self.store(operand, .{ .imm32 = 0 }, err_ty, 0);3985 try self.store(
3986 operand,
3987 .{ .imm32 = 0 },
3988 Type.anyerror,
3989 @intCast(u32, errUnionErrorOffset(payload_ty, self.target)),
3990 );
39363991
3937 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3992 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
39383993
...@@ -3940,11 +3995,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -3940,11 +3995,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
3940 return operand;3995 return operand;
3941 }3996 }
39423997
3943 const err_align = err_set_ty.abiAlignment(self.target);3998 return self.buildPointerOffset(operand, @intCast(u32, errUnionPayloadOffset(payload_ty, self.target)), .new);
3944 const set_size = err_ty.abiSize(self.target);
3945 const offset = mem.alignForwardGeneric(u64, set_size, err_align);
3946
3947 return self.buildPointerOffset(operand, @intCast(u32, offset), .new);
3948}3999}
39494000
3950fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4001fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
src/arch/x86_64/CodeGen.zig+161-81
...@@ -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 errUnionErrorOffset = codegen.errUnionErrorOffset;
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;
...@@ -854,7 +857,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {...@@ -854,7 +857,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
854 const ptr_ty = self.air.typeOfIndex(inst);857 const ptr_ty = self.air.typeOfIndex(inst);
855 const elem_ty = ptr_ty.elemType();858 const elem_ty = ptr_ty.elemType();
856859
857 if (!elem_ty.hasRuntimeBits()) {860 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) {
858 return self.allocMem(inst, @sizeOf(usize), @alignOf(usize));861 return self.allocMem(inst, @sizeOf(usize), @alignOf(usize));
859 }862 }
860863
...@@ -1786,21 +1789,34 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1786,21 +1789,34 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1786 const err_ty = err_union_ty.errorUnionSet();1789 const err_ty = err_union_ty.errorUnionSet();
1787 const payload_ty = err_union_ty.errorUnionPayload();1790 const payload_ty = err_union_ty.errorUnionPayload();
1788 const operand = try self.resolveInst(ty_op.operand);1791 const operand = try self.resolveInst(ty_op.operand);
1789 const operand_lock: ?RegisterLock = switch (operand) {
1790 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1791 else => null,
1792 };
1793 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
17941792
1795 const result: MCValue = result: {1793 const result: MCValue = result: {
1796 if (!payload_ty.hasRuntimeBits()) break :result operand;1794 if (err_ty.errorSetCardinality() == .zero) {
1795 break :result MCValue{ .immediate = 0 };
1796 }
1797
1798 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1799 break :result operand;
1800 }
1801
1802 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
1797 switch (operand) {1803 switch (operand) {
1798 .stack_offset => |off| {1804 .stack_offset => |off| {
1799 break :result MCValue{ .stack_offset = off };1805 const offset = off - @intCast(i32, err_off);
1806 break :result MCValue{ .stack_offset = offset };
1800 },1807 },
1801 .register => {1808 .register => |reg| {
1802 // TODO reuse operand1809 // TODO reuse operand
1803 break :result try self.copyToRegisterWithInstTracking(inst, err_ty, operand);1810 const lock = self.register_manager.lockRegAssumeUnused(reg);
1811 defer self.register_manager.unlockReg(lock);
1812 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
1813 if (err_off > 0) {
1814 const shift = @intCast(u6, err_off * 8);
1815 try self.genShiftBinOpMir(.shr, err_union_ty, result.register, .{ .immediate = shift });
1816 } else {
1817 try self.truncateRegister(Type.anyerror, result.register);
1818 }
1819 break :result result;
1804 },1820 },
1805 else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}),1821 else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}),
1806 }1822 }
...@@ -1815,32 +1831,37 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1815,32 +1831,37 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1815 }1831 }
1816 const err_union_ty = self.air.typeOf(ty_op.operand);1832 const err_union_ty = self.air.typeOf(ty_op.operand);
1817 const payload_ty = err_union_ty.errorUnionPayload();1833 const payload_ty = err_union_ty.errorUnionPayload();
1834 const err_ty = err_union_ty.errorUnionSet();
1835 const operand = try self.resolveInst(ty_op.operand);
1836
1818 const result: MCValue = result: {1837 const result: MCValue = result: {
1819 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;1838 if (err_ty.errorSetCardinality() == .zero) {
1839 // TODO check if we can reuse
1840 break :result operand;
1841 }
18201842
1821 const operand = try self.resolveInst(ty_op.operand);1843 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1822 const operand_lock: ?RegisterLock = switch (operand) {1844 break :result MCValue.none;
1823 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),1845 }
1824 else => null,
1825 };
1826 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
18271846
1828 const abi_align = err_union_ty.abiAlignment(self.target.*);1847 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
1829 const err_ty = err_union_ty.errorUnionSet();
1830 const err_abi_size = mem.alignForwardGeneric(u32, @intCast(u32, err_ty.abiSize(self.target.*)), abi_align);
1831 switch (operand) {1848 switch (operand) {
1832 .stack_offset => |off| {1849 .stack_offset => |off| {
1833 const offset = off - @intCast(i32, err_abi_size);1850 const offset = off - @intCast(i32, payload_off);
1834 break :result MCValue{ .stack_offset = offset };1851 break :result MCValue{ .stack_offset = offset };
1835 },1852 },
1836 .register => {1853 .register => |reg| {
1837 // TODO reuse operand1854 // TODO reuse operand
1838 const shift = @intCast(u6, err_abi_size * @sizeOf(usize));1855 const lock = self.register_manager.lockRegAssumeUnused(reg);
1856 defer self.register_manager.unlockReg(lock);
1839 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);1857 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
1840 try self.genShiftBinOpMir(.shr, Type.usize, result.register, .{ .immediate = shift });1858 if (payload_off > 0) {
1841 break :result MCValue{1859 const shift = @intCast(u6, payload_off * 8);
1842 .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),1860 try self.genShiftBinOpMir(.shr, err_union_ty, result.register, .{ .immediate = shift });
1843 };1861 } else {
1862 try self.truncateRegister(payload_ty, result.register);
1863 }
1864 break :result result;
1844 },1865 },
1845 else => return self.fail("TODO implement unwrap_err_payload for {}", .{operand}),1866 else => return self.fail("TODO implement unwrap_err_payload for {}", .{operand}),
1846 }1867 }
...@@ -1935,24 +1956,37 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {...@@ -1935,24 +1956,37 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
1935/// T to E!T1956/// T to E!T
1936fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {1957fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
1937 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1958 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1959
1938 if (self.liveness.isUnused(inst)) {1960 if (self.liveness.isUnused(inst)) {
1939 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });1961 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
1940 }1962 }
1963
1941 const error_union_ty = self.air.getRefType(ty_op.ty);1964 const error_union_ty = self.air.getRefType(ty_op.ty);
1942 const error_ty = error_union_ty.errorUnionSet();1965 const error_ty = error_union_ty.errorUnionSet();
1943 const payload_ty = error_union_ty.errorUnionPayload();1966 const payload_ty = error_union_ty.errorUnionPayload();
1944 const operand = try self.resolveInst(ty_op.operand);1967 const operand = try self.resolveInst(ty_op.operand);
1945 assert(payload_ty.hasRuntimeBits());
19461968
1947 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));1969 const result: MCValue = result: {
1948 const abi_align = error_union_ty.abiAlignment(self.target.*);1970 if (error_ty.errorSetCardinality() == .zero) {
1949 const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*));1971 break :result operand;
1950 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));1972 }
1951 const offset = mem.alignForwardGeneric(u32, err_abi_size, abi_align);1973
1952 try self.genSetStack(error_ty, stack_offset, .{ .immediate = 0 }, .{});1974 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1953 try self.genSetStack(payload_ty, stack_offset - @intCast(i32, offset), operand, .{});1975 break :result operand;
1976 }
1977
1978 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
1979 const abi_align = error_union_ty.abiAlignment(self.target.*);
1980 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
1981 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
1982 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
1983 try self.genSetStack(payload_ty, stack_offset - @intCast(i32, payload_off), operand, .{});
1984 try self.genSetStack(Type.anyerror, stack_offset - @intCast(i32, err_off), .{ .immediate = 0 }, .{});
1985
1986 break :result MCValue{ .stack_offset = stack_offset };
1987 };
19541988
1955 return self.finishAir(inst, .{ .stack_offset = stack_offset }, .{ ty_op.operand, .none, .none });1989 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1956}1990}
19571991
1958/// E to E!T1992/// E to E!T
...@@ -1962,19 +1996,22 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1962,19 +1996,22 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1962 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });1996 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
1963 }1997 }
1964 const error_union_ty = self.air.getRefType(ty_op.ty);1998 const error_union_ty = self.air.getRefType(ty_op.ty);
1965 const error_ty = error_union_ty.errorUnionSet();
1966 const payload_ty = error_union_ty.errorUnionPayload();1999 const payload_ty = error_union_ty.errorUnionPayload();
1967 const err = try self.resolveInst(ty_op.operand);2000 const operand = try self.resolveInst(ty_op.operand);
2001
1968 const result: MCValue = result: {2002 const result: MCValue = result: {
1969 if (!payload_ty.hasRuntimeBits()) break :result err;2003 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2004 break :result operand;
2005 }
19702006
1971 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));2007 const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*));
1972 const abi_align = error_union_ty.abiAlignment(self.target.*);2008 const abi_align = error_union_ty.abiAlignment(self.target.*);
1973 const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*));
1974 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));2009 const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align));
1975 const offset = mem.alignForwardGeneric(u32, err_abi_size, abi_align);2010 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
1976 try self.genSetStack(error_ty, stack_offset, err, .{});2011 const err_off = errUnionErrorOffset(payload_ty, self.target.*);
1977 try self.genSetStack(payload_ty, stack_offset - @intCast(i32, offset), .undef, .{});2012 try self.genSetStack(Type.anyerror, stack_offset - @intCast(i32, err_off), operand, .{});
2013 try self.genSetStack(payload_ty, stack_offset - @intCast(i32, payload_off), .undef, .{});
2014
1978 break :result MCValue{ .stack_offset = stack_offset };2015 break :result MCValue{ .stack_offset = stack_offset };
1979 };2016 };
19802017
...@@ -2535,7 +2572,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -2535,7 +2572,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
2535 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2572 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2536 const elem_ty = self.air.typeOfIndex(inst);2573 const elem_ty = self.air.typeOfIndex(inst);
2537 const result: MCValue = result: {2574 const result: MCValue = result: {
2538 if (!elem_ty.hasRuntimeBits())2575 if (!elem_ty.hasRuntimeBitsIgnoreComptime())
2539 break :result MCValue.none;2576 break :result MCValue.none;
25402577
2541 const ptr = try self.resolveInst(ty_op.operand);2578 const ptr = try self.resolveInst(ty_op.operand);
...@@ -4102,6 +4139,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -4102,6 +4139,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
4102 const operand = try self.resolveInst(un_op);4139 const operand = try self.resolveInst(un_op);
4103 const ret_ty = self.fn_type.fnReturnType();4140 const ret_ty = self.fn_type.fnReturnType();
4104 switch (self.ret_mcv) {4141 switch (self.ret_mcv) {
4142 .immediate => {
4143 assert(ret_ty.isError());
4144 },
4105 .stack_offset => {4145 .stack_offset => {
4106 const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv);4146 const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv);
4107 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);4147 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
...@@ -4134,6 +4174,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -4134,6 +4174,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
4134 const ptr_ty = self.air.typeOf(un_op);4174 const ptr_ty = self.air.typeOf(un_op);
4135 const elem_ty = ptr_ty.elemType();4175 const elem_ty = ptr_ty.elemType();
4136 switch (self.ret_mcv) {4176 switch (self.ret_mcv) {
4177 .immediate => {
4178 assert(elem_ty.isError());
4179 },
4137 .stack_offset => {4180 .stack_offset => {
4138 const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv);4181 const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv);
4139 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);4182 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
...@@ -4377,7 +4420,6 @@ fn genVarDbgInfo(...@@ -4377,7 +4420,6 @@ fn genVarDbgInfo(
4377fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {4420fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
4378 switch (self.debug_output) {4421 switch (self.debug_output) {
4379 .dwarf => |dw| {4422 .dwarf => |dw| {
4380 assert(ty.hasRuntimeBits());
4381 const dbg_info = &dw.dbg_info;4423 const dbg_info = &dw.dbg_info;
4382 const index = dbg_info.items.len;4424 const index = dbg_info.items.len;
4383 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref44425 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
...@@ -4604,7 +4646,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu...@@ -4604,7 +4646,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu
4604 const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {4646 const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: {
4605 var buf: Type.Payload.ElemType = undefined;4647 var buf: Type.Payload.ElemType = undefined;
4606 const payload_ty = ty.optionalChild(&buf);4648 const payload_ty = ty.optionalChild(&buf);
4607 break :blk if (payload_ty.hasRuntimeBits()) Type.bool else ty;4649 break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime()) Type.bool else ty;
4608 } else ty;4650 } else ty;
46094651
4610 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });4652 try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 });
...@@ -4620,25 +4662,36 @@ fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCV...@@ -4620,25 +4662,36 @@ fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCV
46204662
4621fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4663fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
4622 const err_type = ty.errorUnionSet();4664 const err_type = ty.errorUnionSet();
4623 const payload_type = ty.errorUnionPayload();4665
4624 if (!err_type.hasRuntimeBits()) {4666 if (err_type.errorSetCardinality() == .zero) {
4625 return MCValue{ .immediate = 0 }; // always false4667 return MCValue{ .immediate = 0 }; // always false
4626 }4668 }
46274669
4628 try self.spillCompareFlagsIfOccupied();4670 try self.spillCompareFlagsIfOccupied();
4629 self.compare_flags_inst = inst;4671 self.compare_flags_inst = inst;
46304672
4631 if (!payload_type.hasRuntimeBits()) {4673 const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*);
4632 if (err_type.abiSize(self.target.*) <= 8) {4674 switch (operand) {
4633 try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });4675 .stack_offset => |off| {
4634 return MCValue{ .compare_flags_unsigned = .gt };4676 const offset = off - @intCast(i32, err_off);
4635 } else {4677 try self.genBinOpMir(.cmp, Type.anyerror, .{ .stack_offset = offset }, .{ .immediate = 0 });
4636 return self.fail("TODO isErr for errors with size larger than register size", .{});4678 },
4637 }4679 .register => |reg| {
4638 } else {4680 const maybe_lock = self.register_manager.lockReg(reg);
4639 try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 });4681 defer if (maybe_lock) |lock| self.register_manager.unlockReg(lock);
4640 return MCValue{ .compare_flags_unsigned = .gt };4682 const tmp_reg = try self.copyToTmpRegister(ty, operand);
4683 if (err_off > 0) {
4684 const shift = @intCast(u6, err_off * 8);
4685 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = shift });
4686 } else {
4687 try self.truncateRegister(Type.anyerror, tmp_reg);
4688 }
4689 try self.genBinOpMir(.cmp, Type.anyerror, .{ .register = tmp_reg }, .{ .immediate = 0 });
4690 },
4691 else => return self.fail("TODO implement isErr for {}", .{operand}),
4641 }4692 }
4693
4694 return MCValue{ .compare_flags_unsigned = .gt };
4642}4695}
46434696
4644fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4697fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
...@@ -5461,6 +5514,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5461,6 +5514,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5461 .immediate => |x_big| {5514 .immediate => |x_big| {
5462 const base_reg = opts.dest_stack_base orelse .rbp;5515 const base_reg = opts.dest_stack_base orelse .rbp;
5463 switch (abi_size) {5516 switch (abi_size) {
5517 0 => {
5518 assert(ty.isError());
5519 const payload = try self.addExtra(Mir.ImmPair{
5520 .dest_off = @bitCast(u32, -stack_offset),
5521 .operand = @truncate(u32, x_big),
5522 });
5523 _ = try self.addInst(.{
5524 .tag = .mov_mem_imm,
5525 .ops = Mir.Inst.Ops.encode(.{
5526 .reg1 = base_reg,
5527 .flags = 0b00,
5528 }),
5529 .data = .{ .payload = payload },
5530 });
5531 },
5464 1, 2, 4 => {5532 1, 2, 4 => {
5465 const payload = try self.addExtra(Mir.ImmPair{5533 const payload = try self.addExtra(Mir.ImmPair{
5466 .dest_off = @bitCast(u32, -stack_offset),5534 .dest_off = @bitCast(u32, -stack_offset),
...@@ -6643,7 +6711,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -6643,7 +6711,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
6643 const ref_int = @enumToInt(inst);6711 const ref_int = @enumToInt(inst);
6644 if (ref_int < Air.Inst.Ref.typed_value_map.len) {6712 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
6645 const tv = Air.Inst.Ref.typed_value_map[ref_int];6713 const tv = Air.Inst.Ref.typed_value_map[ref_int];
6646 if (!tv.ty.hasRuntimeBits()) {6714 if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) {
6647 return MCValue{ .none = {} };6715 return MCValue{ .none = {} };
6648 }6716 }
6649 return self.genTypedValue(tv);6717 return self.genTypedValue(tv);
...@@ -6651,7 +6719,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -6651,7 +6719,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
66516719
6652 // If the type has no codegen bits, no need to store it.6720 // If the type has no codegen bits, no need to store it.
6653 const inst_ty = self.air.typeOf(inst);6721 const inst_ty = self.air.typeOf(inst);
6654 if (!inst_ty.hasRuntimeBits())6722 if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError())
6655 return MCValue{ .none = {} };6723 return MCValue{ .none = {} };
66566724
6657 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);6725 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
...@@ -6780,6 +6848,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -6780,6 +6848,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
6780 const target = self.target.*;6848 const target = self.target.*;
67816849
6782 switch (typed_value.ty.zigTypeTag()) {6850 switch (typed_value.ty.zigTypeTag()) {
6851 .Void => return MCValue{ .none = {} },
6783 .Pointer => switch (typed_value.ty.ptrSize()) {6852 .Pointer => switch (typed_value.ty.ptrSize()) {
6784 .Slice => {},6853 .Slice => {},
6785 else => {6854 else => {
...@@ -6841,26 +6910,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -6841,26 +6910,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
6841 }6910 }
6842 },6911 },
6843 .ErrorSet => {6912 .ErrorSet => {
6844 const err_name = typed_value.val.castTag(.@"error").?.data.name;6913 switch (typed_value.val.tag()) {
6845 const module = self.bin_file.options.module.?;6914 .@"error" => {
6846 const global_error_set = module.global_error_set;6915 const err_name = typed_value.val.castTag(.@"error").?.data.name;
6847 const error_index = global_error_set.get(err_name).?;6916 const module = self.bin_file.options.module.?;
6848 return MCValue{ .immediate = error_index };6917 const global_error_set = module.global_error_set;
6918 const error_index = global_error_set.get(err_name).?;
6919 return MCValue{ .immediate = error_index };
6920 },
6921 else => {
6922 // In this case we are rendering an error union which has a 0 bits payload.
6923 return MCValue{ .immediate = 0 };
6924 },
6925 }
6849 },6926 },
6850 .ErrorUnion => {6927 .ErrorUnion => {
6851 const error_type = typed_value.ty.errorUnionSet();6928 const error_type = typed_value.ty.errorUnionSet();
6852 const payload_type = typed_value.ty.errorUnionPayload();6929 const payload_type = typed_value.ty.errorUnionPayload();
68536930
6854 if (typed_value.val.castTag(.eu_payload)) |_| {6931 if (error_type.errorSetCardinality() == .zero) {
6855 if (!payload_type.hasRuntimeBits()) {6932 const payload_val = typed_value.val.castTag(.eu_payload).?.data;
6856 // We use the error type directly as the type.6933 return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
6857 return MCValue{ .immediate = 0 };6934 }
6858 }6935
6859 } else {6936 const is_pl = typed_value.val.errorUnionIsPayload();
6860 if (!payload_type.hasRuntimeBits()) {6937
6861 // We use the error type directly as the type.6938 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
6862 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });6939 // We use the error type directly as the type.
6863 }6940 const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero);
6941 return self.genTypedValue(.{ .ty = error_type, .val = err_val });
6864 }6942 }
6865 },6943 },
68666944
...@@ -6868,7 +6946,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -6868,7 +6946,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
6868 .ComptimeFloat => unreachable,6946 .ComptimeFloat => unreachable,
6869 .Type => unreachable,6947 .Type => unreachable,
6870 .EnumLiteral => unreachable,6948 .EnumLiteral => unreachable,
6871 .Void => unreachable,
6872 .NoReturn => unreachable,6949 .NoReturn => unreachable,
6873 .Undefined => unreachable,6950 .Undefined => unreachable,
6874 .Null => unreachable,6951 .Null => unreachable,
...@@ -6922,11 +6999,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -6922,11 +6999,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
6922 // Return values6999 // Return values
6923 if (ret_ty.zigTypeTag() == .NoReturn) {7000 if (ret_ty.zigTypeTag() == .NoReturn) {
6924 result.return_value = .{ .unreach = {} };7001 result.return_value = .{ .unreach = {} };
6925 } else if (!ret_ty.hasRuntimeBits()) {7002 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
6926 result.return_value = .{ .none = {} };7003 result.return_value = .{ .none = {} };
6927 } else {7004 } else {
6928 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));7005 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
6929 if (ret_ty_size <= 8) {7006 if (ret_ty_size == 0) {
7007 assert(ret_ty.isError());
7008 result.return_value = .{ .immediate = 0 };
7009 } else if (ret_ty_size <= 8) {
6930 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);7010 const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size);
6931 result.return_value = .{ .register = aliased_reg };7011 result.return_value = .{ .register = aliased_reg };
6932 } else {7012 } else {
src/codegen.zig+67-10
...@@ -442,7 +442,10 @@ pub fn generateSymbol(...@@ -442,7 +442,10 @@ pub fn generateSymbol(
442 .Int => {442 .Int => {
443 const info = typed_value.ty.intInfo(target);443 const info = typed_value.ty.intInfo(target);
444 if (info.bits <= 8) {444 if (info.bits <= 8) {
445 const x = @intCast(u8, typed_value.val.toUnsignedInt(target));445 const x: u8 = switch (info.signedness) {
446 .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)),
447 .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt())),
448 };
446 try code.append(x);449 try code.append(x);
447 return Result{ .appended = {} };450 return Result{ .appended = {} };
448 }451 }
...@@ -654,7 +657,7 @@ pub fn generateSymbol(...@@ -654,7 +657,7 @@ pub fn generateSymbol(
654 return Result{ .appended = {} };657 return Result{ .appended = {} };
655 }658 }
656659
657 if (typed_value.ty.isPtrLikeOptional()) {660 if (typed_value.ty.optionalReprIsPayload()) {
658 if (typed_value.val.castTag(.opt_payload)) |payload| {661 if (typed_value.val.castTag(.opt_payload)) |payload| {
659 switch (try generateSymbol(bin_file, src_loc, .{662 switch (try generateSymbol(bin_file, src_loc, .{
660 .ty = payload_type,663 .ty = payload_type,
...@@ -702,16 +705,50 @@ pub fn generateSymbol(...@@ -702,16 +705,50 @@ pub fn generateSymbol(
702 .ErrorUnion => {705 .ErrorUnion => {
703 const error_ty = typed_value.ty.errorUnionSet();706 const error_ty = typed_value.ty.errorUnionSet();
704 const payload_ty = typed_value.ty.errorUnionPayload();707 const payload_ty = typed_value.ty.errorUnionPayload();
708
709 if (error_ty.errorSetCardinality() == .zero) {
710 const payload_val = typed_value.val.castTag(.eu_payload).?.data;
711 return generateSymbol(bin_file, src_loc, .{
712 .ty = payload_ty,
713 .val = payload_val,
714 }, code, debug_output, reloc_info);
715 }
716
705 const is_payload = typed_value.val.errorUnionIsPayload();717 const is_payload = typed_value.val.errorUnionIsPayload();
706718
719 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
720 const err_val = if (is_payload) Value.initTag(.zero) else typed_value.val;
721 return generateSymbol(bin_file, src_loc, .{
722 .ty = error_ty,
723 .val = err_val,
724 }, code, debug_output, reloc_info);
725 }
726
727 const payload_align = payload_ty.abiAlignment(target);
728 const error_align = Type.anyerror.abiAlignment(target);
707 const abi_align = typed_value.ty.abiAlignment(target);729 const abi_align = typed_value.ty.abiAlignment(target);
708730
731 // error value first when its type is larger than the error union's payload
732 if (error_align > payload_align) {
733 switch (try generateSymbol(bin_file, src_loc, .{
734 .ty = error_ty,
735 .val = if (is_payload) Value.initTag(.zero) else typed_value.val,
736 }, code, debug_output, reloc_info)) {
737 .appended => {},
738 .externally_managed => |external_slice| {
739 code.appendSliceAssumeCapacity(external_slice);
740 },
741 .fail => |em| return Result{ .fail = em },
742 }
743 }
744
745 // emit payload part of the error union
709 {746 {
710 const error_val = if (!is_payload) typed_value.val else Value.initTag(.zero);
711 const begin = code.items.len;747 const begin = code.items.len;
748 const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef);
712 switch (try generateSymbol(bin_file, src_loc, .{749 switch (try generateSymbol(bin_file, src_loc, .{
713 .ty = error_ty,750 .ty = payload_ty,
714 .val = error_val,751 .val = payload_val,
715 }, code, debug_output, reloc_info)) {752 }, code, debug_output, reloc_info)) {
716 .appended => {},753 .appended => {},
717 .externally_managed => |external_slice| {754 .externally_managed => |external_slice| {
...@@ -728,12 +765,12 @@ pub fn generateSymbol(...@@ -728,12 +765,12 @@ pub fn generateSymbol(
728 }765 }
729 }766 }
730767
731 if (payload_ty.hasRuntimeBits()) {768 // Payload size is larger than error set, so emit our error set last
769 if (error_align <= payload_align) {
732 const begin = code.items.len;770 const begin = code.items.len;
733 const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef);
734 switch (try generateSymbol(bin_file, src_loc, .{771 switch (try generateSymbol(bin_file, src_loc, .{
735 .ty = payload_ty,772 .ty = error_ty,
736 .val = payload_val,773 .val = if (is_payload) Value.initTag(.zero) else typed_value.val,
737 }, code, debug_output, reloc_info)) {774 }, code, debug_output, reloc_info)) {
738 .appended => {},775 .appended => {},
739 .externally_managed => |external_slice| {776 .externally_managed => |external_slice| {
...@@ -760,7 +797,7 @@ pub fn generateSymbol(...@@ -760,7 +797,7 @@ pub fn generateSymbol(
760 try code.writer().writeInt(u32, kv.value, endian);797 try code.writer().writeInt(u32, kv.value, endian);
761 },798 },
762 else => {799 else => {
763 try code.writer().writeByteNTimes(0, @intCast(usize, typed_value.ty.abiSize(target)));800 try code.writer().writeByteNTimes(0, @intCast(usize, Type.anyerror.abiSize(target)));
764 },801 },
765 }802 }
766 return Result{ .appended = {} };803 return Result{ .appended = {} };
...@@ -853,3 +890,23 @@ fn lowerDeclRef(...@@ -853,3 +890,23 @@ fn lowerDeclRef(
853890
854 return Result{ .appended = {} };891 return Result{ .appended = {} };
855}892}
893
894pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 {
895 const payload_align = payload_ty.abiAlignment(target);
896 const error_align = Type.anyerror.abiAlignment(target);
897 if (payload_align >= error_align) {
898 return 0;
899 } else {
900 return mem.alignForwardGeneric(u64, Type.anyerror.abiSize(target), payload_align);
901 }
902}
903
904pub fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u64 {
905 const payload_align = payload_ty.abiAlignment(target);
906 const error_align = Type.anyerror.abiAlignment(target);
907 if (payload_align >= error_align) {
908 return mem.alignForwardGeneric(u64, payload_ty.abiSize(target), error_align);
909 } else {
910 return 0;
911 }
912}
src/codegen/c.zig+177-85
...@@ -711,21 +711,24 @@ pub const DeclGen = struct {...@@ -711,21 +711,24 @@ pub const DeclGen = struct {
711 .Bool => return writer.print("{}", .{val.toBool()}),711 .Bool => return writer.print("{}", .{val.toBool()}),
712 .Optional => {712 .Optional => {
713 var opt_buf: Type.Payload.ElemType = undefined;713 var opt_buf: Type.Payload.ElemType = undefined;
714 const payload_type = ty.optionalChild(&opt_buf);714 const payload_ty = ty.optionalChild(&opt_buf);
715 if (ty.isPtrLikeOptional()) {715
716 return dg.renderValue(writer, payload_type, val, location);716 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
717 }
718 if (payload_type.abiSize(target) == 0) {
719 const is_null = val.castTag(.opt_payload) == null;717 const is_null = val.castTag(.opt_payload) == null;
720 return writer.print("{}", .{is_null});718 return writer.print("{}", .{is_null});
721 }719 }
720
721 if (ty.optionalReprIsPayload()) {
722 return dg.renderValue(writer, payload_ty, val, location);
723 }
724
722 try writer.writeByte('(');725 try writer.writeByte('(');
723 try dg.renderTypecast(writer, ty);726 try dg.renderTypecast(writer, ty);
724 try writer.writeAll("){");727 try writer.writeAll("){");
725 if (val.castTag(.opt_payload)) |pl| {728 if (val.castTag(.opt_payload)) |pl| {
726 const payload_val = pl.data;729 const payload_val = pl.data;
727 try writer.writeAll(" .is_null = false, .payload = ");730 try writer.writeAll(" .is_null = false, .payload = ");
728 try dg.renderValue(writer, payload_type, payload_val, location);731 try dg.renderValue(writer, payload_ty, payload_val, location);
729 try writer.writeAll(" }");732 try writer.writeAll(" }");
730 } else {733 } else {
731 try writer.writeAll(" .is_null = true }");734 try writer.writeAll(" .is_null = true }");
...@@ -749,6 +752,12 @@ pub const DeclGen = struct {...@@ -749,6 +752,12 @@ pub const DeclGen = struct {
749 const error_type = ty.errorUnionSet();752 const error_type = ty.errorUnionSet();
750 const payload_type = ty.errorUnionPayload();753 const payload_type = ty.errorUnionPayload();
751754
755 if (error_type.errorSetCardinality() == .zero) {
756 // We use the payload directly as the type.
757 const payload_val = val.castTag(.eu_payload).?.data;
758 return dg.renderValue(writer, payload_type, payload_val, location);
759 }
760
752 if (!payload_type.hasRuntimeBits()) {761 if (!payload_type.hasRuntimeBits()) {
753 // We use the error type directly as the type.762 // We use the error type directly as the type.
754 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;763 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
...@@ -894,10 +903,12 @@ pub const DeclGen = struct {...@@ -894,10 +903,12 @@ pub const DeclGen = struct {
894 try w.writeAll("ZIG_COLD ");903 try w.writeAll("ZIG_COLD ");
895 }904 }
896 }905 }
897 const return_ty = dg.decl.ty.fnReturnType();906 const fn_info = dg.decl.ty.fnInfo();
898 if (return_ty.hasRuntimeBits()) {907 if (fn_info.return_type.hasRuntimeBits()) {
899 try dg.renderType(w, return_ty);908 try dg.renderType(w, fn_info.return_type);
900 } else if (return_ty.zigTypeTag() == .NoReturn) {909 } else if (fn_info.return_type.isError()) {
910 try dg.renderType(w, Type.anyerror);
911 } else if (fn_info.return_type.zigTypeTag() == .NoReturn) {
901 try w.writeAll("zig_noreturn void");912 try w.writeAll("zig_noreturn void");
902 } else {913 } else {
903 try w.writeAll("void");914 try w.writeAll("void");
...@@ -905,22 +916,19 @@ pub const DeclGen = struct {...@@ -905,22 +916,19 @@ pub const DeclGen = struct {
905 try w.writeAll(" ");916 try w.writeAll(" ");
906 try dg.renderDeclName(w, dg.decl_index);917 try dg.renderDeclName(w, dg.decl_index);
907 try w.writeAll("(");918 try w.writeAll("(");
908 const param_len = dg.decl.ty.fnParamLen();
909919
910 var index: usize = 0;
911 var params_written: usize = 0;920 var params_written: usize = 0;
912 while (index < param_len) : (index += 1) {921 for (fn_info.param_types) |param_type, index| {
913 const param_type = dg.decl.ty.fnParamType(index);
914 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;922 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
915 if (params_written > 0) {923 if (params_written > 0) {
916 try w.writeAll(", ");924 try w.writeAll(", ");
917 }925 }
918 const name = CValue{ .arg = index };926 const name = CValue{ .arg = index };
919 try dg.renderTypeAndName(w, dg.decl.ty.fnParamType(index), name, .Mut, 0);927 try dg.renderTypeAndName(w, param_type, name, .Mut, 0);
920 params_written += 1;928 params_written += 1;
921 }929 }
922930
923 if (dg.decl.ty.fnIsVarArgs()) {931 if (fn_info.is_var_args) {
924 if (params_written != 0) try w.writeAll(", ");932 if (params_written != 0) try w.writeAll(", ");
925 try w.writeAll("...");933 try w.writeAll("...");
926 } else if (params_written == 0) {934 } else if (params_written == 0) {
...@@ -1156,26 +1164,36 @@ pub const DeclGen = struct {...@@ -1156,26 +1164,36 @@ pub const DeclGen = struct {
1156 }1164 }
11571165
1158 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {1166 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1159 const child_type = t.errorUnionPayload();1167 const payload_ty = t.errorUnionPayload();
1160 const err_set_type = t.errorUnionSet();1168 const error_ty = t.errorUnionSet();
11611169
1162 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);1170 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1163 defer buffer.deinit();1171 defer buffer.deinit();
1164 const bw = buffer.writer();1172 const bw = buffer.writer();
11651173
1166 try bw.writeAll("typedef struct { ");
1167 const payload_name = CValue{ .bytes = "payload" };1174 const payload_name = CValue{ .bytes = "payload" };
1168 try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0);1175 const target = dg.module.getTarget();
1169 try bw.writeAll("; uint16_t error; } ");1176 const payload_align = payload_ty.abiAlignment(target);
1177 const error_align = Type.anyerror.abiAlignment(target);
1178 if (error_align > payload_align) {
1179 try bw.writeAll("typedef struct { ");
1180 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0);
1181 try bw.writeAll("; uint16_t error; } ");
1182 } else {
1183 try bw.writeAll("typedef struct { uint16_t error; ");
1184 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0);
1185 try bw.writeAll("; } ");
1186 }
1187
1170 const name_index = buffer.items.len;1188 const name_index = buffer.items.len;
1171 if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {1189 if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| {
1172 const func = inf_err_set_payload.data.func;1190 const func = inf_err_set_payload.data.func;
1173 try bw.writeAll("zig_E_");1191 try bw.writeAll("zig_E_");
1174 try dg.renderDeclName(bw, func.owner_decl);1192 try dg.renderDeclName(bw, func.owner_decl);
1175 try bw.writeAll(";\n");1193 try bw.writeAll(";\n");
1176 } else {1194 } else {
1177 try bw.print("zig_E_{s}_{s};\n", .{1195 try bw.print("zig_E_{s}_{s};\n", .{
1178 typeToCIdentifier(err_set_type, dg.module), typeToCIdentifier(child_type, dg.module),1196 typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module),
1179 });1197 });
1180 }1198 }
11811199
...@@ -1345,12 +1363,12 @@ pub const DeclGen = struct {...@@ -1345,12 +1363,12 @@ pub const DeclGen = struct {
1345 var opt_buf: Type.Payload.ElemType = undefined;1363 var opt_buf: Type.Payload.ElemType = undefined;
1346 const child_type = t.optionalChild(&opt_buf);1364 const child_type = t.optionalChild(&opt_buf);
13471365
1348 if (t.isPtrLikeOptional()) {1366 if (!child_type.hasRuntimeBitsIgnoreComptime()) {
1349 return dg.renderType(w, child_type);1367 return w.writeAll("bool");
1350 }1368 }
13511369
1352 if (child_type.abiSize(target) == 0) {1370 if (t.optionalReprIsPayload()) {
1353 return w.writeAll("bool");1371 return dg.renderType(w, child_type);
1354 }1372 }
13551373
1356 const name = dg.getTypedefName(t) orelse1374 const name = dg.getTypedefName(t) orelse
...@@ -1359,12 +1377,19 @@ pub const DeclGen = struct {...@@ -1359,12 +1377,19 @@ pub const DeclGen = struct {
1359 return w.writeAll(name);1377 return w.writeAll(name);
1360 },1378 },
1361 .ErrorSet => {1379 .ErrorSet => {
1362 comptime assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2);1380 comptime assert(Type.anyerror.abiSize(builtin.target) == 2);
1363 return w.writeAll("uint16_t");1381 return w.writeAll("uint16_t");
1364 },1382 },
1365 .ErrorUnion => {1383 .ErrorUnion => {
1366 if (t.errorUnionPayload().abiSize(target) == 0) {1384 const error_ty = t.errorUnionSet();
1367 return dg.renderType(w, t.errorUnionSet());1385 const payload_ty = t.errorUnionPayload();
1386
1387 if (error_ty.errorSetCardinality() == .zero) {
1388 return dg.renderType(w, payload_ty);
1389 }
1390
1391 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1392 return dg.renderType(w, Type.anyerror);
1368 }1393 }
13691394
1370 const name = dg.getTypedefName(t) orelse1395 const name = dg.getTypedefName(t) orelse
...@@ -1794,8 +1819,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1794,8 +1819,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1794 .not => try airNot (f, inst),1819 .not => try airNot (f, inst),
17951820
1796 .optional_payload => try airOptionalPayload(f, inst),1821 .optional_payload => try airOptionalPayload(f, inst),
1797 .optional_payload_ptr => try airOptionalPayload(f, inst),1822 .optional_payload_ptr => try airOptionalPayloadPtr(f, inst),
1798 .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst),1823 .optional_payload_ptr_set => try airOptionalPayloadPtrSet(f, inst),
1824 .wrap_optional => try airWrapOptional(f, inst),
17991825
1800 .is_err => try airIsErr(f, inst, false, "!="),1826 .is_err => try airIsErr(f, inst, false, "!="),
1801 .is_non_err => try airIsErr(f, inst, false, "=="),1827 .is_non_err => try airIsErr(f, inst, false, "=="),
...@@ -1824,7 +1850,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1824,7 +1850,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1824 .cond_br => try airCondBr(f, inst),1850 .cond_br => try airCondBr(f, inst),
1825 .br => try airBr(f, inst),1851 .br => try airBr(f, inst),
1826 .switch_br => try airSwitchBr(f, inst),1852 .switch_br => try airSwitchBr(f, inst),
1827 .wrap_optional => try airWrapOptional(f, inst),
1828 .struct_field_ptr => try airStructFieldPtr(f, inst),1853 .struct_field_ptr => try airStructFieldPtr(f, inst),
1829 .array_to_slice => try airArrayToSlice(f, inst),1854 .array_to_slice => try airArrayToSlice(f, inst),
1830 .cmpxchg_weak => try airCmpxchg(f, inst, "weak"),1855 .cmpxchg_weak => try airCmpxchg(f, inst, "weak"),
...@@ -1901,8 +1926,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1901,8 +1926,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1901 .array_elem_val => try airArrayElemVal(f, inst),1926 .array_elem_val => try airArrayElemVal(f, inst),
19021927
1903 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),1928 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),
1904 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
1905 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),1929 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
1930 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
1906 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),1931 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
1907 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),1932 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
1908 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),1933 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
...@@ -2120,11 +2145,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2120,11 +2145,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2120fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {2145fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
2121 const un_op = f.air.instructions.items(.data)[inst].un_op;2146 const un_op = f.air.instructions.items(.data)[inst].un_op;
2122 const writer = f.object.writer();2147 const writer = f.object.writer();
2123 if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) {2148 const ret_ty = f.air.typeOf(un_op);
2149 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2124 const operand = try f.resolveInst(un_op);2150 const operand = try f.resolveInst(un_op);
2125 try writer.writeAll("return ");2151 try writer.writeAll("return ");
2126 try f.writeCValue(writer, operand);2152 try f.writeCValue(writer, operand);
2127 try writer.writeAll(";\n");2153 try writer.writeAll(";\n");
2154 } else if (ret_ty.isError()) {
2155 try writer.writeAll("return 0;");
2128 } else {2156 } else {
2129 try writer.writeAll("return;\n");2157 try writer.writeAll("return;\n");
2130 }2158 }
...@@ -2136,13 +2164,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2136,13 +2164,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2136 const writer = f.object.writer();2164 const writer = f.object.writer();
2137 const ptr_ty = f.air.typeOf(un_op);2165 const ptr_ty = f.air.typeOf(un_op);
2138 const ret_ty = ptr_ty.childType();2166 const ret_ty = ptr_ty.childType();
2139 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {2167 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2168 const ptr = try f.resolveInst(un_op);
2169 try writer.writeAll("return *");
2170 try f.writeCValue(writer, ptr);
2171 try writer.writeAll(";\n");
2172 } else if (ret_ty.isError()) {
2173 try writer.writeAll("return 0;\n");
2174 } else {
2140 try writer.writeAll("return;\n");2175 try writer.writeAll("return;\n");
2141 }2176 }
2142 const ptr = try f.resolveInst(un_op);
2143 try writer.writeAll("return *");
2144 try f.writeCValue(writer, ptr);
2145 try writer.writeAll(";\n");
2146 return CValue.none;2177 return CValue.none;
2147}2178}
21482179
...@@ -2713,19 +2744,20 @@ fn airCall(...@@ -2713,19 +2744,20 @@ fn airCall(
2713 .Pointer => callee_ty.childType(),2744 .Pointer => callee_ty.childType(),
2714 else => unreachable,2745 else => unreachable,
2715 };2746 };
2716 const ret_ty = fn_ty.fnReturnType();
2717 const unused_result = f.liveness.isUnused(inst);
2718 const writer = f.object.writer();2747 const writer = f.object.writer();
27192748
2720 var result_local: CValue = .none;2749 const result_local: CValue = r: {
2721 if (unused_result) {2750 if (f.liveness.isUnused(inst)) {
2722 if (ret_ty.hasRuntimeBits()) {2751 if (loweredFnRetTyHasBits(fn_ty)) {
2723 try writer.print("(void)", .{});2752 try writer.print("(void)", .{});
2753 }
2754 break :r .none;
2755 } else {
2756 const local = try f.allocLocal(fn_ty.fnReturnType(), .Const);
2757 try writer.writeAll(" = ");
2758 break :r local;
2724 }2759 }
2725 } else {2760 };
2726 result_local = try f.allocLocal(ret_ty, .Const);
2727 try writer.writeAll(" = ");
2728 }
27292761
2730 callee: {2762 callee: {
2731 known: {2763 known: {
...@@ -3116,7 +3148,6 @@ fn airIsNull(...@@ -3116,7 +3148,6 @@ fn airIsNull(
3116 const un_op = f.air.instructions.items(.data)[inst].un_op;3148 const un_op = f.air.instructions.items(.data)[inst].un_op;
3117 const writer = f.object.writer();3149 const writer = f.object.writer();
3118 const operand = try f.resolveInst(un_op);3150 const operand = try f.resolveInst(un_op);
3119 const target = f.object.dg.module.getTarget();
31203151
3121 const local = try f.allocLocal(Type.initTag(.bool), .Const);3152 const local = try f.allocLocal(Type.initTag(.bool), .Const);
3122 try writer.writeAll(" = (");3153 try writer.writeAll(" = (");
...@@ -3124,16 +3155,18 @@ fn airIsNull(...@@ -3124,16 +3155,18 @@ fn airIsNull(
31243155
3125 const ty = f.air.typeOf(un_op);3156 const ty = f.air.typeOf(un_op);
3126 var opt_buf: Type.Payload.ElemType = undefined;3157 var opt_buf: Type.Payload.ElemType = undefined;
3127 const payload_type = if (ty.zigTypeTag() == .Pointer)3158 const payload_ty = if (ty.zigTypeTag() == .Pointer)
3128 ty.childType().optionalChild(&opt_buf)3159 ty.childType().optionalChild(&opt_buf)
3129 else3160 else
3130 ty.optionalChild(&opt_buf);3161 ty.optionalChild(&opt_buf);
31313162
3132 if (ty.isPtrLikeOptional()) {3163 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3164 try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });
3165 } else if (ty.isPtrLikeOptional()) {
3133 // operand is a regular pointer, test `operand !=/== NULL`3166 // operand is a regular pointer, test `operand !=/== NULL`
3134 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });3167 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });
3135 } else if (payload_type.abiSize(target) == 0) {3168 } else if (payload_ty.zigTypeTag() == .ErrorSet) {
3136 try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });3169 try writer.print("){s} {s} 0;\n", .{ deref_suffix, operator });
3137 } else {3170 } else {
3138 try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator });3171 try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator });
3139 }3172 }
...@@ -3141,34 +3174,58 @@ fn airIsNull(...@@ -3141,34 +3174,58 @@ fn airIsNull(
3141}3174}
31423175
3143fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {3176fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
3144 if (f.liveness.isUnused(inst))3177 if (f.liveness.isUnused(inst)) return CValue.none;
3178
3179 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3180 const writer = f.object.writer();
3181 const operand = try f.resolveInst(ty_op.operand);
3182 const opt_ty = f.air.typeOf(ty_op.operand);
3183
3184 var buf: Type.Payload.ElemType = undefined;
3185 const payload_ty = opt_ty.optionalChild(&buf);
3186
3187 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3145 return CValue.none;3188 return CValue.none;
3189 }
3190
3191 if (opt_ty.optionalReprIsPayload()) {
3192 return operand;
3193 }
3194
3195 const inst_ty = f.air.typeOfIndex(inst);
3196 const local = try f.allocLocal(inst_ty, .Const);
3197 try writer.writeAll(" = (");
3198 try f.writeCValue(writer, operand);
3199 try writer.writeAll(").payload;\n");
3200 return local;
3201}
3202
3203fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3204 if (f.liveness.isUnused(inst)) return CValue.none;
31463205
3147 const ty_op = f.air.instructions.items(.data)[inst].ty_op;3206 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3148 const writer = f.object.writer();3207 const writer = f.object.writer();
3149 const operand = try f.resolveInst(ty_op.operand);3208 const operand = try f.resolveInst(ty_op.operand);
3150 const operand_ty = f.air.typeOf(ty_op.operand);3209 const ptr_ty = f.air.typeOf(ty_op.operand);
3210 const opt_ty = ptr_ty.childType();
3211 var buf: Type.Payload.ElemType = undefined;
3212 const payload_ty = opt_ty.optionalChild(&buf);
31513213
3152 const opt_ty = if (operand_ty.zigTypeTag() == .Pointer)3214 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3153 operand_ty.elemType()3215 return operand;
3154 else3216 }
3155 operand_ty;
31563217
3157 if (opt_ty.isPtrLikeOptional()) {3218 if (opt_ty.optionalReprIsPayload()) {
3158 // the operand is just a regular pointer, no need to do anything special.3219 // the operand is just a regular pointer, no need to do anything special.
3159 // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C3220 // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C
3160 return operand;3221 return operand;
3161 }3222 }
31623223
3163 const inst_ty = f.air.typeOfIndex(inst);3224 const inst_ty = f.air.typeOfIndex(inst);
3164 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
3165 const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";
3166
3167 const local = try f.allocLocal(inst_ty, .Const);3225 const local = try f.allocLocal(inst_ty, .Const);
3168 try writer.print(" = {s}(", .{maybe_addrof});3226 try writer.writeAll(" = &(");
3169 try f.writeCValue(writer, operand);3227 try f.writeCValue(writer, operand);
31703228 try writer.writeAll(")->payload;\n");
3171 try writer.print("){s}payload;\n", .{maybe_deref});
3172 return local;3229 return local;
3173}3230}
31743231
...@@ -3180,7 +3237,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3180,7 +3237,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
31803237
3181 const opt_ty = operand_ty.elemType();3238 const opt_ty = operand_ty.elemType();
31823239
3183 if (opt_ty.isPtrLikeOptional()) {3240 if (opt_ty.optionalReprIsPayload()) {
3184 // The payload and the optional are the same value.3241 // The payload and the optional are the same value.
3185 // Setting to non-null will be done when the payload is set.3242 // Setting to non-null will be done when the payload is set.
3186 return operand;3243 return operand;
...@@ -3307,7 +3364,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3307,7 +3364,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
3307 return local;3364 return local;
3308}3365}
33093366
3310// *(E!T) -> E NOT *E3367/// *(E!T) -> E
3368/// Note that the result is never a pointer.
3311fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {3369fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3312 if (f.liveness.isUnused(inst))3370 if (f.liveness.isUnused(inst))
3313 return CValue.none;3371 return CValue.none;
...@@ -3319,7 +3377,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3319,7 +3377,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3319 const operand_ty = f.air.typeOf(ty_op.operand);3377 const operand_ty = f.air.typeOf(ty_op.operand);
33203378
3321 if (operand_ty.zigTypeTag() == .Pointer) {3379 if (operand_ty.zigTypeTag() == .Pointer) {
3322 if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) {3380 const err_union_ty = operand_ty.childType();
3381 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
3382 return CValue{ .bytes = "0" };
3383 }
3384 if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) {
3323 return operand;3385 return operand;
3324 }3386 }
3325 const local = try f.allocLocal(inst_ty, .Const);3387 const local = try f.allocLocal(inst_ty, .Const);
...@@ -3328,6 +3390,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3328,6 +3390,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3328 try writer.writeAll(";\n");3390 try writer.writeAll(";\n");
3329 return local;3391 return local;
3330 }3392 }
3393 if (operand_ty.errorUnionSet().errorSetCardinality() == .zero) {
3394 return CValue{ .bytes = "0" };
3395 }
3331 if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {3396 if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {
3332 return operand;3397 return operand;
3333 }3398 }
...@@ -3343,7 +3408,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3343,7 +3408,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3343 return local;3408 return local;
3344}3409}
33453410
3346fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue {3411fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]const u8) !CValue {
3347 if (f.liveness.isUnused(inst))3412 if (f.liveness.isUnused(inst))
3348 return CValue.none;3413 return CValue.none;
33493414
...@@ -3351,17 +3416,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons...@@ -3351,17 +3416,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
3351 const writer = f.object.writer();3416 const writer = f.object.writer();
3352 const operand = try f.resolveInst(ty_op.operand);3417 const operand = try f.resolveInst(ty_op.operand);
3353 const operand_ty = f.air.typeOf(ty_op.operand);3418 const operand_ty = f.air.typeOf(ty_op.operand);
3419 const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;
3420 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
3421
3422 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
3423 return operand;
3424 }
33543425
3355 const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer)
3356 operand_ty.childType()
3357 else
3358 operand_ty;
3359 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {3426 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
3360 return CValue.none;3427 return CValue.none;
3361 }3428 }
33623429
3363 const inst_ty = f.air.typeOfIndex(inst);3430 const inst_ty = f.air.typeOfIndex(inst);
3364 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";3431 const maybe_deref = if (operand_is_ptr) "->" else ".";
33653432
3366 const local = try f.allocLocal(inst_ty, .Const);3433 const local = try f.allocLocal(inst_ty, .Const);
3367 try writer.print(" = {s}(", .{maybe_addrof});3434 try writer.print(" = {s}(", .{maybe_addrof});
...@@ -3380,8 +3447,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3380,8 +3447,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
3380 const operand = try f.resolveInst(ty_op.operand);3447 const operand = try f.resolveInst(ty_op.operand);
33813448
3382 const inst_ty = f.air.typeOfIndex(inst);3449 const inst_ty = f.air.typeOfIndex(inst);
3383 if (inst_ty.isPtrLikeOptional()) {3450 if (inst_ty.optionalReprIsPayload()) {
3384 // the operand is just a regular pointer, no need to do anything special.
3385 return operand;3451 return operand;
3386 }3452 }
33873453
...@@ -3421,6 +3487,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3421,6 +3487,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
3421 const error_ty = error_union_ty.errorUnionSet();3487 const error_ty = error_union_ty.errorUnionSet();
3422 const payload_ty = error_union_ty.errorUnionPayload();3488 const payload_ty = error_union_ty.errorUnionPayload();
34233489
3490 if (error_ty.errorSetCardinality() == .zero) {
3491 // TODO: write undefined bytes through the pointer here
3492 return operand;
3493 }
3494
3424 // First, set the non-error value.3495 // First, set the non-error value.
3425 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {3496 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3426 try f.writeCValueDeref(writer, operand);3497 try f.writeCValueDeref(writer, operand);
...@@ -3464,6 +3535,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3464,6 +3535,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
3464 const operand = try f.resolveInst(ty_op.operand);3535 const operand = try f.resolveInst(ty_op.operand);
34653536
3466 const inst_ty = f.air.typeOfIndex(inst);3537 const inst_ty = f.air.typeOfIndex(inst);
3538 if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
3539 return operand;
3540 }
3467 const local = try f.allocLocal(inst_ty, .Const);3541 const local = try f.allocLocal(inst_ty, .Const);
3468 try writer.writeAll(" = { .error = 0, .payload = ");3542 try writer.writeAll(" = { .error = 0, .payload = ");
3469 try f.writeCValue(writer, operand);3543 try f.writeCValue(writer, operand);
...@@ -3486,16 +3560,23 @@ fn airIsErr(...@@ -3486,16 +3560,23 @@ fn airIsErr(
3486 const operand_ty = f.air.typeOf(un_op);3560 const operand_ty = f.air.typeOf(un_op);
3487 const local = try f.allocLocal(Type.initTag(.bool), .Const);3561 const local = try f.allocLocal(Type.initTag(.bool), .Const);
3488 const payload_ty = operand_ty.errorUnionPayload();3562 const payload_ty = operand_ty.errorUnionPayload();
3563 const error_ty = operand_ty.errorUnionSet();
3564
3489 try writer.writeAll(" = ");3565 try writer.writeAll(" = ");
3490 if (is_ptr) {3566
3491 try f.writeCValueDeref(writer, operand);3567 if (error_ty.errorSetCardinality() == .zero) {
3568 try writer.print("0 {s} 0;\n", .{op_str});
3492 } else {3569 } else {
3493 try f.writeCValue(writer, operand);3570 if (is_ptr) {
3494 }3571 try f.writeCValueDeref(writer, operand);
3495 if (payload_ty.hasRuntimeBits()) {3572 } else {
3496 try writer.writeAll(".error");3573 try f.writeCValue(writer, operand);
3574 }
3575 if (payload_ty.hasRuntimeBits()) {
3576 try writer.writeAll(".error");
3577 }
3578 try writer.print(" {s} 0;\n", .{op_str});
3497 }3579 }
3498 try writer.print(" {s} 0;\n", .{op_str});
3499 return local;3580 return local;
3500}3581}
35013582
...@@ -4129,3 +4210,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {...@@ -4129,3 +4210,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {
4129 },4210 },
4130 }4211 }
4131}4212}
4213
4214fn loweredFnRetTyHasBits(fn_ty: Type) bool {
4215 const ret_ty = fn_ty.fnReturnType();
4216 if (ret_ty.hasRuntimeBitsIgnoreComptime()) {
4217 return true;
4218 }
4219 if (ret_ty.isError()) {
4220 return true;
4221 }
4222 return false;
4223}
src/codegen/llvm.zig+396-301
...@@ -745,7 +745,7 @@ pub const Object = struct {...@@ -745,7 +745,7 @@ pub const Object = struct {
745 const param = llvm_func.getParam(llvm_arg_i);745 const param = llvm_func.getParam(llvm_arg_i);
746 llvm_arg_i += 1;746 llvm_arg_i += 1;
747747
748 const param_llvm_ty = try dg.llvmType(param_ty);748 const param_llvm_ty = try dg.lowerType(param_ty);
749 const abi_size = @intCast(c_uint, param_ty.abiSize(target));749 const abi_size = @intCast(c_uint, param_ty.abiSize(target));
750 const int_llvm_ty = dg.context.intType(abi_size * 8);750 const int_llvm_ty = dg.context.intType(abi_size * 8);
751 const int_ptr_llvm_ty = int_llvm_ty.pointerType(0);751 const int_ptr_llvm_ty = int_llvm_ty.pointerType(0);
...@@ -775,7 +775,7 @@ pub const Object = struct {...@@ -775,7 +775,7 @@ pub const Object = struct {
775 .Struct => {775 .Struct => {
776 const fields = param_ty.structFields().values();776 const fields = param_ty.structFields().values();
777 if (is_by_ref) {777 if (is_by_ref) {
778 const param_llvm_ty = try dg.llvmType(param_ty);778 const param_llvm_ty = try dg.lowerType(param_ty);
779 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);779 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
780 arg_ptr.setAlignment(param_ty.abiAlignment(target));780 arg_ptr.setAlignment(param_ty.abiAlignment(target));
781781
...@@ -1390,7 +1390,7 @@ pub const Object = struct {...@@ -1390,7 +1390,7 @@ pub const Object = struct {
1390 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);1390 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
1391 return di_ty;1391 return di_ty;
1392 }1392 }
1393 if (ty.isPtrLikeOptional()) {1393 if (ty.optionalReprIsPayload()) {
1394 const ptr_di_ty = try o.lowerDebugType(child_ty, resolve);1394 const ptr_di_ty = try o.lowerDebugType(child_ty, resolve);
1395 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.1395 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1396 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty), .{ .mod = o.module });1396 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty), .{ .mod = o.module });
...@@ -1470,10 +1470,25 @@ pub const Object = struct {...@@ -1470,10 +1470,25 @@ pub const Object = struct {
1470 return full_di_ty;1470 return full_di_ty;
1471 },1471 },
1472 .ErrorUnion => {1472 .ErrorUnion => {
1473 const err_set_ty = ty.errorUnionSet();
1474 const payload_ty = ty.errorUnionPayload();1473 const payload_ty = ty.errorUnionPayload();
1474 switch (ty.errorUnionSet().errorSetCardinality()) {
1475 .zero => {
1476 const payload_di_ty = try o.lowerDebugType(payload_ty, .full);
1477 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1478 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(payload_di_ty), .{ .mod = o.module });
1479 return payload_di_ty;
1480 },
1481 .one => {
1482 if (payload_ty.isNoReturn()) {
1483 const di_type = dib.createBasicType("void", 0, DW.ATE.signed);
1484 gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
1485 return di_type;
1486 }
1487 },
1488 .many => {},
1489 }
1475 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {1490 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1476 const err_set_di_ty = try o.lowerDebugType(err_set_ty, .full);1491 const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full);
1477 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.1492 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1478 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(err_set_di_ty), .{ .mod = o.module });1493 try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(err_set_di_ty), .{ .mod = o.module });
1479 return err_set_di_ty;1494 return err_set_di_ty;
...@@ -1496,56 +1511,51 @@ pub const Object = struct {...@@ -1496,56 +1511,51 @@ pub const Object = struct {
1496 break :blk fwd_decl;1511 break :blk fwd_decl;
1497 };1512 };
14981513
1499 const err_set_size = err_set_ty.abiSize(target);1514 const error_size = Type.anyerror.abiSize(target);
1500 const err_set_align = err_set_ty.abiAlignment(target);1515 const error_align = Type.anyerror.abiAlignment(target);
1501 const payload_size = payload_ty.abiSize(target);1516 const payload_size = payload_ty.abiSize(target);
1502 const payload_align = payload_ty.abiAlignment(target);1517 const payload_align = payload_ty.abiAlignment(target);
15031518
1504 var offset: u64 = 0;1519 var error_index: u32 = undefined;
1505 offset += err_set_size;1520 var payload_index: u32 = undefined;
1506 offset = std.mem.alignForwardGeneric(u64, offset, payload_align);1521 var error_offset: u64 = undefined;
1507 const payload_offset = offset;1522 var payload_offset: u64 = undefined;
15081523 if (error_align > payload_align) {
1509 var len: u8 = 2;1524 error_index = 0;
1510 var fields: [3]*llvm.DIType = .{1525 payload_index = 1;
1511 dib.createMemberType(1526 error_offset = 0;
1512 fwd_decl.toScope(),1527 payload_offset = std.mem.alignForwardGeneric(u64, error_size, payload_align);
1513 "tag",1528 } else {
1514 di_file,1529 payload_index = 0;
1515 line,1530 error_index = 1;
1516 err_set_size * 8, // size in bits1531 payload_offset = 0;
1517 err_set_align * 8, // align in bits1532 error_offset = std.mem.alignForwardGeneric(u64, payload_size, error_align);
1518 0, // offset in bits
1519 0, // flags
1520 try o.lowerDebugType(err_set_ty, .full),
1521 ),
1522 dib.createMemberType(
1523 fwd_decl.toScope(),
1524 "value",
1525 di_file,
1526 line,
1527 payload_size * 8, // size in bits
1528 payload_align * 8, // align in bits
1529 payload_offset * 8, // offset in bits
1530 0, // flags
1531 try o.lowerDebugType(payload_ty, .full),
1532 ),
1533 undefined,
1534 };
1535
1536 const error_size = Type.anyerror.abiSize(target);
1537 if (payload_align > error_size) {
1538 fields[2] = fields[1];
1539 const pad_len = @intCast(u32, payload_align - error_size);
1540 fields[1] = dib.createArrayType(
1541 pad_len * 8,
1542 8,
1543 try o.lowerDebugType(Type.u8, .full),
1544 @intCast(c_int, pad_len),
1545 );
1546 len += 1;
1547 }1533 }
15481534
1535 var fields: [2]*llvm.DIType = undefined;
1536 fields[error_index] = dib.createMemberType(
1537 fwd_decl.toScope(),
1538 "tag",
1539 di_file,
1540 line,
1541 error_size * 8, // size in bits
1542 error_align * 8, // align in bits
1543 error_offset * 8, // offset in bits
1544 0, // flags
1545 try o.lowerDebugType(Type.anyerror, .full),
1546 );
1547 fields[payload_index] = dib.createMemberType(
1548 fwd_decl.toScope(),
1549 "value",
1550 di_file,
1551 line,
1552 payload_size * 8, // size in bits
1553 payload_align * 8, // align in bits
1554 payload_offset * 8, // offset in bits
1555 0, // flags
1556 try o.lowerDebugType(payload_ty, .full),
1557 );
1558
1549 const full_di_ty = dib.createStructType(1559 const full_di_ty = dib.createStructType(
1550 compile_unit_scope,1560 compile_unit_scope,
1551 name.ptr,1561 name.ptr,
...@@ -1556,7 +1566,7 @@ pub const Object = struct {...@@ -1556,7 +1566,7 @@ pub const Object = struct {
1556 0, // flags1566 0, // flags
1557 null, // derived from1567 null, // derived from
1558 &fields,1568 &fields,
1559 len,1569 fields.len,
1560 0, // run time lang1570 0, // run time lang
1561 null, // vtable holder1571 null, // vtable holder
1562 "", // unique id1572 "", // unique id
...@@ -2094,7 +2104,7 @@ pub const DeclGen = struct {...@@ -2094,7 +2104,7 @@ pub const DeclGen = struct {
2094 break :init_val decl.val;2104 break :init_val decl.val;
2095 };2105 };
2096 if (init_val.tag() != .unreachable_value) {2106 if (init_val.tag() != .unreachable_value) {
2097 const llvm_init = try dg.genTypedValue(.{ .ty = decl.ty, .val = init_val });2107 const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val });
2098 if (global.globalGetValueType() == llvm_init.typeOf()) {2108 if (global.globalGetValueType() == llvm_init.typeOf()) {
2099 global.setInitializer(llvm_init);2109 global.setInitializer(llvm_init);
2100 } else {2110 } else {
...@@ -2165,7 +2175,7 @@ pub const DeclGen = struct {...@@ -2165,7 +2175,7 @@ pub const DeclGen = struct {
2165 const target = dg.module.getTarget();2175 const target = dg.module.getTarget();
2166 const sret = firstParamSRet(fn_info, target);2176 const sret = firstParamSRet(fn_info, target);
21672177
2168 const fn_type = try dg.llvmType(zig_fn_type);2178 const fn_type = try dg.lowerType(zig_fn_type);
21692179
2170 const fqn = try decl.getFullyQualifiedName(dg.module);2180 const fqn = try decl.getFullyQualifiedName(dg.module);
2171 defer dg.gpa.free(fqn);2181 defer dg.gpa.free(fqn);
...@@ -2192,7 +2202,7 @@ pub const DeclGen = struct {...@@ -2192,7 +2202,7 @@ pub const DeclGen = struct {
2192 dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 02202 dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0
2193 dg.addArgAttr(llvm_fn, 0, "noalias");2203 dg.addArgAttr(llvm_fn, 0, "noalias");
21942204
2195 const raw_llvm_ret_ty = try dg.llvmType(fn_info.return_type);2205 const raw_llvm_ret_ty = try dg.lowerType(fn_info.return_type);
2196 llvm_fn.addSretAttr(0, raw_llvm_ret_ty);2206 llvm_fn.addSretAttr(0, raw_llvm_ret_ty);
2197 }2207 }
21982208
...@@ -2285,7 +2295,7 @@ pub const DeclGen = struct {...@@ -2285,7 +2295,7 @@ pub const DeclGen = struct {
2285 const fqn = try decl.getFullyQualifiedName(dg.module);2295 const fqn = try decl.getFullyQualifiedName(dg.module);
2286 defer dg.gpa.free(fqn);2296 defer dg.gpa.free(fqn);
22872297
2288 const llvm_type = try dg.llvmType(decl.ty);2298 const llvm_type = try dg.lowerType(decl.ty);
2289 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");2299 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
2290 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);2300 const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace(llvm_type, fqn, llvm_addrspace);
2291 gop.value_ptr.* = llvm_global;2301 gop.value_ptr.* = llvm_global;
...@@ -2339,15 +2349,15 @@ pub const DeclGen = struct {...@@ -2339,15 +2349,15 @@ pub const DeclGen = struct {
2339 }2349 }
23402350
2341 fn isUnnamedType(dg: *DeclGen, ty: Type, val: *const llvm.Value) bool {2351 fn isUnnamedType(dg: *DeclGen, ty: Type, val: *const llvm.Value) bool {
2342 // Once `llvmType` succeeds, successive calls to it with the same Zig type2352 // Once `lowerType` succeeds, successive calls to it with the same Zig type
2343 // are guaranteed to succeed. So if a call to `llvmType` fails here it means2353 // are guaranteed to succeed. So if a call to `lowerType` fails here it means
2344 // it is the first time lowering the type, which means the value can't possible2354 // it is the first time lowering the type, which means the value can't possible
2345 // have that type.2355 // have that type.
2346 const llvm_ty = dg.llvmType(ty) catch return true;2356 const llvm_ty = dg.lowerType(ty) catch return true;
2347 return val.typeOf() != llvm_ty;2357 return val.typeOf() != llvm_ty;
2348 }2358 }
23492359
2350 fn llvmType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {2360 fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*const llvm.Type {
2351 const gpa = dg.gpa;2361 const gpa = dg.gpa;
2352 const target = dg.module.getTarget();2362 const target = dg.module.getTarget();
2353 switch (t.zigTypeTag()) {2363 switch (t.zigTypeTag()) {
...@@ -2379,8 +2389,8 @@ pub const DeclGen = struct {...@@ -2379,8 +2389,8 @@ pub const DeclGen = struct {
2379 const ptr_type = t.slicePtrFieldType(&buf);2389 const ptr_type = t.slicePtrFieldType(&buf);
23802390
2381 const fields: [2]*const llvm.Type = .{2391 const fields: [2]*const llvm.Type = .{
2382 try dg.llvmType(ptr_type),2392 try dg.lowerType(ptr_type),
2383 try dg.llvmType(Type.usize),2393 try dg.lowerType(Type.usize),
2384 };2394 };
2385 return dg.context.structType(&fields, fields.len, .False);2395 return dg.context.structType(&fields, fields.len, .False);
2386 }2396 }
...@@ -2396,7 +2406,7 @@ pub const DeclGen = struct {...@@ -2396,7 +2406,7 @@ pub const DeclGen = struct {
2396 else => elem_ty.hasRuntimeBitsIgnoreComptime(),2406 else => elem_ty.hasRuntimeBitsIgnoreComptime(),
2397 };2407 };
2398 const llvm_elem_ty = if (lower_elem_ty)2408 const llvm_elem_ty = if (lower_elem_ty)
2399 try dg.llvmType(elem_ty)2409 try dg.lowerType(elem_ty)
2400 else2410 else
2401 dg.context.intType(8);2411 dg.context.intType(8);
2402 return llvm_elem_ty.pointerType(llvm_addrspace);2412 return llvm_elem_ty.pointerType(llvm_addrspace);
...@@ -2424,12 +2434,12 @@ pub const DeclGen = struct {...@@ -2424,12 +2434,12 @@ pub const DeclGen = struct {
2424 .Array => {2434 .Array => {
2425 const elem_ty = t.childType();2435 const elem_ty = t.childType();
2426 assert(elem_ty.onePossibleValue() == null);2436 assert(elem_ty.onePossibleValue() == null);
2427 const elem_llvm_ty = try dg.llvmType(elem_ty);2437 const elem_llvm_ty = try dg.lowerType(elem_ty);
2428 const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null);2438 const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null);
2429 return elem_llvm_ty.arrayType(@intCast(c_uint, total_len));2439 return elem_llvm_ty.arrayType(@intCast(c_uint, total_len));
2430 },2440 },
2431 .Vector => {2441 .Vector => {
2432 const elem_type = try dg.llvmType(t.childType());2442 const elem_type = try dg.lowerType(t.childType());
2433 return elem_type.vectorType(t.vectorLen());2443 return elem_type.vectorType(t.vectorLen());
2434 },2444 },
2435 .Optional => {2445 .Optional => {
...@@ -2438,8 +2448,8 @@ pub const DeclGen = struct {...@@ -2438,8 +2448,8 @@ pub const DeclGen = struct {
2438 if (!child_ty.hasRuntimeBitsIgnoreComptime()) {2448 if (!child_ty.hasRuntimeBitsIgnoreComptime()) {
2439 return dg.context.intType(1);2449 return dg.context.intType(1);
2440 }2450 }
2441 const payload_llvm_ty = try dg.llvmType(child_ty);2451 const payload_llvm_ty = try dg.lowerType(child_ty);
2442 if (t.isPtrLikeOptional()) {2452 if (t.optionalReprIsPayload()) {
2443 return payload_llvm_ty;2453 return payload_llvm_ty;
2444 }2454 }
24452455
...@@ -2449,28 +2459,33 @@ pub const DeclGen = struct {...@@ -2449,28 +2459,33 @@ pub const DeclGen = struct {
2449 return dg.context.structType(&fields, fields.len, .False);2459 return dg.context.structType(&fields, fields.len, .False);
2450 },2460 },
2451 .ErrorUnion => {2461 .ErrorUnion => {
2452 const error_type = t.errorUnionSet();2462 const payload_ty = t.errorUnionPayload();
2453 const payload_type = t.errorUnionPayload();2463 switch (t.errorUnionSet().errorSetCardinality()) {
2454 const llvm_error_type = try dg.llvmType(error_type);2464 .zero => return dg.lowerType(payload_ty),
2455 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {2465 .one => {
2456 return llvm_error_type;2466 if (payload_ty.isNoReturn()) {
2467 return dg.context.voidType();
2468 }
2469 },
2470 .many => {},
2471 }
2472 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2473 return try dg.lowerType(Type.anyerror);
2457 }2474 }
2458 const llvm_payload_type = try dg.llvmType(payload_type);2475 const llvm_error_type = try dg.lowerType(Type.anyerror);
2476 const llvm_payload_type = try dg.lowerType(payload_ty);
24592477
2460 const payload_align = payload_type.abiAlignment(target);2478 const payload_align = payload_ty.abiAlignment(target);
2461 const error_size = error_type.abiSize(target);2479 const error_align = Type.anyerror.abiAlignment(target);
2462 if (payload_align > error_size) {2480 if (error_align > payload_align) {
2463 const pad_type = dg.context.intType(8).arrayType(@intCast(u32, payload_align - error_size));2481 const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type };
2464 const fields: [3]*const llvm.Type = .{ llvm_error_type, pad_type, llvm_payload_type };
2465 return dg.context.structType(&fields, fields.len, .False);2482 return dg.context.structType(&fields, fields.len, .False);
2466 } else {2483 } else {
2467 const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type };2484 const fields: [2]*const llvm.Type = .{ llvm_payload_type, llvm_error_type };
2468 return dg.context.structType(&fields, fields.len, .False);2485 return dg.context.structType(&fields, fields.len, .False);
2469 }2486 }
2470 },2487 },
2471 .ErrorSet => {2488 .ErrorSet => return dg.context.intType(16),
2472 return dg.context.intType(16);
2473 },
2474 .Struct => {2489 .Struct => {
2475 const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module });2490 const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module });
2476 if (gop.found_existing) return gop.value_ptr.*;2491 if (gop.found_existing) return gop.value_ptr.*;
...@@ -2507,7 +2522,7 @@ pub const DeclGen = struct {...@@ -2507,7 +2522,7 @@ pub const DeclGen = struct {
2507 const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));2522 const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
2508 try llvm_field_types.append(gpa, llvm_array_ty);2523 try llvm_field_types.append(gpa, llvm_array_ty);
2509 }2524 }
2510 const field_llvm_ty = try dg.llvmType(field_ty);2525 const field_llvm_ty = try dg.lowerType(field_ty);
2511 try llvm_field_types.append(gpa, field_llvm_ty);2526 try llvm_field_types.append(gpa, field_llvm_ty);
25122527
2513 offset += field_ty.abiSize(target);2528 offset += field_ty.abiSize(target);
...@@ -2536,7 +2551,7 @@ pub const DeclGen = struct {...@@ -2536,7 +2551,7 @@ pub const DeclGen = struct {
2536 if (struct_obj.layout == .Packed) {2551 if (struct_obj.layout == .Packed) {
2537 var buf: Type.Payload.Bits = undefined;2552 var buf: Type.Payload.Bits = undefined;
2538 const int_ty = struct_obj.packedIntegerType(target, &buf);2553 const int_ty = struct_obj.packedIntegerType(target, &buf);
2539 const int_llvm_ty = try dg.llvmType(int_ty);2554 const int_llvm_ty = try dg.lowerType(int_ty);
2540 gop.value_ptr.* = int_llvm_ty;2555 gop.value_ptr.* = int_llvm_ty;
2541 return int_llvm_ty;2556 return int_llvm_ty;
2542 }2557 }
...@@ -2571,7 +2586,7 @@ pub const DeclGen = struct {...@@ -2571,7 +2586,7 @@ pub const DeclGen = struct {
2571 const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));2586 const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
2572 try llvm_field_types.append(gpa, llvm_array_ty);2587 try llvm_field_types.append(gpa, llvm_array_ty);
2573 }2588 }
2574 const field_llvm_ty = try dg.llvmType(field.ty);2589 const field_llvm_ty = try dg.lowerType(field.ty);
2575 try llvm_field_types.append(gpa, field_llvm_ty);2590 try llvm_field_types.append(gpa, field_llvm_ty);
25762591
2577 offset += field.ty.abiSize(target);2592 offset += field.ty.abiSize(target);
...@@ -2606,7 +2621,7 @@ pub const DeclGen = struct {...@@ -2606,7 +2621,7 @@ pub const DeclGen = struct {
2606 const union_obj = t.cast(Type.Payload.Union).?.data;2621 const union_obj = t.cast(Type.Payload.Union).?.data;
26072622
2608 if (layout.payload_size == 0) {2623 if (layout.payload_size == 0) {
2609 const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);2624 const enum_tag_llvm_ty = try dg.lowerType(union_obj.tag_ty);
2610 gop.value_ptr.* = enum_tag_llvm_ty;2625 gop.value_ptr.* = enum_tag_llvm_ty;
2611 return enum_tag_llvm_ty;2626 return enum_tag_llvm_ty;
2612 }2627 }
...@@ -2618,7 +2633,7 @@ pub const DeclGen = struct {...@@ -2618,7 +2633,7 @@ pub const DeclGen = struct {
2618 gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls2633 gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls
26192634
2620 const aligned_field = union_obj.fields.values()[layout.most_aligned_field];2635 const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
2621 const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty);2636 const llvm_aligned_field_ty = try dg.lowerType(aligned_field.ty);
26222637
2623 const llvm_payload_ty = t: {2638 const llvm_payload_ty = t: {
2624 if (layout.most_aligned_field_size == layout.payload_size) {2639 if (layout.most_aligned_field_size == layout.payload_size) {
...@@ -2637,7 +2652,7 @@ pub const DeclGen = struct {...@@ -2637,7 +2652,7 @@ pub const DeclGen = struct {
2637 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);2652 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);
2638 return llvm_union_ty;2653 return llvm_union_ty;
2639 }2654 }
2640 const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);2655 const enum_tag_llvm_ty = try dg.lowerType(union_obj.tag_ty);
26412656
2642 // Put the tag before or after the payload depending on which one's2657 // Put the tag before or after the payload depending on which one's
2643 // alignment is greater.2658 // alignment is greater.
...@@ -2659,7 +2674,7 @@ pub const DeclGen = struct {...@@ -2659,7 +2674,7 @@ pub const DeclGen = struct {
2659 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);2674 llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
2660 return llvm_union_ty;2675 return llvm_union_ty;
2661 },2676 },
2662 .Fn => return llvmTypeFn(dg, t),2677 .Fn => return lowerTypeFn(dg, t),
2663 .ComptimeInt => unreachable,2678 .ComptimeInt => unreachable,
2664 .ComptimeFloat => unreachable,2679 .ComptimeFloat => unreachable,
2665 .Type => unreachable,2680 .Type => unreachable,
...@@ -2674,7 +2689,7 @@ pub const DeclGen = struct {...@@ -2674,7 +2689,7 @@ pub const DeclGen = struct {
2674 }2689 }
2675 }2690 }
26762691
2677 fn llvmTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*const llvm.Type {2692 fn lowerTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*const llvm.Type {
2678 const target = dg.module.getTarget();2693 const target = dg.module.getTarget();
2679 const fn_info = fn_ty.fnInfo();2694 const fn_info = fn_ty.fnInfo();
2680 const llvm_ret_ty = try lowerFnRetTy(dg, fn_info);2695 const llvm_ret_ty = try lowerFnRetTy(dg, fn_info);
...@@ -2683,7 +2698,7 @@ pub const DeclGen = struct {...@@ -2683,7 +2698,7 @@ pub const DeclGen = struct {
2683 defer llvm_params.deinit();2698 defer llvm_params.deinit();
26842699
2685 if (firstParamSRet(fn_info, target)) {2700 if (firstParamSRet(fn_info, target)) {
2686 const llvm_sret_ty = try dg.llvmType(fn_info.return_type);2701 const llvm_sret_ty = try dg.lowerType(fn_info.return_type);
2687 try llvm_params.append(llvm_sret_ty.pointerType(0));2702 try llvm_params.append(llvm_sret_ty.pointerType(0));
2688 }2703 }
26892704
...@@ -2695,7 +2710,7 @@ pub const DeclGen = struct {...@@ -2695,7 +2710,7 @@ pub const DeclGen = struct {
2695 .data = dg.object.getStackTraceType(),2710 .data = dg.object.getStackTraceType(),
2696 };2711 };
2697 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);2712 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2698 try llvm_params.append(try dg.llvmType(ptr_ty));2713 try llvm_params.append(try dg.lowerType(ptr_ty));
2699 }2714 }
27002715
2701 var it = iterateParamTypes(dg, fn_info);2716 var it = iterateParamTypes(dg, fn_info);
...@@ -2703,11 +2718,11 @@ pub const DeclGen = struct {...@@ -2703,11 +2718,11 @@ pub const DeclGen = struct {
2703 .no_bits => continue,2718 .no_bits => continue,
2704 .byval => {2719 .byval => {
2705 const param_ty = fn_info.param_types[it.zig_index - 1];2720 const param_ty = fn_info.param_types[it.zig_index - 1];
2706 try llvm_params.append(try dg.llvmType(param_ty));2721 try llvm_params.append(try dg.lowerType(param_ty));
2707 },2722 },
2708 .byref => {2723 .byref => {
2709 const param_ty = fn_info.param_types[it.zig_index - 1];2724 const param_ty = fn_info.param_types[it.zig_index - 1];
2710 const raw_llvm_ty = try dg.llvmType(param_ty);2725 const raw_llvm_ty = try dg.lowerType(param_ty);
2711 try llvm_params.append(raw_llvm_ty.pointerType(0));2726 try llvm_params.append(raw_llvm_ty.pointerType(0));
2712 },2727 },
2713 .abi_sized_int => {2728 .abi_sized_int => {
...@@ -2749,7 +2764,7 @@ pub const DeclGen = struct {...@@ -2749,7 +2764,7 @@ pub const DeclGen = struct {
2749 // one field; in this case keep the type information2764 // one field; in this case keep the type information
2750 // to avoid the potentially costly ptrtoint/bitcast.2765 // to avoid the potentially costly ptrtoint/bitcast.
2751 if (bits_used == 0 and field_abi_bits == int_bits) {2766 if (bits_used == 0 and field_abi_bits == int_bits) {
2752 const llvm_field_ty = try dg.llvmType(field.ty);2767 const llvm_field_ty = try dg.lowerType(field.ty);
2753 llvm_params.appendAssumeCapacity(llvm_field_ty);2768 llvm_params.appendAssumeCapacity(llvm_field_ty);
2754 field_i += 1;2769 field_i += 1;
2755 if (field_i >= fields.len) {2770 if (field_i >= fields.len) {
...@@ -2787,16 +2802,16 @@ pub const DeclGen = struct {...@@ -2787,16 +2802,16 @@ pub const DeclGen = struct {
2787 );2802 );
2788 }2803 }
27892804
2790 fn genTypedValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value {2805 fn lowerValue(dg: *DeclGen, tv: TypedValue) Error!*const llvm.Value {
2791 if (tv.val.isUndef()) {2806 if (tv.val.isUndef()) {
2792 const llvm_type = try dg.llvmType(tv.ty);2807 const llvm_type = try dg.lowerType(tv.ty);
2793 return llvm_type.getUndef();2808 return llvm_type.getUndef();
2794 }2809 }
2795 const target = dg.module.getTarget();2810 const target = dg.module.getTarget();
27962811
2797 switch (tv.ty.zigTypeTag()) {2812 switch (tv.ty.zigTypeTag()) {
2798 .Bool => {2813 .Bool => {
2799 const llvm_type = try dg.llvmType(tv.ty);2814 const llvm_type = try dg.lowerType(tv.ty);
2800 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();2815 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
2801 },2816 },
2802 // TODO this duplicates code with Pointer but they should share the handling2817 // TODO this duplicates code with Pointer but they should share the handling
...@@ -2857,7 +2872,7 @@ pub const DeclGen = struct {...@@ -2857,7 +2872,7 @@ pub const DeclGen = struct {
2857 return unsigned_val;2872 return unsigned_val;
2858 },2873 },
2859 .Float => {2874 .Float => {
2860 const llvm_ty = try dg.llvmType(tv.ty);2875 const llvm_ty = try dg.lowerType(tv.ty);
2861 switch (tv.ty.floatBits(target)) {2876 switch (tv.ty.floatBits(target)) {
2862 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)),2877 16, 32, 64 => return llvm_ty.constReal(tv.val.toFloat(f64)),
2863 80 => {2878 80 => {
...@@ -2894,7 +2909,7 @@ pub const DeclGen = struct {...@@ -2894,7 +2909,7 @@ pub const DeclGen = struct {
2894 const decl = dg.module.declPtr(decl_index);2909 const decl = dg.module.declPtr(decl_index);
2895 dg.module.markDeclAlive(decl);2910 dg.module.markDeclAlive(decl);
2896 const val = try dg.resolveGlobalDecl(decl_index);2911 const val = try dg.resolveGlobalDecl(decl_index);
2897 const llvm_var_type = try dg.llvmType(tv.ty);2912 const llvm_var_type = try dg.lowerType(tv.ty);
2898 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");2913 const llvm_addrspace = dg.llvmAddressSpace(decl.@"addrspace");
2899 const llvm_type = llvm_var_type.pointerType(llvm_addrspace);2914 const llvm_type = llvm_var_type.pointerType(llvm_addrspace);
2900 return val.constBitCast(llvm_type);2915 return val.constBitCast(llvm_type);
...@@ -2903,11 +2918,11 @@ pub const DeclGen = struct {...@@ -2903,11 +2918,11 @@ pub const DeclGen = struct {
2903 const slice = tv.val.castTag(.slice).?.data;2918 const slice = tv.val.castTag(.slice).?.data;
2904 var buf: Type.SlicePtrFieldTypeBuffer = undefined;2919 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2905 const fields: [2]*const llvm.Value = .{2920 const fields: [2]*const llvm.Value = .{
2906 try dg.genTypedValue(.{2921 try dg.lowerValue(.{
2907 .ty = tv.ty.slicePtrFieldType(&buf),2922 .ty = tv.ty.slicePtrFieldType(&buf),
2908 .val = slice.ptr,2923 .val = slice.ptr,
2909 }),2924 }),
2910 try dg.genTypedValue(.{2925 try dg.lowerValue(.{
2911 .ty = Type.usize,2926 .ty = Type.usize,
2912 .val = slice.len,2927 .val = slice.len,
2913 }),2928 }),
...@@ -2915,15 +2930,15 @@ pub const DeclGen = struct {...@@ -2915,15 +2930,15 @@ pub const DeclGen = struct {
2915 return dg.context.constStruct(&fields, fields.len, .False);2930 return dg.context.constStruct(&fields, fields.len, .False);
2916 },2931 },
2917 .int_u64, .one, .int_big_positive => {2932 .int_u64, .one, .int_big_positive => {
2918 const llvm_usize = try dg.llvmType(Type.usize);2933 const llvm_usize = try dg.lowerType(Type.usize);
2919 const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(target), .False);2934 const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(target), .False);
2920 return llvm_int.constIntToPtr(try dg.llvmType(tv.ty));2935 return llvm_int.constIntToPtr(try dg.lowerType(tv.ty));
2921 },2936 },
2922 .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => {2937 .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => {
2923 return dg.lowerParentPtr(tv.val, tv.ty.childType());2938 return dg.lowerParentPtr(tv.val, tv.ty.childType());
2924 },2939 },
2925 .null_value, .zero => {2940 .null_value, .zero => {
2926 const llvm_type = try dg.llvmType(tv.ty);2941 const llvm_type = try dg.lowerType(tv.ty);
2927 return llvm_type.constNull();2942 return llvm_type.constNull();
2928 },2943 },
2929 else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{2944 else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{
...@@ -2978,7 +2993,7 @@ pub const DeclGen = struct {...@@ -2978,7 +2993,7 @@ pub const DeclGen = struct {
2978 defer gpa.free(llvm_elems);2993 defer gpa.free(llvm_elems);
2979 var need_unnamed = false;2994 var need_unnamed = false;
2980 for (elem_vals[0..len]) |elem_val, i| {2995 for (elem_vals[0..len]) |elem_val, i| {
2981 llvm_elems[i] = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_val });2996 llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val });
2982 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]);2997 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]);
2983 }2998 }
2984 if (need_unnamed) {2999 if (need_unnamed) {
...@@ -2988,7 +3003,7 @@ pub const DeclGen = struct {...@@ -2988,7 +3003,7 @@ pub const DeclGen = struct {
2988 .True,3003 .True,
2989 );3004 );
2990 } else {3005 } else {
2991 const llvm_elem_ty = try dg.llvmType(elem_ty);3006 const llvm_elem_ty = try dg.lowerType(elem_ty);
2992 return llvm_elem_ty.constArray(3007 return llvm_elem_ty.constArray(
2993 llvm_elems.ptr,3008 llvm_elems.ptr,
2994 @intCast(c_uint, llvm_elems.len),3009 @intCast(c_uint, llvm_elems.len),
...@@ -3008,13 +3023,13 @@ pub const DeclGen = struct {...@@ -3008,13 +3023,13 @@ pub const DeclGen = struct {
3008 var need_unnamed = false;3023 var need_unnamed = false;
3009 if (len != 0) {3024 if (len != 0) {
3010 for (llvm_elems[0..len]) |*elem| {3025 for (llvm_elems[0..len]) |*elem| {
3011 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val });3026 elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val });
3012 }3027 }
3013 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]);3028 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]);
3014 }3029 }
30153030
3016 if (sentinel) |sent| {3031 if (sentinel) |sent| {
3017 llvm_elems[len] = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent });3032 llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent });
3018 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]);3033 need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]);
3019 }3034 }
30203035
...@@ -3025,7 +3040,7 @@ pub const DeclGen = struct {...@@ -3025,7 +3040,7 @@ pub const DeclGen = struct {
3025 .True,3040 .True,
3026 );3041 );
3027 } else {3042 } else {
3028 const llvm_elem_ty = try dg.llvmType(elem_ty);3043 const llvm_elem_ty = try dg.lowerType(elem_ty);
3029 return llvm_elem_ty.constArray(3044 return llvm_elem_ty.constArray(
3030 llvm_elems.ptr,3045 llvm_elems.ptr,
3031 @intCast(c_uint, llvm_elems.len),3046 @intCast(c_uint, llvm_elems.len),
...@@ -3035,13 +3050,13 @@ pub const DeclGen = struct {...@@ -3035,13 +3050,13 @@ pub const DeclGen = struct {
3035 .empty_array_sentinel => {3050 .empty_array_sentinel => {
3036 const elem_ty = tv.ty.elemType();3051 const elem_ty = tv.ty.elemType();
3037 const sent_val = tv.ty.sentinel().?;3052 const sent_val = tv.ty.sentinel().?;
3038 const sentinel = try dg.genTypedValue(.{ .ty = elem_ty, .val = sent_val });3053 const sentinel = try dg.lowerValue(.{ .ty = elem_ty, .val = sent_val });
3039 const llvm_elems: [1]*const llvm.Value = .{sentinel};3054 const llvm_elems: [1]*const llvm.Value = .{sentinel};
3040 const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]);3055 const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]);
3041 if (need_unnamed) {3056 if (need_unnamed) {
3042 return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True);3057 return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True);
3043 } else {3058 } else {
3044 const llvm_elem_ty = try dg.llvmType(elem_ty);3059 const llvm_elem_ty = try dg.lowerType(elem_ty);
3045 return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len);3060 return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len);
3046 }3061 }
3047 },3062 },
...@@ -3056,19 +3071,19 @@ pub const DeclGen = struct {...@@ -3056,19 +3071,19 @@ pub const DeclGen = struct {
3056 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {3071 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3057 return non_null_bit;3072 return non_null_bit;
3058 }3073 }
3059 if (tv.ty.isPtrLikeOptional()) {3074 if (tv.ty.optionalReprIsPayload()) {
3060 if (tv.val.castTag(.opt_payload)) |payload| {3075 if (tv.val.castTag(.opt_payload)) |payload| {
3061 return dg.genTypedValue(.{ .ty = payload_ty, .val = payload.data });3076 return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data });
3062 } else if (is_pl) {3077 } else if (is_pl) {
3063 return dg.genTypedValue(.{ .ty = payload_ty, .val = tv.val });3078 return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val });
3064 } else {3079 } else {
3065 const llvm_ty = try dg.llvmType(tv.ty);3080 const llvm_ty = try dg.lowerType(tv.ty);
3066 return llvm_ty.constNull();3081 return llvm_ty.constNull();
3067 }3082 }
3068 }3083 }
3069 assert(payload_ty.zigTypeTag() != .Fn);3084 assert(payload_ty.zigTypeTag() != .Fn);
3070 const fields: [2]*const llvm.Value = .{3085 const fields: [2]*const llvm.Value = .{
3071 try dg.genTypedValue(.{3086 try dg.lowerValue(.{
3072 .ty = payload_ty,3087 .ty = payload_ty,
3073 .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),3088 .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef),
3074 }),3089 }),
...@@ -3087,7 +3102,7 @@ pub const DeclGen = struct {...@@ -3087,7 +3102,7 @@ pub const DeclGen = struct {
3087 return dg.resolveLlvmFunction(fn_decl_index);3102 return dg.resolveLlvmFunction(fn_decl_index);
3088 },3103 },
3089 .ErrorSet => {3104 .ErrorSet => {
3090 const llvm_ty = try dg.llvmType(tv.ty);3105 const llvm_ty = try dg.lowerType(Type.anyerror);
3091 switch (tv.val.tag()) {3106 switch (tv.val.tag()) {
3092 .@"error" => {3107 .@"error" => {
3093 const err_name = tv.val.castTag(.@"error").?.data.name;3108 const err_name = tv.val.castTag(.@"error").?.data.name;
...@@ -3101,40 +3116,39 @@ pub const DeclGen = struct {...@@ -3101,40 +3116,39 @@ pub const DeclGen = struct {
3101 }3116 }
3102 },3117 },
3103 .ErrorUnion => {3118 .ErrorUnion => {
3104 const error_type = tv.ty.errorUnionSet();
3105 const payload_type = tv.ty.errorUnionPayload();3119 const payload_type = tv.ty.errorUnionPayload();
3120 if (tv.ty.errorUnionSet().errorSetCardinality() == .zero) {
3121 const payload_val = tv.val.castTag(.eu_payload).?.data;
3122 return dg.lowerValue(.{ .ty = payload_type, .val = payload_val });
3123 }
3106 const is_pl = tv.val.errorUnionIsPayload();3124 const is_pl = tv.val.errorUnionIsPayload();
31073125
3108 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {3126 if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
3109 // We use the error type directly as the type.3127 // We use the error type directly as the type.
3110 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);3128 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
3111 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });3129 return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val });
3112 }3130 }
3113 var len: u8 = 2;
3114 var fields: [3]*const llvm.Value = .{
3115 try dg.genTypedValue(.{
3116 .ty = error_type,
3117 .val = if (is_pl) Value.initTag(.zero) else tv.val,
3118 }),
3119 try dg.genTypedValue(.{
3120 .ty = payload_type,
3121 .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
3122 }),
3123 undefined,
3124 };
31253131
3126 const payload_align = payload_type.abiAlignment(target);3132 const payload_align = payload_type.abiAlignment(target);
3127 const error_size = error_type.abiSize(target);3133 const error_align = Type.anyerror.abiAlignment(target);
3128 if (payload_align > error_size) {3134 const llvm_error_value = try dg.lowerValue(.{
3129 fields[2] = fields[1];3135 .ty = Type.anyerror,
3130 const pad_type = dg.context.intType(8).arrayType(@intCast(u32, payload_align - error_size));3136 .val = if (is_pl) Value.initTag(.zero) else tv.val,
3131 fields[1] = pad_type.getUndef();3137 });
3132 len += 1;3138 const llvm_payload_value = try dg.lowerValue(.{
3139 .ty = payload_type,
3140 .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
3141 });
3142 if (error_align > payload_align) {
3143 const fields: [2]*const llvm.Value = .{ llvm_error_value, llvm_payload_value };
3144 return dg.context.constStruct(&fields, fields.len, .False);
3145 } else {
3146 const fields: [2]*const llvm.Value = .{ llvm_payload_value, llvm_error_value };
3147 return dg.context.constStruct(&fields, fields.len, .False);
3133 }3148 }
3134 return dg.context.constStruct(&fields, len, .False);
3135 },3149 },
3136 .Struct => {3150 .Struct => {
3137 const llvm_struct_ty = try dg.llvmType(tv.ty);3151 const llvm_struct_ty = try dg.lowerType(tv.ty);
3138 const field_vals = tv.val.castTag(.aggregate).?.data;3152 const field_vals = tv.val.castTag(.aggregate).?.data;
3139 const gpa = dg.gpa;3153 const gpa = dg.gpa;
31403154
...@@ -3167,7 +3181,7 @@ pub const DeclGen = struct {...@@ -3167,7 +3181,7 @@ pub const DeclGen = struct {
3167 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());3181 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
3168 }3182 }
31693183
3170 const field_llvm_val = try dg.genTypedValue(.{3184 const field_llvm_val = try dg.lowerValue(.{
3171 .ty = field_ty,3185 .ty = field_ty,
3172 .val = field_vals[i],3186 .val = field_vals[i],
3173 });3187 });
...@@ -3215,7 +3229,7 @@ pub const DeclGen = struct {...@@ -3215,7 +3229,7 @@ pub const DeclGen = struct {
3215 const field = fields[i];3229 const field = fields[i];
3216 if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;3230 if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
32173231
3218 const non_int_val = try dg.genTypedValue(.{3232 const non_int_val = try dg.lowerValue(.{
3219 .ty = field.ty,3233 .ty = field.ty,
3220 .val = field_val,3234 .val = field_val,
3221 });3235 });
...@@ -3259,7 +3273,7 @@ pub const DeclGen = struct {...@@ -3259,7 +3273,7 @@ pub const DeclGen = struct {
3259 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());3273 llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef());
3260 }3274 }
32613275
3262 const field_llvm_val = try dg.genTypedValue(.{3276 const field_llvm_val = try dg.lowerValue(.{
3263 .ty = field.ty,3277 .ty = field.ty,
3264 .val = field_vals[i],3278 .val = field_vals[i],
3265 });3279 });
...@@ -3294,13 +3308,13 @@ pub const DeclGen = struct {...@@ -3294,13 +3308,13 @@ pub const DeclGen = struct {
3294 }3308 }
3295 },3309 },
3296 .Union => {3310 .Union => {
3297 const llvm_union_ty = try dg.llvmType(tv.ty);3311 const llvm_union_ty = try dg.lowerType(tv.ty);
3298 const tag_and_val = tv.val.castTag(.@"union").?.data;3312 const tag_and_val = tv.val.castTag(.@"union").?.data;
32993313
3300 const layout = tv.ty.unionGetLayout(target);3314 const layout = tv.ty.unionGetLayout(target);
33013315
3302 if (layout.payload_size == 0) {3316 if (layout.payload_size == 0) {
3303 return genTypedValue(dg, .{3317 return lowerValue(dg, .{
3304 .ty = tv.ty.unionTagType().?,3318 .ty = tv.ty.unionTagType().?,
3305 .val = tag_and_val.tag,3319 .val = tag_and_val.tag,
3306 });3320 });
...@@ -3314,7 +3328,7 @@ pub const DeclGen = struct {...@@ -3314,7 +3328,7 @@ pub const DeclGen = struct {
3314 const padding_len = @intCast(c_uint, layout.payload_size);3328 const padding_len = @intCast(c_uint, layout.payload_size);
3315 break :p dg.context.intType(8).arrayType(padding_len).getUndef();3329 break :p dg.context.intType(8).arrayType(padding_len).getUndef();
3316 }3330 }
3317 const field = try genTypedValue(dg, .{ .ty = field_ty, .val = tag_and_val.val });3331 const field = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val });
3318 const field_size = field_ty.abiSize(target);3332 const field_size = field_ty.abiSize(target);
3319 if (field_size == layout.payload_size) {3333 if (field_size == layout.payload_size) {
3320 break :p field;3334 break :p field;
...@@ -3340,7 +3354,7 @@ pub const DeclGen = struct {...@@ -3340,7 +3354,7 @@ pub const DeclGen = struct {
3340 return llvm_union_ty.constNamedStruct(&fields, fields.len);3354 return llvm_union_ty.constNamedStruct(&fields, fields.len);
3341 }3355 }
3342 }3356 }
3343 const llvm_tag_value = try genTypedValue(dg, .{3357 const llvm_tag_value = try lowerValue(dg, .{
3344 .ty = tv.ty.unionTagType().?,3358 .ty = tv.ty.unionTagType().?,
3345 .val = tag_and_val.tag,3359 .val = tag_and_val.tag,
3346 });3360 });
...@@ -3377,7 +3391,7 @@ pub const DeclGen = struct {...@@ -3377,7 +3391,7 @@ pub const DeclGen = struct {
3377 .data = bytes[i],3391 .data = bytes[i],
3378 };3392 };
33793393
3380 elem.* = try dg.genTypedValue(.{3394 elem.* = try dg.lowerValue(.{
3381 .ty = elem_ty,3395 .ty = elem_ty,
3382 .val = Value.initPayload(&byte_payload.base),3396 .val = Value.initPayload(&byte_payload.base),
3383 });3397 });
...@@ -3397,7 +3411,7 @@ pub const DeclGen = struct {...@@ -3397,7 +3411,7 @@ pub const DeclGen = struct {
3397 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len);3411 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, vector_len);
3398 defer dg.gpa.free(llvm_elems);3412 defer dg.gpa.free(llvm_elems);
3399 for (llvm_elems) |*elem, i| {3413 for (llvm_elems) |*elem, i| {
3400 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = elem_vals[i] });3414 elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_vals[i] });
3401 }3415 }
3402 return llvm.constVector(3416 return llvm.constVector(
3403 llvm_elems.ptr,3417 llvm_elems.ptr,
...@@ -3412,7 +3426,7 @@ pub const DeclGen = struct {...@@ -3412,7 +3426,7 @@ pub const DeclGen = struct {
3412 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, len);3426 const llvm_elems = try dg.gpa.alloc(*const llvm.Value, len);
3413 defer dg.gpa.free(llvm_elems);3427 defer dg.gpa.free(llvm_elems);
3414 for (llvm_elems) |*elem| {3428 for (llvm_elems) |*elem| {
3415 elem.* = try dg.genTypedValue(.{ .ty = elem_ty, .val = val });3429 elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val });
3416 }3430 }
3417 return llvm.constVector(3431 return llvm.constVector(
3418 llvm_elems.ptr,3432 llvm_elems.ptr,
...@@ -3462,7 +3476,7 @@ pub const DeclGen = struct {...@@ -3462,7 +3476,7 @@ pub const DeclGen = struct {
3462 if (ptr_child_ty.eql(decl.ty, dg.module)) {3476 if (ptr_child_ty.eql(decl.ty, dg.module)) {
3463 return llvm_ptr;3477 return llvm_ptr;
3464 } else {3478 } else {
3465 return llvm_ptr.constBitCast((try dg.llvmType(ptr_child_ty)).pointerType(0));3479 return llvm_ptr.constBitCast((try dg.lowerType(ptr_child_ty)).pointerType(0));
3466 }3480 }
3467 }3481 }
34683482
...@@ -3484,15 +3498,15 @@ pub const DeclGen = struct {...@@ -3484,15 +3498,15 @@ pub const DeclGen = struct {
3484 },3498 },
3485 .int_i64 => {3499 .int_i64 => {
3486 const int = ptr_val.castTag(.int_i64).?.data;3500 const int = ptr_val.castTag(.int_i64).?.data;
3487 const llvm_usize = try dg.llvmType(Type.usize);3501 const llvm_usize = try dg.lowerType(Type.usize);
3488 const llvm_int = llvm_usize.constInt(@bitCast(u64, int), .False);3502 const llvm_int = llvm_usize.constInt(@bitCast(u64, int), .False);
3489 return llvm_int.constIntToPtr((try dg.llvmType(ptr_child_ty)).pointerType(0));3503 return llvm_int.constIntToPtr((try dg.lowerType(ptr_child_ty)).pointerType(0));
3490 },3504 },
3491 .int_u64 => {3505 .int_u64 => {
3492 const int = ptr_val.castTag(.int_u64).?.data;3506 const int = ptr_val.castTag(.int_u64).?.data;
3493 const llvm_usize = try dg.llvmType(Type.usize);3507 const llvm_usize = try dg.lowerType(Type.usize);
3494 const llvm_int = llvm_usize.constInt(int, .False);3508 const llvm_int = llvm_usize.constInt(int, .False);
3495 return llvm_int.constIntToPtr((try dg.llvmType(ptr_child_ty)).pointerType(0));3509 return llvm_int.constIntToPtr((try dg.lowerType(ptr_child_ty)).pointerType(0));
3496 },3510 },
3497 .field_ptr => blk: {3511 .field_ptr => blk: {
3498 const field_ptr = ptr_val.castTag(.field_ptr).?.data;3512 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
...@@ -3541,7 +3555,7 @@ pub const DeclGen = struct {...@@ -3541,7 +3555,7 @@ pub const DeclGen = struct {
3541 const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);3555 const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, elem_ptr.elem_ty);
3542 bitcast_needed = !elem_ptr.elem_ty.eql(ptr_child_ty, dg.module);3556 bitcast_needed = !elem_ptr.elem_ty.eql(ptr_child_ty, dg.module);
35433557
3544 const llvm_usize = try dg.llvmType(Type.usize);3558 const llvm_usize = try dg.lowerType(Type.usize);
3545 const indices: [1]*const llvm.Value = .{3559 const indices: [1]*const llvm.Value = .{
3546 llvm_usize.constInt(elem_ptr.index, .False),3560 llvm_usize.constInt(elem_ptr.index, .False),
3547 };3561 };
...@@ -3555,7 +3569,9 @@ pub const DeclGen = struct {...@@ -3555,7 +3569,9 @@ pub const DeclGen = struct {
3555 const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf);3569 const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf);
3556 bitcast_needed = !payload_ty.eql(ptr_child_ty, dg.module);3570 bitcast_needed = !payload_ty.eql(ptr_child_ty, dg.module);
35573571
3558 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or payload_ty.isPtrLikeOptional()) {3572 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or
3573 payload_ty.optionalReprIsPayload())
3574 {
3559 // In this case, we represent pointer to optional the same as pointer3575 // In this case, we represent pointer to optional the same as pointer
3560 // to the payload.3576 // to the payload.
3561 break :blk parent_llvm_ptr;3577 break :blk parent_llvm_ptr;
...@@ -3592,7 +3608,7 @@ pub const DeclGen = struct {...@@ -3592,7 +3608,7 @@ pub const DeclGen = struct {
3592 else => unreachable,3608 else => unreachable,
3593 };3609 };
3594 if (bitcast_needed) {3610 if (bitcast_needed) {
3595 return llvm_ptr.constBitCast((try dg.llvmType(ptr_child_ty)).pointerType(0));3611 return llvm_ptr.constBitCast((try dg.lowerType(ptr_child_ty)).pointerType(0));
3596 } else {3612 } else {
3597 return llvm_ptr;3613 return llvm_ptr;
3598 }3614 }
...@@ -3611,11 +3627,11 @@ pub const DeclGen = struct {...@@ -3611,11 +3627,11 @@ pub const DeclGen = struct {
3611 .data = tv.val.sliceLen(self.module),3627 .data = tv.val.sliceLen(self.module),
3612 };3628 };
3613 const fields: [2]*const llvm.Value = .{3629 const fields: [2]*const llvm.Value = .{
3614 try self.genTypedValue(.{3630 try self.lowerValue(.{
3615 .ty = ptr_ty,3631 .ty = ptr_ty,
3616 .val = tv.val,3632 .val = tv.val,
3617 }),3633 }),
3618 try self.genTypedValue(.{3634 try self.lowerValue(.{
3619 .ty = Type.usize,3635 .ty = Type.usize,
3620 .val = Value.initPayload(&slice_len.base),3636 .val = Value.initPayload(&slice_len.base),
3621 }),3637 }),
...@@ -3647,7 +3663,7 @@ pub const DeclGen = struct {...@@ -3647,7 +3663,7 @@ pub const DeclGen = struct {
3647 else3663 else
3648 try self.resolveGlobalDecl(decl_index);3664 try self.resolveGlobalDecl(decl_index);
36493665
3650 const llvm_type = try self.llvmType(tv.ty);3666 const llvm_type = try self.lowerType(tv.ty);
3651 if (tv.ty.zigTypeTag() == .Int) {3667 if (tv.ty.zigTypeTag() == .Int) {
3652 return llvm_val.constPtrToInt(llvm_type);3668 return llvm_val.constPtrToInt(llvm_type);
3653 } else {3669 } else {
...@@ -3662,8 +3678,8 @@ pub const DeclGen = struct {...@@ -3662,8 +3678,8 @@ pub const DeclGen = struct {
3662 // The value cannot be undefined, because we use the `nonnull` annotation3678 // The value cannot be undefined, because we use the `nonnull` annotation
3663 // for non-optional pointers. We also need to respect the alignment, even though3679 // for non-optional pointers. We also need to respect the alignment, even though
3664 // the address will never be dereferenced.3680 // the address will never be dereferenced.
3665 const llvm_usize = try dg.llvmType(Type.usize);3681 const llvm_usize = try dg.lowerType(Type.usize);
3666 const llvm_ptr_ty = try dg.llvmType(ptr_ty);3682 const llvm_ptr_ty = try dg.lowerType(ptr_ty);
3667 if (alignment != 0) {3683 if (alignment != 0) {
3668 return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty);3684 return llvm_usize.constInt(alignment, .False).constIntToPtr(llvm_ptr_ty);
3669 }3685 }
...@@ -3842,7 +3858,7 @@ pub const FuncGen = struct {...@@ -3842,7 +3858,7 @@ pub const FuncGen = struct {
38423858
3843 const val = self.air.value(inst).?;3859 const val = self.air.value(inst).?;
3844 const ty = self.air.typeOf(inst);3860 const ty = self.air.typeOf(inst);
3845 const llvm_val = try self.dg.genTypedValue(.{ .ty = ty, .val = val });3861 const llvm_val = try self.dg.lowerValue(.{ .ty = ty, .val = val });
3846 if (!isByRef(ty)) {3862 if (!isByRef(ty)) {
3847 gop.value_ptr.* = llvm_val;3863 gop.value_ptr.* = llvm_val;
3848 return llvm_val;3864 return llvm_val;
...@@ -3860,7 +3876,7 @@ pub const FuncGen = struct {...@@ -3860,7 +3876,7 @@ pub const FuncGen = struct {
3860 // Because of LLVM limitations for lowering certain types such as unions,3876 // Because of LLVM limitations for lowering certain types such as unions,
3861 // the type of global constants might not match the type it is supposed to3877 // the type of global constants might not match the type it is supposed to
3862 // be, and so we must bitcast the pointer at the usage sites.3878 // be, and so we must bitcast the pointer at the usage sites.
3863 const wanted_llvm_ty = try self.dg.llvmType(ty);3879 const wanted_llvm_ty = try self.dg.lowerType(ty);
3864 const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(0);3880 const wanted_llvm_ptr_ty = wanted_llvm_ty.pointerType(0);
3865 const casted_ptr = global.constBitCast(wanted_llvm_ptr_ty);3881 const casted_ptr = global.constBitCast(wanted_llvm_ptr_ty);
3866 gop.value_ptr.* = casted_ptr;3882 gop.value_ptr.* = casted_ptr;
...@@ -4084,7 +4100,7 @@ pub const FuncGen = struct {...@@ -4084,7 +4100,7 @@ pub const FuncGen = struct {
4084 defer llvm_args.deinit();4100 defer llvm_args.deinit();
40854101
4086 const ret_ptr = if (!sret) null else blk: {4102 const ret_ptr = if (!sret) null else blk: {
4087 const llvm_ret_ty = try self.dg.llvmType(return_type);4103 const llvm_ret_ty = try self.dg.lowerType(return_type);
4088 const ret_ptr = self.buildAlloca(llvm_ret_ty);4104 const ret_ptr = self.buildAlloca(llvm_ret_ty);
4089 ret_ptr.setAlignment(return_type.abiAlignment(target));4105 ret_ptr.setAlignment(return_type.abiAlignment(target));
4090 try llvm_args.append(ret_ptr);4106 try llvm_args.append(ret_ptr);
...@@ -4116,7 +4132,7 @@ pub const FuncGen = struct {...@@ -4116,7 +4132,7 @@ pub const FuncGen = struct {
4116 // which is always lowered to an LLVM type of `*i8`.4132 // which is always lowered to an LLVM type of `*i8`.
4117 // 2. The argument is a global which does act as a pointer, however4133 // 2. The argument is a global which does act as a pointer, however
4118 // a bitcast is needed in order for the LLVM types to match.4134 // a bitcast is needed in order for the LLVM types to match.
4119 const llvm_param_ty = try self.dg.llvmType(param_ty);4135 const llvm_param_ty = try self.dg.lowerType(param_ty);
4120 const casted_ptr = self.builder.buildBitCast(llvm_arg, llvm_param_ty, "");4136 const casted_ptr = self.builder.buildBitCast(llvm_arg, llvm_param_ty, "");
4121 try llvm_args.append(casted_ptr);4137 try llvm_args.append(casted_ptr);
4122 } else {4138 } else {
...@@ -4163,7 +4179,7 @@ pub const FuncGen = struct {...@@ -4163,7 +4179,7 @@ pub const FuncGen = struct {
4163 );4179 );
4164 const int_ptr = self.buildAlloca(int_llvm_ty);4180 const int_ptr = self.buildAlloca(int_llvm_ty);
4165 int_ptr.setAlignment(alignment);4181 int_ptr.setAlignment(alignment);
4166 const param_llvm_ty = try self.dg.llvmType(param_ty);4182 const param_llvm_ty = try self.dg.lowerType(param_ty);
4167 const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");4183 const casted_ptr = self.builder.buildBitCast(int_ptr, param_llvm_ty.pointerType(0), "");
4168 const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);4184 const store_inst = self.builder.buildStore(llvm_arg, casted_ptr);
4169 store_inst.setAlignment(alignment);4185 store_inst.setAlignment(alignment);
...@@ -4274,7 +4290,7 @@ pub const FuncGen = struct {...@@ -4274,7 +4290,7 @@ pub const FuncGen = struct {
4274 return null;4290 return null;
4275 }4291 }
42764292
4277 const llvm_ret_ty = try self.dg.llvmType(return_type);4293 const llvm_ret_ty = try self.dg.lowerType(return_type);
42784294
4279 if (ret_ptr) |rp| {4295 if (ret_ptr) |rp| {
4280 call.setCallSret(llvm_ret_ty);4296 call.setCallSret(llvm_ret_ty);
...@@ -4338,11 +4354,19 @@ pub const FuncGen = struct {...@@ -4338,11 +4354,19 @@ pub const FuncGen = struct {
4338 _ = self.builder.buildRetVoid();4354 _ = self.builder.buildRetVoid();
4339 return null;4355 return null;
4340 }4356 }
4357 const fn_info = self.dg.decl.ty.fnInfo();
4341 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {4358 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
4342 _ = self.builder.buildRetVoid();4359 if (fn_info.return_type.isError()) {
4360 // Functions with an empty error set are emitted with an error code
4361 // return type and return zero so they can be function pointers coerced
4362 // to functions that return anyerror.
4363 const err_int = try self.dg.lowerType(Type.anyerror);
4364 _ = self.builder.buildRet(err_int.constInt(0, .False));
4365 } else {
4366 _ = self.builder.buildRetVoid();
4367 }
4343 return null;4368 return null;
4344 }4369 }
4345 const fn_info = self.dg.decl.ty.fnInfo();
4346 const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);4370 const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
4347 const operand = try self.resolveInst(un_op);4371 const operand = try self.resolveInst(un_op);
4348 const llvm_ret_ty = operand.typeOf();4372 const llvm_ret_ty = operand.typeOf();
...@@ -4369,15 +4393,27 @@ pub const FuncGen = struct {...@@ -4369,15 +4393,27 @@ pub const FuncGen = struct {
4369 const un_op = self.air.instructions.items(.data)[inst].un_op;4393 const un_op = self.air.instructions.items(.data)[inst].un_op;
4370 const ptr_ty = self.air.typeOf(un_op);4394 const ptr_ty = self.air.typeOf(un_op);
4371 const ret_ty = ptr_ty.childType();4395 const ret_ty = ptr_ty.childType();
4372 if (!ret_ty.hasRuntimeBitsIgnoreComptime() or self.ret_ptr != null) {4396 const fn_info = self.dg.decl.ty.fnInfo();
4397 if (!ret_ty.hasRuntimeBitsIgnoreComptime()) {
4398 if (fn_info.return_type.isError()) {
4399 // Functions with an empty error set are emitted with an error code
4400 // return type and return zero so they can be function pointers coerced
4401 // to functions that return anyerror.
4402 const err_int = try self.dg.lowerType(Type.anyerror);
4403 _ = self.builder.buildRet(err_int.constInt(0, .False));
4404 } else {
4405 _ = self.builder.buildRetVoid();
4406 }
4407 return null;
4408 }
4409 if (self.ret_ptr != null) {
4373 _ = self.builder.buildRetVoid();4410 _ = self.builder.buildRetVoid();
4374 return null;4411 return null;
4375 }4412 }
4376 const ptr = try self.resolveInst(un_op);4413 const ptr = try self.resolveInst(un_op);
4377 const target = self.dg.module.getTarget();4414 const target = self.dg.module.getTarget();
4378 const fn_info = self.dg.decl.ty.fnInfo();
4379 const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);4415 const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
4380 const llvm_ret_ty = try self.dg.llvmType(ret_ty);4416 const llvm_ret_ty = try self.dg.lowerType(ret_ty);
4381 const casted_ptr = if (abi_ret_ty == llvm_ret_ty) ptr else p: {4417 const casted_ptr = if (abi_ret_ty == llvm_ret_ty) ptr else p: {
4382 const ptr_abi_ty = abi_ret_ty.pointerType(0);4418 const ptr_abi_ty = abi_ret_ty.pointerType(0);
4383 break :p self.builder.buildBitCast(ptr, ptr_abi_ty, "");4419 break :p self.builder.buildBitCast(ptr, ptr_abi_ty, "");
...@@ -4439,7 +4475,9 @@ pub const FuncGen = struct {...@@ -4439,7 +4475,9 @@ pub const FuncGen = struct {
4439 .Int, .Bool, .Pointer, .ErrorSet => scalar_ty,4475 .Int, .Bool, .Pointer, .ErrorSet => scalar_ty,
4440 .Optional => blk: {4476 .Optional => blk: {
4441 const payload_ty = operand_ty.optionalChild(&opt_buffer);4477 const payload_ty = operand_ty.optionalChild(&opt_buffer);
4442 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.isPtrLikeOptional()) {4478 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or
4479 operand_ty.optionalReprIsPayload())
4480 {
4443 break :blk operand_ty;4481 break :blk operand_ty;
4444 }4482 }
4445 // We need to emit instructions to check for equality/inequality4483 // We need to emit instructions to check for equality/inequality
...@@ -4556,7 +4594,7 @@ pub const FuncGen = struct {...@@ -4556,7 +4594,7 @@ pub const FuncGen = struct {
4556 const is_body = inst_ty.zigTypeTag() == .Fn;4594 const is_body = inst_ty.zigTypeTag() == .Fn;
4557 if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime()) return null;4595 if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime()) return null;
45584596
4559 const raw_llvm_ty = try self.dg.llvmType(inst_ty);4597 const raw_llvm_ty = try self.dg.lowerType(inst_ty);
45604598
4561 const llvm_ty = ty: {4599 const llvm_ty = ty: {
4562 // If the zig tag type is a function, this represents an actual function body; not4600 // If the zig tag type is a function, this represents an actual function body; not
...@@ -4696,9 +4734,9 @@ pub const FuncGen = struct {...@@ -4696,9 +4734,9 @@ pub const FuncGen = struct {
4696 const ty_op = self.air.instructions.items(.data)[inst].ty_op;4734 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
4697 const operand_ty = self.air.typeOf(ty_op.operand);4735 const operand_ty = self.air.typeOf(ty_op.operand);
4698 const array_ty = operand_ty.childType();4736 const array_ty = operand_ty.childType();
4699 const llvm_usize = try self.dg.llvmType(Type.usize);4737 const llvm_usize = try self.dg.lowerType(Type.usize);
4700 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);4738 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);
4701 const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));4739 const slice_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
4702 if (!array_ty.hasRuntimeBitsIgnoreComptime()) {4740 if (!array_ty.hasRuntimeBitsIgnoreComptime()) {
4703 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");4741 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");
4704 }4742 }
...@@ -4723,7 +4761,7 @@ pub const FuncGen = struct {...@@ -4723,7 +4761,7 @@ pub const FuncGen = struct {
47234761
4724 const dest_ty = self.air.typeOfIndex(inst);4762 const dest_ty = self.air.typeOfIndex(inst);
4725 const dest_scalar_ty = dest_ty.scalarType();4763 const dest_scalar_ty = dest_ty.scalarType();
4726 const dest_llvm_ty = try self.dg.llvmType(dest_ty);4764 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
4727 const target = self.dg.module.getTarget();4765 const target = self.dg.module.getTarget();
47284766
4729 if (intrinsicsAllowed(dest_scalar_ty, target)) {4767 if (intrinsicsAllowed(dest_scalar_ty, target)) {
...@@ -4774,7 +4812,7 @@ pub const FuncGen = struct {...@@ -4774,7 +4812,7 @@ pub const FuncGen = struct {
47744812
4775 const dest_ty = self.air.typeOfIndex(inst);4813 const dest_ty = self.air.typeOfIndex(inst);
4776 const dest_scalar_ty = dest_ty.scalarType();4814 const dest_scalar_ty = dest_ty.scalarType();
4777 const dest_llvm_ty = try self.dg.llvmType(dest_ty);4815 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
47784816
4779 if (intrinsicsAllowed(operand_scalar_ty, target)) {4817 if (intrinsicsAllowed(operand_scalar_ty, target)) {
4780 // TODO set fast math flag4818 // TODO set fast math flag
...@@ -4801,7 +4839,7 @@ pub const FuncGen = struct {...@@ -4801,7 +4839,7 @@ pub const FuncGen = struct {
4801 compiler_rt_dest_abbrev,4839 compiler_rt_dest_abbrev,
4802 }) catch unreachable;4840 }) catch unreachable;
48034841
4804 const operand_llvm_ty = try self.dg.llvmType(operand_ty);4842 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
4805 const param_types = [1]*const llvm.Type{operand_llvm_ty};4843 const param_types = [1]*const llvm.Type{operand_llvm_ty};
4806 const libc_fn = self.getLibcFunction(fn_name, &param_types, libc_ret_ty);4844 const libc_fn = self.getLibcFunction(fn_name, &param_types, libc_ret_ty);
4807 const params = [1]*const llvm.Value{operand};4845 const params = [1]*const llvm.Value{operand};
...@@ -4962,7 +5000,7 @@ pub const FuncGen = struct {...@@ -4962,7 +5000,7 @@ pub const FuncGen = struct {
4962 const containing_int = struct_llvm_val;5000 const containing_int = struct_llvm_val;
4963 const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);5001 const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);
4964 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");5002 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
4965 const elem_llvm_ty = try self.dg.llvmType(field_ty);5003 const elem_llvm_ty = try self.dg.lowerType(field_ty);
4966 if (field_ty.zigTypeTag() == .Float) {5004 if (field_ty.zigTypeTag() == .Float) {
4967 const elem_bits = @intCast(c_uint, field_ty.bitSize(target));5005 const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
4968 const same_size_int = self.context.intType(elem_bits);5006 const same_size_int = self.context.intType(elem_bits);
...@@ -4994,7 +5032,7 @@ pub const FuncGen = struct {...@@ -4994,7 +5032,7 @@ pub const FuncGen = struct {
4994 return self.load(field_ptr, field_ptr_ty);5032 return self.load(field_ptr, field_ptr_ty);
4995 },5033 },
4996 .Union => {5034 .Union => {
4997 const llvm_field_ty = try self.dg.llvmType(field_ty);5035 const llvm_field_ty = try self.dg.lowerType(field_ty);
4998 const layout = struct_ty.unionGetLayout(target);5036 const layout = struct_ty.unionGetLayout(target);
4999 const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);5037 const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
5000 const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, "");5038 const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, "");
...@@ -5021,7 +5059,7 @@ pub const FuncGen = struct {...@@ -5021,7 +5059,7 @@ pub const FuncGen = struct {
5021 const struct_ty = self.air.getRefType(ty_pl.ty).childType();5059 const struct_ty = self.air.getRefType(ty_pl.ty).childType();
5022 const field_offset = struct_ty.structFieldOffset(extra.field_index, target);5060 const field_offset = struct_ty.structFieldOffset(extra.field_index, target);
50235061
5024 const res_ty = try self.dg.llvmType(self.air.getRefType(ty_pl.ty));5062 const res_ty = try self.dg.lowerType(self.air.getRefType(ty_pl.ty));
5025 if (field_offset == 0) {5063 if (field_offset == 0) {
5026 return self.builder.buildBitCast(field_ptr, res_ty, "");5064 return self.builder.buildBitCast(field_ptr, res_ty, "");
5027 }5065 }
...@@ -5351,7 +5389,7 @@ pub const FuncGen = struct {...@@ -5351,7 +5389,7 @@ pub const FuncGen = struct {
5351 }5389 }
53525390
5353 const ret_ty = self.air.typeOfIndex(inst);5391 const ret_ty = self.air.typeOfIndex(inst);
5354 const ret_llvm_ty = try self.dg.llvmType(ret_ty);5392 const ret_llvm_ty = try self.dg.lowerType(ret_ty);
5355 const llvm_fn_ty = llvm.functionType(5393 const llvm_fn_ty = llvm.functionType(
5356 ret_llvm_ty,5394 ret_llvm_ty,
5357 llvm_param_types.ptr,5395 llvm_param_types.ptr,
...@@ -5392,8 +5430,8 @@ pub const FuncGen = struct {...@@ -5392,8 +5430,8 @@ pub const FuncGen = struct {
5392 const operand = try self.resolveInst(un_op);5430 const operand = try self.resolveInst(un_op);
5393 const operand_ty = self.air.typeOf(un_op);5431 const operand_ty = self.air.typeOf(un_op);
5394 const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;5432 const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
5395 if (optional_ty.isPtrLikeOptional()) {5433 if (optional_ty.optionalReprIsPayload()) {
5396 const optional_llvm_ty = try self.dg.llvmType(optional_ty);5434 const optional_llvm_ty = try self.dg.lowerType(optional_ty);
5397 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;5435 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
5398 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");5436 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
5399 }5437 }
...@@ -5430,21 +5468,33 @@ pub const FuncGen = struct {...@@ -5430,21 +5468,33 @@ pub const FuncGen = struct {
5430 const operand = try self.resolveInst(un_op);5468 const operand = try self.resolveInst(un_op);
5431 const err_union_ty = self.air.typeOf(un_op);5469 const err_union_ty = self.air.typeOf(un_op);
5432 const payload_ty = err_union_ty.errorUnionPayload();5470 const payload_ty = err_union_ty.errorUnionPayload();
5433 const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));5471 const err_set_ty = try self.dg.lowerType(Type.initTag(.anyerror));
5434 const zero = err_set_ty.constNull();5472 const zero = err_set_ty.constNull();
54355473
5474 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5475 const llvm_i1 = self.context.intType(1);
5476 switch (op) {
5477 .EQ => return llvm_i1.constInt(1, .False), // 0 == 0
5478 .NE => return llvm_i1.constInt(0, .False), // 0 != 0
5479 else => unreachable,
5480 }
5481 }
5482
5436 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5483 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5437 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;5484 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
5438 return self.builder.buildICmp(op, loaded, zero, "");5485 return self.builder.buildICmp(op, loaded, zero, "");
5439 }5486 }
54405487
5488 const target = self.dg.module.getTarget();
5489 const err_field_index = errUnionErrorOffset(payload_ty, target);
5490
5441 if (operand_is_ptr or isByRef(err_union_ty)) {5491 if (operand_is_ptr or isByRef(err_union_ty)) {
5442 const err_field_ptr = self.builder.buildStructGEP(operand, 0, "");5492 const err_field_ptr = self.builder.buildStructGEP(operand, err_field_index, "");
5443 const loaded = self.builder.buildLoad(err_field_ptr, "");5493 const loaded = self.builder.buildLoad(err_field_ptr, "");
5444 return self.builder.buildICmp(op, loaded, zero, "");5494 return self.builder.buildICmp(op, loaded, zero, "");
5445 }5495 }
54465496
5447 const loaded = self.builder.buildExtractValue(operand, 0, "");5497 const loaded = self.builder.buildExtractValue(operand, err_field_index, "");
5448 return self.builder.buildICmp(op, loaded, zero, "");5498 return self.builder.buildICmp(op, loaded, zero, "");
5449 }5499 }
54505500
...@@ -5462,10 +5512,10 @@ pub const FuncGen = struct {...@@ -5462,10 +5512,10 @@ pub const FuncGen = struct {
5462 // a pointer to a zero-bit value.5512 // a pointer to a zero-bit value.
54635513
5464 // TODO once we update to LLVM 14 this bitcast won't be necessary.5514 // TODO once we update to LLVM 14 this bitcast won't be necessary.
5465 const res_ptr_ty = try self.dg.llvmType(result_ty);5515 const res_ptr_ty = try self.dg.lowerType(result_ty);
5466 return self.builder.buildBitCast(operand, res_ptr_ty, "");5516 return self.builder.buildBitCast(operand, res_ptr_ty, "");
5467 }5517 }
5468 if (optional_ty.isPtrLikeOptional()) {5518 if (optional_ty.optionalReprIsPayload()) {
5469 // The payload and the optional are the same value.5519 // The payload and the optional are the same value.
5470 return operand;5520 return operand;
5471 }5521 }
...@@ -5490,10 +5540,10 @@ pub const FuncGen = struct {...@@ -5490,10 +5540,10 @@ pub const FuncGen = struct {
5490 _ = self.builder.buildStore(non_null_bit, operand);5540 _ = self.builder.buildStore(non_null_bit, operand);
54915541
5492 // TODO once we update to LLVM 14 this bitcast won't be necessary.5542 // TODO once we update to LLVM 14 this bitcast won't be necessary.
5493 const res_ptr_ty = try self.dg.llvmType(result_ty);5543 const res_ptr_ty = try self.dg.lowerType(result_ty);
5494 return self.builder.buildBitCast(operand, res_ptr_ty, "");5544 return self.builder.buildBitCast(operand, res_ptr_ty, "");
5495 }5545 }
5496 if (optional_ty.isPtrLikeOptional()) {5546 if (optional_ty.optionalReprIsPayload()) {
5497 // The payload and the optional are the same value.5547 // The payload and the optional are the same value.
5498 // Setting to non-null will be done when the payload is set.5548 // Setting to non-null will be done when the payload is set.
5499 return operand;5549 return operand;
...@@ -5527,7 +5577,7 @@ pub const FuncGen = struct {...@@ -5527,7 +5577,7 @@ pub const FuncGen = struct {
5527 const payload_ty = self.air.typeOfIndex(inst);5577 const payload_ty = self.air.typeOfIndex(inst);
5528 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null;5578 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null;
55295579
5530 if (optional_ty.isPtrLikeOptional()) {5580 if (optional_ty.optionalReprIsPayload()) {
5531 // Payload value is the same as the optional value.5581 // Payload value is the same as the optional value.
5532 return operand;5582 return operand;
5533 }5583 }
...@@ -5544,17 +5594,23 @@ pub const FuncGen = struct {...@@ -5544,17 +5594,23 @@ pub const FuncGen = struct {
55445594
5545 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5595 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5546 const operand = try self.resolveInst(ty_op.operand);5596 const operand = try self.resolveInst(ty_op.operand);
5547 const result_ty = self.air.getRefType(ty_op.ty);5597 const operand_ty = self.air.typeOf(ty_op.operand);
5598 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
5599 // If the error set has no fields, then the payload and the error
5600 // union are the same value.
5601 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5602 return operand;
5603 }
5604 const result_ty = self.air.typeOfIndex(inst);
5548 const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;5605 const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
5549
5550 const target = self.dg.module.getTarget();5606 const target = self.dg.module.getTarget();
5551 const offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;5607 const offset = errUnionPayloadOffset(payload_ty, target);
55525608
5553 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5609 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5554 if (!operand_is_ptr) return null;5610 if (!operand_is_ptr) return null;
55555611
5556 // TODO once we update to LLVM 14 this bitcast won't be necessary.5612 // TODO once we update to LLVM 14 this bitcast won't be necessary.
5557 const res_ptr_ty = try self.dg.llvmType(result_ty);5613 const res_ptr_ty = try self.dg.lowerType(result_ty);
5558 return self.builder.buildBitCast(operand, res_ptr_ty, "");5614 return self.builder.buildBitCast(operand, res_ptr_ty, "");
5559 }5615 }
5560 if (operand_is_ptr or isByRef(payload_ty)) {5616 if (operand_is_ptr or isByRef(payload_ty)) {
...@@ -5574,54 +5630,69 @@ pub const FuncGen = struct {...@@ -5574,54 +5630,69 @@ pub const FuncGen = struct {
5574 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5630 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5575 const operand = try self.resolveInst(ty_op.operand);5631 const operand = try self.resolveInst(ty_op.operand);
5576 const operand_ty = self.air.typeOf(ty_op.operand);5632 const operand_ty = self.air.typeOf(ty_op.operand);
5577 const err_set_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;5633 const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
5634 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5635 const err_llvm_ty = try self.dg.lowerType(Type.anyerror);
5636 if (operand_is_ptr) {
5637 return self.builder.buildBitCast(operand, err_llvm_ty.pointerType(0), "");
5638 } else {
5639 return err_llvm_ty.constInt(0, .False);
5640 }
5641 }
55785642
5579 const payload_ty = err_set_ty.errorUnionPayload();5643 const payload_ty = err_union_ty.errorUnionPayload();
5580 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5644 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5581 if (!operand_is_ptr) return operand;5645 if (!operand_is_ptr) return operand;
5582 return self.builder.buildLoad(operand, "");5646 return self.builder.buildLoad(operand, "");
5583 }5647 }
55845648
5585 if (operand_is_ptr or isByRef(err_set_ty)) {5649 const target = self.dg.module.getTarget();
5586 const err_field_ptr = self.builder.buildStructGEP(operand, 0, "");5650 const offset = errUnionErrorOffset(payload_ty, target);
5651
5652 if (operand_is_ptr or isByRef(err_union_ty)) {
5653 const err_field_ptr = self.builder.buildStructGEP(operand, offset, "");
5587 return self.builder.buildLoad(err_field_ptr, "");5654 return self.builder.buildLoad(err_field_ptr, "");
5588 }5655 }
55895656
5590 return self.builder.buildExtractValue(operand, 0, "");5657 return self.builder.buildExtractValue(operand, offset, "");
5591 }5658 }
55925659
5593 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {5660 fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
5594 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5661 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5595 const operand = try self.resolveInst(ty_op.operand);5662 const operand = try self.resolveInst(ty_op.operand);
5596 const error_set_ty = self.air.typeOf(ty_op.operand).childType();5663 const error_union_ty = self.air.typeOf(ty_op.operand).childType();
55975664
5598 const error_ty = error_set_ty.errorUnionSet();5665 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
5599 const payload_ty = error_set_ty.errorUnionPayload();5666 // TODO: write undefined bytes through the pointer here
5600 const non_error_val = try self.dg.genTypedValue(.{ .ty = error_ty, .val = Value.zero });5667 return operand;
5668 }
5669 const payload_ty = error_union_ty.errorUnionPayload();
5670 const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = Value.zero });
5601 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5671 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5602 // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.
5603 _ = self.builder.buildStore(non_error_val, operand);5672 _ = self.builder.buildStore(non_error_val, operand);
5604 return operand;5673 return operand;
5605 }5674 }
5606 const index_type = self.context.intType(32);5675 const index_type = self.context.intType(32);
5676 const target = self.dg.module.getTarget();
5607 {5677 {
5678 const error_offset = errUnionErrorOffset(payload_ty, target);
5608 // First set the non-error value.5679 // First set the non-error value.
5609 const indices: [2]*const llvm.Value = .{5680 const indices: [2]*const llvm.Value = .{
5610 index_type.constNull(), // dereference the pointer5681 index_type.constNull(), // dereference the pointer
5611 index_type.constNull(), // first field is the payload5682 index_type.constInt(error_offset, .False),
5612 };5683 };
5613 const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");5684 const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
5614 _ = self.builder.buildStore(non_error_val, non_null_ptr);5685 const store_inst = self.builder.buildStore(non_error_val, non_null_ptr);
5686 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
5615 }5687 }
5616 // Then return the payload pointer (only if it is used).5688 // Then return the payload pointer (only if it is used).
5617 if (self.liveness.isUnused(inst))5689 if (self.liveness.isUnused(inst))
5618 return null;5690 return null;
56195691
5620 const target = self.dg.module.getTarget();5692 const payload_offset = errUnionPayloadOffset(payload_ty, target);
5621 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;
5622 const indices: [2]*const llvm.Value = .{5693 const indices: [2]*const llvm.Value = .{
5623 index_type.constNull(), // dereference the pointer5694 index_type.constNull(), // dereference the pointer
5624 index_type.constInt(payload_offset, .False), // second field is the payload5695 index_type.constInt(payload_offset, .False),
5625 };5696 };
5626 return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");5697 return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
5627 }5698 }
...@@ -5646,8 +5717,10 @@ pub const FuncGen = struct {...@@ -5646,8 +5717,10 @@ pub const FuncGen = struct {
5646 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit;5717 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit;
5647 const operand = try self.resolveInst(ty_op.operand);5718 const operand = try self.resolveInst(ty_op.operand);
5648 const optional_ty = self.air.typeOfIndex(inst);5719 const optional_ty = self.air.typeOfIndex(inst);
5649 if (optional_ty.isPtrLikeOptional()) return operand;5720 if (optional_ty.optionalReprIsPayload()) {
5650 const llvm_optional_ty = try self.dg.llvmType(optional_ty);5721 return operand;
5722 }
5723 const llvm_optional_ty = try self.dg.lowerType(optional_ty);
5651 if (isByRef(optional_ty)) {5724 if (isByRef(optional_ty)) {
5652 const optional_ptr = self.buildAlloca(llvm_optional_ty);5725 const optional_ptr = self.buildAlloca(llvm_optional_ty);
5653 const payload_ptr = self.builder.buildStructGEP(optional_ptr, 0, "");5726 const payload_ptr = self.builder.buildStructGEP(optional_ptr, 0, "");
...@@ -5669,21 +5742,26 @@ pub const FuncGen = struct {...@@ -5669,21 +5742,26 @@ pub const FuncGen = struct {
5669 if (self.liveness.isUnused(inst)) return null;5742 if (self.liveness.isUnused(inst)) return null;
56705743
5671 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5744 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5672 const payload_ty = self.air.typeOf(ty_op.operand);5745 const inst_ty = self.air.typeOfIndex(inst);
5673 const operand = try self.resolveInst(ty_op.operand);5746 const operand = try self.resolveInst(ty_op.operand);
5747 if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
5748 return operand;
5749 }
5750 const payload_ty = self.air.typeOf(ty_op.operand);
5674 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5751 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5675 return operand;5752 return operand;
5676 }5753 }
5677 const inst_ty = self.air.typeOfIndex(inst);5754 const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull();
5678 const ok_err_code = self.context.intType(16).constNull();5755 const err_un_llvm_ty = try self.dg.lowerType(inst_ty);
5679 const err_un_llvm_ty = try self.dg.llvmType(inst_ty);
56805756
5681 const target = self.dg.module.getTarget();5757 const target = self.dg.module.getTarget();
5682 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;5758 const payload_offset = errUnionPayloadOffset(payload_ty, target);
5759 const error_offset = errUnionErrorOffset(payload_ty, target);
5683 if (isByRef(inst_ty)) {5760 if (isByRef(inst_ty)) {
5684 const result_ptr = self.buildAlloca(err_un_llvm_ty);5761 const result_ptr = self.buildAlloca(err_un_llvm_ty);
5685 const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");5762 const err_ptr = self.builder.buildStructGEP(result_ptr, error_offset, "");
5686 _ = self.builder.buildStore(ok_err_code, err_ptr);5763 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
5764 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
5687 const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");5765 const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");
5688 var ptr_ty_payload: Type.Payload.ElemType = .{5766 var ptr_ty_payload: Type.Payload.ElemType = .{
5689 .base = .{ .tag = .single_mut_pointer },5767 .base = .{ .tag = .single_mut_pointer },
...@@ -5694,7 +5772,7 @@ pub const FuncGen = struct {...@@ -5694,7 +5772,7 @@ pub const FuncGen = struct {
5694 return result_ptr;5772 return result_ptr;
5695 }5773 }
56965774
5697 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, 0, "");5775 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), ok_err_code, error_offset, "");
5698 return self.builder.buildInsertValue(partial, operand, payload_offset, "");5776 return self.builder.buildInsertValue(partial, operand, payload_offset, "");
5699 }5777 }
57005778
...@@ -5708,14 +5786,16 @@ pub const FuncGen = struct {...@@ -5708,14 +5786,16 @@ pub const FuncGen = struct {
5708 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5786 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5709 return operand;5787 return operand;
5710 }5788 }
5711 const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);5789 const err_un_llvm_ty = try self.dg.lowerType(err_un_ty);
57125790
5713 const target = self.dg.module.getTarget();5791 const target = self.dg.module.getTarget();
5714 const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1;5792 const payload_offset = errUnionPayloadOffset(payload_ty, target);
5793 const error_offset = errUnionErrorOffset(payload_ty, target);
5715 if (isByRef(err_un_ty)) {5794 if (isByRef(err_un_ty)) {
5716 const result_ptr = self.buildAlloca(err_un_llvm_ty);5795 const result_ptr = self.buildAlloca(err_un_llvm_ty);
5717 const err_ptr = self.builder.buildStructGEP(result_ptr, 0, "");5796 const err_ptr = self.builder.buildStructGEP(result_ptr, error_offset, "");
5718 _ = self.builder.buildStore(operand, err_ptr);5797 const store_inst = self.builder.buildStore(operand, err_ptr);
5798 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
5719 const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");5799 const payload_ptr = self.builder.buildStructGEP(result_ptr, payload_offset, "");
5720 var ptr_ty_payload: Type.Payload.ElemType = .{5800 var ptr_ty_payload: Type.Payload.ElemType = .{
5721 .base = .{ .tag = .single_mut_pointer },5801 .base = .{ .tag = .single_mut_pointer },
...@@ -5728,7 +5808,7 @@ pub const FuncGen = struct {...@@ -5728,7 +5808,7 @@ pub const FuncGen = struct {
5728 return result_ptr;5808 return result_ptr;
5729 }5809 }
57305810
5731 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, 0, "");5811 const partial = self.builder.buildInsertValue(err_un_llvm_ty.getUndef(), operand, error_offset, "");
5732 // TODO set payload bytes to undef5812 // TODO set payload bytes to undef
5733 return partial;5813 return partial;
5734 }5814 }
...@@ -5791,7 +5871,7 @@ pub const FuncGen = struct {...@@ -5791,7 +5871,7 @@ pub const FuncGen = struct {
5791 const ptr = try self.resolveInst(bin_op.lhs);5871 const ptr = try self.resolveInst(bin_op.lhs);
5792 const len = try self.resolveInst(bin_op.rhs);5872 const len = try self.resolveInst(bin_op.rhs);
5793 const inst_ty = self.air.typeOfIndex(inst);5873 const inst_ty = self.air.typeOfIndex(inst);
5794 const llvm_slice_ty = try self.dg.llvmType(inst_ty);5874 const llvm_slice_ty = try self.dg.lowerType(inst_ty);
57955875
5796 // In case of slicing a global, the result type looks something like `{ i8*, i64 }`5876 // In case of slicing a global, the result type looks something like `{ i8*, i64 }`
5797 // but `ptr` is pointing to the global directly. If it's an array, we would want to5877 // but `ptr` is pointing to the global directly. If it's an array, we would want to
...@@ -5799,7 +5879,7 @@ pub const FuncGen = struct {...@@ -5799,7 +5879,7 @@ pub const FuncGen = struct {
5799 // This prevents an assertion failure.5879 // This prevents an assertion failure.
5800 var buf: Type.SlicePtrFieldTypeBuffer = undefined;5880 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
5801 const ptr_ty = inst_ty.slicePtrFieldType(&buf);5881 const ptr_ty = inst_ty.slicePtrFieldType(&buf);
5802 const ptr_llvm_ty = try self.dg.llvmType(ptr_ty);5882 const ptr_llvm_ty = try self.dg.lowerType(ptr_ty);
5803 const casted_ptr = self.builder.buildBitCast(ptr, ptr_llvm_ty, "");5883 const casted_ptr = self.builder.buildBitCast(ptr, ptr_llvm_ty, "");
5804 const partial = self.builder.buildInsertValue(llvm_slice_ty.getUndef(), casted_ptr, 0, "");5884 const partial = self.builder.buildInsertValue(llvm_slice_ty.getUndef(), casted_ptr, 0, "");
5805 return self.builder.buildInsertValue(partial, len, 1, "");5885 return self.builder.buildInsertValue(partial, len, 1, "");
...@@ -5965,7 +6045,7 @@ pub const FuncGen = struct {...@@ -5965,7 +6045,7 @@ pub const FuncGen = struct {
5965 // const d = @divTrunc(a, b);6045 // const d = @divTrunc(a, b);
5966 // const r = @rem(a, b);6046 // const r = @rem(a, b);
5967 // return if (r == 0) d else d - ((a < 0) ^ (b < 0));6047 // return if (r == 0) d else d - ((a < 0) ^ (b < 0));
5968 const result_llvm_ty = try self.dg.llvmType(inst_ty);6048 const result_llvm_ty = try self.dg.lowerType(inst_ty);
5969 const zero = result_llvm_ty.constNull();6049 const zero = result_llvm_ty.constNull();
5970 const div_trunc = self.builder.buildSDiv(lhs, rhs, "");6050 const div_trunc = self.builder.buildSDiv(lhs, rhs, "");
5971 const rem = self.builder.buildSRem(lhs, rhs, "");6051 const rem = self.builder.buildSRem(lhs, rhs, "");
...@@ -6015,7 +6095,7 @@ pub const FuncGen = struct {...@@ -6015,7 +6095,7 @@ pub const FuncGen = struct {
6015 const lhs = try self.resolveInst(bin_op.lhs);6095 const lhs = try self.resolveInst(bin_op.lhs);
6016 const rhs = try self.resolveInst(bin_op.rhs);6096 const rhs = try self.resolveInst(bin_op.rhs);
6017 const inst_ty = self.air.typeOfIndex(inst);6097 const inst_ty = self.air.typeOfIndex(inst);
6018 const inst_llvm_ty = try self.dg.llvmType(inst_ty);6098 const inst_llvm_ty = try self.dg.lowerType(inst_ty);
6019 const scalar_ty = inst_ty.scalarType();6099 const scalar_ty = inst_ty.scalarType();
60206100
6021 if (scalar_ty.isRuntimeFloat()) {6101 if (scalar_ty.isRuntimeFloat()) {
...@@ -6099,8 +6179,8 @@ pub const FuncGen = struct {...@@ -6099,8 +6179,8 @@ pub const FuncGen = struct {
60996179
6100 const intrinsic_name = if (scalar_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic;6180 const intrinsic_name = if (scalar_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic;
61016181
6102 const llvm_lhs_ty = try self.dg.llvmType(lhs_ty);6182 const llvm_lhs_ty = try self.dg.lowerType(lhs_ty);
6103 const llvm_dest_ty = try self.dg.llvmType(dest_ty);6183 const llvm_dest_ty = try self.dg.lowerType(dest_ty);
61046184
6105 const tg = self.dg.module.getTarget();6185 const tg = self.dg.module.getTarget();
61066186
...@@ -6208,7 +6288,7 @@ pub const FuncGen = struct {...@@ -6208,7 +6288,7 @@ pub const FuncGen = struct {
6208 ) !*const llvm.Value {6288 ) !*const llvm.Value {
6209 const target = self.dg.module.getTarget();6289 const target = self.dg.module.getTarget();
6210 const scalar_ty = ty.scalarType();6290 const scalar_ty = ty.scalarType();
6211 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);6291 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
62126292
6213 if (intrinsicsAllowed(scalar_ty, target)) {6293 if (intrinsicsAllowed(scalar_ty, target)) {
6214 const llvm_predicate: llvm.RealPredicate = switch (pred) {6294 const llvm_predicate: llvm.RealPredicate = switch (pred) {
...@@ -6308,8 +6388,8 @@ pub const FuncGen = struct {...@@ -6308,8 +6388,8 @@ pub const FuncGen = struct {
6308 ) !*const llvm.Value {6388 ) !*const llvm.Value {
6309 const target = self.dg.module.getTarget();6389 const target = self.dg.module.getTarget();
6310 const scalar_ty = ty.scalarType();6390 const scalar_ty = ty.scalarType();
6311 const llvm_ty = try self.dg.llvmType(ty);6391 const llvm_ty = try self.dg.lowerType(ty);
6312 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);6392 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
63136393
6314 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);6394 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
6315 var fn_name_buf: [64]u8 = undefined;6395 var fn_name_buf: [64]u8 = undefined;
...@@ -6403,12 +6483,12 @@ pub const FuncGen = struct {...@@ -6403,12 +6483,12 @@ pub const FuncGen = struct {
6403 const rhs_scalar_ty = rhs_ty.scalarType();6483 const rhs_scalar_ty = rhs_ty.scalarType();
64046484
6405 const dest_ty = self.air.typeOfIndex(inst);6485 const dest_ty = self.air.typeOfIndex(inst);
6406 const llvm_dest_ty = try self.dg.llvmType(dest_ty);6486 const llvm_dest_ty = try self.dg.lowerType(dest_ty);
64076487
6408 const tg = self.dg.module.getTarget();6488 const tg = self.dg.module.getTarget();
64096489
6410 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))6490 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6411 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")6491 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
6412 else6492 else
6413 rhs;6493 rhs;
64146494
...@@ -6468,7 +6548,7 @@ pub const FuncGen = struct {...@@ -6468,7 +6548,7 @@ pub const FuncGen = struct {
6468 const tg = self.dg.module.getTarget();6548 const tg = self.dg.module.getTarget();
64696549
6470 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))6550 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6471 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")6551 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
6472 else6552 else
6473 rhs;6553 rhs;
6474 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, "");6554 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, "");
...@@ -6491,7 +6571,7 @@ pub const FuncGen = struct {...@@ -6491,7 +6571,7 @@ pub const FuncGen = struct {
6491 const tg = self.dg.module.getTarget();6571 const tg = self.dg.module.getTarget();
64926572
6493 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))6573 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6494 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")6574 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_type), "")
6495 else6575 else
6496 rhs;6576 rhs;
6497 return self.builder.buildShl(lhs, casted_rhs, "");6577 return self.builder.buildShl(lhs, casted_rhs, "");
...@@ -6513,7 +6593,7 @@ pub const FuncGen = struct {...@@ -6513,7 +6593,7 @@ pub const FuncGen = struct {
6513 const tg = self.dg.module.getTarget();6593 const tg = self.dg.module.getTarget();
65146594
6515 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))6595 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6516 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")6596 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
6517 else6597 else
6518 rhs;6598 rhs;
6519 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");6599 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");
...@@ -6536,7 +6616,7 @@ pub const FuncGen = struct {...@@ -6536,7 +6616,7 @@ pub const FuncGen = struct {
6536 const tg = self.dg.module.getTarget();6616 const tg = self.dg.module.getTarget();
65376617
6538 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))6618 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6539 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")6619 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
6540 else6620 else
6541 rhs;6621 rhs;
6542 const is_signed_int = lhs_scalar_ty.isSignedInt();6622 const is_signed_int = lhs_scalar_ty.isSignedInt();
...@@ -6564,7 +6644,7 @@ pub const FuncGen = struct {...@@ -6564,7 +6644,7 @@ pub const FuncGen = struct {
6564 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6644 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6565 const dest_ty = self.air.typeOfIndex(inst);6645 const dest_ty = self.air.typeOfIndex(inst);
6566 const dest_info = dest_ty.intInfo(target);6646 const dest_info = dest_ty.intInfo(target);
6567 const dest_llvm_ty = try self.dg.llvmType(dest_ty);6647 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
6568 const operand = try self.resolveInst(ty_op.operand);6648 const operand = try self.resolveInst(ty_op.operand);
6569 const operand_ty = self.air.typeOf(ty_op.operand);6649 const operand_ty = self.air.typeOf(ty_op.operand);
6570 const operand_info = operand_ty.intInfo(target);6650 const operand_info = operand_ty.intInfo(target);
...@@ -6586,7 +6666,7 @@ pub const FuncGen = struct {...@@ -6586,7 +6666,7 @@ pub const FuncGen = struct {
65866666
6587 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6667 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6588 const operand = try self.resolveInst(ty_op.operand);6668 const operand = try self.resolveInst(ty_op.operand);
6589 const dest_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));6669 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
6590 return self.builder.buildTrunc(operand, dest_llvm_ty, "");6670 return self.builder.buildTrunc(operand, dest_llvm_ty, "");
6591 }6671 }
65926672
...@@ -6604,7 +6684,7 @@ pub const FuncGen = struct {...@@ -6604,7 +6684,7 @@ pub const FuncGen = struct {
6604 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {6684 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {
6605 return softF80TruncOrExt(self, operand, src_bits, dest_bits);6685 return softF80TruncOrExt(self, operand, src_bits, dest_bits);
6606 }6686 }
6607 const dest_llvm_ty = try self.dg.llvmType(dest_ty);6687 const dest_llvm_ty = try self.dg.lowerType(dest_ty);
6608 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");6688 return self.builder.buildFPTrunc(operand, dest_llvm_ty, "");
6609 }6689 }
66106690
...@@ -6622,7 +6702,7 @@ pub const FuncGen = struct {...@@ -6622,7 +6702,7 @@ pub const FuncGen = struct {
6622 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {6702 if (!backendSupportsF80(target) and (src_bits == 80 or dest_bits == 80)) {
6623 return softF80TruncOrExt(self, operand, src_bits, dest_bits);6703 return softF80TruncOrExt(self, operand, src_bits, dest_bits);
6624 }6704 }
6625 const dest_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));6705 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
6626 return self.builder.buildFPExt(operand, dest_llvm_ty, "");6706 return self.builder.buildFPExt(operand, dest_llvm_ty, "");
6627 }6707 }
66286708
...@@ -6632,7 +6712,7 @@ pub const FuncGen = struct {...@@ -6632,7 +6712,7 @@ pub const FuncGen = struct {
66326712
6633 const un_op = self.air.instructions.items(.data)[inst].un_op;6713 const un_op = self.air.instructions.items(.data)[inst].un_op;
6634 const operand = try self.resolveInst(un_op);6714 const operand = try self.resolveInst(un_op);
6635 const dest_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));6715 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
6636 return self.builder.buildPtrToInt(operand, dest_llvm_ty, "");6716 return self.builder.buildPtrToInt(operand, dest_llvm_ty, "");
6637 }6717 }
66386718
...@@ -6640,12 +6720,12 @@ pub const FuncGen = struct {...@@ -6640,12 +6720,12 @@ pub const FuncGen = struct {
6640 if (self.liveness.isUnused(inst)) return null;6720 if (self.liveness.isUnused(inst)) return null;
66416721
6642 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6722 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6643 const operand = try self.resolveInst(ty_op.operand);
6644 const operand_ty = self.air.typeOf(ty_op.operand);6723 const operand_ty = self.air.typeOf(ty_op.operand);
6645 const inst_ty = self.air.typeOfIndex(inst);6724 const inst_ty = self.air.typeOfIndex(inst);
6725 const operand = try self.resolveInst(ty_op.operand);
6646 const operand_is_ref = isByRef(operand_ty);6726 const operand_is_ref = isByRef(operand_ty);
6647 const result_is_ref = isByRef(inst_ty);6727 const result_is_ref = isByRef(inst_ty);
6648 const llvm_dest_ty = try self.dg.llvmType(inst_ty);6728 const llvm_dest_ty = try self.dg.lowerType(inst_ty);
6649 const target = self.dg.module.getTarget();6729 const target = self.dg.module.getTarget();
66506730
6651 if (operand_is_ref and result_is_ref) {6731 if (operand_is_ref and result_is_ref) {
...@@ -6665,14 +6745,14 @@ pub const FuncGen = struct {...@@ -6665,14 +6745,14 @@ pub const FuncGen = struct {
6665 const array_ptr = self.buildAlloca(llvm_dest_ty);6745 const array_ptr = self.buildAlloca(llvm_dest_ty);
6666 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;6746 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
6667 if (bitcast_ok) {6747 if (bitcast_ok) {
6668 const llvm_vector_ty = try self.dg.llvmType(operand_ty);6748 const llvm_vector_ty = try self.dg.lowerType(operand_ty);
6669 const casted_ptr = self.builder.buildBitCast(array_ptr, llvm_vector_ty.pointerType(0), "");6749 const casted_ptr = self.builder.buildBitCast(array_ptr, llvm_vector_ty.pointerType(0), "");
6670 const llvm_store = self.builder.buildStore(operand, casted_ptr);6750 const llvm_store = self.builder.buildStore(operand, casted_ptr);
6671 llvm_store.setAlignment(inst_ty.abiAlignment(target));6751 llvm_store.setAlignment(inst_ty.abiAlignment(target));
6672 } else {6752 } else {
6673 // If the ABI size of the element type is not evenly divisible by size in bits;6753 // If the ABI size of the element type is not evenly divisible by size in bits;
6674 // a simple bitcast will not work, and we fall back to extractelement.6754 // a simple bitcast will not work, and we fall back to extractelement.
6675 const llvm_usize = try self.dg.llvmType(Type.usize);6755 const llvm_usize = try self.dg.lowerType(Type.usize);
6676 const llvm_u32 = self.context.intType(32);6756 const llvm_u32 = self.context.intType(32);
6677 const zero = llvm_usize.constNull();6757 const zero = llvm_usize.constNull();
6678 const vector_len = operand_ty.arrayLen();6758 const vector_len = operand_ty.arrayLen();
...@@ -6689,7 +6769,7 @@ pub const FuncGen = struct {...@@ -6689,7 +6769,7 @@ pub const FuncGen = struct {
6689 return array_ptr;6769 return array_ptr;
6690 } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) {6770 } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) {
6691 const elem_ty = operand_ty.childType();6771 const elem_ty = operand_ty.childType();
6692 const llvm_vector_ty = try self.dg.llvmType(inst_ty);6772 const llvm_vector_ty = try self.dg.lowerType(inst_ty);
6693 if (!operand_is_ref) {6773 if (!operand_is_ref) {
6694 return self.dg.todo("implement bitcast non-ref array to vector", .{});6774 return self.dg.todo("implement bitcast non-ref array to vector", .{});
6695 }6775 }
...@@ -6706,7 +6786,7 @@ pub const FuncGen = struct {...@@ -6706,7 +6786,7 @@ pub const FuncGen = struct {
6706 } else {6786 } else {
6707 // If the ABI size of the element type is not evenly divisible by size in bits;6787 // If the ABI size of the element type is not evenly divisible by size in bits;
6708 // a simple bitcast will not work, and we fall back to extractelement.6788 // a simple bitcast will not work, and we fall back to extractelement.
6709 const llvm_usize = try self.dg.llvmType(Type.usize);6789 const llvm_usize = try self.dg.lowerType(Type.usize);
6710 const llvm_u32 = self.context.intType(32);6790 const llvm_u32 = self.context.intType(32);
6711 const zero = llvm_usize.constNull();6791 const zero = llvm_usize.constNull();
6712 const vector_len = operand_ty.arrayLen();6792 const vector_len = operand_ty.arrayLen();
...@@ -6738,7 +6818,7 @@ pub const FuncGen = struct {...@@ -6738,7 +6818,7 @@ pub const FuncGen = struct {
6738 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));6818 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
6739 const result_ptr = self.buildAlloca(llvm_dest_ty);6819 const result_ptr = self.buildAlloca(llvm_dest_ty);
6740 result_ptr.setAlignment(alignment);6820 result_ptr.setAlignment(alignment);
6741 const operand_llvm_ty = try self.dg.llvmType(operand_ty);6821 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
6742 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");6822 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
6743 const store_inst = self.builder.buildStore(operand, casted_ptr);6823 const store_inst = self.builder.buildStore(operand, casted_ptr);
6744 store_inst.setAlignment(alignment);6824 store_inst.setAlignment(alignment);
...@@ -6752,7 +6832,7 @@ pub const FuncGen = struct {...@@ -6752,7 +6832,7 @@ pub const FuncGen = struct {
6752 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));6832 const alignment = @maximum(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target));
6753 const result_ptr = self.buildAlloca(llvm_dest_ty);6833 const result_ptr = self.buildAlloca(llvm_dest_ty);
6754 result_ptr.setAlignment(alignment);6834 result_ptr.setAlignment(alignment);
6755 const operand_llvm_ty = try self.dg.llvmType(operand_ty);6835 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
6756 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");6836 const casted_ptr = self.builder.buildBitCast(result_ptr, operand_llvm_ty.pointerType(0), "");
6757 const store_inst = self.builder.buildStore(operand, casted_ptr);6837 const store_inst = self.builder.buildStore(operand, casted_ptr);
6758 store_inst.setAlignment(alignment);6838 store_inst.setAlignment(alignment);
...@@ -6826,7 +6906,7 @@ pub const FuncGen = struct {...@@ -6826,7 +6906,7 @@ pub const FuncGen = struct {
6826 const pointee_type = ptr_ty.childType();6906 const pointee_type = ptr_ty.childType();
6827 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);6907 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
68286908
6829 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);6909 const pointee_llvm_ty = try self.dg.lowerType(pointee_type);
6830 const alloca_inst = self.buildAlloca(pointee_llvm_ty);6910 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
6831 const target = self.dg.module.getTarget();6911 const target = self.dg.module.getTarget();
6832 const alignment = ptr_ty.ptrAlignment(target);6912 const alignment = ptr_ty.ptrAlignment(target);
...@@ -6840,7 +6920,7 @@ pub const FuncGen = struct {...@@ -6840,7 +6920,7 @@ pub const FuncGen = struct {
6840 const ret_ty = ptr_ty.childType();6920 const ret_ty = ptr_ty.childType();
6841 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);6921 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
6842 if (self.ret_ptr) |ret_ptr| return ret_ptr;6922 if (self.ret_ptr) |ret_ptr| return ret_ptr;
6843 const ret_llvm_ty = try self.dg.llvmType(ret_ty);6923 const ret_llvm_ty = try self.dg.lowerType(ret_ty);
6844 const target = self.dg.module.getTarget();6924 const target = self.dg.module.getTarget();
6845 const alloca_inst = self.buildAlloca(ret_llvm_ty);6925 const alloca_inst = self.buildAlloca(ret_llvm_ty);
6846 alloca_inst.setAlignment(ptr_ty.ptrAlignment(target));6926 alloca_inst.setAlignment(ptr_ty.ptrAlignment(target));
...@@ -6871,7 +6951,7 @@ pub const FuncGen = struct {...@@ -6871,7 +6951,7 @@ pub const FuncGen = struct {
6871 const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");6951 const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
6872 const fill_char = u8_llvm_ty.constInt(0xaa, .False);6952 const fill_char = u8_llvm_ty.constInt(0xaa, .False);
6873 const dest_ptr_align = ptr_ty.ptrAlignment(target);6953 const dest_ptr_align = ptr_ty.ptrAlignment(target);
6874 const usize_llvm_ty = try self.dg.llvmType(Type.usize);6954 const usize_llvm_ty = try self.dg.lowerType(Type.usize);
6875 const len = usize_llvm_ty.constInt(operand_size, .False);6955 const len = usize_llvm_ty.constInt(operand_size, .False);
6876 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());6956 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
6877 if (self.dg.module.comp.bin_file.options.valgrind) {6957 if (self.dg.module.comp.bin_file.options.valgrind) {
...@@ -6908,7 +6988,7 @@ pub const FuncGen = struct {...@@ -6908,7 +6988,7 @@ pub const FuncGen = struct {
6908 const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{});6988 const llvm_fn = self.getIntrinsic("llvm.returnaddress", &.{});
6909 const params = [_]*const llvm.Value{llvm_i32.constNull()};6989 const params = [_]*const llvm.Value{llvm_i32.constNull()};
6910 const ptr_val = self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");6990 const ptr_val = self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");
6911 const llvm_usize = try self.dg.llvmType(Type.usize);6991 const llvm_usize = try self.dg.lowerType(Type.usize);
6912 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");6992 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
6913 }6993 }
69146994
...@@ -6926,7 +7006,7 @@ pub const FuncGen = struct {...@@ -6926,7 +7006,7 @@ pub const FuncGen = struct {
69267006
6927 const params = [_]*const llvm.Value{llvm_i32.constNull()};7007 const params = [_]*const llvm.Value{llvm_i32.constNull()};
6928 const ptr_val = self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");7008 const ptr_val = self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");
6929 const llvm_usize = try self.dg.llvmType(Type.usize);7009 const llvm_usize = try self.dg.lowerType(Type.usize);
6930 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");7010 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
6931 }7011 }
69327012
...@@ -6971,15 +7051,15 @@ pub const FuncGen = struct {...@@ -6971,15 +7051,15 @@ pub const FuncGen = struct {
69717051
6972 var payload = self.builder.buildExtractValue(result, 0, "");7052 var payload = self.builder.buildExtractValue(result, 0, "");
6973 if (opt_abi_ty != null) {7053 if (opt_abi_ty != null) {
6974 payload = self.builder.buildTrunc(payload, try self.dg.llvmType(operand_ty), "");7054 payload = self.builder.buildTrunc(payload, try self.dg.lowerType(operand_ty), "");
6975 }7055 }
6976 const success_bit = self.builder.buildExtractValue(result, 1, "");7056 const success_bit = self.builder.buildExtractValue(result, 1, "");
69777057
6978 if (optional_ty.isPtrLikeOptional()) {7058 if (optional_ty.optionalReprIsPayload()) {
6979 return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, "");7059 return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, "");
6980 }7060 }
69817061
6982 const optional_llvm_ty = try self.dg.llvmType(optional_ty);7062 const optional_llvm_ty = try self.dg.lowerType(optional_ty);
6983 const non_null_bit = self.builder.buildNot(success_bit, "");7063 const non_null_bit = self.builder.buildNot(success_bit, "");
6984 const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");7064 const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, "");
6985 return self.builder.buildInsertValue(partial, non_null_bit, 1, "");7065 return self.builder.buildInsertValue(partial, non_null_bit, 1, "");
...@@ -7015,7 +7095,7 @@ pub const FuncGen = struct {...@@ -7015,7 +7095,7 @@ pub const FuncGen = struct {
7015 ordering,7095 ordering,
7016 single_threaded,7096 single_threaded,
7017 );7097 );
7018 const operand_llvm_ty = try self.dg.llvmType(operand_ty);7098 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7019 if (is_float) {7099 if (is_float) {
7020 return self.builder.buildBitCast(uncasted_result, operand_llvm_ty, "");7100 return self.builder.buildBitCast(uncasted_result, operand_llvm_ty, "");
7021 } else {7101 } else {
...@@ -7028,7 +7108,7 @@ pub const FuncGen = struct {...@@ -7028,7 +7108,7 @@ pub const FuncGen = struct {
7028 }7108 }
70297109
7030 // It's a pointer but we need to treat it as an int.7110 // It's a pointer but we need to treat it as an int.
7031 const usize_llvm_ty = try self.dg.llvmType(Type.usize);7111 const usize_llvm_ty = try self.dg.lowerType(Type.usize);
7032 const casted_ptr = self.builder.buildBitCast(ptr, usize_llvm_ty.pointerType(0), "");7112 const casted_ptr = self.builder.buildBitCast(ptr, usize_llvm_ty.pointerType(0), "");
7033 const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");7113 const casted_operand = self.builder.buildPtrToInt(operand, usize_llvm_ty, "");
7034 const uncasted_result = self.builder.buildAtomicRmw(7114 const uncasted_result = self.builder.buildAtomicRmw(
...@@ -7038,7 +7118,7 @@ pub const FuncGen = struct {...@@ -7038,7 +7118,7 @@ pub const FuncGen = struct {
7038 ordering,7118 ordering,
7039 single_threaded,7119 single_threaded,
7040 );7120 );
7041 const operand_llvm_ty = try self.dg.llvmType(operand_ty);7121 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7042 return self.builder.buildIntToPtr(uncasted_result, operand_llvm_ty, "");7122 return self.builder.buildIntToPtr(uncasted_result, operand_llvm_ty, "");
7043 }7123 }
70447124
...@@ -7057,7 +7137,7 @@ pub const FuncGen = struct {...@@ -7057,7 +7137,7 @@ pub const FuncGen = struct {
7057 const casted_ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), "");7137 const casted_ptr = self.builder.buildBitCast(ptr, abi_ty.pointerType(0), "");
7058 const load_inst = (try self.load(casted_ptr, ptr_ty)).?;7138 const load_inst = (try self.load(casted_ptr, ptr_ty)).?;
7059 load_inst.setOrdering(ordering);7139 load_inst.setOrdering(ordering);
7060 return self.builder.buildTrunc(load_inst, try self.dg.llvmType(operand_ty), "");7140 return self.builder.buildTrunc(load_inst, try self.dg.lowerType(operand_ty), "");
7061 }7141 }
7062 const load_inst = (try self.load(ptr, ptr_ty)).?;7142 const load_inst = (try self.load(ptr, ptr_ty)).?;
7063 load_inst.setOrdering(ordering);7143 load_inst.setOrdering(ordering);
...@@ -7198,13 +7278,13 @@ pub const FuncGen = struct {...@@ -7198,13 +7278,13 @@ pub const FuncGen = struct {
7198 const operand = try self.resolveInst(ty_op.operand);7278 const operand = try self.resolveInst(ty_op.operand);
71997279
7200 const llvm_i1 = self.context.intType(1);7280 const llvm_i1 = self.context.intType(1);
7201 const operand_llvm_ty = try self.dg.llvmType(operand_ty);7281 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7202 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});7282 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
72037283
7204 const params = [_]*const llvm.Value{ operand, llvm_i1.constNull() };7284 const params = [_]*const llvm.Value{ operand, llvm_i1.constNull() };
7205 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");7285 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
7206 const result_ty = self.air.typeOfIndex(inst);7286 const result_ty = self.air.typeOfIndex(inst);
7207 const result_llvm_ty = try self.dg.llvmType(result_ty);7287 const result_llvm_ty = try self.dg.lowerType(result_ty);
72087288
7209 const target = self.dg.module.getTarget();7289 const target = self.dg.module.getTarget();
7210 const bits = operand_ty.intInfo(target).bits;7290 const bits = operand_ty.intInfo(target).bits;
...@@ -7226,12 +7306,12 @@ pub const FuncGen = struct {...@@ -7226,12 +7306,12 @@ pub const FuncGen = struct {
7226 const operand = try self.resolveInst(ty_op.operand);7306 const operand = try self.resolveInst(ty_op.operand);
72277307
7228 const params = [_]*const llvm.Value{operand};7308 const params = [_]*const llvm.Value{operand};
7229 const operand_llvm_ty = try self.dg.llvmType(operand_ty);7309 const operand_llvm_ty = try self.dg.lowerType(operand_ty);
7230 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});7310 const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
72317311
7232 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");7312 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
7233 const result_ty = self.air.typeOfIndex(inst);7313 const result_ty = self.air.typeOfIndex(inst);
7234 const result_llvm_ty = try self.dg.llvmType(result_ty);7314 const result_llvm_ty = try self.dg.lowerType(result_ty);
72357315
7236 const target = self.dg.module.getTarget();7316 const target = self.dg.module.getTarget();
7237 const bits = operand_ty.intInfo(target).bits;7317 const bits = operand_ty.intInfo(target).bits;
...@@ -7255,7 +7335,7 @@ pub const FuncGen = struct {...@@ -7255,7 +7335,7 @@ pub const FuncGen = struct {
7255 assert(bits % 8 == 0);7335 assert(bits % 8 == 0);
72567336
7257 var operand = try self.resolveInst(ty_op.operand);7337 var operand = try self.resolveInst(ty_op.operand);
7258 var operand_llvm_ty = try self.dg.llvmType(operand_ty);7338 var operand_llvm_ty = try self.dg.lowerType(operand_ty);
72597339
7260 if (bits % 16 == 8) {7340 if (bits % 16 == 8) {
7261 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte7341 // If not an even byte-multiple, we need zero-extend + shift-left 1 byte
...@@ -7289,7 +7369,7 @@ pub const FuncGen = struct {...@@ -7289,7 +7369,7 @@ pub const FuncGen = struct {
7289 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");7369 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
72907370
7291 const result_ty = self.air.typeOfIndex(inst);7371 const result_ty = self.air.typeOfIndex(inst);
7292 const result_llvm_ty = try self.dg.llvmType(result_ty);7372 const result_llvm_ty = try self.dg.lowerType(result_ty);
7293 const result_bits = result_ty.intInfo(target).bits;7373 const result_bits = result_ty.intInfo(target).bits;
7294 if (bits > result_bits) {7374 if (bits > result_bits) {
7295 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");7375 return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, "");
...@@ -7332,14 +7412,14 @@ pub const FuncGen = struct {...@@ -7332,14 +7412,14 @@ pub const FuncGen = struct {
7332 }7412 }
73337413
7334 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);7414 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
7335 const llvm_ret_ty = try self.dg.llvmType(slice_ty);7415 const llvm_ret_ty = try self.dg.lowerType(slice_ty);
7336 const usize_llvm_ty = try self.dg.llvmType(Type.usize);7416 const usize_llvm_ty = try self.dg.lowerType(Type.usize);
7337 const target = self.dg.module.getTarget();7417 const target = self.dg.module.getTarget();
7338 const slice_alignment = slice_ty.abiAlignment(target);7418 const slice_alignment = slice_ty.abiAlignment(target);
73397419
7340 var int_tag_type_buffer: Type.Payload.Bits = undefined;7420 var int_tag_type_buffer: Type.Payload.Bits = undefined;
7341 const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer);7421 const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer);
7342 const param_types = [_]*const llvm.Type{try self.dg.llvmType(int_tag_ty)};7422 const param_types = [_]*const llvm.Type{try self.dg.lowerType(int_tag_ty)};
73437423
7344 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);7424 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
7345 const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);7425 const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
...@@ -7396,7 +7476,7 @@ pub const FuncGen = struct {...@@ -7396,7 +7476,7 @@ pub const FuncGen = struct {
7396 .base = .{ .tag = .enum_field_index },7476 .base = .{ .tag = .enum_field_index },
7397 .data = @intCast(u32, field_index),7477 .data = @intCast(u32, field_index),
7398 };7478 };
7399 break :int try self.dg.genTypedValue(.{7479 break :int try self.dg.lowerValue(.{
7400 .ty = enum_ty,7480 .ty = enum_ty,
7401 .val = Value.initPayload(&tag_val_payload.base),7481 .val = Value.initPayload(&tag_val_payload.base),
7402 });7482 });
...@@ -7421,8 +7501,8 @@ pub const FuncGen = struct {...@@ -7421,8 +7501,8 @@ pub const FuncGen = struct {
74217501
7422 // Function signature: fn (anyerror) bool7502 // Function signature: fn (anyerror) bool
74237503
7424 const ret_llvm_ty = try self.dg.llvmType(Type.bool);7504 const ret_llvm_ty = try self.dg.lowerType(Type.bool);
7425 const anyerror_llvm_ty = try self.dg.llvmType(Type.anyerror);7505 const anyerror_llvm_ty = try self.dg.lowerType(Type.anyerror);
7426 const param_types = [_]*const llvm.Type{anyerror_llvm_ty};7506 const param_types = [_]*const llvm.Type{anyerror_llvm_ty};
74277507
7428 const fn_type = llvm.functionType(ret_llvm_ty, &param_types, param_types.len, .False);7508 const fn_type = llvm.functionType(ret_llvm_ty, &param_types, param_types.len, .False);
...@@ -7531,7 +7611,7 @@ pub const FuncGen = struct {...@@ -7531,7 +7611,7 @@ pub const FuncGen = struct {
7531 .Add => switch (scalar_ty.zigTypeTag()) {7611 .Add => switch (scalar_ty.zigTypeTag()) {
7532 .Int => return self.builder.buildAddReduce(operand),7612 .Int => return self.builder.buildAddReduce(operand),
7533 .Float => {7613 .Float => {
7534 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);7614 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
7535 const neutral_value = scalar_llvm_ty.constReal(-0.0);7615 const neutral_value = scalar_llvm_ty.constReal(-0.0);
7536 return self.builder.buildFPAddReduce(neutral_value, operand);7616 return self.builder.buildFPAddReduce(neutral_value, operand);
7537 },7617 },
...@@ -7540,7 +7620,7 @@ pub const FuncGen = struct {...@@ -7540,7 +7620,7 @@ pub const FuncGen = struct {
7540 .Mul => switch (scalar_ty.zigTypeTag()) {7620 .Mul => switch (scalar_ty.zigTypeTag()) {
7541 .Int => return self.builder.buildMulReduce(operand),7621 .Int => return self.builder.buildMulReduce(operand),
7542 .Float => {7622 .Float => {
7543 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);7623 const scalar_llvm_ty = try self.dg.lowerType(scalar_ty);
7544 const neutral_value = scalar_llvm_ty.constReal(1.0);7624 const neutral_value = scalar_llvm_ty.constReal(1.0);
7545 return self.builder.buildFPMulReduce(neutral_value, operand);7625 return self.builder.buildFPMulReduce(neutral_value, operand);
7546 },7626 },
...@@ -7556,7 +7636,7 @@ pub const FuncGen = struct {...@@ -7556,7 +7636,7 @@ pub const FuncGen = struct {
7556 const result_ty = self.air.typeOfIndex(inst);7636 const result_ty = self.air.typeOfIndex(inst);
7557 const len = @intCast(usize, result_ty.arrayLen());7637 const len = @intCast(usize, result_ty.arrayLen());
7558 const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);7638 const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
7559 const llvm_result_ty = try self.dg.llvmType(result_ty);7639 const llvm_result_ty = try self.dg.lowerType(result_ty);
7560 const target = self.dg.module.getTarget();7640 const target = self.dg.module.getTarget();
75617641
7562 switch (result_ty.zigTypeTag()) {7642 switch (result_ty.zigTypeTag()) {
...@@ -7644,7 +7724,7 @@ pub const FuncGen = struct {...@@ -7644,7 +7724,7 @@ pub const FuncGen = struct {
7644 .Array => {7724 .Array => {
7645 assert(isByRef(result_ty));7725 assert(isByRef(result_ty));
76467726
7647 const llvm_usize = try self.dg.llvmType(Type.usize);7727 const llvm_usize = try self.dg.lowerType(Type.usize);
7648 const alloca_inst = self.buildAlloca(llvm_result_ty);7728 const alloca_inst = self.buildAlloca(llvm_result_ty);
7649 alloca_inst.setAlignment(result_ty.abiAlignment(target));7729 alloca_inst.setAlignment(result_ty.abiAlignment(target));
76507730
...@@ -7679,7 +7759,7 @@ pub const FuncGen = struct {...@@ -7679,7 +7759,7 @@ pub const FuncGen = struct {
7679 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;7759 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
7680 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;7760 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
7681 const union_ty = self.air.typeOfIndex(inst);7761 const union_ty = self.air.typeOfIndex(inst);
7682 const union_llvm_ty = try self.dg.llvmType(union_ty);7762 const union_llvm_ty = try self.dg.lowerType(union_ty);
7683 const target = self.dg.module.getTarget();7763 const target = self.dg.module.getTarget();
7684 const layout = union_ty.unionGetLayout(target);7764 const layout = union_ty.unionGetLayout(target);
7685 if (layout.payload_size == 0) {7765 if (layout.payload_size == 0) {
...@@ -7699,8 +7779,8 @@ pub const FuncGen = struct {...@@ -7699,8 +7779,8 @@ pub const FuncGen = struct {
7699 const union_obj = union_ty.cast(Type.Payload.Union).?.data;7779 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
7700 assert(union_obj.haveFieldTypes());7780 assert(union_obj.haveFieldTypes());
7701 const field = union_obj.fields.values()[extra.field_index];7781 const field = union_obj.fields.values()[extra.field_index];
7702 const field_llvm_ty = try self.dg.llvmType(field.ty);7782 const field_llvm_ty = try self.dg.lowerType(field.ty);
7703 const tag_llvm_ty = try self.dg.llvmType(union_obj.tag_ty);7783 const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty);
7704 const field_size = field.ty.abiSize(target);7784 const field_size = field.ty.abiSize(target);
7705 const field_align = field.normalAlignment(target);7785 const field_align = field.normalAlignment(target);
77067786
...@@ -7936,7 +8016,7 @@ pub const FuncGen = struct {...@@ -7936,7 +8016,7 @@ pub const FuncGen = struct {
79368016
7937 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);8017 const slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
7938 const slice_alignment = slice_ty.abiAlignment(self.dg.module.getTarget());8018 const slice_alignment = slice_ty.abiAlignment(self.dg.module.getTarget());
7939 const llvm_slice_ty = try self.dg.llvmType(slice_ty);8019 const llvm_slice_ty = try self.dg.lowerType(slice_ty);
7940 const llvm_slice_ptr_ty = llvm_slice_ty.pointerType(0); // TODO: Address space8020 const llvm_slice_ptr_ty = llvm_slice_ty.pointerType(0); // TODO: Address space
79418021
7942 const error_name_table_global = self.dg.object.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table");8022 const error_name_table_global = self.dg.object.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table");
...@@ -8000,7 +8080,7 @@ pub const FuncGen = struct {...@@ -8000,7 +8080,7 @@ pub const FuncGen = struct {
8000 // out the relevant bits when accessing the pointee.8080 // out the relevant bits when accessing the pointee.
8001 // Here we perform a bitcast because we want to use the host_size8081 // Here we perform a bitcast because we want to use the host_size
8002 // as the llvm pointer element type.8082 // as the llvm pointer element type.
8003 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));8083 const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
8004 // TODO this can be removed if we change host_size to be bits instead8084 // TODO this can be removed if we change host_size to be bits instead
8005 // of bytes.8085 // of bytes.
8006 return self.builder.buildBitCast(struct_ptr, result_llvm_ty, "");8086 return self.builder.buildBitCast(struct_ptr, result_llvm_ty, "");
...@@ -8015,7 +8095,7 @@ pub const FuncGen = struct {...@@ -8015,7 +8095,7 @@ pub const FuncGen = struct {
8015 // end of the struct. Treat our struct pointer as an array of two and get8095 // end of the struct. Treat our struct pointer as an array of two and get
8016 // the index to the element at index `1` to get a pointer to the end of8096 // the index to the element at index `1` to get a pointer to the end of
8017 // the struct.8097 // the struct.
8018 const llvm_usize = try self.dg.llvmType(Type.usize);8098 const llvm_usize = try self.dg.lowerType(Type.usize);
8019 const llvm_index = llvm_usize.constInt(1, .False);8099 const llvm_index = llvm_usize.constInt(1, .False);
8020 const indices: [1]*const llvm.Value = .{llvm_index};8100 const indices: [1]*const llvm.Value = .{llvm_index};
8021 return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");8101 return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");
...@@ -8036,7 +8116,7 @@ pub const FuncGen = struct {...@@ -8036,7 +8116,7 @@ pub const FuncGen = struct {
8036 ) !?*const llvm.Value {8116 ) !?*const llvm.Value {
8037 const union_obj = union_ty.cast(Type.Payload.Union).?.data;8117 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
8038 const field = &union_obj.fields.values()[field_index];8118 const field = &union_obj.fields.values()[field_index];
8039 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));8119 const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
8040 if (!field.ty.hasRuntimeBitsIgnoreComptime()) {8120 if (!field.ty.hasRuntimeBitsIgnoreComptime()) {
8041 return null;8121 return null;
8042 }8122 }
...@@ -8075,7 +8155,7 @@ pub const FuncGen = struct {...@@ -8075,7 +8155,7 @@ pub const FuncGen = struct {
8075 const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());8155 const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());
8076 if (info.host_size == 0) {8156 if (info.host_size == 0) {
8077 if (isByRef(info.pointee_type)) {8157 if (isByRef(info.pointee_type)) {
8078 const elem_llvm_ty = try self.dg.llvmType(info.pointee_type);8158 const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
8079 const result_align = info.pointee_type.abiAlignment(target);8159 const result_align = info.pointee_type.abiAlignment(target);
8080 const max_align = @maximum(result_align, ptr_alignment);8160 const max_align = @maximum(result_align, ptr_alignment);
8081 const result_ptr = self.buildAlloca(elem_llvm_ty);8161 const result_ptr = self.buildAlloca(elem_llvm_ty);
...@@ -8108,7 +8188,7 @@ pub const FuncGen = struct {...@@ -8108,7 +8188,7 @@ pub const FuncGen = struct {
8108 const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target));8188 const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target));
8109 const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False);8189 const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False);
8110 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");8190 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
8111 const elem_llvm_ty = try self.dg.llvmType(info.pointee_type);8191 const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
81128192
8113 if (isByRef(info.pointee_type)) {8193 if (isByRef(info.pointee_type)) {
8114 const result_align = info.pointee_type.abiAlignment(target);8194 const result_align = info.pointee_type.abiAlignment(target);
...@@ -8546,7 +8626,14 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool...@@ -8546,7 +8626,14 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
8546/// be effectively bitcasted to the actual return type.8626/// be effectively bitcasted to the actual return type.
8547fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.Type {8627fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.Type {
8548 if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) {8628 if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) {
8549 return dg.context.voidType();8629 // If the return type is an error set or an error union, then we make this
8630 // anyerror return type instead, so that it can be coerced into a function
8631 // pointer type which has anyerror as the return type.
8632 if (fn_info.return_type.isError()) {
8633 return dg.lowerType(Type.anyerror);
8634 } else {
8635 return dg.context.voidType();
8636 }
8550 }8637 }
8551 const target = dg.module.getTarget();8638 const target = dg.module.getTarget();
8552 switch (fn_info.cc) {8639 switch (fn_info.cc) {
...@@ -8554,7 +8641,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm....@@ -8554,7 +8641,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
8554 if (isByRef(fn_info.return_type)) {8641 if (isByRef(fn_info.return_type)) {
8555 return dg.context.voidType();8642 return dg.context.voidType();
8556 } else {8643 } else {
8557 return dg.llvmType(fn_info.return_type);8644 return dg.lowerType(fn_info.return_type);
8558 }8645 }
8559 },8646 },
8560 .C => {8647 .C => {
...@@ -8575,24 +8662,24 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm....@@ -8575,24 +8662,24 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
8575 else => false,8662 else => false,
8576 };8663 };
8577 switch (target.cpu.arch) {8664 switch (target.cpu.arch) {
8578 .mips, .mipsel => return dg.llvmType(fn_info.return_type),8665 .mips, .mipsel => return dg.lowerType(fn_info.return_type),
8579 .x86_64 => switch (target.os.tag) {8666 .x86_64 => switch (target.os.tag) {
8580 .windows => switch (x86_64_abi.classifyWindows(fn_info.return_type, target)) {8667 .windows => switch (x86_64_abi.classifyWindows(fn_info.return_type, target)) {
8581 .integer => {8668 .integer => {
8582 if (is_scalar) {8669 if (is_scalar) {
8583 return dg.llvmType(fn_info.return_type);8670 return dg.lowerType(fn_info.return_type);
8584 } else {8671 } else {
8585 const abi_size = fn_info.return_type.abiSize(target);8672 const abi_size = fn_info.return_type.abiSize(target);
8586 return dg.context.intType(@intCast(c_uint, abi_size * 8));8673 return dg.context.intType(@intCast(c_uint, abi_size * 8));
8587 }8674 }
8588 },8675 },
8589 .memory => return dg.context.voidType(),8676 .memory => return dg.context.voidType(),
8590 .sse => return dg.llvmType(fn_info.return_type),8677 .sse => return dg.lowerType(fn_info.return_type),
8591 else => unreachable,8678 else => unreachable,
8592 },8679 },
8593 else => {8680 else => {
8594 if (is_scalar) {8681 if (is_scalar) {
8595 return dg.llvmType(fn_info.return_type);8682 return dg.lowerType(fn_info.return_type);
8596 }8683 }
8597 const classes = x86_64_abi.classifySystemV(fn_info.return_type, target);8684 const classes = x86_64_abi.classifySystemV(fn_info.return_type, target);
8598 if (classes[0] == .memory) {8685 if (classes[0] == .memory) {
...@@ -8633,10 +8720,10 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm....@@ -8633,10 +8720,10 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
8633 },8720 },
8634 },8721 },
8635 // TODO investigate C ABI for other architectures8722 // TODO investigate C ABI for other architectures
8636 else => return dg.llvmType(fn_info.return_type),8723 else => return dg.lowerType(fn_info.return_type),
8637 }8724 }
8638 },8725 },
8639 else => return dg.llvmType(fn_info.return_type),8726 else => return dg.lowerType(fn_info.return_type),
8640 }8727 }
8641}8728}
86428729
...@@ -8991,3 +9078,11 @@ fn buildAllocaInner(...@@ -8991,3 +9078,11 @@ fn buildAllocaInner(
89919078
8992 return builder.buildAlloca(llvm_ty, "");9079 return builder.buildAlloca(llvm_ty, "");
8993}9080}
9081
9082fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 {
9083 return @boolToInt(Type.anyerror.abiAlignment(target) > payload_ty.abiAlignment(target));
9084}
9085
9086fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u1 {
9087 return @boolToInt(Type.anyerror.abiAlignment(target) <= payload_ty.abiAlignment(target));
9088}
src/link/Dwarf.zig+6-4
...@@ -498,9 +498,11 @@ pub const DeclState = struct {...@@ -498,9 +498,11 @@ pub const DeclState = struct {
498 .ErrorUnion => {498 .ErrorUnion => {
499 const error_ty = ty.errorUnionSet();499 const error_ty = ty.errorUnionSet();
500 const payload_ty = ty.errorUnionPayload();500 const payload_ty = ty.errorUnionPayload();
501 const payload_align = payload_ty.abiAlignment(target);
502 const error_align = Type.anyerror.abiAlignment(target);
501 const abi_size = ty.abiSize(target);503 const abi_size = ty.abiSize(target);
502 const abi_align = ty.abiAlignment(target);504 const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(target) else 0;
503 const payload_off = mem.alignForwardGeneric(u64, error_ty.abiSize(target), abi_align);505 const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(target);
504506
505 // DW.AT.structure_type507 // DW.AT.structure_type
506 try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));508 try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));
...@@ -534,7 +536,7 @@ pub const DeclState = struct {...@@ -534,7 +536,7 @@ pub const DeclState = struct {
534 try dbg_info_buffer.resize(index + 4);536 try dbg_info_buffer.resize(index + 4);
535 try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null);537 try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null);
536 // DW.AT.data_member_location, DW.FORM.sdata538 // DW.AT.data_member_location, DW.FORM.sdata
537 try dbg_info_buffer.append(0);539 try leb128.writeULEB128(dbg_info_buffer.writer(), error_off);
538540
539 // DW.AT.structure_type delimit children541 // DW.AT.structure_type delimit children
540 try dbg_info_buffer.append(0);542 try dbg_info_buffer.append(0);
...@@ -2293,7 +2295,7 @@ fn addDbgInfoErrorSet(...@@ -2293,7 +2295,7 @@ fn addDbgInfoErrorSet(
2293 // DW.AT.enumeration_type2295 // DW.AT.enumeration_type
2294 try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type));2296 try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type));
2295 // DW.AT.byte_size, DW.FORM.sdata2297 // DW.AT.byte_size, DW.FORM.sdata
2296 const abi_size = ty.abiSize(target);2298 const abi_size = Type.anyerror.abiSize(target);
2297 try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);2299 try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size);
2298 // DW.AT.name, DW.FORM.string2300 // DW.AT.name, DW.FORM.string
2299 const name = try ty.nameAllocArena(arena, module);2301 const name = try ty.nameAllocArena(arena, module);
src/type.zig+298-60
...@@ -2317,10 +2317,7 @@ pub const Type = extern union {...@@ -2317,10 +2317,7 @@ pub const Type = extern union {
2317 .const_slice_u8_sentinel_0,2317 .const_slice_u8_sentinel_0,
2318 .array_u8_sentinel_0,2318 .array_u8_sentinel_0,
2319 .anyerror_void_error_union,2319 .anyerror_void_error_union,
2320 .error_set,
2321 .error_set_single,
2322 .error_set_inferred,2320 .error_set_inferred,
2323 .error_set_merged,
2324 .manyptr_u8,2321 .manyptr_u8,
2325 .manyptr_const_u8,2322 .manyptr_const_u8,
2326 .manyptr_const_u8_sentinel_0,2323 .manyptr_const_u8_sentinel_0,
...@@ -2361,12 +2358,23 @@ pub const Type = extern union {...@@ -2361,12 +2358,23 @@ pub const Type = extern union {
2361 .fn_void_no_args,2358 .fn_void_no_args,
2362 .fn_naked_noreturn_no_args,2359 .fn_naked_noreturn_no_args,
2363 .fn_ccc_void_no_args,2360 .fn_ccc_void_no_args,
2361 .error_set_single,
2364 => return false,2362 => return false,
23652363
2364 .error_set => {
2365 const err_set_obj = ty.castTag(.error_set).?.data;
2366 const names = err_set_obj.names.keys();
2367 return names.len > 1;
2368 },
2369 .error_set_merged => {
2370 const name_map = ty.castTag(.error_set_merged).?.data;
2371 const names = name_map.keys();
2372 return names.len > 1;
2373 },
2374
2366 // These types have more than one possible value, so the result is the same as2375 // These types have more than one possible value, so the result is the same as
2367 // asking whether they are comptime-only types.2376 // asking whether they are comptime-only types.
2368 .anyframe_T,2377 .anyframe_T,
2369 .optional,
2370 .optional_single_mut_pointer,2378 .optional_single_mut_pointer,
2371 .optional_single_const_pointer,2379 .optional_single_const_pointer,
2372 .single_const_pointer,2380 .single_const_pointer,
...@@ -2388,6 +2396,41 @@ pub const Type = extern union {...@@ -2388,6 +2396,41 @@ pub const Type = extern union {
2388 }2396 }
2389 },2397 },
23902398
2399 .optional => {
2400 var buf: Payload.ElemType = undefined;
2401 const child_ty = ty.optionalChild(&buf);
2402 if (child_ty.isNoReturn()) {
2403 // Then the optional is comptime-known to be null.
2404 return false;
2405 }
2406 if (ignore_comptime_only) {
2407 return true;
2408 } else if (sema_kit) |sk| {
2409 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, child_ty));
2410 } else {
2411 return !comptimeOnly(child_ty);
2412 }
2413 },
2414
2415 .error_union => {
2416 // This code needs to be kept in sync with the equivalent switch prong
2417 // in abiSizeAdvanced.
2418 const data = ty.castTag(.error_union).?.data;
2419 switch (data.error_set.errorSetCardinality()) {
2420 .zero => return hasRuntimeBitsAdvanced(data.payload, ignore_comptime_only, sema_kit),
2421 .one => return !data.payload.isNoReturn(),
2422 .many => {
2423 if (ignore_comptime_only) {
2424 return true;
2425 } else if (sema_kit) |sk| {
2426 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
2427 } else {
2428 return !comptimeOnly(ty);
2429 }
2430 },
2431 }
2432 },
2433
2391 .@"struct" => {2434 .@"struct" => {
2392 const struct_obj = ty.castTag(.@"struct").?.data;2435 const struct_obj = ty.castTag(.@"struct").?.data;
2393 if (sema_kit) |sk| {2436 if (sema_kit) |sk| {
...@@ -2467,12 +2510,6 @@ pub const Type = extern union {...@@ -2467,12 +2510,6 @@ pub const Type = extern union {
24672510
2468 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,2511 .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0,
24692512
2470 .error_union => {
2471 const payload = ty.castTag(.error_union).?.data;
2472 return (try payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) or
2473 (try payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit));
2474 },
2475
2476 .tuple, .anon_struct => {2513 .tuple, .anon_struct => {
2477 const tuple = ty.tupleFields();2514 const tuple = ty.tupleFields();
2478 for (tuple.types) |field_ty, i| {2515 for (tuple.types) |field_ty, i| {
...@@ -2647,13 +2684,22 @@ pub const Type = extern union {...@@ -2647,13 +2684,22 @@ pub const Type = extern union {
2647 };2684 };
2648 }2685 }
26492686
2650 pub fn isNoReturn(self: Type) bool {2687 /// TODO add enums with no fields here
2651 const definitely_correct_result =2688 pub fn isNoReturn(ty: Type) bool {
2652 self.tag_if_small_enough != .bound_fn and2689 switch (ty.tag()) {
2653 self.zigTypeTag() == .NoReturn;2690 .noreturn => return true,
2654 const fast_result = self.tag_if_small_enough == Tag.noreturn;2691 .error_set => {
2655 assert(fast_result == definitely_correct_result);2692 const err_set_obj = ty.castTag(.error_set).?.data;
2656 return fast_result;2693 const names = err_set_obj.names.keys();
2694 return names.len == 0;
2695 },
2696 .error_set_merged => {
2697 const name_map = ty.castTag(.error_set_merged).?.data;
2698 const names = name_map.keys();
2699 return names.len == 0;
2700 },
2701 else => return false,
2702 }
2657 }2703 }
26582704
2659 /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit.2705 /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit.
...@@ -2852,13 +2898,30 @@ pub const Type = extern union {...@@ -2852,13 +2898,30 @@ pub const Type = extern union {
2852 else => unreachable,2898 else => unreachable,
2853 },2899 },
28542900
2855 .error_set,2901 // TODO revisit this when we have the concept of the error tag type
2856 .error_set_single,
2857 .anyerror_void_error_union,2902 .anyerror_void_error_union,
2858 .anyerror,2903 .anyerror,
2859 .error_set_inferred,2904 .error_set_inferred,
2860 .error_set_merged,2905 => return AbiAlignmentAdvanced{ .scalar = 2 },
2861 => return AbiAlignmentAdvanced{ .scalar = 2 }, // TODO revisit this when we have the concept of the error tag type2906
2907 .error_set => {
2908 const err_set_obj = ty.castTag(.error_set).?.data;
2909 const names = err_set_obj.names.keys();
2910 if (names.len <= 1) {
2911 return AbiAlignmentAdvanced{ .scalar = 0 };
2912 } else {
2913 return AbiAlignmentAdvanced{ .scalar = 2 };
2914 }
2915 },
2916 .error_set_merged => {
2917 const name_map = ty.castTag(.error_set_merged).?.data;
2918 const names = name_map.keys();
2919 if (names.len <= 1) {
2920 return AbiAlignmentAdvanced{ .scalar = 0 };
2921 } else {
2922 return AbiAlignmentAdvanced{ .scalar = 2 };
2923 }
2924 },
28622925
2863 .array, .array_sentinel => return ty.elemType().abiAlignmentAdvanced(target, strat),2926 .array, .array_sentinel => return ty.elemType().abiAlignmentAdvanced(target, strat),
28642927
...@@ -2881,8 +2944,16 @@ pub const Type = extern union {...@@ -2881,8 +2944,16 @@ pub const Type = extern union {
2881 var buf: Payload.ElemType = undefined;2944 var buf: Payload.ElemType = undefined;
2882 const child_type = ty.optionalChild(&buf);2945 const child_type = ty.optionalChild(&buf);
28832946
2884 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr()) {2947 switch (child_type.zigTypeTag()) {
2885 return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };2948 .Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
2949 .ErrorSet => switch (child_type.errorSetCardinality()) {
2950 // `?error{}` is comptime-known to be null.
2951 .zero => return AbiAlignmentAdvanced{ .scalar = 0 },
2952 .one => return AbiAlignmentAdvanced{ .scalar = 1 },
2953 .many => return abiAlignmentAdvanced(Type.anyerror, target, strat),
2954 },
2955 .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 },
2956 else => {},
2886 }2957 }
28872958
2888 switch (strat) {2959 switch (strat) {
...@@ -2900,31 +2971,35 @@ pub const Type = extern union {...@@ -2900,31 +2971,35 @@ pub const Type = extern union {
2900 },2971 },
29012972
2902 .error_union => {2973 .error_union => {
2974 // This code needs to be kept in sync with the equivalent switch prong
2975 // in abiSizeAdvanced.
2903 const data = ty.castTag(.error_union).?.data;2976 const data = ty.castTag(.error_union).?.data;
2977 switch (data.error_set.errorSetCardinality()) {
2978 .zero => return abiAlignmentAdvanced(data.payload, target, strat),
2979 .one => {
2980 if (data.payload.isNoReturn()) {
2981 return AbiAlignmentAdvanced{ .scalar = 0 };
2982 }
2983 },
2984 .many => {},
2985 }
2986 const code_align = abiAlignment(Type.anyerror, target);
2904 switch (strat) {2987 switch (strat) {
2905 .eager, .sema_kit => {2988 .eager, .sema_kit => {
2906 if (!(try data.error_set.hasRuntimeBitsAdvanced(false, sema_kit))) {2989 if (!(try data.payload.hasRuntimeBitsAdvanced(false, sema_kit))) {
2907 return data.payload.abiAlignmentAdvanced(target, strat);2990 return AbiAlignmentAdvanced{ .scalar = code_align };
2908 } else if (!(try data.payload.hasRuntimeBitsAdvanced(false, sema_kit))) {
2909 return data.error_set.abiAlignmentAdvanced(target, strat);
2910 }2991 }
2911 return AbiAlignmentAdvanced{ .scalar = @maximum(2992 return AbiAlignmentAdvanced{ .scalar = @maximum(
2993 code_align,
2912 (try data.payload.abiAlignmentAdvanced(target, strat)).scalar,2994 (try data.payload.abiAlignmentAdvanced(target, strat)).scalar,
2913 (try data.error_set.abiAlignmentAdvanced(target, strat)).scalar,
2914 ) };2995 ) };
2915 },2996 },
2916 .lazy => |arena| {2997 .lazy => |arena| {
2917 switch (try data.payload.abiAlignmentAdvanced(target, strat)) {2998 switch (try data.payload.abiAlignmentAdvanced(target, strat)) {
2918 .scalar => |payload_align| {2999 .scalar => |payload_align| {
2919 if (payload_align == 0) {3000 return AbiAlignmentAdvanced{
2920 return data.error_set.abiAlignmentAdvanced(target, strat);3001 .scalar = @maximum(code_align, payload_align),
2921 }3002 };
2922 switch (try data.error_set.abiAlignmentAdvanced(target, strat)) {
2923 .scalar => |err_set_align| {
2924 return AbiAlignmentAdvanced{ .scalar = @maximum(payload_align, err_set_align) };
2925 },
2926 .val => {},
2927 }
2928 },3003 },
2929 .val => {},3004 .val => {},
2930 }3005 }
...@@ -3018,6 +3093,7 @@ pub const Type = extern union {...@@ -3018,6 +3093,7 @@ pub const Type = extern union {
3018 .@"undefined",3093 .@"undefined",
3019 .enum_literal,3094 .enum_literal,
3020 .type_info,3095 .type_info,
3096 .error_set_single,
3021 => return AbiAlignmentAdvanced{ .scalar = 0 },3097 => return AbiAlignmentAdvanced{ .scalar = 0 },
30223098
3023 .noreturn,3099 .noreturn,
...@@ -3136,6 +3212,7 @@ pub const Type = extern union {...@@ -3136,6 +3212,7 @@ pub const Type = extern union {
3136 .empty_struct_literal,3212 .empty_struct_literal,
3137 .empty_struct,3213 .empty_struct,
3138 .void,3214 .void,
3215 .error_set_single,
3139 => return AbiSizeAdvanced{ .scalar = 0 },3216 => return AbiSizeAdvanced{ .scalar = 0 },
31403217
3141 .@"struct", .tuple, .anon_struct => switch (ty.containerLayout()) {3218 .@"struct", .tuple, .anon_struct => switch (ty.containerLayout()) {
...@@ -3291,14 +3368,30 @@ pub const Type = extern union {...@@ -3291,14 +3368,30 @@ pub const Type = extern union {
3291 },3368 },
32923369
3293 // TODO revisit this when we have the concept of the error tag type3370 // TODO revisit this when we have the concept of the error tag type
3294 .error_set,
3295 .error_set_single,
3296 .anyerror_void_error_union,3371 .anyerror_void_error_union,
3297 .anyerror,3372 .anyerror,
3298 .error_set_inferred,3373 .error_set_inferred,
3299 .error_set_merged,
3300 => return AbiSizeAdvanced{ .scalar = 2 },3374 => return AbiSizeAdvanced{ .scalar = 2 },
33013375
3376 .error_set => {
3377 const err_set_obj = ty.castTag(.error_set).?.data;
3378 const names = err_set_obj.names.keys();
3379 if (names.len <= 1) {
3380 return AbiSizeAdvanced{ .scalar = 0 };
3381 } else {
3382 return AbiSizeAdvanced{ .scalar = 2 };
3383 }
3384 },
3385 .error_set_merged => {
3386 const name_map = ty.castTag(.error_set_merged).?.data;
3387 const names = name_map.keys();
3388 if (names.len <= 1) {
3389 return AbiSizeAdvanced{ .scalar = 0 };
3390 } else {
3391 return AbiSizeAdvanced{ .scalar = 2 };
3392 }
3393 },
3394
3302 .i16, .u16 => return AbiSizeAdvanced{ .scalar = intAbiSize(16, target) },3395 .i16, .u16 => return AbiSizeAdvanced{ .scalar = intAbiSize(16, target) },
3303 .i32, .u32 => return AbiSizeAdvanced{ .scalar = intAbiSize(32, target) },3396 .i32, .u32 => return AbiSizeAdvanced{ .scalar = intAbiSize(32, target) },
3304 .i64, .u64 => return AbiSizeAdvanced{ .scalar = intAbiSize(64, target) },3397 .i64, .u64 => return AbiSizeAdvanced{ .scalar = intAbiSize(64, target) },
...@@ -3312,37 +3405,81 @@ pub const Type = extern union {...@@ -3312,37 +3405,81 @@ pub const Type = extern union {
3312 .optional => {3405 .optional => {
3313 var buf: Payload.ElemType = undefined;3406 var buf: Payload.ElemType = undefined;
3314 const child_type = ty.optionalChild(&buf);3407 const child_type = ty.optionalChild(&buf);
3408
3409 if (child_type.isNoReturn()) {
3410 return AbiSizeAdvanced{ .scalar = 0 };
3411 }
3412
3315 if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };3413 if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };
33163414
3317 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())3415 switch (child_type.zigTypeTag()) {
3318 return AbiSizeAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) };3416 .Pointer => {
3417 const ptr_info = child_type.ptrInfo().data;
3418 const has_null = switch (ptr_info.size) {
3419 .Slice, .C => true,
3420 else => ptr_info.@"allowzero",
3421 };
3422 if (!has_null) {
3423 const ptr_size_bytes = @divExact(target.cpu.arch.ptrBitWidth(), 8);
3424 return AbiSizeAdvanced{ .scalar = ptr_size_bytes };
3425 }
3426 },
3427 .ErrorSet => return abiSizeAdvanced(Type.anyerror, target, strat),
3428 else => {},
3429 }
33193430
3320 // Optional types are represented as a struct with the child type as the first3431 // Optional types are represented as a struct with the child type as the first
3321 // field and a boolean as the second. Since the child type's abi alignment is3432 // field and a boolean as the second. Since the child type's abi alignment is
3322 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal3433 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
3323 // to the child type's ABI alignment.3434 // to the child type's ABI alignment.
3324 return AbiSizeAdvanced{ .scalar = child_type.abiAlignment(target) + child_type.abiSize(target) };3435 return AbiSizeAdvanced{
3436 .scalar = child_type.abiAlignment(target) + child_type.abiSize(target),
3437 };
3325 },3438 },
33263439
3327 .error_union => {3440 .error_union => {
3441 // This code needs to be kept in sync with the equivalent switch prong
3442 // in abiAlignmentAdvanced.
3328 const data = ty.castTag(.error_union).?.data;3443 const data = ty.castTag(.error_union).?.data;
3329 if (!data.error_set.hasRuntimeBits() and !data.payload.hasRuntimeBits()) {3444 // Here we need to care whether or not the error set is *empty* or whether
3330 return AbiSizeAdvanced{ .scalar = 0 };3445 // it only has *one possible value*. In the former case, it means there
3331 } else if (!data.error_set.hasRuntimeBits()) {3446 // cannot possibly be an error, meaning the ABI size is equivalent to the
3332 return AbiSizeAdvanced{ .scalar = data.payload.abiSize(target) };3447 // payload ABI size. In the latter case, we need to account for the "tag"
3333 } else if (!data.payload.hasRuntimeBits()) {3448 // because even if both the payload type and the error set type of an
3334 return AbiSizeAdvanced{ .scalar = data.error_set.abiSize(target) };3449 // error union have no runtime bits, an error union still has
3450 // 1 bit of data which is whether or not the value is an error.
3451 // Zig still uses the error code encoding at runtime, even when only 1 bit
3452 // would suffice. This prevents coercions from needing to branch.
3453 switch (data.error_set.errorSetCardinality()) {
3454 .zero => return abiSizeAdvanced(data.payload, target, strat),
3455 .one => {
3456 if (data.payload.isNoReturn()) {
3457 return AbiSizeAdvanced{ .scalar = 0 };
3458 }
3459 },
3460 .many => {},
3461 }
3462 const code_size = abiSize(Type.anyerror, target);
3463 if (!data.payload.hasRuntimeBits()) {
3464 // Same as anyerror.
3465 return AbiSizeAdvanced{ .scalar = code_size };
3335 }3466 }
3336 const code_align = abiAlignment(data.error_set, target);3467 const code_align = abiAlignment(Type.anyerror, target);
3337 const payload_align = abiAlignment(data.payload, target);3468 const payload_align = abiAlignment(data.payload, target);
3338 const big_align = @maximum(code_align, payload_align);
3339 const payload_size = abiSize(data.payload, target);3469 const payload_size = abiSize(data.payload, target);
33403470
3341 var size: u64 = 0;3471 var size: u64 = 0;
3342 size += abiSize(data.error_set, target);3472 if (code_align > payload_align) {
3343 size = std.mem.alignForwardGeneric(u64, size, payload_align);3473 size += code_size;
3344 size += payload_size;3474 size = std.mem.alignForwardGeneric(u64, size, payload_align);
3345 size = std.mem.alignForwardGeneric(u64, size, big_align);3475 size += payload_size;
3476 size = std.mem.alignForwardGeneric(u64, size, code_align);
3477 } else {
3478 size += payload_size;
3479 size = std.mem.alignForwardGeneric(u64, size, code_align);
3480 size += code_size;
3481 size = std.mem.alignForwardGeneric(u64, size, payload_align);
3482 }
3346 return AbiSizeAdvanced{ .scalar = size };3483 return AbiSizeAdvanced{ .scalar = size };
3347 },3484 },
3348 }3485 }
...@@ -3832,8 +3969,39 @@ pub const Type = extern union {...@@ -3832,8 +3969,39 @@ pub const Type = extern union {
3832 return ty.ptrInfo().data.@"allowzero";3969 return ty.ptrInfo().data.@"allowzero";
3833 }3970 }
38343971
3972 /// See also `isPtrLikeOptional`.
3973 pub fn optionalReprIsPayload(ty: Type) bool {
3974 switch (ty.tag()) {
3975 .optional_single_const_pointer,
3976 .optional_single_mut_pointer,
3977 .c_const_pointer,
3978 .c_mut_pointer,
3979 => return true,
3980
3981 .optional => {
3982 const child_ty = ty.castTag(.optional).?.data;
3983 switch (child_ty.zigTypeTag()) {
3984 .Pointer => {
3985 const info = child_ty.ptrInfo().data;
3986 switch (info.size) {
3987 .Slice, .C => return false,
3988 .Many, .One => return !info.@"allowzero",
3989 }
3990 },
3991 .ErrorSet => return true,
3992 else => return false,
3993 }
3994 },
3995
3996 .pointer => return ty.castTag(.pointer).?.data.size == .C,
3997
3998 else => return false,
3999 }
4000 }
4001
3835 /// Returns true if the type is optional and would be lowered to a single pointer4002 /// Returns true if the type is optional and would be lowered to a single pointer
3836 /// address value, using 0 for null. Note that this returns true for C pointers.4003 /// address value, using 0 for null. Note that this returns true for C pointers.
4004 /// See also `hasOptionalRepr`.
3837 pub fn isPtrLikeOptional(self: Type) bool {4005 pub fn isPtrLikeOptional(self: Type) bool {
3838 switch (self.tag()) {4006 switch (self.tag()) {
3839 .optional_single_const_pointer,4007 .optional_single_const_pointer,
...@@ -4166,6 +4334,35 @@ pub const Type = extern union {...@@ -4166,6 +4334,35 @@ pub const Type = extern union {
4166 };4334 };
4167 }4335 }
41684336
4337 const ErrorSetCardinality = enum { zero, one, many };
4338
4339 pub fn errorSetCardinality(ty: Type) ErrorSetCardinality {
4340 switch (ty.tag()) {
4341 .anyerror => return .many,
4342 .error_set_inferred => return .many,
4343 .error_set_single => return .one,
4344 .error_set => {
4345 const err_set_obj = ty.castTag(.error_set).?.data;
4346 const names = err_set_obj.names.keys();
4347 switch (names.len) {
4348 0 => return .zero,
4349 1 => return .one,
4350 else => return .many,
4351 }
4352 },
4353 .error_set_merged => {
4354 const name_map = ty.castTag(.error_set_merged).?.data;
4355 const names = name_map.keys();
4356 switch (names.len) {
4357 0 => return .zero,
4358 1 => return .one,
4359 else => return .many,
4360 }
4361 },
4362 else => unreachable,
4363 }
4364 }
4365
4169 /// Returns true if it is an error set that includes anyerror, false otherwise.4366 /// Returns true if it is an error set that includes anyerror, false otherwise.
4170 /// Note that the result may be a false negative if the type did not get error set4367 /// Note that the result may be a false negative if the type did not get error set
4171 /// resolution prior to this call.4368 /// resolution prior to this call.
...@@ -4658,16 +4855,11 @@ pub const Type = extern union {...@@ -4658,16 +4855,11 @@ pub const Type = extern union {
4658 .const_slice,4855 .const_slice,
4659 .mut_slice,4856 .mut_slice,
4660 .anyopaque,4857 .anyopaque,
4661 .optional,
4662 .optional_single_mut_pointer,4858 .optional_single_mut_pointer,
4663 .optional_single_const_pointer,4859 .optional_single_const_pointer,
4664 .enum_literal,4860 .enum_literal,
4665 .anyerror_void_error_union,4861 .anyerror_void_error_union,
4666 .error_union,
4667 .error_set,
4668 .error_set_single,
4669 .error_set_inferred,4862 .error_set_inferred,
4670 .error_set_merged,
4671 .@"opaque",4863 .@"opaque",
4672 .var_args_param,4864 .var_args_param,
4673 .manyptr_u8,4865 .manyptr_u8,
...@@ -4696,6 +4888,52 @@ pub const Type = extern union {...@@ -4696,6 +4888,52 @@ pub const Type = extern union {
4696 .bound_fn,4888 .bound_fn,
4697 => return null,4889 => return null,
46984890
4891 .optional => {
4892 var buf: Payload.ElemType = undefined;
4893 const child_ty = ty.optionalChild(&buf);
4894 if (child_ty.isNoReturn()) {
4895 return Value.@"null";
4896 } else {
4897 return null;
4898 }
4899 },
4900
4901 .error_union => {
4902 const error_ty = ty.errorUnionSet();
4903 switch (error_ty.errorSetCardinality()) {
4904 .zero => {
4905 const payload_ty = ty.errorUnionPayload();
4906 if (onePossibleValue(payload_ty)) |payload_val| {
4907 _ = payload_val;
4908 return Value.initTag(.the_only_possible_value);
4909 } else {
4910 return null;
4911 }
4912 },
4913 .one => {
4914 if (ty.errorUnionPayload().isNoReturn()) {
4915 const error_val = onePossibleValue(error_ty).?;
4916 return error_val;
4917 } else {
4918 return null;
4919 }
4920 },
4921 .many => return null,
4922 }
4923 },
4924
4925 .error_set_single => return Value.initTag(.the_only_possible_value),
4926 .error_set => {
4927 const err_set_obj = ty.castTag(.error_set).?.data;
4928 if (err_set_obj.names.count() > 1) return null;
4929 return Value.initTag(.the_only_possible_value);
4930 },
4931 .error_set_merged => {
4932 const name_map = ty.castTag(.error_set_merged).?.data;
4933 if (name_map.count() > 1) return null;
4934 return Value.initTag(.the_only_possible_value);
4935 },
4936
4699 .@"struct" => {4937 .@"struct" => {
4700 const s = ty.castTag(.@"struct").?.data;4938 const s = ty.castTag(.@"struct").?.data;
4701 assert(s.haveFieldTypes());4939 assert(s.haveFieldTypes());
test/behavior/error.zig+97-5
...@@ -121,7 +121,7 @@ test "debug info for optional error set" {...@@ -121,7 +121,7 @@ test "debug info for optional error set" {
121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
122 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;122 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
123123
124 const SomeError = error{Hello};124 const SomeError = error{ Hello, Hello2 };
125 var a_local_variable: ?SomeError = null;125 var a_local_variable: ?SomeError = null;
126 _ = a_local_variable;126 _ = a_local_variable;
127}127}
...@@ -148,18 +148,46 @@ test "implicit cast to optional to error union to return result loc" {...@@ -148,18 +148,46 @@ test "implicit cast to optional to error union to return result loc" {
148 //comptime S.entry(); TODO148 //comptime S.entry(); TODO
149}149}
150150
151test "error: fn returning empty error set can be passed as fn returning any error" {151test "fn returning empty error set can be passed as fn returning any error" {
152 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
154 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
155
152 entry();156 entry();
153 comptime entry();157 comptime entry();
154}158}
155159
160test "fn returning empty error set can be passed as fn returning any error - pointer" {
161 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
162 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
165
166 entryPtr();
167 comptime entryPtr();
168}
169
156fn entry() void {170fn entry() void {
157 foo2(bar2);171 foo2(bar2);
158}172}
159173
174fn entryPtr() void {
175 var ptr = &bar2;
176 fooPtr(ptr);
177}
178
160fn foo2(f: fn () anyerror!void) void {179fn foo2(f: fn () anyerror!void) void {
161 const x = f();180 const x = f();
162 x catch {};181 x catch {
182 @panic("fail");
183 };
184}
185
186fn fooPtr(f: *const fn () anyerror!void) void {
187 const x = f();
188 x catch {
189 @panic("fail");
190 };
163}191}
164192
165fn bar2() (error{}!void) {}193fn bar2() (error{}!void) {}
...@@ -239,7 +267,10 @@ fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void {...@@ -239,7 +267,10 @@ fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void {
239}267}
240268
241test "comptime err to int of error set with only 1 possible value" {269test "comptime err to int of error set with only 1 possible value" {
242 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO270 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
271 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
243274
244 testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));275 testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
245 comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));276 comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
...@@ -409,9 +440,11 @@ test "return function call to error set from error union function" {...@@ -409,9 +440,11 @@ test "return function call to error set from error union function" {
409}440}
410441
411test "optional error set is the same size as error set" {442test "optional error set is the same size as error set" {
412 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO443 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
413445
414 comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror));446 comptime try expect(@sizeOf(?anyerror) == @sizeOf(anyerror));
447 comptime try expect(@alignOf(?anyerror) == @alignOf(anyerror));
415 const S = struct {448 const S = struct {
416 fn returnsOptErrSet() ?anyerror {449 fn returnsOptErrSet() ?anyerror {
417 return null;450 return null;
...@@ -421,6 +454,65 @@ test "optional error set is the same size as error set" {...@@ -421,6 +454,65 @@ test "optional error set is the same size as error set" {
421 comptime try expect(S.returnsOptErrSet() == null);454 comptime try expect(S.returnsOptErrSet() == null);
422}455}
423456
457test "optional error set with only one error is the same size as bool" {
458 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
460 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
461
462 const E = error{only};
463 comptime try expect(@sizeOf(?E) == @sizeOf(bool));
464 comptime try expect(@alignOf(?E) == @alignOf(bool));
465 const S = struct {
466 fn gimmeNull() ?E {
467 return null;
468 }
469 fn gimmeErr() ?E {
470 return error.only;
471 }
472 };
473 try expect(S.gimmeNull() == null);
474 try expect(error.only == S.gimmeErr().?);
475 comptime try expect(S.gimmeNull() == null);
476 comptime try expect(error.only == S.gimmeErr().?);
477}
478
479test "optional empty error set" {
480 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
481
482 comptime try expect(@sizeOf(error{}!void) == @sizeOf(void));
483 comptime try expect(@alignOf(error{}!void) == @alignOf(void));
484
485 var x: ?error{} = undefined;
486 if (x != null) {
487 @compileError("test failed");
488 }
489}
490
491test "empty error set plus zero-bit payload" {
492 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
495
496 comptime try expect(@sizeOf(error{}!void) == @sizeOf(void));
497 comptime try expect(@alignOf(error{}!void) == @alignOf(void));
498
499 var x: error{}!void = undefined;
500 if (x) |payload| {
501 if (payload != {}) {
502 @compileError("test failed");
503 }
504 } else |_| {
505 @compileError("test failed");
506 }
507 const S = struct {
508 fn empty() error{}!void {}
509 fn inferred() !void {
510 return empty();
511 }
512 };
513 try S.inferred();
514}
515
424test "nested catch" {516test "nested catch" {
425 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO517 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
426 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO518 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/eval.zig-27
...@@ -425,7 +425,6 @@ test "f64 at compile time is lossy" {...@@ -425,7 +425,6 @@ test "f64 at compile time is lossy" {
425}425}
426426
427test {427test {
428 if (builtin.zig_backend != .stage1 and builtin.os.tag == .macos) return error.SkipZigTest;
429 comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192);428 comptime try expect(@as(f128, 1 << 113) == 10384593717069655257060992658440192);
430}429}
431430
...@@ -573,28 +572,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio...@@ -573,28 +572,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
573 }572 }
574}573}
575574
576test "call method on bound fn referring to var instance" {
577 if (builtin.zig_backend != .stage1) {
578 // Let's delay solving this one; I want to try to eliminate bound functions from
579 // the language.
580 return error.SkipZigTest; // TODO
581 }
582
583 try expect(bound_fn() == 1237);
584}
585
586const SimpleStruct = struct {
587 field: i32,
588
589 fn method(self: *const SimpleStruct) i32 {
590 return self.field + 3;
591 }
592};
593
594var simple_struct = SimpleStruct{ .field = 1234 };
595
596const bound_fn = simple_struct.method;
597
598test "ptr to local array argument at comptime" {575test "ptr to local array argument at comptime" {
599 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO576 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
600 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -669,8 +646,6 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {...@@ -669,8 +646,6 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
669}646}
670647
671test "comptime function with mutable pointer is not memoized" {648test "comptime function with mutable pointer is not memoized" {
672 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
673
674 comptime {649 comptime {
675 var x: i32 = 1;650 var x: i32 = 1;
676 const ptr = &x;651 const ptr = &x;
...@@ -685,8 +660,6 @@ fn increment(value: *i32) void {...@@ -685,8 +660,6 @@ fn increment(value: *i32) void {
685}660}
686661
687test "const ptr to comptime mutable data is not memoized" {662test "const ptr to comptime mutable data is not memoized" {
688 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
689
690 comptime {663 comptime {
691 var foo = SingleFieldStruct{ .x = 1 };664 var foo = SingleFieldStruct{ .x = 1 };
692 try expect(foo.read_x() == 1);665 try expect(foo.read_x() == 1);
test/cases/compile_errors/call method on bound fn referring to var instance.zig created+20
...@@ -0,0 +1,20 @@
1export fn entry() void {
2 bad(bound_fn() == 1237);
3}
4const SimpleStruct = struct {
5 field: i32,
6
7 fn method(self: *const SimpleStruct) i32 {
8 return self.field + 3;
9 }
10};
11var simple_struct = SimpleStruct{ .field = 1234 };
12const bound_fn = simple_struct.method;
13fn bad(ok: bool) void {
14 _ = ok;
15}
16// error
17// target=native
18// backend=stage2
19//
20// :12:18: error: unable to resolve comptime value