| ... | @@ -6975,6 +6975,7 @@ fn intCast( | ... | @@ -6975,6 +6975,7 @@ fn intCast( |
| 6975 | operand_src: LazySrcLoc, | 6975 | operand_src: LazySrcLoc, |
| 6976 | runtime_safety: bool, | 6976 | runtime_safety: bool, |
| 6977 | ) CompileError!Air.Inst.Ref { | 6977 | ) CompileError!Air.Inst.Ref { |
| | 6978 | // TODO: Add support for vectors |
| 6978 | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty); | 6979 | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty); |
| 6979 | _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); | 6980 | _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); |
| 6980 | | 6981 | |
| ... | @@ -7010,27 +7011,44 @@ fn intCast( | ... | @@ -7010,27 +7011,44 @@ fn intCast( |
| 7010 | const wanted_info = dest_ty.intInfo(target); | 7011 | const wanted_info = dest_ty.intInfo(target); |
| 7011 | const actual_bits = actual_info.bits; | 7012 | const actual_bits = actual_info.bits; |
| 7012 | const wanted_bits = wanted_info.bits; | 7013 | const wanted_bits = wanted_info.bits; |
| 7013 | | 7014 | const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); |
| | 7015 | const wanted_value_bits = wanted_bits - @boolToInt(wanted_info.signedness == .signed); |
| | 7016 | |
| | 7017 | // range shrinkage |
| | 7018 | // requirement: int value fits into target type |
| | 7019 | if (wanted_value_bits < actual_value_bits) { |
| | 7020 | const dest_max_val = try dest_ty.maxInt(sema.arena, target); |
| | 7021 | const dest_max = try sema.addConstant(operand_ty, dest_max_val); |
| | 7022 | const diff = try block.addBinOp(.subwrap, dest_max, operand); |
| | 7023 | |
| | 7024 | if (actual_info.signedness == .signed) { |
| | 7025 | // Reinterpret the sign-bit as part of the value. This will make |
| | 7026 | // negative differences (`operand` > `dest_max`) appear too big. |
| | 7027 | const unsigned_operand_ty = try Type.Tag.int_unsigned.create(sema.arena, actual_bits); |
| | 7028 | const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff); |
| | 7029 | |
| | 7030 | // If the destination type is signed, then we need to double its |
| | 7031 | // range to account for negative values. |
| | 7032 | const dest_range_val = if (wanted_info.signedness == .signed) range_val: { |
| | 7033 | const range_minus_one = try dest_max_val.shl(Value.one, unsigned_operand_ty, sema.arena, target); |
| | 7034 | break :range_val try range_minus_one.intAdd(Value.one, unsigned_operand_ty, sema.arena, target); |
| | 7035 | } else dest_max_val; |
| | 7036 | const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val); |
| | 7037 | |
| | 7038 | const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range); |
| | 7039 | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); |
| | 7040 | } else { |
| | 7041 | const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max); |
| | 7042 | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); |
| | 7043 | } |
| | 7044 | } |
| | 7045 | // no shrinkage, yes sign loss |
| 7014 | // requirement: signed to unsigned >= 0 | 7046 | // requirement: signed to unsigned >= 0 |
| 7015 | if (actual_info.signedness == .signed and | 7047 | else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) { |
| 7016 | wanted_info.signedness == .unsigned) | 7048 | const zero_inst = try sema.addConstant(operand_ty, Value.zero); |
| 7017 | { | | |
| 7018 | const zero_inst = try sema.addConstant(sema.typeOf(operand), Value.zero); | | |
| 7019 | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); | 7049 | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); |
| 7020 | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); | 7050 | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); |
| 7021 | } | 7051 | } |
| 7022 | | | |
| 7023 | // requirement: unsigned int value fits into target type | | |
| 7024 | if (actual_bits > wanted_bits or | | |
| 7025 | (actual_bits == wanted_bits and | | |
| 7026 | actual_info.signedness == .unsigned and | | |
| 7027 | wanted_info.signedness == .signed)) | | |
| 7028 | { | | |
| 7029 | const max_int = try dest_ty.maxInt(sema.arena, target); | | |
| 7030 | const max_int_inst = try sema.addConstant(operand_ty, max_int); | | |
| 7031 | const is_in_range = try block.addBinOp(.cmp_lte, operand, max_int_inst); | | |
| 7032 | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); | | |
| 7033 | } | | |
| 7034 | } | 7052 | } |
| 7035 | return block.addTyOp(.intcast, dest_ty, operand); | 7053 | return block.addTyOp(.intcast, dest_ty, operand); |
| 7036 | } | 7054 | } |