| ... | @@ -7020,22 +7020,25 @@ fn intCast( | ... | @@ -7020,22 +7020,25 @@ fn intCast( |
| 7020 | operand_src: LazySrcLoc, | 7020 | operand_src: LazySrcLoc, |
| 7021 | runtime_safety: bool, | 7021 | runtime_safety: bool, |
| 7022 | ) CompileError!Air.Inst.Ref { | 7022 | ) CompileError!Air.Inst.Ref { |
| 7023 | // TODO: Add support for vectors | 7023 | const operand_ty = sema.typeOf(operand); |
| 7024 | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_ty); | 7024 | const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src); |
| 7025 | _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); | 7025 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 7026 | | 7026 | |
| 7027 | if (try sema.isComptimeKnown(block, operand_src, operand)) { | 7027 | if (try sema.isComptimeKnown(block, operand_src, operand)) { |
| 7028 | return sema.coerce(block, dest_ty, operand, operand_src); | 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 | return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{}); | 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 | if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| { | 7036 | if ((try sema.typeHasOnePossibleValue(block, dest_ty_src, dest_ty))) |opv| { |
| 7034 | // requirement: intCast(u0, input) iff input == 0 | 7037 | // requirement: intCast(u0, input) iff input == 0 |
| 7035 | if (runtime_safety and block.wantSafety()) { | 7038 | if (runtime_safety and block.wantSafety()) { |
| 7036 | try sema.requireRuntimeBlock(block, operand_src); | 7039 | try sema.requireRuntimeBlock(block, operand_src); |
| 7037 | const target = sema.mod.getTarget(); | 7040 | const target = sema.mod.getTarget(); |
| 7038 | const wanted_info = dest_ty.intInfo(target); | 7041 | const wanted_info = dest_scalar_ty.intInfo(target); |
| 7039 | const wanted_bits = wanted_info.bits; | 7042 | const wanted_bits = wanted_info.bits; |
| 7040 | | 7043 | |
| 7041 | if (wanted_bits == 0) { | 7044 | if (wanted_bits == 0) { |
| ... | @@ -7051,9 +7054,8 @@ fn intCast( | ... | @@ -7051,9 +7054,8 @@ fn intCast( |
| 7051 | try sema.requireRuntimeBlock(block, operand_src); | 7054 | try sema.requireRuntimeBlock(block, operand_src); |
| 7052 | if (runtime_safety and block.wantSafety()) { | 7055 | if (runtime_safety and block.wantSafety()) { |
| 7053 | const target = sema.mod.getTarget(); | 7056 | const target = sema.mod.getTarget(); |
| 7054 | const operand_ty = sema.typeOf(operand); | 7057 | const actual_info = operand_scalar_ty.intInfo(target); |
| 7055 | const actual_info = operand_ty.intInfo(target); | 7058 | const wanted_info = dest_scalar_ty.intInfo(target); |
| 7056 | const wanted_info = dest_ty.intInfo(target); | | |
| 7057 | const actual_bits = actual_info.bits; | 7059 | const actual_bits = actual_info.bits; |
| 7058 | const wanted_bits = wanted_info.bits; | 7060 | const wanted_bits = wanted_info.bits; |
| 7059 | const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); | 7061 | const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); |
| ... | @@ -7062,7 +7064,11 @@ fn intCast( | ... | @@ -7062,7 +7064,11 @@ fn intCast( |
| 7062 | // range shrinkage | 7064 | // range shrinkage |
| 7063 | // requirement: int value fits into target type | 7065 | // requirement: int value fits into target type |
| 7064 | if (wanted_value_bits < actual_value_bits) { | 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 | const dest_max = try sema.addConstant(operand_ty, dest_max_val); | 7072 | const dest_max = try sema.addConstant(operand_ty, dest_max_val); |
| 7067 | const diff = try block.addBinOp(.subwrap, dest_max, operand); | 7073 | const diff = try block.addBinOp(.subwrap, dest_max, operand); |
| 7068 | | 7074 | |
| ... | @@ -7080,19 +7086,59 @@ fn intCast( | ... | @@ -7080,19 +7086,59 @@ fn intCast( |
| 7080 | } else dest_max_val; | 7086 | } else dest_max_val; |
| 7081 | const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val); | 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); | 7089 | const ok = if (is_vector) ok: { |
| 7084 | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); | 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 | } else { | 7104 | } else { |
| 7086 | const is_in_range = try block.addBinOp(.cmp_lte, diff, dest_max); | 7105 | const ok = if (is_vector) ok: { |
| 7087 | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); | 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 | } | 7121 | } else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) { |
| 7090 | // no shrinkage, yes sign loss | 7122 | // no shrinkage, yes sign loss |
| 7091 | // requirement: signed to unsigned >= 0 | 7123 | // requirement: signed to unsigned >= 0 |
| 7092 | else if (actual_info.signedness == .signed and wanted_info.signedness == .unsigned) { | 7124 | const ok = if (is_vector) ok: { |
| 7093 | const zero_inst = try sema.addConstant(operand_ty, Value.zero); | 7125 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); |
| 7094 | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); | 7126 | const zero_inst = try sema.addConstant(operand_ty, zero_val); |
| 7095 | try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data); | 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 | return block.addTyOp(.intcast, dest_ty, operand); | 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,8 +14563,8 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14517 | const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); | 14563 | const dest_scalar_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 14518 | const operand = sema.resolveInst(extra.rhs); | 14564 | const operand = sema.resolveInst(extra.rhs); |
| 14519 | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty); | 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 | const operand_ty = sema.typeOf(operand); | 14566 | const operand_ty = sema.typeOf(operand); |
| | 14567 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 14522 | const is_vector = operand_ty.zigTypeTag() == .Vector; | 14568 | const is_vector = operand_ty.zigTypeTag() == .Vector; |
| 14523 | const dest_ty = if (is_vector) | 14569 | const dest_ty = if (is_vector) |
| 14524 | try Type.vector(sema.arena, operand_ty.vectorLen(), dest_scalar_ty) | 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,7 +14732,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14686 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 14732 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 14687 | const operand = sema.resolveInst(inst_data.operand); | 14733 | const operand = sema.resolveInst(inst_data.operand); |
| 14688 | const operand_ty = sema.typeOf(operand); | 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 | const target = sema.mod.getTarget(); | 14736 | const target = sema.mod.getTarget(); |
| 14691 | const bits = scalar_ty.intInfo(target).bits; | 14737 | const bits = scalar_ty.intInfo(target).bits; |
| 14692 | if (bits % 8 != 0) { | 14738 | if (bits % 8 != 0) { |
| ... | @@ -14743,7 +14789,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -14743,7 +14789,7 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 14743 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 14789 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 14744 | const operand = sema.resolveInst(inst_data.operand); | 14790 | const operand = sema.resolveInst(inst_data.operand); |
| 14745 | const operand_ty = sema.typeOf(operand); | 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 | if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| { | 14794 | if (try sema.typeHasOnePossibleValue(block, operand_src, operand_ty)) |val| { |
| 14749 | return sema.addConstant(operand_ty, val); | 14795 | return sema.addConstant(operand_ty, val); |
| ... | @@ -15095,10 +15141,9 @@ fn checkIntOrVector( | ... | @@ -15095,10 +15141,9 @@ fn checkIntOrVector( |
| 15095 | fn checkIntOrVectorAllowComptime( | 15141 | fn checkIntOrVectorAllowComptime( |
| 15096 | sema: *Sema, | 15142 | sema: *Sema, |
| 15097 | block: *Block, | 15143 | block: *Block, |
| 15098 | operand: Air.Inst.Ref, | 15144 | operand_ty: Type, |
| 15099 | operand_src: LazySrcLoc, | 15145 | operand_src: LazySrcLoc, |
| 15100 | ) CompileError!Type { | 15146 | ) CompileError!Type { |
| 15101 | const operand_ty = sema.typeOf(operand); | | |
| 15102 | switch (try operand_ty.zigTypeTagOrPoison()) { | 15147 | switch (try operand_ty.zigTypeTagOrPoison()) { |
| 15103 | .Int, .ComptimeInt => return operand_ty, | 15148 | .Int, .ComptimeInt => return operand_ty, |
| 15104 | .Vector => { | 15149 | .Vector => { |