| ... | ... | @@ -10227,34 +10227,57 @@ fn zirShl( |
| 10227 | 10227 | } else rhs; |
| 10228 | 10228 | |
| 10229 | 10229 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 10230 | | if (block.wantSafety() and air_tag == .shl_exact) { |
| 10231 | | const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty); |
| 10232 | | const op_ov = try block.addInst(.{ |
| 10233 | | .tag = .shl_with_overflow, |
| 10234 | | .data = .{ .ty_pl = .{ |
| 10235 | | .ty = try sema.addType(op_ov_tuple_ty), |
| 10236 | | .payload = try sema.addExtra(Air.Bin{ |
| 10237 | | .lhs = lhs, |
| 10238 | | .rhs = rhs, |
| 10239 | | }), |
| 10240 | | } }, |
| 10241 | | }); |
| 10242 | | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); |
| 10243 | | const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) |
| 10244 | | try block.addInst(.{ |
| 10245 | | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| 10246 | | .data = .{ .reduce = .{ |
| 10247 | | .operand = ov_bit, |
| 10248 | | .operation = .Or, |
| 10230 | if (block.wantSafety()) { |
| 10231 | const bit_count = scalar_ty.intInfo(target).bits; |
| 10232 | if (!std.math.isPowerOfTwo(bit_count)) { |
| 10233 | const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); |
| 10234 | |
| 10235 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { |
| 10236 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); |
| 10237 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty)); |
| 10238 | break :ok try block.addInst(.{ |
| 10239 | .tag = .reduce, |
| 10240 | .data = .{ .reduce = .{ |
| 10241 | .operand = lt, |
| 10242 | .operation = .And, |
| 10243 | } }, |
| 10244 | }); |
| 10245 | } else ok: { |
| 10246 | const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val); |
| 10247 | break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst); |
| 10248 | }; |
| 10249 | try sema.addSafetyCheck(block, ok, .shift_rhs_too_big); |
| 10250 | } |
| 10251 | |
| 10252 | if (air_tag == .shl_exact) { |
| 10253 | const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty); |
| 10254 | const op_ov = try block.addInst(.{ |
| 10255 | .tag = .shl_with_overflow, |
| 10256 | .data = .{ .ty_pl = .{ |
| 10257 | .ty = try sema.addType(op_ov_tuple_ty), |
| 10258 | .payload = try sema.addExtra(Air.Bin{ |
| 10259 | .lhs = lhs, |
| 10260 | .rhs = rhs, |
| 10261 | }), |
| 10249 | 10262 | } }, |
| 10250 | | }) |
| 10251 | | else |
| 10252 | | ov_bit; |
| 10253 | | const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); |
| 10254 | | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); |
| 10263 | }); |
| 10264 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); |
| 10265 | const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) |
| 10266 | try block.addInst(.{ |
| 10267 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| 10268 | .data = .{ .reduce = .{ |
| 10269 | .operand = ov_bit, |
| 10270 | .operation = .Or, |
| 10271 | } }, |
| 10272 | }) |
| 10273 | else |
| 10274 | ov_bit; |
| 10275 | const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); |
| 10276 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); |
| 10255 | 10277 | |
| 10256 | | try sema.addSafetyCheck(block, no_ov, .shl_overflow); |
| 10257 | | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); |
| 10278 | try sema.addSafetyCheck(block, no_ov, .shl_overflow); |
| 10279 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); |
| 10280 | } |
| 10258 | 10281 | } |
| 10259 | 10282 | return block.addBinOp(air_tag, lhs, new_rhs); |
| 10260 | 10283 | } |
| ... | ... | @@ -10333,20 +10356,43 @@ fn zirShr( |
| 10333 | 10356 | |
| 10334 | 10357 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 10335 | 10358 | const result = try block.addBinOp(air_tag, lhs, rhs); |
| 10336 | | if (block.wantSafety() and air_tag == .shr_exact) { |
| 10337 | | const back = try block.addBinOp(.shl, result, rhs); |
| 10338 | | |
| 10339 | | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { |
| 10340 | | const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty)); |
| 10341 | | break :ok try block.addInst(.{ |
| 10342 | | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| 10343 | | .data = .{ .reduce = .{ |
| 10344 | | .operand = eql, |
| 10345 | | .operation = .And, |
| 10346 | | } }, |
| 10347 | | }); |
| 10348 | | } else try block.addBinOp(.cmp_eq, lhs, back); |
| 10349 | | try sema.addSafetyCheck(block, ok, .shr_overflow); |
| 10359 | if (block.wantSafety()) { |
| 10360 | const bit_count = scalar_ty.intInfo(target).bits; |
| 10361 | if (!std.math.isPowerOfTwo(bit_count)) { |
| 10362 | const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); |
| 10363 | |
| 10364 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { |
| 10365 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); |
| 10366 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty)); |
| 10367 | break :ok try block.addInst(.{ |
| 10368 | .tag = .reduce, |
| 10369 | .data = .{ .reduce = .{ |
| 10370 | .operand = lt, |
| 10371 | .operation = .And, |
| 10372 | } }, |
| 10373 | }); |
| 10374 | } else ok: { |
| 10375 | const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val); |
| 10376 | break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst); |
| 10377 | }; |
| 10378 | try sema.addSafetyCheck(block, ok, .shift_rhs_too_big); |
| 10379 | } |
| 10380 | |
| 10381 | if (air_tag == .shr_exact) { |
| 10382 | const back = try block.addBinOp(.shl, result, rhs); |
| 10383 | |
| 10384 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { |
| 10385 | const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty)); |
| 10386 | break :ok try block.addInst(.{ |
| 10387 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| 10388 | .data = .{ .reduce = .{ |
| 10389 | .operand = eql, |
| 10390 | .operation = .And, |
| 10391 | } }, |
| 10392 | }); |
| 10393 | } else try block.addBinOp(.cmp_eq, lhs, back); |
| 10394 | try sema.addSafetyCheck(block, ok, .shr_overflow); |
| 10395 | } |
| 10350 | 10396 | } |
| 10351 | 10397 | return result; |
| 10352 | 10398 | } |
| ... | ... | @@ -19972,6 +20018,7 @@ pub const PanicId = enum { |
| 19972 | 20018 | inactive_union_field, |
| 19973 | 20019 | integer_part_out_of_bounds, |
| 19974 | 20020 | corrupt_switch, |
| 20021 | shift_rhs_too_big, |
| 19975 | 20022 | }; |
| 19976 | 20023 | |
| 19977 | 20024 | fn addSafetyCheck( |
| ... | ... | @@ -20268,6 +20315,7 @@ fn safetyPanic( |
| 20268 | 20315 | .inactive_union_field => "access of inactive union field", |
| 20269 | 20316 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", |
| 20270 | 20317 | .corrupt_switch => "switch on corrupt value", |
| 20318 | .shift_rhs_too_big => "shift amount is greater than the type size", |
| 20271 | 20319 | }; |
| 20272 | 20320 | |
| 20273 | 20321 | const msg_inst = msg_inst: { |