authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-16 16:10:11+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-23 15:40:11+03:00
log55fe34100f8b516480cf530eb58d00ea8b665765
treea687757a7988bd2998304aa0c51fa7243af1f789
parent76d099950aa2e5fee4897c8bc401946f39ed87a4

Sema: exact division safety


4 files changed, 56 insertions(+), 8 deletions(-)

src/Sema.zig+43
......@@ -11917,6 +11917,47 @@ fn analyzeArithmetic(
1191711917 },
1191811918 else => {},
1191911919 }
11920 if (rs.air_tag == .div_exact) {
11921 const result = try block.addBinOp(.div_exact, casted_lhs, casted_rhs);
11922 const ok = if (scalar_tag == .Float) ok: {
11923 const floored = try block.addUnOp(.floor, result);
11924
11925 if (resolved_type.zigTypeTag() == .Vector) {
11926 const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type));
11927 break :ok try block.addInst(.{
11928 .tag = .reduce,
11929 .data = .{ .reduce = .{
11930 .operand = eql,
11931 .operation = .And,
11932 } },
11933 });
11934 } else {
11935 const is_in_range = try block.addBinOp(.cmp_eq, result, floored);
11936 break :ok is_in_range;
11937 }
11938 } else ok: {
11939 const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs);
11940
11941 if (resolved_type.zigTypeTag() == .Vector) {
11942 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
11943 const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
11944 const eql = try block.addCmpVector(remainder, zero, .eq, try sema.addType(resolved_type));
11945 break :ok try block.addInst(.{
11946 .tag = .reduce,
11947 .data = .{ .reduce = .{
11948 .operand = eql,
11949 .operation = .And,
11950 } },
11951 });
11952 } else {
11953 const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
11954 const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero);
11955 break :ok is_in_range;
11956 }
11957 };
11958 try sema.addSafetyCheck(block, ok, .exact_division_remainder);
11959 return result;
11960 }
1192011961 }
1192111962 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
1192211963}
......@@ -18856,6 +18897,7 @@ pub const PanicId = enum {
1885618897 shr_overflow,
1885718898 divide_by_zero,
1885818899 remainder_division_zero_negative,
18900 exact_division_remainder,
1885918901};
1886018902
1886118903fn addSafetyCheck(
......@@ -19077,6 +19119,7 @@ fn safetyPanic(
1907719119 .shr_overflow => "right shift overflowed bits",
1907819120 .divide_by_zero => "division by zero",
1907919121 .remainder_division_zero_negative => "remainder division by zero or negative value",
19122 .exact_division_remainder => "exact division produced remainder",
1908019123 };
1908119124
1908219125 const msg_inst = msg_inst: {
test/behavior/math.zig+1
......@@ -377,6 +377,7 @@ fn testBinaryNot(x: u16) !void {
377377}
378378
379379test "division" {
380 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
380381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
381382 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
382383 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/cases/safety/exact division failure - vectors.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "exact division produced remainder")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -17,5 +19,5 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
1719 return @divExact(a, b);
1820}
1921// run
20// backend=stage1
21// target=native
\ No newline at end of file
22// backend=llvm
23// target=native
test/cases/safety/exact division failure.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = stack_trace;
6 std.process.exit(0);
5 if (std.mem.eql(u8, message, "exact division produced remainder")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn divExact(a: i32, b: i32) i32 {
1517 return @divExact(a, b);
1618}
1719// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native