| ... | ... | @@ -7020,22 +7020,25 @@ fn intCast( |
| 7020 | 7020 | operand_src: LazySrcLoc, |
| 7021 | 7021 | runtime_safety: bool, |
| 7022 | 7022 | ) CompileError!Air.Inst.Ref { |
| 7023 | | // TODO: Add support for vectors |
| 7024 | | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty); |
| 7025 | | _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); |
| 7023 | const operand_ty = sema.typeOf(operand); |
| 7024 | const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src); |
| 7025 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 7026 | 7026 | |
| 7027 | 7027 | if (try sema.isComptimeKnown(block, operand_src, operand)) { |
| 7028 | 7028 | return sema.coerce(block, dest_ty, operand, operand_src); |
| 7029 | | } else if (dest_is_comptime_int) { |
| 7029 | } else if (dest_scalar_ty.zigTypeTag() == .ComptimeInt) { |
| 7030 | 7030 | return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{}); |
| 7031 | 7031 | } |
| 7032 | 7032 | |
| 7033 | try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src); |
| 7034 | const is_vector = dest_ty.zigTypeTag() == .Vector; |
| 7035 | |
| 7033 | 7036 | if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| { |
| 7034 | 7037 | // requirement: intCast(u0, input) iff input == 0 |
| 7035 | 7038 | if (runtime_safety and block.wantSafety()) { |
| 7036 | 7039 | try sema.requireRuntimeBlock(block, operand_src); |
| 7037 | 7040 | const target = sema.mod.getTarget(); |
| 7038 | | const wanted_info = dest_ty.intInfo(target); |
| 7041 | const wanted_info = dest_scalar_ty.intInfo(target); |
| 7039 | 7042 | const wanted_bits = wanted_info.bits; |
| 7040 | 7043 | |
| 7041 | 7044 | if (wanted_bits == 0) { |
| ... | ... | @@ -7051,9 +7054,8 @@ fn intCast( |
| 7051 | 7054 | try sema.requireRuntimeBlock(block, operand_src); |
| 7052 | 7055 | if (runtime_safety and block.wantSafety()) { |
| 7053 | 7056 | const target = sema.mod.getTarget(); |
| 7054 | | const operand_ty = sema.typeOf(operand); |
| 7055 | | const actual_info = operand_ty.intInfo(target); |
| 7056 | | const wanted_info = dest_ty.intInfo(target); |
| 7057 | const actual_info = operand_scalar_ty.intInfo(target); |
| 7058 | const wanted_info = dest_scalar_ty.intInfo(target); |
| 7057 | 7059 | const actual_bits = actual_info.bits; |
| 7058 | 7060 | const wanted_bits = wanted_info.bits; |
| 7059 | 7061 | const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); |
| ... | ... | @@ -7062,7 +7064,11 @@ fn intCast( |
| 7062 | 7064 | // range shrinkage |
| 7063 | 7065 | // requirement: int value fits into target type |
| 7064 | 7066 | if (wanted_value_bits < actual_value_bits) { |
| 7065 | | const dest_max_val = try dest_ty.maxInt(sema.arena, target); |
| 7067 | const dest_max_val_scalar = try dest_scalar_ty.maxInt(sema.arena, target); |
| 7068 | const dest_max_val = if (is_vector) |
| 7069 | try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar) |
| 7070 | else |
| 7071 | dest_max_val_scalar; |
| 7066 | 7072 | const dest_max = try sema.addConstant(operand_ty, dest_max_val); |
| 7067 | 7073 | const diff = try block.addBinOp(.subwrap, dest_max, operand); |
| 7068 | 7074 | |
| ... | ... | @@ -7080,19 +7086,59 @@ fn intCast( |
| 7080 | 7086 | } else dest_max_val; |
| 7081 | 7087 | const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val); |
| 7082 | 7088 | |
| 7083 | | const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range); |
| 7084 | | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); |
| 7089 | const ok = if (is_vector) ok: { |
| 7090 | const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty)); |
| 7091 | const all_in_range = try block.addInst(.{ |
| 7092 | .tag = .reduce, |
| 7093 | .data = .{ .reduce = .{ |
| 7094 | .operand = is_in_range, |
| 7095 | .operation = .And, |
| 7096 | } }, |
| 7097 | }); |
| 7098 | break :ok all_in_range; |
| 7099 | } else ok: { |
| 7100 | const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range); |
| 7101 | break :ok is_in_range; |
| 7102 | }; |
| 7103 | try sema.addSafetyCheck(block, ok, .cast_truncated_data); |
| 7085 | 7104 | } else { |
| 7086 | | const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max); |
| 7087 | | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); |
| 7105 | const ok = if (is_vector) ok: { |
| 7106 | const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty)); |
| 7107 | const all_in_range = try block.addInst(.{ |
| 7108 | .tag = .reduce, |
| 7109 | .data = .{ .reduce = .{ |
| 7110 | .operand = is_in_range, |
| 7111 | .operation = .And, |
| 7112 | } }, |
| 7113 | }); |
| 7114 | break :ok all_in_range; |
| 7115 | } else ok: { |
| 7116 | const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max); |
| 7117 | break :ok is_in_range; |
| 7118 | }; |
| 7119 | try sema.addSafetyCheck(block, ok, .cast_truncated_data); |
| 7088 | 7120 | } |
| 7089 | | } |
| 7090 | | // no shrinkage, yes sign loss |
| 7091 | | // requirement: signed to unsigned >= 0 |
| 7092 | | else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) { |
| 7093 | | const zero_inst = try sema.addConstant(operand_ty, Value.zero); |
| 7094 | | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); |
| 7095 | | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); |
| 7121 | } else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) { |
| 7122 | // no shrinkage, yes sign loss |
| 7123 | // requirement: signed to unsigned >= 0 |
| 7124 | const ok = if (is_vector) ok: { |
| 7125 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); |
| 7126 | const zero_inst = try sema.addConstant(operand_ty, zero_val); |
| 7127 | const is_in_range = try block.addCmpVector(operand, zero_inst, .lte, try sema.addType(operand_ty)); |
| 7128 | const all_in_range = try block.addInst(.{ |
| 7129 | .tag = .reduce, |
| 7130 | .data = .{ .reduce = .{ |
| 7131 | .operand = is_in_range, |
| 7132 | .operation = .And, |
| 7133 | } }, |
| 7134 | }); |
| 7135 | break :ok all_in_range; |
| 7136 | } else ok: { |
| 7137 | const zero_inst = try sema.addConstant(operand_ty, Value.zero); |
| 7138 | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); |
| 7139 | break :ok is_in_range; |
| 7140 | }; |
| 7141 | try sema.addSafetyCheck(block, ok, .cast_truncated_data); |
| 7096 | 7142 | } |
| 7097 | 7143 | } |
| 7098 | 7144 | return block.addTyOp(.intcast, dest_ty, operand); |
| ... | ... | @@ -14517,8 +14563,8 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14517 | 14563 | const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 14518 | 14564 | const operand = sema.resolveInst(extra.rhs); |
| 14519 | 14565 | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty); |
| 14520 | | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand, operand_src); |
| 14521 | 14566 | const operand_ty = sema.typeOf(operand); |
| 14567 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 14522 | 14568 | const is_vector = operand_ty.zigTypeTag() == .Vector; |
| 14523 | 14569 | const dest_ty = if (is_vector) |
| 14524 | 14570 | try Type.vector(sema.arena, operand_ty.vectorLen(), dest_scalar_ty) |
| ... | ... | @@ -14686,7 +14732,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14686 | 14732 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 14687 | 14733 | const operand = sema.resolveInst(inst_data.operand); |
| 14688 | 14734 | const operand_ty = sema.typeOf(operand); |
| 14689 | | const scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand, operand_src); |
| 14735 | const scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 14690 | 14736 | const target = sema.mod.getTarget(); |
| 14691 | 14737 | const bits = scalar_ty.intInfo(target).bits; |
| 14692 | 14738 | if (bits % 8 != 0) { |
| ... | ... | @@ -14743,7 +14789,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 14743 | 14789 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 14744 | 14790 | const operand = sema.resolveInst(inst_data.operand); |
| 14745 | 14791 | const operand_ty = sema.typeOf(operand); |
| 14746 | | _ = try sema.checkIntOrVectorAllowComptime(block, operand, operand_src); |
| 14792 | _ = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 14747 | 14793 | |
| 14748 | 14794 | if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| { |
| 14749 | 14795 | return sema.addConstant(operand_ty, val); |
| ... | ... | @@ -15095,10 +15141,9 @@ fn checkIntOrVector( |
| 15095 | 15141 | fn checkIntOrVectorAllowComptime( |
| 15096 | 15142 | sema: *Sema, |
| 15097 | 15143 | block: *Block, |
| 15098 | | operand: Air.Inst.Ref, |
| 15144 | operand_ty: Type, |
| 15099 | 15145 | operand_src: LazySrcLoc, |
| 15100 | 15146 | ) CompileError!Type { |
| 15101 | | const operand_ty = sema.typeOf(operand); |
| 15102 | 15147 | switch (try operand_ty.zigTypeTagOrPoison()) { |
| 15103 | 15148 | .Int, .ComptimeInt => return operand_ty, |
| 15104 | 15149 | .Vector => { |