authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-16 02:15:24+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-23 15:40:11+03:00
log9f10dfcb546556b26b420633c7fa4d7de39f8fd7
treeedb35dc05ff550500b7b2fb8c08f09e984a1c065
parent4d20d6874c418f596c576cea48985de6ef3a3dd2

Sema: implement shr_exact runtime safety


3 files changed, 57 insertions(+), 41 deletions(-)

src/Sema.zig+45-33
...@@ -9996,40 +9996,34 @@ fn zirShl(...@@ -9996,40 +9996,34 @@ fn zirShl(
9996 } else rhs;9996 } else rhs;
99979997
9998 try sema.requireRuntimeBlock(block, src, runtime_src);9998 try sema.requireRuntimeBlock(block, src, runtime_src);
9999 if (block.wantSafety()) {9999 if (block.wantSafety() and air_tag == .shl_exact) {
10000 const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) {10000 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);
10001 .shl_exact => .shl_with_overflow,10001 const op_ov = try block.addInst(.{
10002 else => null,10002 .tag = .shl_with_overflow,
10003 };10003 .data = .{ .ty_pl = .{
10004 if (maybe_op_ov) |op_ov_tag| {10004 .ty = try sema.addType(op_ov_tuple_ty),
10005 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);10005 .payload = try sema.addExtra(Air.Bin{
10006 const op_ov = try block.addInst(.{10006 .lhs = lhs,
10007 .tag = op_ov_tag,10007 .rhs = rhs,
10008 .data = .{ .ty_pl = .{10008 }),
10009 .ty = try sema.addType(op_ov_tuple_ty),10009 } },
10010 .payload = try sema.addExtra(Air.Bin{10010 });
10011 .lhs = lhs,10011 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
10012 .rhs = rhs,10012 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
10013 }),10013 try block.addInst(.{
10014 .tag = .reduce,
10015 .data = .{ .reduce = .{
10016 .operand = ov_bit,
10017 .operation = .Or,
10014 } },10018 } },
10015 });10019 })
10016 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);10020 else
10017 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)10021 ov_bit;
10018 try block.addInst(.{10022 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
10019 .tag = .reduce,10023 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
10020 .data = .{ .reduce = .{
10021 .operand = ov_bit,
10022 .operation = .Or,
10023 } },
10024 })
10025 else
10026 ov_bit;
10027 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
10028 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
1002910024
10030 try sema.addSafetyCheck(block, no_ov, .shl_overflow);10025 try sema.addSafetyCheck(block, no_ov, .shl_overflow);
10031 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);10026 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
10032 }
10033 }10027 }
10034 return block.addBinOp(air_tag, lhs, new_rhs);10028 return block.addBinOp(air_tag, lhs, new_rhs);
10035}10029}
...@@ -10107,7 +10101,23 @@ fn zirShr(...@@ -10107,7 +10101,23 @@ fn zirShr(
10107 } else rhs_src;10101 } else rhs_src;
1010810102
10109 try sema.requireRuntimeBlock(block, src, runtime_src);10103 try sema.requireRuntimeBlock(block, src, runtime_src);
10110 return block.addBinOp(air_tag, lhs, rhs);10104 const result = try block.addBinOp(air_tag, lhs, rhs);
10105 if (block.wantSafety() and air_tag == .shr_exact) {
10106 const back = try block.addBinOp(.shl, result, rhs);
10107
10108 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
10109 const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty));
10110 break :ok try block.addInst(.{
10111 .tag = .reduce,
10112 .data = .{ .reduce = .{
10113 .operand = eql,
10114 .operation = .And,
10115 } },
10116 });
10117 } else try block.addBinOp(.cmp_eq, lhs, back);
10118 try sema.addSafetyCheck(block, ok, .shr_overflow);
10119 }
10120 return result;
10111}10121}
1011210122
10113fn zirBitwise(10123fn zirBitwise(
...@@ -18802,6 +18812,7 @@ pub const PanicId = enum {...@@ -18802,6 +18812,7 @@ pub const PanicId = enum {
18802 cast_truncated_data,18812 cast_truncated_data,
18803 integer_overflow,18813 integer_overflow,
18804 shl_overflow,18814 shl_overflow,
18815 shr_overflow,
18805};18816};
1880618817
18807fn addSafetyCheck(18818fn addSafetyCheck(
...@@ -19019,6 +19030,7 @@ fn safetyPanic(...@@ -19019,6 +19030,7 @@ fn safetyPanic(
19019 .cast_truncated_data => "integer cast truncated bits",19030 .cast_truncated_data => "integer cast truncated bits",
19020 .integer_overflow => "integer overflow",19031 .integer_overflow => "integer overflow",
19021 .shl_overflow => "left shift overflowed bits",19032 .shl_overflow => "left shift overflowed bits",
19033 .shr_overflow => "right shift overflowed bits",
19022 };19034 };
1902319035
19024 const msg_inst = msg_inst: {19036 const msg_inst = msg_inst: {
test/cases/safety/signed shift right overflow.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub 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, "right shift overflowed bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn shr(a: i16, b: u4) i16 {...@@ -15,5 +17,5 @@ fn shr(a: i16, b: u4) i16 {
15 return @shrExact(a, b);17 return @shrExact(a, b);
16}18}
17// run19// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/unsigned shift right overflow.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub 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, "right shift overflowed bits")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn shr(a: u16, b: u4) u16 {...@@ -15,5 +17,5 @@ fn shr(a: u16, b: u4) u16 {
15 return @shrExact(a, b);17 return @shrExact(a, b);
16}18}
17// run19// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native