| author | |
| committer | |
| log | f95faac5aeeebe0b77ff7023513cdd3e34b71de1 |
| tree | 77b8094d7da9c171dc29794fa2640e86c11e18bc |
| parent | 24f0900ecba3ea67b7c6df31836ed40de22b7ab8 |
Note that this commit also changes the layout of optional for all
other backends using `src/codegen.zig` without updating them!19 files changed, 243 insertions(+), 149 deletions(-)
src/arch/x86_64/CodeGen.zig+199-121| ... | @@ -1871,55 +1871,74 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1871,55 +1871,74 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 1871 | 1871 | ||
| 1872 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | 1872 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1873 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1873 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1874 | if (self.liveness.isUnused(inst)) { | ||
| 1875 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | const payload_ty = self.air.typeOfIndex(inst); | ||
| 1879 | const optional_ty = self.air.typeOf(ty_op.operand); | ||
| 1880 | const operand = try self.resolveInst(ty_op.operand); | ||
| 1881 | const result: MCValue = result: { | 1874 | const result: MCValue = result: { |
| 1882 | if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; | 1875 | if (self.liveness.isUnused(inst)) break :result .none; |
| 1883 | if (optional_ty.isPtrLikeOptional()) { | 1876 | |
| 1884 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { | 1877 | const pl_ty = self.air.typeOfIndex(inst); |
| 1885 | break :result operand; | 1878 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 1879 | |||
| 1880 | if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) { | ||
| 1881 | switch (opt_mcv) { | ||
| 1882 | .register => |reg| try self.truncateRegister(pl_ty, reg), | ||
| 1883 | else => {}, | ||
| 1886 | } | 1884 | } |
| 1887 | break :result try self.copyToRegisterWithInstTracking(inst, payload_ty, operand); | 1885 | break :result opt_mcv; |
| 1888 | } | 1886 | } |
| 1889 | 1887 | ||
| 1890 | const offset = optional_ty.abiSize(self.target.*) - payload_ty.abiSize(self.target.*); | 1888 | const pl_mcv = try self.allocRegOrMem(inst, true); |
| 1891 | switch (operand) { | 1889 | try self.setRegOrMem(pl_ty, pl_mcv, opt_mcv); |
| 1892 | .stack_offset => |off| { | 1890 | break :result pl_mcv; |
| 1893 | break :result MCValue{ .stack_offset = off - @intCast(i32, offset) }; | ||
| 1894 | }, | ||
| 1895 | .register => { | ||
| 1896 | // TODO reuse the operand | ||
| 1897 | const result = try self.copyToRegisterWithInstTracking(inst, optional_ty, operand); | ||
| 1898 | const shift = @intCast(u8, offset * @sizeOf(usize)); | ||
| 1899 | try self.genShiftBinOpMir(.shr, optional_ty, result.register, .{ .immediate = @intCast(u8, shift) }); | ||
| 1900 | break :result result; | ||
| 1901 | }, | ||
| 1902 | else => return self.fail("TODO implement optional_payload when operand is {}", .{operand}), | ||
| 1903 | } | ||
| 1904 | }; | 1891 | }; |
| 1905 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1892 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1906 | } | 1893 | } |
| 1907 | 1894 | ||
| 1908 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | 1895 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1909 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1896 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1910 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1897 | const result: MCValue = result: { |
| 1911 | .dead | 1898 | if (self.liveness.isUnused(inst)) break :result .dead; |
| 1912 | else | 1899 | |
| 1913 | return self.fail("TODO implement .optional_payload_ptr for {}", .{self.target.cpu.arch}); | 1900 | const dst_ty = self.air.typeOfIndex(inst); |
| 1901 | const opt_mcv = try self.resolveInst(ty_op.operand); | ||
| 1902 | |||
| 1903 | break :result if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) | ||
| 1904 | opt_mcv | ||
| 1905 | else | ||
| 1906 | try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv); | ||
| 1907 | }; | ||
| 1914 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1908 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1915 | } | 1909 | } |
| 1916 | 1910 | ||
| 1917 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | 1911 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 1918 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1912 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1919 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1913 | const result = result: { |
| 1920 | .dead | 1914 | const dst_ty = self.air.typeOfIndex(inst); |
| 1921 | else | 1915 | const src_ty = self.air.typeOf(ty_op.operand); |
| 1922 | return self.fail("TODO implement .optional_payload_ptr_set for {}", .{self.target.cpu.arch}); | 1916 | const opt_ty = src_ty.childType(); |
| 1917 | const src_mcv = try self.resolveInst(ty_op.operand); | ||
| 1918 | |||
| 1919 | if (opt_ty.optionalReprIsPayload()) { | ||
| 1920 | break :result if (self.liveness.isUnused(inst)) | ||
| 1921 | .dead | ||
| 1922 | else if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | ||
| 1923 | src_mcv | ||
| 1924 | else | ||
| 1925 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); | ||
| 1926 | } | ||
| 1927 | |||
| 1928 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | ||
| 1929 | src_mcv | ||
| 1930 | else | ||
| 1931 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); | ||
| 1932 | |||
| 1933 | const pl_ty = dst_ty.childType(); | ||
| 1934 | const pl_abi_size = @intCast(i32, pl_ty.abiSize(self.target.*)); | ||
| 1935 | try self.asmMemoryImmediate( | ||
| 1936 | .mov, | ||
| 1937 | Memory.sib(.byte, .{ .base = dst_mcv.register, .disp = pl_abi_size }), | ||
| 1938 | Immediate.u(1), | ||
| 1939 | ); | ||
| 1940 | break :result if (self.liveness.isUnused(inst)) .dead else dst_mcv; | ||
| 1941 | }; | ||
| 1923 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1942 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1924 | } | 1943 | } |
| 1925 | 1944 | ||
| ... | @@ -2150,41 +2169,45 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2150,41 +2169,45 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 2150 | 2169 | ||
| 2151 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 2170 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2152 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2171 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2153 | if (self.liveness.isUnused(inst)) { | ||
| 2154 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | ||
| 2155 | } | ||
| 2156 | |||
| 2157 | const payload_ty = self.air.typeOf(ty_op.operand); | ||
| 2158 | const result: MCValue = result: { | 2172 | const result: MCValue = result: { |
| 2159 | if (!payload_ty.hasRuntimeBits()) { | 2173 | if (self.liveness.isUnused(inst)) break :result .dead; |
| 2160 | break :result MCValue{ .immediate = 1 }; | ||
| 2161 | } | ||
| 2162 | 2174 | ||
| 2163 | const optional_ty = self.air.typeOfIndex(inst); | 2175 | const pl_ty = self.air.typeOf(ty_op.operand); |
| 2164 | const operand = try self.resolveInst(ty_op.operand); | 2176 | if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 }; |
| 2165 | const operand_lock: ?RegisterLock = switch (operand) { | 2177 | |
| 2178 | const opt_ty = self.air.typeOfIndex(inst); | ||
| 2179 | const pl_mcv = try self.resolveInst(ty_op.operand); | ||
| 2180 | const same_repr = opt_ty.optionalReprIsPayload(); | ||
| 2181 | if (same_repr and self.reuseOperand(inst, ty_op.operand, 0, pl_mcv)) break :result pl_mcv; | ||
| 2182 | |||
| 2183 | const pl_lock: ?RegisterLock = switch (pl_mcv) { | ||
| 2166 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 2184 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2167 | else => null, | 2185 | else => null, |
| 2168 | }; | 2186 | }; |
| 2169 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | 2187 | defer if (pl_lock) |lock| self.register_manager.unlockReg(lock); |
| 2170 | 2188 | ||
| 2171 | if (optional_ty.isPtrLikeOptional()) { | 2189 | const opt_mcv = try self.allocRegOrMem(inst, true); |
| 2172 | // TODO should we check if we can reuse the operand? | 2190 | try self.setRegOrMem(pl_ty, opt_mcv, pl_mcv); |
| 2173 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) { | ||
| 2174 | break :result operand; | ||
| 2175 | } | ||
| 2176 | break :result try self.copyToRegisterWithInstTracking(inst, payload_ty, operand); | ||
| 2177 | } | ||
| 2178 | 2191 | ||
| 2179 | const optional_abi_size = @intCast(u32, optional_ty.abiSize(self.target.*)); | 2192 | if (!same_repr) { |
| 2180 | const optional_abi_align = optional_ty.abiAlignment(self.target.*); | 2193 | const pl_abi_size = @intCast(i32, pl_ty.abiSize(self.target.*)); |
| 2181 | const payload_abi_size = @intCast(u32, payload_ty.abiSize(self.target.*)); | 2194 | switch (opt_mcv) { |
| 2182 | const offset = optional_abi_size - payload_abi_size; | 2195 | else => unreachable, |
| 2183 | 2196 | ||
| 2184 | const stack_offset = @intCast(i32, try self.allocMem(inst, optional_abi_size, optional_abi_align)); | 2197 | .register => |opt_reg| try self.asmRegisterImmediate( |
| 2185 | try self.genSetStack(Type.bool, stack_offset, .{ .immediate = 1 }, .{}); | 2198 | .bts, |
| 2186 | try self.genSetStack(payload_ty, stack_offset - @intCast(i32, offset), operand, .{}); | 2199 | opt_reg, |
| 2187 | break :result MCValue{ .stack_offset = stack_offset }; | 2200 | Immediate.u(@intCast(u6, pl_abi_size * 8)), |
| 2201 | ), | ||
| 2202 | |||
| 2203 | .stack_offset => |off| try self.asmMemoryImmediate( | ||
| 2204 | .mov, | ||
| 2205 | Memory.sib(.byte, .{ .base = .rsp, .disp = pl_abi_size - off }), | ||
| 2206 | Immediate.u(0), | ||
| 2207 | ), | ||
| 2208 | } | ||
| 2209 | } | ||
| 2210 | break :result opt_mcv; | ||
| 2188 | }; | 2211 | }; |
| 2189 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2212 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2190 | } | 2213 | } |
| ... | @@ -2619,7 +2642,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2619,7 +2642,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 2619 | }, | 2642 | }, |
| 2620 | .register => { | 2643 | .register => { |
| 2621 | const shift: u6 = if (layout.tag_align < layout.payload_align) | 2644 | const shift: u6 = if (layout.tag_align < layout.payload_align) |
| 2622 | @intCast(u6, layout.payload_size * @sizeOf(usize)) | 2645 | @intCast(u6, layout.payload_size * 8) |
| 2623 | else | 2646 | else |
| 2624 | 0; | 2647 | 0; |
| 2625 | const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand); | 2648 | const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand); |
| ... | @@ -3271,7 +3294,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3271,7 +3294,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3271 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); | 3294 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 3272 | 3295 | ||
| 3273 | // Shift by struct_field_offset. | 3296 | // Shift by struct_field_offset. |
| 3274 | const shift = @intCast(u8, struct_field_offset * @sizeOf(usize)); | 3297 | const shift = @intCast(u8, struct_field_offset * 8); |
| 3275 | try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift }); | 3298 | try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift }); |
| 3276 | 3299 | ||
| 3277 | // Mask with reg.bitSize() - struct_field_size | 3300 | // Mask with reg.bitSize() - struct_field_size |
| ... | @@ -4928,25 +4951,107 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4928,25 +4951,107 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4928 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); | 4951 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); |
| 4929 | } | 4952 | } |
| 4930 | 4953 | ||
| 4931 | fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 4954 | fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue { |
| 4932 | try self.spillEflagsIfOccupied(); | 4955 | try self.spillEflagsIfOccupied(); |
| 4933 | self.eflags_inst = inst; | 4956 | self.eflags_inst = inst; |
| 4934 | 4957 | ||
| 4935 | const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: { | 4958 | var pl_buf: Type.Payload.ElemType = undefined; |
| 4936 | var buf: Type.Payload.ElemType = undefined; | 4959 | const pl_ty = opt_ty.optionalChild(&pl_buf); |
| 4937 | const payload_ty = ty.optionalChild(&buf); | 4960 | |
| 4938 | break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime()) Type.bool else ty; | 4961 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 4939 | } else ty; | 4962 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload()) |
| 4963 | .{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty } | ||
| 4964 | else | ||
| 4965 | .{ .off = @intCast(i32, pl_ty.abiSize(self.target.*)), .ty = Type.bool }; | ||
| 4940 | 4966 | ||
| 4941 | try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 }); | 4967 | switch (opt_mcv) { |
| 4968 | .none, | ||
| 4969 | .unreach, | ||
| 4970 | .dead, | ||
| 4971 | .undef, | ||
| 4972 | .immediate, | ||
| 4973 | .register_overflow, | ||
| 4974 | .ptr_stack_offset, | ||
| 4975 | .eflags, | ||
| 4976 | => unreachable, | ||
| 4977 | |||
| 4978 | .register => |opt_reg| { | ||
| 4979 | if (some_info.off == 0) { | ||
| 4980 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | ||
| 4981 | const alias_reg = registerAlias(opt_reg, some_abi_size); | ||
| 4982 | assert(some_abi_size * 8 == alias_reg.bitSize()); | ||
| 4983 | try self.asmRegisterRegister(.@"test", alias_reg, alias_reg); | ||
| 4984 | return .{ .eflags = .z }; | ||
| 4985 | } | ||
| 4986 | assert(some_info.ty.tag() == .bool); | ||
| 4987 | const opt_abi_size = @intCast(u32, opt_ty.abiSize(self.target.*)); | ||
| 4988 | try self.asmRegisterImmediate( | ||
| 4989 | .bt, | ||
| 4990 | registerAlias(opt_reg, opt_abi_size), | ||
| 4991 | Immediate.u(@intCast(u6, some_info.off * 8)), | ||
| 4992 | ); | ||
| 4993 | return .{ .eflags = .nc }; | ||
| 4994 | }, | ||
| 4942 | 4995 | ||
| 4943 | return MCValue{ .eflags = .e }; | 4996 | .memory, .linker_load => { |
| 4997 | const addr_reg = (try self.register_manager.allocReg(null, gp)).to64(); | ||
| 4998 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | ||
| 4999 | defer self.register_manager.unlockReg(addr_reg_lock); | ||
| 5000 | |||
| 5001 | try self.loadMemPtrIntoRegister(addr_reg, Type.usize, opt_mcv); | ||
| 5002 | |||
| 5003 | // To get the actual address of the value we want to modify we have to go through the GOT | ||
| 5004 | try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ | ||
| 5005 | .base = addr_reg, | ||
| 5006 | .disp = 0, | ||
| 5007 | })); | ||
| 5008 | |||
| 5009 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | ||
| 5010 | try self.asmMemoryImmediate(.cmp, Memory.sib( | ||
| 5011 | Memory.PtrSize.fromSize(some_abi_size), | ||
| 5012 | .{ .base = addr_reg, .disp = some_info.off }, | ||
| 5013 | ), Immediate.u(0)); | ||
| 5014 | return .{ .eflags = .e }; | ||
| 5015 | }, | ||
| 5016 | |||
| 5017 | .stack_offset => |off| { | ||
| 5018 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | ||
| 5019 | try self.asmMemoryImmediate(.cmp, Memory.sib( | ||
| 5020 | Memory.PtrSize.fromSize(some_abi_size), | ||
| 5021 | .{ .base = .rbp, .disp = some_info.off - off }, | ||
| 5022 | ), Immediate.u(0)); | ||
| 5023 | return .{ .eflags = .e }; | ||
| 5024 | }, | ||
| 5025 | } | ||
| 4944 | } | 5026 | } |
| 4945 | 5027 | ||
| 4946 | fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 5028 | fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 4947 | const is_null_res = try self.isNull(inst, ty, operand); | 5029 | try self.spillEflagsIfOccupied(); |
| 4948 | assert(is_null_res.eflags == .e); | 5030 | self.eflags_inst = inst; |
| 4949 | return MCValue{ .eflags = is_null_res.eflags.negate() }; | 5031 | |
| 5032 | const opt_ty = ptr_ty.childType(); | ||
| 5033 | var pl_buf: Type.Payload.ElemType = undefined; | ||
| 5034 | const pl_ty = opt_ty.optionalChild(&pl_buf); | ||
| 5035 | |||
| 5036 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 5037 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload()) | ||
| 5038 | .{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty } | ||
| 5039 | else | ||
| 5040 | .{ .off = @intCast(i32, pl_ty.abiSize(self.target.*)), .ty = Type.bool }; | ||
| 5041 | |||
| 5042 | const ptr_reg = switch (ptr_mcv) { | ||
| 5043 | .register => |reg| reg, | ||
| 5044 | else => try self.copyToTmpRegister(ptr_ty, ptr_mcv), | ||
| 5045 | }; | ||
| 5046 | const ptr_lock = self.register_manager.lockReg(ptr_reg); | ||
| 5047 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); | ||
| 5048 | |||
| 5049 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | ||
| 5050 | try self.asmMemoryImmediate(.cmp, Memory.sib( | ||
| 5051 | Memory.PtrSize.fromSize(some_abi_size), | ||
| 5052 | .{ .base = ptr_reg, .disp = some_info.off }, | ||
| 5053 | ), Immediate.u(0)); | ||
| 5054 | return .{ .eflags = .e }; | ||
| 4950 | } | 5055 | } |
| 4951 | 5056 | ||
| 4952 | fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 5057 | fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { |
| ... | @@ -5012,29 +5117,11 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5012,29 +5117,11 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 5012 | 5117 | ||
| 5013 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 5118 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5014 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 5119 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5015 | 5120 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 5016 | if (self.liveness.isUnused(inst)) { | 5121 | const operand = try self.resolveInst(un_op); |
| 5017 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); | 5122 | const ty = self.air.typeOf(un_op); |
| 5018 | } | 5123 | break :result try self.isNullPtr(inst, ty, operand); |
| 5019 | |||
| 5020 | const operand_ptr = try self.resolveInst(un_op); | ||
| 5021 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { | ||
| 5022 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | ||
| 5023 | else => null, | ||
| 5024 | }; | 5124 | }; |
| 5025 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); | ||
| 5026 | |||
| 5027 | const ptr_ty = self.air.typeOf(un_op); | ||
| 5028 | const elem_ty = ptr_ty.childType(); | ||
| 5029 | const operand = if (elem_ty.isPtrLikeOptional() and self.reuseOperand(inst, un_op, 0, operand_ptr)) | ||
| 5030 | // The MCValue that holds the pointer can be re-used as the value. | ||
| 5031 | operand_ptr | ||
| 5032 | else | ||
| 5033 | try self.allocTempRegOrMem(elem_ty, true); | ||
| 5034 | try self.load(operand, operand_ptr, ptr_ty); | ||
| 5035 | |||
| 5036 | const result = try self.isNull(inst, elem_ty, operand); | ||
| 5037 | |||
| 5038 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 5125 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 5039 | } | 5126 | } |
| 5040 | 5127 | ||
| ... | @@ -5043,36 +5130,24 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5043,36 +5130,24 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 5043 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 5130 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 5044 | const operand = try self.resolveInst(un_op); | 5131 | const operand = try self.resolveInst(un_op); |
| 5045 | const ty = self.air.typeOf(un_op); | 5132 | const ty = self.air.typeOf(un_op); |
| 5046 | break :result try self.isNonNull(inst, ty, operand); | 5133 | break :result switch (try self.isNull(inst, ty, operand)) { |
| 5134 | .eflags => |cc| .{ .eflags = cc.negate() }, | ||
| 5135 | else => unreachable, | ||
| 5136 | }; | ||
| 5047 | }; | 5137 | }; |
| 5048 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 5138 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 5049 | } | 5139 | } |
| 5050 | 5140 | ||
| 5051 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 5141 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5052 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 5142 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5053 | 5143 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | |
| 5054 | if (self.liveness.isUnused(inst)) { | 5144 | const operand = try self.resolveInst(un_op); |
| 5055 | return self.finishAir(inst, .dead, .{ un_op, .none, .none }); | 5145 | const ty = self.air.typeOf(un_op); |
| 5056 | } | 5146 | break :result switch (try self.isNullPtr(inst, ty, operand)) { |
| 5057 | 5147 | .eflags => |cc| .{ .eflags = cc.negate() }, | |
| 5058 | const operand_ptr = try self.resolveInst(un_op); | 5148 | else => unreachable, |
| 5059 | const operand_ptr_lock: ?RegisterLock = switch (operand_ptr) { | 5149 | }; |
| 5060 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | ||
| 5061 | else => null, | ||
| 5062 | }; | 5150 | }; |
| 5063 | defer if (operand_ptr_lock) |lock| self.register_manager.unlockReg(lock); | ||
| 5064 | |||
| 5065 | const ptr_ty = self.air.typeOf(un_op); | ||
| 5066 | const elem_ty = ptr_ty.childType(); | ||
| 5067 | const operand = if (elem_ty.isPtrLikeOptional() and self.reuseOperand(inst, un_op, 0, operand_ptr)) | ||
| 5068 | // The MCValue that holds the pointer can be re-used as the value. | ||
| 5069 | operand_ptr | ||
| 5070 | else | ||
| 5071 | try self.allocTempRegOrMem(elem_ty, true); | ||
| 5072 | try self.load(operand, operand_ptr, ptr_ty); | ||
| 5073 | |||
| 5074 | const result = try self.isNonNull(inst, ptr_ty.elemType(), operand); | ||
| 5075 | |||
| 5076 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 5151 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 5077 | } | 5152 | } |
| 5078 | 5153 | ||
| ... | @@ -6967,7 +7042,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { | ... | @@ -6967,7 +7042,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 6967 | /// Truncates the value in the register in place. | 7042 | /// Truncates the value in the register in place. |
| 6968 | /// Clobbers any remaining bits. | 7043 | /// Clobbers any remaining bits. |
| 6969 | fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | 7044 | fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 6970 | const int_info = ty.intInfo(self.target.*); | 7045 | const int_info = if (ty.isAbiInt()) ty.intInfo(self.target.*) else std.builtin.Type.Int{ |
| 7046 | .signedness = .unsigned, | ||
| 7047 | .bits = @intCast(u16, ty.bitSize(self.target.*)), | ||
| 7048 | }; | ||
| 6971 | const max_reg_bit_width = Register.rax.bitSize(); | 7049 | const max_reg_bit_width = Register.rax.bitSize(); |
| 6972 | switch (int_info.signedness) { | 7050 | switch (int_info.signedness) { |
| 6973 | .signed => { | 7051 | .signed => { |
src/arch/x86_64/Emit.zig+4| ... | @@ -75,6 +75,10 @@ pub fn lowerMir(emit: *Emit) InnerError!void { | ... | @@ -75,6 +75,10 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 75 | .@"and", | 75 | .@"and", |
| 76 | .bsf, | 76 | .bsf, |
| 77 | .bsr, | 77 | .bsr, |
| 78 | .bt, | ||
| 79 | .btc, | ||
| 80 | .btr, | ||
| 81 | .bts, | ||
| 78 | .call, | 82 | .call, |
| 79 | .cbw, | 83 | .cbw, |
| 80 | .cwde, | 84 | .cwde, |
src/arch/x86_64/Encoding.zig+1-1| ... | @@ -307,7 +307,7 @@ pub const Mnemonic = enum { | ... | @@ -307,7 +307,7 @@ pub const Mnemonic = enum { |
| 307 | // zig fmt: off | 307 | // zig fmt: off |
| 308 | // General-purpose | 308 | // General-purpose |
| 309 | adc, add, @"and", | 309 | adc, add, @"and", |
| 310 | bsf, bsr, | 310 | bsf, bsr, bt, btc, btr, bts, |
| 311 | call, cbw, cdq, cdqe, | 311 | call, cbw, cdq, cdqe, |
| 312 | cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna, | 312 | cmova, cmovae, cmovb, cmovbe, cmovc, cmove, cmovg, cmovge, cmovl, cmovle, cmovna, |
| 313 | cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno, | 313 | cmovnae, cmovnb, cmovnbe, cmovnc, cmovne, cmovng, cmovnge, cmovnl, cmovnle, cmovno, |
src/arch/x86_64/Mir.zig+8| ... | @@ -42,6 +42,14 @@ pub const Inst = struct { | ... | @@ -42,6 +42,14 @@ pub const Inst = struct { |
| 42 | bsf, | 42 | bsf, |
| 43 | /// Bit scan reverse | 43 | /// Bit scan reverse |
| 44 | bsr, | 44 | bsr, |
| 45 | /// Bit test | ||
| 46 | bt, | ||
| 47 | /// Bit test and complement | ||
| 48 | btc, | ||
| 49 | /// Bit test and reset | ||
| 50 | btr, | ||
| 51 | /// Bit test and set | ||
| 52 | bts, | ||
| 45 | /// Call | 53 | /// Call |
| 46 | call, | 54 | call, |
| 47 | /// Convert byte to word | 55 | /// Convert byte to word |
src/arch/x86_64/encodings.zig+28| ... | @@ -89,6 +89,34 @@ pub const table = &[_]Entry{ | ... | @@ -89,6 +89,34 @@ pub const table = &[_]Entry{ |
| 89 | .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none }, | 89 | .{ .bsr, .rm, .r32, .rm32, .none, .none, &.{ 0x0f, 0xbd }, 0, .none }, |
| 90 | .{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long }, | 90 | .{ .bsr, .rm, .r64, .rm64, .none, .none, &.{ 0x0f, 0xbd }, 0, .long }, |
| 91 | 91 | ||
| 92 | .{ .bt, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, | ||
| 93 | .{ .bt, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xa3 }, 0, .none }, | ||
| 94 | .{ .bt, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xa3 }, 0, .long }, | ||
| 95 | .{ .bt, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none }, | ||
| 96 | .{ .bt, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .none }, | ||
| 97 | .{ .bt, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 4, .long }, | ||
| 98 | |||
| 99 | .{ .btc, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xbb }, 0, .none }, | ||
| 100 | .{ .btc, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xbb }, 0, .none }, | ||
| 101 | .{ .btc, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xbb }, 0, .long }, | ||
| 102 | .{ .btc, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none }, | ||
| 103 | .{ .btc, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .none }, | ||
| 104 | .{ .btc, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 7, .long }, | ||
| 105 | |||
| 106 | .{ .btr, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none }, | ||
| 107 | .{ .btr, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb3 }, 0, .none }, | ||
| 108 | .{ .btr, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb3 }, 0, .long }, | ||
| 109 | .{ .btr, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none }, | ||
| 110 | .{ .btr, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .none }, | ||
| 111 | .{ .btr, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 6, .long }, | ||
| 112 | |||
| 113 | .{ .bts, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xab }, 0, .none }, | ||
| 114 | .{ .bts, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xab }, 0, .none }, | ||
| 115 | .{ .bts, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xab }, 0, .long }, | ||
| 116 | .{ .bts, .mi, .rm16, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none }, | ||
| 117 | .{ .bts, .mi, .rm32, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .none }, | ||
| 118 | .{ .bts, .mi, .rm64, .imm8, .none, .none, &.{ 0x0f, 0xba }, 5, .long }, | ||
| 119 | |||
| 92 | // This is M encoding according to Intel, but D makes more sense here. | 120 | // This is M encoding according to Intel, but D makes more sense here. |
| 93 | .{ .call, .d, .rel32, .none, .none, .none, &.{ 0xe8 }, 0, .none }, | 121 | .{ .call, .d, .rel32, .none, .none, .none, &.{ 0xe8 }, 0, .none }, |
| 94 | .{ .call, .m, .rm64, .none, .none, .none, &.{ 0xff }, 2, .none }, | 122 | .{ .call, .m, .rm64, .none, .none, .none, &.{ 0xff }, 2, .none }, |
src/codegen.zig+3-2| ... | @@ -608,7 +608,6 @@ pub fn generateSymbol( | ... | @@ -608,7 +608,6 @@ pub fn generateSymbol( |
| 608 | const payload_type = typed_value.ty.optionalChild(&opt_buf); | 608 | const payload_type = typed_value.ty.optionalChild(&opt_buf); |
| 609 | const is_pl = !typed_value.val.isNull(); | 609 | const is_pl = !typed_value.val.isNull(); |
| 610 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | 610 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; |
| 611 | const offset = abi_size - (math.cast(usize, payload_type.abiSize(target)) orelse return error.Overflow); | ||
| 612 | 611 | ||
| 613 | if (!payload_type.hasRuntimeBits()) { | 612 | if (!payload_type.hasRuntimeBits()) { |
| 614 | try code.writer().writeByteNTimes(@boolToInt(is_pl), abi_size); | 613 | try code.writer().writeByteNTimes(@boolToInt(is_pl), abi_size); |
| ... | @@ -639,8 +638,8 @@ pub fn generateSymbol( | ... | @@ -639,8 +638,8 @@ pub fn generateSymbol( |
| 639 | return Result.ok; | 638 | return Result.ok; |
| 640 | } | 639 | } |
| 641 | 640 | ||
| 641 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(target)) orelse return error.Overflow) - 1; | ||
| 642 | const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef); | 642 | const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef); |
| 643 | try code.writer().writeByteNTimes(@boolToInt(is_pl), offset); | ||
| 644 | switch (try generateSymbol(bin_file, src_loc, .{ | 643 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 645 | .ty = payload_type, | 644 | .ty = payload_type, |
| 646 | .val = value, | 645 | .val = value, |
| ... | @@ -648,6 +647,8 @@ pub fn generateSymbol( | ... | @@ -648,6 +647,8 @@ pub fn generateSymbol( |
| 648 | .ok => {}, | 647 | .ok => {}, |
| 649 | .fail => |em| return Result{ .fail = em }, | 648 | .fail => |em| return Result{ .fail = em }, |
| 650 | } | 649 | } |
| 650 | try code.writer().writeByte(@boolToInt(is_pl)); | ||
| 651 | try code.writer().writeByteNTimes(0, padding); | ||
| 651 | 652 | ||
| 652 | return Result.ok; | 653 | return Result.ok; |
| 653 | }, | 654 | }, |
test/behavior/bugs/12984.zig-1| ... | @@ -14,7 +14,6 @@ pub const CustomDraw = DeleagateWithContext(fn (?OnConfirm) void); | ... | @@ -14,7 +14,6 @@ pub const CustomDraw = DeleagateWithContext(fn (?OnConfirm) void); |
| 14 | test "simple test" { | 14 | test "simple test" { |
| 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 16 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 16 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 17 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 18 | 17 | ||
| 19 | var c: CustomDraw = undefined; | 18 | var c: CustomDraw = undefined; |
| 20 | _ = c; | 19 | _ = c; |
test/behavior/bugs/13785.zig-1| ... | @@ -3,7 +3,6 @@ const std = @import("std"); | ... | @@ -3,7 +3,6 @@ const std = @import("std"); |
| 3 | 3 | ||
| 4 | const S = packed struct { a: u0 = 0 }; | 4 | const S = packed struct { a: u0 = 0 }; |
| 5 | test { | 5 | test { |
| 6 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/call.zig-1| ... | @@ -329,7 +329,6 @@ test "inline call preserves tail call" { | ... | @@ -329,7 +329,6 @@ test "inline call preserves tail call" { |
| 329 | test "inline call doesn't re-evaluate non generic struct" { | 329 | test "inline call doesn't re-evaluate non generic struct" { |
| 330 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 330 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 331 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 331 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 332 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 333 | 332 | ||
| 334 | const S = struct { | 333 | const S = struct { |
| 335 | fn foo(f: struct { a: u8, b: u8 }) !void { | 334 | fn foo(f: struct { a: u8, b: u8 }) !void { |
test/behavior/cast.zig-1| ... | @@ -1206,7 +1206,6 @@ fn cast128Float(x: u128) f128 { | ... | @@ -1206,7 +1206,6 @@ fn cast128Float(x: u128) f128 { |
| 1206 | test "implicit cast from *[N]T to ?[*]T" { | 1206 | test "implicit cast from *[N]T to ?[*]T" { |
| 1207 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1207 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1208 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1208 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1209 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1210 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1211 | 1210 | ||
| 1212 | var x: ?[*]u16 = null; | 1211 | var x: ?[*]u16 = null; |
test/behavior/error.zig-1| ... | @@ -451,7 +451,6 @@ test "optional error set is the same size as error set" { | ... | @@ -451,7 +451,6 @@ test "optional error set is the same size as error set" { |
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | test "nested catch" { | 453 | test "nested catch" { |
| 454 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 455 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 454 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 456 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 455 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 457 | 456 |
test/behavior/if.zig-1| ... | @@ -130,7 +130,6 @@ test "if peer expressions inferred optional type" { | ... | @@ -130,7 +130,6 @@ test "if peer expressions inferred optional type" { |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | test "if-else expression with runtime condition result location is inferred optional" { | 132 | test "if-else expression with runtime condition result location is inferred optional" { |
| 133 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 134 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 134 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 135 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/null.zig-2| ... | @@ -29,7 +29,6 @@ test "optional type" { | ... | @@ -29,7 +29,6 @@ test "optional type" { |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | test "test maybe object and get a pointer to the inner value" { | 31 | test "test maybe object and get a pointer to the inner value" { |
| 32 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 34 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 33 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -138,7 +137,6 @@ test "optional pointer to 0 bit type null value at runtime" { | ... | @@ -138,7 +137,6 @@ test "optional pointer to 0 bit type null value at runtime" { |
| 138 | } | 137 | } |
| 139 | 138 | ||
| 140 | test "if var maybe pointer" { | 139 | test "if var maybe pointer" { |
| 141 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 142 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 140 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 143 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 141 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 144 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 142 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/optional.zig-7| ... | @@ -91,7 +91,6 @@ test "address of unwrap optional" { | ... | @@ -91,7 +91,6 @@ test "address of unwrap optional" { |
| 91 | test "nested optional field in struct" { | 91 | test "nested optional field in struct" { |
| 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 93 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 93 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 94 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 95 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 94 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 96 | 95 | ||
| 97 | const S2 = struct { | 96 | const S2 = struct { |
| ... | @@ -109,7 +108,6 @@ test "nested optional field in struct" { | ... | @@ -109,7 +108,6 @@ test "nested optional field in struct" { |
| 109 | test "equality compare optional with non-optional" { | 108 | test "equality compare optional with non-optional" { |
| 110 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 109 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 111 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 110 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 112 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 113 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 111 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 114 | 112 | ||
| 115 | try test_cmp_optional_non_optional(); | 113 | try test_cmp_optional_non_optional(); |
| ... | @@ -227,7 +225,6 @@ test "assigning to an unwrapped optional field in an inline loop" { | ... | @@ -227,7 +225,6 @@ test "assigning to an unwrapped optional field in an inline loop" { |
| 227 | } | 225 | } |
| 228 | 226 | ||
| 229 | test "coerce an anon struct literal to optional struct" { | 227 | test "coerce an anon struct literal to optional struct" { |
| 230 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 231 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 228 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 232 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 229 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 233 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 230 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -247,7 +244,6 @@ test "coerce an anon struct literal to optional struct" { | ... | @@ -247,7 +244,6 @@ test "coerce an anon struct literal to optional struct" { |
| 247 | } | 244 | } |
| 248 | 245 | ||
| 249 | test "0-bit child type coerced to optional return ptr result location" { | 246 | test "0-bit child type coerced to optional return ptr result location" { |
| 250 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 251 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 247 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 252 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 248 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 253 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 249 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -299,7 +295,6 @@ test "0-bit child type coerced to optional" { | ... | @@ -299,7 +295,6 @@ test "0-bit child type coerced to optional" { |
| 299 | } | 295 | } |
| 300 | 296 | ||
| 301 | test "array of optional unaligned types" { | 297 | test "array of optional unaligned types" { |
| 302 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 298 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 304 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 299 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 305 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 300 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -336,7 +331,6 @@ test "array of optional unaligned types" { | ... | @@ -336,7 +331,6 @@ test "array of optional unaligned types" { |
| 336 | } | 331 | } |
| 337 | 332 | ||
| 338 | test "optional pointer to zero bit optional payload" { | 333 | test "optional pointer to zero bit optional payload" { |
| 339 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 340 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 334 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 341 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 335 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 342 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 336 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -450,7 +444,6 @@ test "Optional slice size is optimized" { | ... | @@ -450,7 +444,6 @@ test "Optional slice size is optimized" { |
| 450 | test "peer type resolution in nested if expressions" { | 444 | test "peer type resolution in nested if expressions" { |
| 451 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 445 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 452 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 446 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 453 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 454 | 447 | ||
| 455 | const Thing = struct { n: i32 }; | 448 | const Thing = struct { n: i32 }; |
| 456 | var a = false; | 449 | var a = false; |
test/behavior/ptrcast.zig-1| ... | @@ -18,7 +18,6 @@ fn testReinterpretBytesAsInteger() !void { | ... | @@ -18,7 +18,6 @@ fn testReinterpretBytesAsInteger() !void { |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | test "reinterpret an array over multiple elements, with no well-defined layout" { | 20 | test "reinterpret an array over multiple elements, with no well-defined layout" { |
| 21 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 22 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 23 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 24 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 23 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/struct.zig-3| ... | @@ -1149,7 +1149,6 @@ test "anon init through error unions and optionals" { | ... | @@ -1149,7 +1149,6 @@ test "anon init through error unions and optionals" { |
| 1149 | } | 1149 | } |
| 1150 | 1150 | ||
| 1151 | test "anon init through optional" { | 1151 | test "anon init through optional" { |
| 1152 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1153 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1152 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1153 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1155 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1154 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -1456,7 +1455,6 @@ test "struct has only one reference" { | ... | @@ -1456,7 +1455,6 @@ test "struct has only one reference" { |
| 1456 | test "no dependency loop on pointer to optional struct" { | 1455 | test "no dependency loop on pointer to optional struct" { |
| 1457 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1456 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1458 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1459 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1460 | 1458 | ||
| 1461 | const S = struct { | 1459 | const S = struct { |
| 1462 | const A = struct { b: B }; | 1460 | const A = struct { b: B }; |
| ... | @@ -1509,7 +1507,6 @@ test "no dependency loop on optional field wrapped in generic function" { | ... | @@ -1509,7 +1507,6 @@ test "no dependency loop on optional field wrapped in generic function" { |
| 1509 | } | 1507 | } |
| 1510 | 1508 | ||
| 1511 | test "optional field init with tuple" { | 1509 | test "optional field init with tuple" { |
| 1512 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1513 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1510 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1514 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1511 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1515 | 1512 |
test/behavior/tuple.zig-4| ... | @@ -263,7 +263,6 @@ test "initializing anon struct with mixed comptime-runtime fields" { | ... | @@ -263,7 +263,6 @@ test "initializing anon struct with mixed comptime-runtime fields" { |
| 263 | test "tuple in tuple passed to generic function" { | 263 | test "tuple in tuple passed to generic function" { |
| 264 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 264 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 265 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 265 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 266 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 267 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 266 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 268 | 267 | ||
| 269 | const S = struct { | 268 | const S = struct { |
| ... | @@ -283,7 +282,6 @@ test "tuple in tuple passed to generic function" { | ... | @@ -283,7 +282,6 @@ test "tuple in tuple passed to generic function" { |
| 283 | test "coerce tuple to tuple" { | 282 | test "coerce tuple to tuple" { |
| 284 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 283 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 285 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 284 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 286 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 287 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 285 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 288 | 286 | ||
| 289 | const T = std.meta.Tuple(&.{u8}); | 287 | const T = std.meta.Tuple(&.{u8}); |
| ... | @@ -298,7 +296,6 @@ test "coerce tuple to tuple" { | ... | @@ -298,7 +296,6 @@ test "coerce tuple to tuple" { |
| 298 | test "tuple type with void field" { | 296 | test "tuple type with void field" { |
| 299 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 297 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 300 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 298 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 301 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 302 | 299 | ||
| 303 | const T = std.meta.Tuple(&[_]type{void}); | 300 | const T = std.meta.Tuple(&[_]type{void}); |
| 304 | const x = T{{}}; | 301 | const x = T{{}}; |
| ... | @@ -335,7 +332,6 @@ test "zero sized struct in tuple handled correctly" { | ... | @@ -335,7 +332,6 @@ test "zero sized struct in tuple handled correctly" { |
| 335 | test "tuple type with void field and a runtime field" { | 332 | test "tuple type with void field and a runtime field" { |
| 336 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 333 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 337 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 334 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 338 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 339 | 335 | ||
| 340 | const T = std.meta.Tuple(&[_]type{ usize, void }); | 336 | const T = std.meta.Tuple(&[_]type{ usize, void }); |
| 341 | var t: T = .{ 5, {} }; | 337 | var t: T = .{ 5, {} }; |
test/behavior/union.zig-1| ... | @@ -1227,7 +1227,6 @@ test "union tag is set when initiated as a temporary value at runtime" { | ... | @@ -1227,7 +1227,6 @@ test "union tag is set when initiated as a temporary value at runtime" { |
| 1227 | } | 1227 | } |
| 1228 | 1228 | ||
| 1229 | test "extern union most-aligned field is smaller" { | 1229 | test "extern union most-aligned field is smaller" { |
| 1230 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1231 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1230 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1232 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1231 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1233 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1232 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/while.zig-1| ... | @@ -341,7 +341,6 @@ test "else continue outer while" { | ... | @@ -341,7 +341,6 @@ test "else continue outer while" { |
| 341 | } | 341 | } |
| 342 | 342 | ||
| 343 | test "try terminating an infinite loop" { | 343 | test "try terminating an infinite loop" { |
| 344 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 345 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 344 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 346 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 345 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 347 | 346 |