| author | |
| committer | |
| log | 55fe34100f8b516480cf530eb58d00ea8b665765 |
| tree | a687757a7988bd2998304aa0c51fa7243af1f789 |
| parent | 76d099950aa2e5fee4897c8bc401946f39ed87a4 |
4 files changed, 56 insertions(+), 8 deletions(-)
src/Sema.zig+43| ... | @@ -11917,6 +11917,47 @@ fn analyzeArithmetic( | ... | @@ -11917,6 +11917,47 @@ fn analyzeArithmetic( |
| 11917 | }, | 11917 | }, |
| 11918 | else => {}, | 11918 | else => {}, |
| 11919 | } | 11919 | } |
| 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 | } | ||
| 11920 | } | 11961 | } |
| 11921 | return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); | 11962 | return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs); |
| 11922 | } | 11963 | } |
| ... | @@ -18856,6 +18897,7 @@ pub const PanicId = enum { | ... | @@ -18856,6 +18897,7 @@ pub const PanicId = enum { |
| 18856 | shr_overflow, | 18897 | shr_overflow, |
| 18857 | divide_by_zero, | 18898 | divide_by_zero, |
| 18858 | remainder_division_zero_negative, | 18899 | remainder_division_zero_negative, |
| 18900 | exact_division_remainder, | ||
| 18859 | }; | 18901 | }; |
| 18860 | 18902 | ||
| 18861 | fn addSafetyCheck( | 18903 | fn addSafetyCheck( |
| ... | @@ -19077,6 +19119,7 @@ fn safetyPanic( | ... | @@ -19077,6 +19119,7 @@ fn safetyPanic( |
| 19077 | .shr_overflow => "right shift overflowed bits", | 19119 | .shr_overflow => "right shift overflowed bits", |
| 19078 | .divide_by_zero => "division by zero", | 19120 | .divide_by_zero => "division by zero", |
| 19079 | .remainder_division_zero_negative => "remainder division by zero or negative value", | 19121 | .remainder_division_zero_negative => "remainder division by zero or negative value", |
| 19122 | .exact_division_remainder => "exact division produced remainder", | ||
| 19080 | }; | 19123 | }; |
| 19081 | 19124 | ||
| 19082 | const msg_inst = msg_inst: { | 19125 | const msg_inst = msg_inst: { |
test/behavior/math.zig+1| ... | @@ -377,6 +377,7 @@ fn testBinaryNot(x: u16) !void { | ... | @@ -377,6 +377,7 @@ fn testBinaryNot(x: u16) !void { |
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | test "division" { | 379 | test "division" { |
| 380 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 380 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 381 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 381 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 382 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 382 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 383 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
test/cases/safety/exact division failure - vectors.zig	+6-4| ... | @@ -1,9 +1,11 @@ | ... | @@ -1,9 +1,11 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | ||
| 5 | _ = stack_trace; | 4 | _ = 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); | ||
| 7 | } | 9 | } |
| 8 | 10 | ||
| 9 | pub fn main() !void { | 11 | pub fn main() !void { |
| ... | @@ -17,5 +19,5 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { | ... | @@ -17,5 +19,5 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { |
| 17 | return @divExact(a, b); | 19 | return @divExact(a, b); |
| 18 | } | 20 | } |
| 19 | // run | 21 | // 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 @@ | ... | @@ -1,9 +1,11 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | ||
| 5 | _ = stack_trace; | 4 | _ = 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); | ||
| 7 | } | 9 | } |
| 8 | 10 | ||
| 9 | pub fn main() !void { | 11 | pub fn main() !void { |
| ... | @@ -15,5 +17,5 @@ fn divExact(a: i32, b: i32) i32 { | ... | @@ -15,5 +17,5 @@ fn divExact(a: i32, b: i32) i32 { |
| 15 | return @divExact(a, b); | 17 | return @divExact(a, b); |
| 16 | } | 18 | } |
| 17 | // run | 19 | // run |
| 18 | // backend=stage1 | ||
| 19 | // target=native | ||
| \ No newline at end of file | |||
| 20 | // backend=llvm | ||
| 21 | // target=native | ||