authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-19 06:49:50-04:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-21 08:49:54+01:00
logf95faac5aeeebe0b77ff7023513cdd3e34b71de1
tree77b8094d7da9c171dc29794fa2640e86c11e18bc
parent24f0900ecba3ea67b7c6df31836ed40de22b7ab8

x86_64: (re)implement optional ops

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 {
18711871
1872fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {1872fn 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 }
18891887
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}
19071894
1908fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void {1895fn 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 .dead1898 if (self.liveness.isUnused(inst)) break :result .dead;
1912 else1899
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}
19161910
1917fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {1911fn 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 .dead1914 const dst_ty = self.air.typeOfIndex(inst);
1921 else1915 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}
19251944
...@@ -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 {
21502169
2151fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {2170fn 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 }
21622174
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);
21702188
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 }
21782191
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,
21832196
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 else2646 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);
32723295
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 });
32763299
3277 // Mask with reg.bitSize() - struct_field_size3300 // 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}
49304953
4931fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {4954fn 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;
49344957
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 };
49404966
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 },
49424995
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}
49455027
4946fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {5028fn 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}
49515056
4952fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {5057fn 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 {
50125117
5013fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void {5118fn 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;
50155120 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}
50405127
...@@ -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}
50505140
5051fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void {5141fn 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;
50535143 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)) {
50575147 .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}
50785153
...@@ -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.
6969fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {7044fn 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: off307 // zig fmt: off
308 // General-purpose308 // 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 reverse43 /// 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 /// Call53 /// Call
46 call,54 call,
47 /// Convert byte to word55 /// 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 },
9191
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);
612611
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 }
641640
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);
651652
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);
14test "simple test" {14test "simple test" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1817
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");
33
4const S = packed struct { a: u0 = 0 };4const S = packed struct { a: u0 = 0 };
5test {5test {
6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 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" {
329test "inline call doesn't re-evaluate non generic struct" {329test "inline call doesn't re-evaluate non generic struct" {
330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
332 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
333332
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 {
1206test "implicit cast from *[N]T to ?[*]T" {1206test "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; // TODO1208 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; // TODO1209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12111210
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}
452452
453test "nested catch" {453test "nested catch" {
454 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
455 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
456 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO455 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
457456
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}
131131
132test "if-else expression with runtime condition result location is inferred optional" {132test "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; // TODO135 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}
3030
31test "test maybe object and get a pointer to the inner value" {31test "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; // TODO34 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}
139138
140test "if var maybe pointer" {139test "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; // TODO142 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" {
91test "nested optional field in struct" {91test "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; // TODO93 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; // TODO94 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9695
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" {
109test "equality compare optional with non-optional" {108test "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; // TODO110 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; // TODO111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
114112
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}
228226
229test "coerce an anon struct literal to optional struct" {227test "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; // TODO228 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO230 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}
248245
249test "0-bit child type coerced to optional return ptr result location" {246test "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; // TODO247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO248 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO249 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}
300296
301test "array of optional unaligned types" {297test "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; // TODO298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO300 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}
337332
338test "optional pointer to zero bit optional payload" {333test "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; // TODO334 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO335 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO336 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" {
450test "peer type resolution in nested if expressions" {444test "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;
454447
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}
1919
20test "reinterpret an array over multiple elements, with no well-defined layout" {20test "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; // TODO21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO23 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}
11501150
1151test "anon init through optional" {1151test "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; // TODO1152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1154 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" {
1456test "no dependency loop on pointer to optional struct" {1455test "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; // TODO1457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1459 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14601458
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}
15101508
1511test "optional field init with tuple" {1509test "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; // TODO1510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15151512
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" {
263test "tuple in tuple passed to generic function" {263test "tuple in tuple passed to generic function" {
264 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO264 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO265 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; // TODO266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
268267
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" {
283test "coerce tuple to tuple" {282test "coerce tuple to tuple" {
284 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO284 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; // TODO285 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
288286
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" {
298test "tuple type with void field" {296test "tuple type with void field" {
299 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO297 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
300 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO298 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
301 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
302299
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" {
335test "tuple type with void field and a runtime field" {332test "tuple type with void field and a runtime field" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO333 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
337 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO334 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
338 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
339335
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}
12281228
1229test "extern union most-aligned field is smaller" {1229test "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; // TODO1230 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1232 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}
342342
343test "try terminating an infinite loop" {343test "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; // TODO344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
347346