| ... | @@ -10227,34 +10227,57 @@ fn zirShl( | ... | @@ -10227,34 +10227,57 @@ fn zirShl( |
| 10227 | } else rhs; | 10227 | } else rhs; |
| 10228 | | 10228 | |
| 10229 | try sema.requireRuntimeBlock(block, src, runtime_src); | 10229 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 10230 | if (block.wantSafety() and air_tag == .shl_exact) { | 10230 | if (block.wantSafety()) { |
| 10231 | const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty); | 10231 | const bit_count = scalar_ty.intInfo(target).bits; |
| 10232 | const op_ov = try block.addInst(.{ | 10232 | if (!std.math.isPowerOfTwo(bit_count)) { |
| 10233 | .tag = .shl_with_overflow, | 10233 | const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); |
| 10234 | .data = .{ .ty_pl = .{ | 10234 | |
| 10235 | .ty = try sema.addType(op_ov_tuple_ty), | 10235 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { |
| 10236 | .payload = try sema.addExtra(Air.Bin{ | 10236 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); |
| 10237 | .lhs = lhs, | 10237 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty)); |
| 10238 | .rhs = rhs, | 10238 | break :ok try block.addInst(.{ |
| 10239 | }), | 10239 | .tag = .reduce, |
| 10240 | } }, | 10240 | .data = .{ .reduce = .{ |
| 10241 | }); | 10241 | .operand = lt, |
| 10242 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); | 10242 | .operation = .And, |
| 10243 | const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) | 10243 | } }, |
| 10244 | try block.addInst(.{ | 10244 | }); |
| 10245 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | 10245 | } else ok: { |
| 10246 | .data = .{ .reduce = .{ | 10246 | const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val); |
| 10247 | .operand = ov_bit, | 10247 | break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst); |
| 10248 | .operation = .Or, | 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 | }) | 10263 | }); |
| 10251 | else | 10264 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); |
| 10252 | ov_bit; | 10265 | const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) |
| 10253 | const zero_ov = try sema.addConstant(Type.@"u1", Value.zero); | 10266 | try block.addInst(.{ |
| 10254 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); | 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); | 10278 | try sema.addSafetyCheck(block, no_ov, .shl_overflow); |
| 10257 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); | 10279 | return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty); |
| | 10280 | } |
| 10258 | } | 10281 | } |
| 10259 | return block.addBinOp(air_tag, lhs, new_rhs); | 10282 | return block.addBinOp(air_tag, lhs, new_rhs); |
| 10260 | } | 10283 | } |
| ... | @@ -10333,20 +10356,43 @@ fn zirShr( | ... | @@ -10333,20 +10356,43 @@ fn zirShr( |
| 10333 | | 10356 | |
| 10334 | try sema.requireRuntimeBlock(block, src, runtime_src); | 10357 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 10335 | const result = try block.addBinOp(air_tag, lhs, rhs); | 10358 | const result = try block.addBinOp(air_tag, lhs, rhs); |
| 10336 | if (block.wantSafety() and air_tag == .shr_exact) { | 10359 | if (block.wantSafety()) { |
| 10337 | const back = try block.addBinOp(.shl, result, rhs); | 10360 | const bit_count = scalar_ty.intInfo(target).bits; |
| 10338 | | 10361 | if (!std.math.isPowerOfTwo(bit_count)) { |
| 10339 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { | 10362 | const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); |
| 10340 | const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty)); | 10363 | |
| 10341 | break :ok try block.addInst(.{ | 10364 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { |
| 10342 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | 10365 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); |
| 10343 | .data = .{ .reduce = .{ | 10366 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty)); |
| 10344 | .operand = eql, | 10367 | break :ok try block.addInst(.{ |
| 10345 | .operation = .And, | 10368 | .tag = .reduce, |
| 10346 | } }, | 10369 | .data = .{ .reduce = .{ |
| 10347 | }); | 10370 | .operand = lt, |
| 10348 | } else try block.addBinOp(.cmp_eq, lhs, back); | 10371 | .operation = .And, |
| 10349 | try sema.addSafetyCheck(block, ok, .shr_overflow); | 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 | return result; | 10397 | return result; |
| 10352 | } | 10398 | } |
| ... | @@ -19972,6 +20018,7 @@ pub const PanicId = enum { | ... | @@ -19972,6 +20018,7 @@ pub const PanicId = enum { |
| 19972 | inactive_union_field, | 20018 | inactive_union_field, |
| 19973 | integer_part_out_of_bounds, | 20019 | integer_part_out_of_bounds, |
| 19974 | corrupt_switch, | 20020 | corrupt_switch, |
| | 20021 | shift_rhs_too_big, |
| 19975 | }; | 20022 | }; |
| 19976 | | 20023 | |
| 19977 | fn addSafetyCheck( | 20024 | fn addSafetyCheck( |
| ... | @@ -20268,6 +20315,7 @@ fn safetyPanic( | ... | @@ -20268,6 +20315,7 @@ fn safetyPanic( |
| 20268 | .inactive_union_field => "access of inactive union field", | 20315 | .inactive_union_field => "access of inactive union field", |
| 20269 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", | 20316 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", |
| 20270 | .corrupt_switch => "switch on corrupt value", | 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 | const msg_inst = msg_inst: { | 20321 | const msg_inst = msg_inst: { |