authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-27 15:24:39-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-27 15:24:39-04:00
log0501962b4c01ee511aa0ae4b41cca4af7209bd8e
tree15a60984f65d9cbbb748c5ee64ba0d966d804225
parentd15bbebe2e6b8fcbfcd730a6c0d1be621b27045d
parente1bb09648fbd827975b9f589fa849aabefe73f67
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11321 from Luukdegram/wasm-overflow

stage2: wasm - Implement overflow arithmetic

2 files changed, 156 insertions(+), 32 deletions(-)

src/arch/wasm/CodeGen.zig+156-25
...@@ -1303,10 +1303,16 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1303,10 +1303,16 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1303 .bool_and => self.airBinOp(inst, .@"and"),1303 .bool_and => self.airBinOp(inst, .@"and"),
1304 .bool_or => self.airBinOp(inst, .@"or"),1304 .bool_or => self.airBinOp(inst, .@"or"),
1305 .rem => self.airBinOp(inst, .rem),1305 .rem => self.airBinOp(inst, .rem),
1306 .shl, .shl_exact => self.airBinOp(inst, .shl),1306 .shl => self.airWrapBinOp(inst, .shl),
1307 .shl_exact => self.airBinOp(inst, .shl),
1307 .shr, .shr_exact => self.airBinOp(inst, .shr),1308 .shr, .shr_exact => self.airBinOp(inst, .shr),
1308 .xor => self.airBinOp(inst, .xor),1309 .xor => self.airBinOp(inst, .xor),
13091310
1311 .add_with_overflow => self.airBinOpOverflow(inst, .add),
1312 .sub_with_overflow => self.airBinOpOverflow(inst, .sub),
1313 .shl_with_overflow => self.airBinOpOverflow(inst, .shl),
1314 .mul_with_overflow => self.airBinOpOverflow(inst, .mul),
1315
1310 .cmp_eq => self.airCmp(inst, .eq),1316 .cmp_eq => self.airCmp(inst, .eq),
1311 .cmp_gte => self.airCmp(inst, .gte),1317 .cmp_gte => self.airCmp(inst, .gte),
1312 .cmp_gt => self.airCmp(inst, .gt),1318 .cmp_gt => self.airCmp(inst, .gt),
...@@ -1461,13 +1467,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1461,13 +1467,6 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1461 .atomic_rmw,1467 .atomic_rmw,
1462 .tag_name,1468 .tag_name,
1463 .mul_add,1469 .mul_add,
1464
1465 // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/10248
1466 // is implemented in the frontend before implementing them here in the wasm backend.
1467 .add_with_overflow,
1468 .sub_with_overflow,
1469 .mul_with_overflow,
1470 .shl_with_overflow,
1471 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),1470 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
1472 };1471 };
1473}1472}
...@@ -1754,24 +1753,28 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -1754,24 +1753,28 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
1754 const lhs = try self.resolveInst(bin_op.lhs);1753 const lhs = try self.resolveInst(bin_op.lhs);
1755 const rhs = try self.resolveInst(bin_op.rhs);1754 const rhs = try self.resolveInst(bin_op.rhs);
1756 const operand_ty = self.air.typeOfIndex(inst);1755 const operand_ty = self.air.typeOfIndex(inst);
1756 const ty = self.air.typeOf(bin_op.lhs);
17571757
1758 if (isByRef(operand_ty, self.target)) {1758 if (isByRef(operand_ty, self.target)) {
1759 return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty.fmtDebug()});1759 return self.fail("TODO: Implement binary operation for type: {}", .{operand_ty.fmtDebug()});
1760 }1760 }
17611761
1762 return self.binOp(lhs, rhs, ty, op);
1763}
1764
1765fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
1762 try self.emitWValue(lhs);1766 try self.emitWValue(lhs);
1763 try self.emitWValue(rhs);1767 try self.emitWValue(rhs);
17641768
1765 const bin_ty = self.air.typeOf(bin_op.lhs);
1766 const opcode: wasm.Opcode = buildOpcode(.{1769 const opcode: wasm.Opcode = buildOpcode(.{
1767 .op = op,1770 .op = op,
1768 .valtype1 = typeToValtype(bin_ty, self.target),1771 .valtype1 = typeToValtype(ty, self.target),
1769 .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned,1772 .signedness = if (ty.isSignedInt()) .signed else .unsigned,
1770 });1773 });
1771 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));1774 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
17721775
1773 // save the result in a temporary1776 // save the result in a temporary
1774 const bin_local = try self.allocLocal(bin_ty);1777 const bin_local = try self.allocLocal(ty);
1775 try self.addLabel(.local_set, bin_local.local);1778 try self.addLabel(.local_set, bin_local.local);
1776 return bin_local;1779 return bin_local;
1777}1780}
...@@ -1781,18 +1784,21 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -1781,18 +1784,21 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
1781 const lhs = try self.resolveInst(bin_op.lhs);1784 const lhs = try self.resolveInst(bin_op.lhs);
1782 const rhs = try self.resolveInst(bin_op.rhs);1785 const rhs = try self.resolveInst(bin_op.rhs);
17831786
1787 return self.wrapBinOp(lhs, rhs, self.air.typeOf(bin_op.lhs), op);
1788}
1789
1790fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
1784 try self.emitWValue(lhs);1791 try self.emitWValue(lhs);
1785 try self.emitWValue(rhs);1792 try self.emitWValue(rhs);
17861793
1787 const bin_ty = self.air.typeOf(bin_op.lhs);
1788 const opcode: wasm.Opcode = buildOpcode(.{1794 const opcode: wasm.Opcode = buildOpcode(.{
1789 .op = op,1795 .op = op,
1790 .valtype1 = typeToValtype(bin_ty, self.target),1796 .valtype1 = typeToValtype(ty, self.target),
1791 .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned,1797 .signedness = if (ty.isSignedInt()) .signed else .unsigned,
1792 });1798 });
1793 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));1799 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
17941800
1795 const int_info = bin_ty.intInfo(self.target);1801 const int_info = ty.intInfo(self.target);
1796 const bitsize = int_info.bits;1802 const bitsize = int_info.bits;
1797 const is_signed = int_info.signedness == .signed;1803 const is_signed = int_info.signedness == .signed;
1798 // if target type bitsize is x < 32 and 32 > x < 64, we perform1804 // if target type bitsize is x < 32 and 32 > x < 64, we perform
...@@ -1820,7 +1826,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -1820,7 +1826,7 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
1820 }1826 }
18211827
1822 // save the result in a temporary1828 // save the result in a temporary
1823 const bin_local = try self.allocLocal(bin_ty);1829 const bin_local = try self.allocLocal(ty);
1824 try self.addLabel(.local_set, bin_local.local);1830 try self.addLabel(.local_set, bin_local.local);
1825 return bin_local;1831 return bin_local;
1826}1832}
...@@ -2202,18 +2208,21 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2202,18 +2208,21 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2202 const lhs = try self.resolveInst(bin_op.lhs);2208 const lhs = try self.resolveInst(bin_op.lhs);
2203 const rhs = try self.resolveInst(bin_op.rhs);2209 const rhs = try self.resolveInst(bin_op.rhs);
2204 const operand_ty = self.air.typeOf(bin_op.lhs);2210 const operand_ty = self.air.typeOf(bin_op.lhs);
2211 return self.cmp(lhs, rhs, operand_ty, op);
2212}
22052213
2206 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {2214fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {
2215 if (ty.zigTypeTag() == .Optional and !ty.isPtrLikeOptional()) {
2207 var buf: Type.Payload.ElemType = undefined;2216 var buf: Type.Payload.ElemType = undefined;
2208 const payload_ty = operand_ty.optionalChild(&buf);2217 const payload_ty = ty.optionalChild(&buf);
2209 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {2218 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
2210 // When we hit this case, we must check the value of optionals2219 // When we hit this case, we must check the value of optionals
2211 // that are not pointers. This means first checking against non-null for2220 // that are not pointers. This means first checking against non-null for
2212 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs2221 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs
2213 return self.cmpOptionals(lhs, rhs, operand_ty, op);2222 return self.cmpOptionals(lhs, rhs, ty, op);
2214 }2223 }
2215 } else if (isByRef(operand_ty, self.target)) {2224 } else if (isByRef(ty, self.target)) {
2216 return self.cmpBigInt(lhs, rhs, operand_ty, op);2225 return self.cmpBigInt(lhs, rhs, ty, op);
2217 }2226 }
22182227
2219 // ensure that when we compare pointers, we emit2228 // ensure that when we compare pointers, we emit
...@@ -2229,13 +2238,13 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2229,13 +2238,13 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
22292238
2230 const signedness: std.builtin.Signedness = blk: {2239 const signedness: std.builtin.Signedness = blk: {
2231 // by default we tell the operand type is unsigned (i.e. bools and enum values)2240 // by default we tell the operand type is unsigned (i.e. bools and enum values)
2232 if (operand_ty.zigTypeTag() != .Int) break :blk .unsigned;2241 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
22332242
2234 // incase of an actual integer, we emit the correct signedness2243 // incase of an actual integer, we emit the correct signedness
2235 break :blk operand_ty.intInfo(self.target).signedness;2244 break :blk ty.intInfo(self.target).signedness;
2236 };2245 };
2237 const opcode: wasm.Opcode = buildOpcode(.{2246 const opcode: wasm.Opcode = buildOpcode(.{
2238 .valtype1 = typeToValtype(operand_ty, self.target),2247 .valtype1 = typeToValtype(ty, self.target),
2239 .op = switch (op) {2248 .op = switch (op) {
2240 .lt => .lt,2249 .lt => .lt,
2241 .lte => .le,2250 .lte => .le,
...@@ -3730,3 +3739,125 @@ fn airPtrSliceFieldPtr(self: *Self, inst: Air.Inst.Index, offset: u32) InnerErro...@@ -3730,3 +3739,125 @@ fn airPtrSliceFieldPtr(self: *Self, inst: Air.Inst.Index, offset: u32) InnerErro
3730 const slice_ptr = try self.resolveInst(ty_op.operand);3739 const slice_ptr = try self.resolveInst(ty_op.operand);
3731 return self.buildPointerOffset(slice_ptr, offset, .new);3740 return self.buildPointerOffset(slice_ptr, offset, .new);
3732}3741}
3742
3743fn airBinOpOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
3744 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3745
3746 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3747 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
3748 const lhs = try self.resolveInst(extra.lhs);
3749 const rhs = try self.resolveInst(extra.rhs);
3750 const lhs_ty = self.air.typeOf(extra.lhs);
3751
3752 // We store the bit if it's overflowed or not in this. As it's zero-initialized
3753 // we only need to update it if an overflow (or underflow) occured.
3754 const overflow_bit = try self.allocLocal(Type.initTag(.u1));
3755 const int_info = lhs_ty.intInfo(self.target);
3756 const wasm_bits = toWasmBits(int_info.bits) orelse {
3757 return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits});
3758 };
3759
3760 const zero = switch (wasm_bits) {
3761 32 => WValue{ .imm32 = 0 },
3762 64 => WValue{ .imm64 = 0 },
3763 else => unreachable,
3764 };
3765 const int_max = (@as(u65, 1) << @intCast(u7, int_info.bits - @boolToInt(int_info.signedness == .signed))) - 1;
3766 const int_max_wvalue = switch (wasm_bits) {
3767 32 => WValue{ .imm32 = @intCast(u32, int_max) },
3768 64 => WValue{ .imm64 = @intCast(u64, int_max) },
3769 else => unreachable,
3770 };
3771 const int_min = if (int_info.signedness == .unsigned)
3772 @as(i64, 0)
3773 else
3774 -@as(i64, 1) << @intCast(u6, int_info.bits - 1);
3775 const int_min_wvalue = switch (wasm_bits) {
3776 32 => WValue{ .imm32 = @bitCast(u32, @intCast(i32, int_min)) },
3777 64 => WValue{ .imm64 = @bitCast(u64, int_min) },
3778 else => unreachable,
3779 };
3780
3781 if (int_info.signedness == .unsigned and op == .add) {
3782 const diff = try self.binOp(int_max_wvalue, lhs, lhs_ty, .sub);
3783 const cmp_res = try self.cmp(rhs, diff, lhs_ty, .gt);
3784 try self.emitWValue(cmp_res);
3785 try self.addLabel(.local_set, overflow_bit.local);
3786 } else if (int_info.signedness == .unsigned and op == .sub) {
3787 const cmp_res = try self.cmp(lhs, rhs, lhs_ty, .lt);
3788 try self.emitWValue(cmp_res);
3789 try self.addLabel(.local_set, overflow_bit.local);
3790 } else if (int_info.signedness == .signed and op != .shl) {
3791 // for overflow, we first check if lhs is > 0 (or lhs < 0 in case of subtraction). If not, we will not overflow.
3792 // We first create an outer block, where we handle overflow.
3793 // Then we create an inner block, where underflow is handled.
3794 try self.startBlock(.block, wasm.block_empty);
3795 try self.startBlock(.block, wasm.block_empty);
3796 {
3797 try self.emitWValue(lhs);
3798 const cmp_result = try self.cmp(lhs, zero, lhs_ty, .lt);
3799 try self.emitWValue(cmp_result);
3800 }
3801 try self.addLabel(.br_if, 0); // break to outer block, and handle underflow
3802
3803 // handle overflow
3804 {
3805 const diff = try self.binOp(int_max_wvalue, lhs, lhs_ty, .sub);
3806 const cmp_res = try self.cmp(rhs, diff, lhs_ty, if (op == .add) .gt else .lt);
3807 try self.emitWValue(cmp_res);
3808 try self.addLabel(.local_set, overflow_bit.local);
3809 }
3810 try self.addLabel(.br, 1); // break from blocks, and continue regular flow.
3811 try self.endBlock();
3812
3813 // handle underflow
3814 {
3815 const diff = try self.binOp(int_min_wvalue, lhs, lhs_ty, .sub);
3816 const cmp_res = try self.cmp(rhs, diff, lhs_ty, if (op == .add) .lt else .gt);
3817 try self.emitWValue(cmp_res);
3818 try self.addLabel(.local_set, overflow_bit.local);
3819 }
3820 try self.endBlock();
3821 }
3822
3823 const bin_op = if (op == .shl) blk: {
3824 const tmp_val = try self.binOp(lhs, rhs, lhs_ty, op);
3825 const cmp_res = try self.cmp(tmp_val, int_max_wvalue, lhs_ty, .gt);
3826 try self.emitWValue(cmp_res);
3827 try self.addLabel(.local_set, overflow_bit.local);
3828
3829 try self.emitWValue(tmp_val);
3830 try self.emitWValue(int_max_wvalue);
3831 switch (wasm_bits) {
3832 32 => try self.addTag(.i32_and),
3833 64 => try self.addTag(.i64_and),
3834 else => unreachable,
3835 }
3836 try self.addLabel(.local_set, tmp_val.local);
3837 break :blk tmp_val;
3838 } else if (op == .mul) blk: {
3839 const bin_op = try self.wrapBinOp(lhs, rhs, lhs_ty, op);
3840 try self.startBlock(.block, wasm.block_empty);
3841 // check if 0. true => Break out of block as cannot over -or underflow.
3842 try self.emitWValue(lhs);
3843 switch (wasm_bits) {
3844 32 => try self.addTag(.i32_eqz),
3845 64 => try self.addTag(.i64_eqz),
3846 else => unreachable,
3847 }
3848 try self.addLabel(.br_if, 0);
3849 const div = try self.binOp(bin_op, lhs, lhs_ty, .div);
3850 const cmp_res = try self.cmp(div, rhs, lhs_ty, .neq);
3851 try self.emitWValue(cmp_res);
3852 try self.addLabel(.local_set, overflow_bit.local);
3853 try self.endBlock();
3854 break :blk bin_op;
3855 } else try self.wrapBinOp(lhs, rhs, lhs_ty, op);
3856
3857 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
3858 try self.store(result_ptr, bin_op, lhs_ty, 0);
3859 const offset = @intCast(u32, lhs_ty.abiSize(self.target));
3860 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset);
3861
3862 return result_ptr;
3863}
test/behavior/math.zig-7
...@@ -639,7 +639,6 @@ test "128-bit multiplication" {...@@ -639,7 +639,6 @@ test "128-bit multiplication" {
639639
640test "@addWithOverflow" {640test "@addWithOverflow" {
641 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO641 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
642 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
643 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO642 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO643 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
645 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO644 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -661,7 +660,6 @@ test "@addWithOverflow" {...@@ -661,7 +660,6 @@ test "@addWithOverflow" {
661660
662test "small int addition" {661test "small int addition" {
663 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO662 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
664 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
665 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO663 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
666 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO664 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
667 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -686,7 +684,6 @@ test "small int addition" {...@@ -686,7 +684,6 @@ test "small int addition" {
686684
687test "@mulWithOverflow" {685test "@mulWithOverflow" {
688 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO686 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
689 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
690 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO687 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
691 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO688 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
692 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO689 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -708,7 +705,6 @@ test "@mulWithOverflow" {...@@ -708,7 +705,6 @@ test "@mulWithOverflow" {
708705
709test "@subWithOverflow" {706test "@subWithOverflow" {
710 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO707 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
711 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
712 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO708 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
713 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
714 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -730,7 +726,6 @@ test "@subWithOverflow" {...@@ -730,7 +726,6 @@ test "@subWithOverflow" {
730726
731test "@shlWithOverflow" {727test "@shlWithOverflow" {
732 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO728 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
733 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
734 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO729 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
735 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO730 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
736 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO731 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -752,7 +747,6 @@ test "@shlWithOverflow" {...@@ -752,7 +747,6 @@ test "@shlWithOverflow" {
752747
753test "overflow arithmetic with u0 values" {748test "overflow arithmetic with u0 values" {
754 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO749 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
755 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
756 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO750 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
757751
758 var result: u0 = undefined;752 var result: u0 = undefined;
...@@ -879,7 +873,6 @@ test "quad hex float literal parsing accurate" {...@@ -879,7 +873,6 @@ test "quad hex float literal parsing accurate" {
879}873}
880874
881test "truncating shift left" {875test "truncating shift left" {
882 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
883 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO876 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
884877
885 try testShlTrunc(maxInt(u16));878 try testShlTrunc(maxInt(u16));