@@ -8912,21 +8912,10 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8912
8912
8913
8913
try sema.requireRuntimeBlock(block, src, operand_src);
8914
8914
if (block.wantSafety()) {
8915
- if (zcu.backendSupportsFeature(.safety_checked_instructions )) {
8915
+ if (zcu.backendSupportsFeature(.panic_fn )) {
8916
8916
_ = try sema.preparePanicId(src, .invalid_enum_value);
8917
- return block.addTyOp(.intcast_safe, dest_ty, operand);
8918
- } else {
8919
- // Slightly silly fallback case...
8920
- const int_tag_ty = dest_ty.intTagType(zcu);
8921
- // Use `intCast`, since it'll set up the Sema-emitted safety checks for us!
8922
- const int_val = try sema.intCast(block, src, int_tag_ty, src, operand, src, true, true);
8923
- const result = try block.addBitCast(dest_ty, int_val);
8924
- if (!dest_ty.isNonexhaustiveEnum(zcu) and zcu.backendSupportsFeature(.is_named_enum_value)) {
8925
- const ok = try block.addUnOp(.is_named_enum_value, result);
8926
- try sema.addSafetyCheck(block, src, ok, .invalid_enum_value);
8927
- }
8928
- return result;
8929
8917
}
8918
+ return block.addTyOp(.intcast_safe, dest_ty, operand);
8930
8919
}
8931
8920
return block.addTyOp(.intcast, dest_ty, operand);
8932
8921
}
@@ -10331,90 +10320,11 @@ fn intCast(
10331
10320
10332
10321
try sema.requireRuntimeBlock(block, src, operand_src);
10333
10322
if (runtime_safety and block.wantSafety()) {
10334
- if (zcu.backendSupportsFeature(.safety_checked_instructions )) {
10323
+ if (zcu.backendSupportsFeature(.panic_fn )) {
10335
10324
_ = try sema.preparePanicId(src, .negative_to_unsigned);
10336
10325
_ = try sema.preparePanicId(src, .cast_truncated_data);
10337
- return block.addTyOp(.intcast_safe, dest_ty, operand);
10338
- }
10339
- const actual_info = operand_scalar_ty.intInfo(zcu);
10340
- const wanted_info = dest_scalar_ty.intInfo(zcu);
10341
- const actual_bits = actual_info.bits;
10342
- const wanted_bits = wanted_info.bits;
10343
- const actual_value_bits = actual_bits - @intFromBool(actual_info.signedness == .signed);
10344
- const wanted_value_bits = wanted_bits - @intFromBool(wanted_info.signedness == .signed);
10345
-
10346
- // range shrinkage
10347
- // requirement: int value fits into target type
10348
- if (wanted_value_bits < actual_value_bits) {
10349
- const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(pt, operand_scalar_ty);
10350
- const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar);
10351
- const dest_max = Air.internedToRef(dest_max_val.toIntern());
10352
-
10353
- if (actual_info.signedness == .signed) {
10354
- const diff = try block.addBinOp(.sub_wrap, dest_max, operand);
10355
-
10356
- // Reinterpret the sign-bit as part of the value. This will make
10357
- // negative differences (`operand` > `dest_max`) appear too big.
10358
- const unsigned_scalar_operand_ty = try pt.intType(.unsigned, actual_bits);
10359
- const unsigned_operand_ty = if (is_vector) try pt.vectorType(.{
10360
- .len = dest_ty.vectorLen(zcu),
10361
- .child = unsigned_scalar_operand_ty.toIntern(),
10362
- }) else unsigned_scalar_operand_ty;
10363
- const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff);
10364
-
10365
- // If the destination type is signed, then we need to double its
10366
- // range to account for negative values.
10367
- const dest_range_val = if (wanted_info.signedness == .signed) range_val: {
10368
- const one_scalar = try pt.intValue(unsigned_scalar_operand_ty, 1);
10369
- const one = if (is_vector) Value.fromInterned(try pt.intern(.{ .aggregate = .{
10370
- .ty = unsigned_operand_ty.toIntern(),
10371
- .storage = .{ .repeated_elem = one_scalar.toIntern() },
10372
- } })) else one_scalar;
10373
- const range_minus_one = try dest_max_val.shl(one, unsigned_operand_ty, sema.arena, pt);
10374
- const result = try arith.addWithOverflow(sema, unsigned_operand_ty, range_minus_one, one);
10375
- assert(result.overflow_bit.compareAllWithZero(.eq, zcu));
10376
- break :range_val result.wrapped_result;
10377
- } else try pt.getCoerced(dest_max_val, unsigned_operand_ty);
10378
- const dest_range = Air.internedToRef(dest_range_val.toIntern());
10379
-
10380
- const ok = if (is_vector) ok: {
10381
- const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte);
10382
- const all_in_range = try block.addReduce(is_in_range, .And);
10383
- break :ok all_in_range;
10384
- } else ok: {
10385
- const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);
10386
- break :ok is_in_range;
10387
- };
10388
- // TODO negative_to_unsigned?
10389
- try sema.addSafetyCheck(block, src, ok, if (safety_panics_are_enum) .invalid_enum_value else .cast_truncated_data);
10390
- } else {
10391
- const ok = if (is_vector) ok: {
10392
- const is_in_range = try block.addCmpVector(operand, dest_max, .lte);
10393
- const all_in_range = try block.addReduce(is_in_range, .And);
10394
- break :ok all_in_range;
10395
- } else ok: {
10396
- const is_in_range = try block.addBinOp(.cmp_lte, operand, dest_max);
10397
- break :ok is_in_range;
10398
- };
10399
- try sema.addSafetyCheck(block, src, ok, if (safety_panics_are_enum) .invalid_enum_value else .cast_truncated_data);
10400
- }
10401
- } else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) {
10402
- // no shrinkage, yes sign loss
10403
- // requirement: signed to unsigned >= 0
10404
- const ok = if (is_vector) ok: {
10405
- const scalar_zero = try pt.intValue(operand_scalar_ty, 0);
10406
- const zero_val = try sema.splat(operand_ty, scalar_zero);
10407
- const zero_inst = Air.internedToRef(zero_val.toIntern());
10408
- const is_in_range = try block.addCmpVector(operand, zero_inst, .gte);
10409
- const all_in_range = try block.addReduce(is_in_range, .And);
10410
- break :ok all_in_range;
10411
- } else ok: {
10412
- const zero_inst = Air.internedToRef((try pt.intValue(operand_ty, 0)).toIntern());
10413
- const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
10414
- break :ok is_in_range;
10415
- };
10416
- try sema.addSafetyCheck(block, src, ok, if (safety_panics_are_enum) .invalid_enum_value else .negative_to_unsigned);
10417
10326
}
10327
+ return block.addTyOp(.intcast_safe, dest_ty, operand);
10418
10328
}
10419
10329
return block.addTyOp(.intcast, dest_ty, operand);
10420
10330
}
@@ -14316,7 +14226,7 @@ fn zirShl(
14316
14226
}
14317
14227
14318
14228
if (air_tag == .shl_exact) {
14319
- const op_ov_tuple_ty = try sema .overflowArithmeticTupleType(lhs_ty);
14229
+ const op_ov_tuple_ty = try pt .overflowArithmeticTupleType(lhs_ty);
14320
14230
const op_ov = try block.addInst(.{
14321
14231
.tag = .shl_with_overflow,
14322
14232
.data = .{ .ty_pl = .{
@@ -16111,7 +16021,7 @@ fn zirOverflowArithmetic(
16111
16021
const maybe_lhs_val = try sema.resolveValue(lhs);
16112
16022
const maybe_rhs_val = try sema.resolveValue(rhs);
16113
16023
16114
- const tuple_ty = try sema .overflowArithmeticTupleType(dest_ty);
16024
+ const tuple_ty = try pt .overflowArithmeticTupleType(dest_ty);
16115
16025
const overflow_ty: Type = .fromInterned(ip.indexToKey(tuple_ty.toIntern()).tuple_type.types.get(ip)[1]);
16116
16026
16117
16027
var result: struct {
@@ -16284,24 +16194,6 @@ fn splat(sema: *Sema, ty: Type, val: Value) !Value {
16284
16194
return Value.fromInterned(repeated);
16285
16195
}
16286
16196
16287
- fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type {
16288
- const pt = sema.pt;
16289
- const zcu = pt.zcu;
16290
- const ip = &zcu.intern_pool;
16291
- const ov_ty: Type = if (ty.zigTypeTag(zcu) == .vector) try pt.vectorType(.{
16292
- .len = ty.vectorLen(zcu),
16293
- .child = .u1_type,
16294
- }) else .u1;
16295
-
16296
- const types = [2]InternPool.Index{ ty.toIntern(), ov_ty.toIntern() };
16297
- const values = [2]InternPool.Index{ .none, .none };
16298
- const tuple_ty = try ip.getTupleType(zcu.gpa, pt.tid, .{
16299
- .types = &types,
16300
- .values = &values,
16301
- });
16302
- return .fromInterned(tuple_ty);
16303
- }
16304
-
16305
16197
fn analyzeArithmetic(
16306
16198
sema: *Sema,
16307
16199
block: *Block,
@@ -16477,41 +16369,10 @@ fn analyzeArithmetic(
16477
16369
}
16478
16370
16479
16371
if (block.wantSafety() and want_safety and scalar_tag == .int) {
16480
- if (zcu.backendSupportsFeature(.safety_checked_instructions)) {
16481
- if (air_tag != air_tag_safe) {
16482
- _ = try sema.preparePanicId(src, .integer_overflow);
16483
- }
16484
- return block.addBinOp(air_tag_safe, casted_lhs, casted_rhs);
16485
- } else {
16486
- const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) {
16487
- .add => .add_with_overflow,
16488
- .sub => .sub_with_overflow,
16489
- .mul => .mul_with_overflow,
16490
- else => null,
16491
- };
16492
- if (maybe_op_ov) |op_ov_tag| {
16493
- const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(resolved_type);
16494
- const op_ov = try block.addInst(.{
16495
- .tag = op_ov_tag,
16496
- .data = .{ .ty_pl = .{
16497
- .ty = Air.internedToRef(op_ov_tuple_ty.toIntern()),
16498
- .payload = try sema.addExtra(Air.Bin{
16499
- .lhs = casted_lhs,
16500
- .rhs = casted_rhs,
16501
- }),
16502
- } },
16503
- });
16504
- const ov_bit = try sema.tupleFieldValByIndex(block, op_ov, 1, op_ov_tuple_ty);
16505
- const any_ov_bit = if (resolved_type.zigTypeTag(zcu) == .vector)
16506
- try block.addReduce(ov_bit, .Or)
16507
- else
16508
- ov_bit;
16509
- const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, .zero_u1);
16510
-
16511
- try sema.addSafetyCheck(block, src, no_ov, .integer_overflow);
16512
- return sema.tupleFieldValByIndex(block, op_ov, 0, op_ov_tuple_ty);
16513
- }
16372
+ if (air_tag != air_tag_safe and zcu.backendSupportsFeature(.panic_fn)) {
16373
+ _ = try sema.preparePanicId(src, .integer_overflow);
16514
16374
}
16375
+ return block.addBinOp(air_tag_safe, casted_lhs, casted_rhs);
16515
16376
}
16516
16377
return block.addBinOp(air_tag, casted_lhs, casted_rhs);
16517
16378
}
0 commit comments