authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-08-27 17:03:42+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-28 12:32:02-07:00
log8d036d1d78bd6db5fd39b30c6182196c1e49a3db
treeae65a34daabcc80a7b1faf04918fd8fb9ead2565
parentc6024691cfc3fa329cf1b7ac9fcb0855b7211aa0

Sema: allow cast builtins on vectors

The following cast builtins did not previously work on vectors, and have been made to: * `@floatCast` * `@ptrFromInt` * `@intFromPtr` * `@floatFromInt` * `@intFromFloat` * `@intFromBool` Resolves: #16267

4 files changed, 416 insertions(+), 76 deletions(-)

src/AstGen.zig+1-1
......@@ -8041,7 +8041,7 @@ fn builtinCall(
80418041 .compile_error => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0], .compile_error),
80428042 .set_eval_branch_quota => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .set_eval_branch_quota),
80438043 .int_from_enum => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .int_from_enum),
8044 .int_from_bool => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .int_from_bool),
8044 .int_from_bool => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .int_from_bool),
80458045 .embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0], .embed_file),
80468046 .error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .anyerror_type } }, params[0], .error_name),
80478047 .set_runtime_safety => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_runtime_safety),
src/Sema.zig+285-73
......@@ -9750,19 +9750,52 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
97509750 const mod = sema.mod;
97519751 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
97529752 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9753 const ptr = try sema.resolveInst(inst_data.operand);
9754 const ptr_ty = sema.typeOf(ptr);
9753 const operand = try sema.resolveInst(inst_data.operand);
9754 const operand_ty = sema.typeOf(operand);
9755 const ptr_ty = operand_ty.scalarType(mod);
9756 const is_vector = operand_ty.zigTypeTag(mod) == .Vector;
97559757 if (!ptr_ty.isPtrAtRuntime(mod)) {
97569758 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(mod)});
97579759 }
9758 if (try sema.resolveMaybeUndefValIntable(ptr)) |ptr_val| {
9759 return Air.internedToRef((try mod.intValue(
9760 Type.usize,
9761 (try ptr_val.getUnsignedIntAdvanced(mod, sema)).?,
9762 )).toIntern());
9760 if (try sema.resolveMaybeUndefValIntable(operand)) |operand_val| ct: {
9761 if (!is_vector) {
9762 return Air.internedToRef((try mod.intValue(
9763 Type.usize,
9764 (try operand_val.getUnsignedIntAdvanced(mod, sema)).?,
9765 )).toIntern());
9766 }
9767 const len = operand_ty.vectorLen(mod);
9768 const dest_ty = try mod.vectorType(.{ .child = .usize_type, .len = len });
9769 const new_elems = try sema.arena.alloc(InternPool.Index, len);
9770 for (new_elems, 0..) |*new_elem, i| {
9771 const ptr_val = try operand_val.elemValue(mod, i);
9772 const addr = try ptr_val.getUnsignedIntAdvanced(mod, sema) orelse {
9773 // A vector element wasn't an integer pointer. This is a runtime operation.
9774 break :ct;
9775 };
9776 new_elem.* = (try mod.intValue(
9777 Type.usize,
9778 addr,
9779 )).toIntern();
9780 }
9781 return Air.internedToRef(try mod.intern(.{ .aggregate = .{
9782 .ty = dest_ty.toIntern(),
9783 .storage = .{ .elems = new_elems },
9784 } }));
97639785 }
97649786 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
9765 return block.addUnOp(.int_from_ptr, ptr);
9787 if (!is_vector) {
9788 return block.addUnOp(.int_from_ptr, operand);
9789 }
9790 const len = operand_ty.vectorLen(mod);
9791 const dest_ty = try mod.vectorType(.{ .child = .usize_type, .len = len });
9792 const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
9793 for (new_elems, 0..) |*new_elem, i| {
9794 const idx_ref = try mod.intRef(Type.usize, i);
9795 const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
9796 new_elem.* = try block.addUnOp(.int_from_ptr, old_elem);
9797 }
9798 return block.addAggregateInit(dest_ty, new_elems);
97669799}
97679800
97689801fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -10133,44 +10166,73 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1013310166 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
1013410167
1013510168 const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@floatCast");
10169 const dest_scalar_ty = dest_ty.scalarType(mod);
10170
1013610171 const operand = try sema.resolveInst(extra.rhs);
10172 const operand_ty = sema.typeOf(operand);
10173 const operand_scalar_ty = operand_ty.scalarType(mod);
10174
10175 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, src, operand_src);
10176 const is_vector = dest_ty.zigTypeTag(mod) == .Vector;
1013710177
1013810178 const target = mod.getTarget();
10139 const dest_is_comptime_float = switch (dest_ty.zigTypeTag(mod)) {
10179 const dest_is_comptime_float = switch (dest_scalar_ty.zigTypeTag(mod)) {
1014010180 .ComptimeFloat => true,
1014110181 .Float => false,
1014210182 else => return sema.fail(
1014310183 block,
1014410184 src,
10145 "expected float type, found '{}'",
10185 "expected float or vector type, found '{}'",
1014610186 .{dest_ty.fmt(mod)},
1014710187 ),
1014810188 };
1014910189
10150 const operand_ty = sema.typeOf(operand);
10151 switch (operand_ty.zigTypeTag(mod)) {
10190 switch (operand_scalar_ty.zigTypeTag(mod)) {
1015210191 .ComptimeFloat, .Float, .ComptimeInt => {},
1015310192 else => return sema.fail(
1015410193 block,
1015510194 operand_src,
10156 "expected float type, found '{}'",
10195 "expected float or vector type, found '{}'",
1015710196 .{operand_ty.fmt(mod)},
1015810197 ),
1015910198 }
1016010199
1016110200 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
10162 return Air.internedToRef((try operand_val.floatCast(dest_ty, mod)).toIntern());
10201 if (!is_vector) {
10202 return Air.internedToRef((try operand_val.floatCast(dest_ty, mod)).toIntern());
10203 }
10204 const vec_len = operand_ty.vectorLen(mod);
10205 const new_elems = try sema.arena.alloc(InternPool.Index, vec_len);
10206 for (new_elems, 0..) |*new_elem, i| {
10207 const old_elem = try operand_val.elemValue(mod, i);
10208 new_elem.* = (try old_elem.floatCast(dest_scalar_ty, mod)).toIntern();
10209 }
10210 return Air.internedToRef(try mod.intern(.{ .aggregate = .{
10211 .ty = dest_ty.toIntern(),
10212 .storage = .{ .elems = new_elems },
10213 } }));
1016310214 }
1016410215 if (dest_is_comptime_float) {
1016510216 return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{});
1016610217 }
10167 const src_bits = operand_ty.floatBits(target);
10168 const dst_bits = dest_ty.floatBits(target);
10218 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
10219
10220 const src_bits = operand_scalar_ty.floatBits(target);
10221 const dst_bits = dest_scalar_ty.floatBits(target);
1016910222 if (dst_bits >= src_bits) {
1017010223 return sema.coerce(block, dest_ty, operand, operand_src);
1017110224 }
10172 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
10173 return block.addTyOp(.fptrunc, dest_ty, operand);
10225 if (!is_vector) {
10226 return block.addTyOp(.fptrunc, dest_ty, operand);
10227 }
10228 const vec_len = operand_ty.vectorLen(mod);
10229 const new_elems = try sema.arena.alloc(Air.Inst.Ref, vec_len);
10230 for (new_elems, 0..) |*new_elem, i| {
10231 const idx_ref = try mod.intRef(Type.usize, i);
10232 const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
10233 new_elem.* = try block.addTyOp(.fptrunc, dest_scalar_ty, old_elem);
10234 }
10235 return block.addAggregateInit(dest_ty, new_elems);
1017410236}
1017510237
1017610238fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -19761,13 +19823,51 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1976119823fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1976219824 const mod = sema.mod;
1976319825 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
19826 const src = inst_data.src();
1976419827 const operand = try sema.resolveInst(inst_data.operand);
19828 const operand_ty = sema.typeOf(operand);
19829 const is_vector = operand_ty.zigTypeTag(mod) == .Vector;
19830 const operand_scalar_ty = operand_ty.scalarType(mod);
19831 if (operand_scalar_ty.toIntern() != .bool_type) {
19832 return sema.fail(block, src, "expected 'bool', found '{}'", .{operand_scalar_ty.zigTypeTag(mod)});
19833 }
1976519834 if (try sema.resolveMaybeUndefVal(operand)) |val| {
19766 if (val.isUndef(mod)) return mod.undefRef(Type.u1);
19767 if (val.toBool()) return Air.internedToRef((try mod.intValue(Type.u1, 1)).toIntern());
19768 return Air.internedToRef((try mod.intValue(Type.u1, 0)).toIntern());
19835 if (!is_vector) {
19836 if (val.isUndef(mod)) return mod.undefRef(Type.u1);
19837 if (val.toBool()) return Air.internedToRef((try mod.intValue(Type.u1, 1)).toIntern());
19838 return Air.internedToRef((try mod.intValue(Type.u1, 0)).toIntern());
19839 }
19840 const len = operand_ty.vectorLen(mod);
19841 const dest_ty = try mod.vectorType(.{ .child = .u1_type, .len = len });
19842 if (val.isUndef(mod)) return mod.undefRef(dest_ty);
19843 const new_elems = try sema.arena.alloc(InternPool.Index, len);
19844 for (new_elems, 0..) |*new_elem, i| {
19845 const old_elem = try val.elemValue(mod, i);
19846 const new_val = if (old_elem.isUndef(mod))
19847 try mod.undefValue(Type.u1)
19848 else if (old_elem.toBool())
19849 try mod.intValue(Type.u1, 1)
19850 else
19851 try mod.intValue(Type.u1, 0);
19852 new_elem.* = new_val.toIntern();
19853 }
19854 return Air.internedToRef(try mod.intern(.{ .aggregate = .{
19855 .ty = dest_ty.toIntern(),
19856 .storage = .{ .elems = new_elems },
19857 } }));
19858 }
19859 if (!is_vector) {
19860 return block.addUnOp(.int_from_bool, operand);
1976919861 }
19770 return block.addUnOp(.int_from_bool, operand);
19862 const len = operand_ty.vectorLen(mod);
19863 const dest_ty = try mod.vectorType(.{ .child = .u1_type, .len = len });
19864 const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
19865 for (new_elems, 0..) |*new_elem, i| {
19866 const idx_ref = try mod.intRef(Type.usize, i);
19867 const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
19868 new_elem.* = try block.addUnOp(.int_from_bool, old_elem);
19869 }
19870 return block.addAggregateInit(dest_ty, new_elems);
1977119871}
1977219872
1977319873fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -21050,34 +21150,74 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
2105021150 const operand = try sema.resolveInst(extra.rhs);
2105121151 const operand_ty = sema.typeOf(operand);
2105221152
21053 _ = try sema.checkIntType(block, src, dest_ty);
21054 try sema.checkFloatType(block, operand_src, operand_ty);
21153 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, src, operand_src);
21154 const is_vector = dest_ty.zigTypeTag(mod) == .Vector;
2105521155
21056 if (try sema.resolveMaybeUndefVal(operand)) |val| {
21057 const result_val = try sema.intFromFloat(block, operand_src, val, operand_ty, dest_ty);
21156 const dest_scalar_ty = dest_ty.scalarType(mod);
21157 const operand_scalar_ty = operand_ty.scalarType(mod);
21158
21159 _ = try sema.checkIntType(block, src, dest_scalar_ty);
21160 try sema.checkFloatType(block, operand_src, operand_scalar_ty);
21161
21162 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
21163 const result_val = try sema.intFromFloat(block, operand_src, operand_val, operand_ty, dest_ty);
2105821164 return Air.internedToRef(result_val.toIntern());
21059 } else if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
21165 } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
2106021166 return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime-known");
2106121167 }
2106221168
2106321169 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
21064 if (dest_ty.intInfo(mod).bits == 0) {
21170 if (dest_scalar_ty.intInfo(mod).bits == 0) {
21171 if (!is_vector) {
21172 if (block.wantSafety()) {
21173 const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, Air.internedToRef((try mod.floatValue(operand_ty, 0.0)).toIntern()));
21174 try sema.addSafetyCheck(block, src, ok, .integer_part_out_of_bounds);
21175 }
21176 return Air.internedToRef((try mod.intValue(dest_ty, 0)).toIntern());
21177 }
21178 if (block.wantSafety()) {
21179 const len = dest_ty.vectorLen(mod);
21180 for (0..len) |i| {
21181 const idx_ref = try mod.intRef(Type.usize, i);
21182 const elem_ref = try block.addBinOp(.array_elem_val, operand, idx_ref);
21183 const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, elem_ref, Air.internedToRef((try mod.floatValue(operand_scalar_ty, 0.0)).toIntern()));
21184 try sema.addSafetyCheck(block, src, ok, .integer_part_out_of_bounds);
21185 }
21186 }
21187 return Air.internedToRef(try mod.intern(.{ .aggregate = .{
21188 .ty = dest_ty.toIntern(),
21189 .storage = .{ .repeated_elem = (try mod.intValue(dest_scalar_ty, 0)).toIntern() },
21190 } }));
21191 }
21192 if (!is_vector) {
21193 const result = try block.addTyOp(if (block.float_mode == .Optimized) .int_from_float_optimized else .int_from_float, dest_ty, operand);
2106521194 if (block.wantSafety()) {
21066 const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, Air.internedToRef((try mod.floatValue(operand_ty, 0.0)).toIntern()));
21195 const back = try block.addTyOp(.float_from_int, operand_ty, result);
21196 const diff = try block.addBinOp(.sub, operand, back);
21197 const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, Air.internedToRef((try mod.floatValue(operand_ty, 1.0)).toIntern()));
21198 const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, Air.internedToRef((try mod.floatValue(operand_ty, -1.0)).toIntern()));
21199 const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
2106721200 try sema.addSafetyCheck(block, src, ok, .integer_part_out_of_bounds);
2106821201 }
21069 return Air.internedToRef((try mod.intValue(dest_ty, 0)).toIntern());
21202 return result;
2107021203 }
21071 const result = try block.addTyOp(if (block.float_mode == .Optimized) .int_from_float_optimized else .int_from_float, dest_ty, operand);
21072 if (block.wantSafety()) {
21073 const back = try block.addTyOp(.float_from_int, operand_ty, result);
21074 const diff = try block.addBinOp(.sub, operand, back);
21075 const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, Air.internedToRef((try mod.floatValue(operand_ty, 1.0)).toIntern()));
21076 const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, Air.internedToRef((try mod.floatValue(operand_ty, -1.0)).toIntern()));
21077 const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
21078 try sema.addSafetyCheck(block, src, ok, .integer_part_out_of_bounds);
21204 const len = dest_ty.vectorLen(mod);
21205 const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
21206 for (new_elems, 0..) |*new_elem, i| {
21207 const idx_ref = try mod.intRef(Type.usize, i);
21208 const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
21209 const result = try block.addTyOp(if (block.float_mode == .Optimized) .int_from_float_optimized else .int_from_float, dest_scalar_ty, old_elem);
21210 if (block.wantSafety()) {
21211 const back = try block.addTyOp(.float_from_int, operand_scalar_ty, result);
21212 const diff = try block.addBinOp(.sub, old_elem, back);
21213 const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, Air.internedToRef((try mod.floatValue(operand_scalar_ty, 1.0)).toIntern()));
21214 const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, Air.internedToRef((try mod.floatValue(operand_scalar_ty, -1.0)).toIntern()));
21215 const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
21216 try sema.addSafetyCheck(block, src, ok, .integer_part_out_of_bounds);
21217 }
21218 new_elem.* = result;
2107921219 }
21080 return result;
21220 return block.addAggregateInit(dest_ty, new_elems);
2108121221}
2108221222
2108321223fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -21090,18 +21230,34 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
2109021230 const operand = try sema.resolveInst(extra.rhs);
2109121231 const operand_ty = sema.typeOf(operand);
2109221232
21093 try sema.checkFloatType(block, src, dest_ty);
21094 _ = try sema.checkIntType(block, operand_src, operand_ty);
21233 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, src, operand_src);
21234 const is_vector = dest_ty.zigTypeTag(mod) == .Vector;
21235
21236 const dest_scalar_ty = dest_ty.scalarType(mod);
21237 const operand_scalar_ty = operand_ty.scalarType(mod);
2109521238
21096 if (try sema.resolveMaybeUndefVal(operand)) |val| {
21097 const result_val = try val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, sema.mod, sema);
21239 try sema.checkFloatType(block, src, dest_scalar_ty);
21240 _ = try sema.checkIntType(block, operand_src, operand_scalar_ty);
21241
21242 if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
21243 const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, mod, sema);
2109821244 return Air.internedToRef(result_val.toIntern());
21099 } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
21245 } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeFloat) {
2110021246 return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime-known");
2110121247 }
2110221248
21103 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
21104 return block.addTyOp(.float_from_int, dest_ty, operand);
21249 try sema.requireRuntimeBlock(block, src, operand_src);
21250 if (!is_vector) {
21251 return block.addTyOp(.float_from_int, dest_ty, operand);
21252 }
21253 const len = operand_ty.vectorLen(mod);
21254 const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
21255 for (new_elems, 0..) |*new_elem, i| {
21256 const idx_ref = try mod.intRef(Type.usize, i);
21257 const old_elem = try block.addBinOp(.array_elem_val, operand, idx_ref);
21258 new_elem.* = try block.addTyOp(.float_from_int, dest_scalar_ty, old_elem);
21259 }
21260 return block.addAggregateInit(dest_ty, new_elems);
2110521261}
2110621262
2110721263fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -21113,9 +21269,20 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2111321269
2111421270 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
2111521271 const operand_res = try sema.resolveInst(extra.rhs);
21116 const operand_coerced = try sema.coerce(block, Type.usize, operand_res, operand_src);
2111721272
21118 const ptr_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu, "@ptrFromInt");
21273 const uncoerced_operand_ty = sema.typeOf(operand_res);
21274 const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu, "@ptrFromInt");
21275 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, uncoerced_operand_ty, src, operand_src);
21276
21277 const is_vector = dest_ty.zigTypeTag(mod) == .Vector;
21278 const operand_ty = if (is_vector) operand_ty: {
21279 const len = dest_ty.vectorLen(mod);
21280 break :operand_ty try mod.vectorType(.{ .child = .usize_type, .len = len });
21281 } else Type.usize;
21282
21283 const operand_coerced = try sema.coerce(block, operand_ty, operand_res, operand_src);
21284
21285 const ptr_ty = dest_ty.scalarType(mod);
2111921286 try sema.checkPtrType(block, src, ptr_ty);
2112021287 const elem_ty = ptr_ty.elemType2(mod);
2112121288 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);
......@@ -21131,38 +21298,83 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2113121298 }
2113221299
2113321300 if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
21134 const addr = val.toUnsignedInt(mod);
21135 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
21136 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});
21137 if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0)
21138 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
21139
21140 const ptr_val = switch (ptr_ty.zigTypeTag(mod)) {
21141 .Optional => (try mod.intern(.{ .opt = .{
21142 .ty = ptr_ty.toIntern(),
21143 .val = if (addr == 0) .none else (try mod.ptrIntValue(ptr_ty.childType(mod), addr)).toIntern(),
21144 } })).toValue(),
21145 .Pointer => try mod.ptrIntValue(ptr_ty, addr),
21146 else => unreachable,
21147 };
21148 return Air.internedToRef(ptr_val.toIntern());
21301 if (!is_vector) {
21302 const ptr_val = try sema.ptrFromIntVal(block, operand_src, val, ptr_ty, ptr_align);
21303 return Air.internedToRef(ptr_val.toIntern());
21304 }
21305 const len = dest_ty.vectorLen(mod);
21306 const new_elems = try sema.arena.alloc(InternPool.Index, len);
21307 for (new_elems, 0..) |*new_elem, i| {
21308 const elem = try val.elemValue(mod, i);
21309 const ptr_val = try sema.ptrFromIntVal(block, operand_src, elem, ptr_ty, ptr_align);
21310 new_elem.* = ptr_val.toIntern();
21311 }
21312 return Air.internedToRef(try mod.intern(.{ .aggregate = .{
21313 .ty = dest_ty.toIntern(),
21314 .storage = .{ .elems = new_elems },
21315 } }));
2114921316 }
2115021317
2115121318 try sema.requireRuntimeBlock(block, src, operand_src);
21152 if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) {
21153 if (!ptr_ty.isAllowzeroPtr(mod)) {
21154 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
21155 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
21319 if (!is_vector) {
21320 if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) {
21321 if (!ptr_ty.isAllowzeroPtr(mod)) {
21322 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
21323 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
21324 }
21325 if (ptr_align > 1) {
21326 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());
21327 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
21328 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
21329 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
21330 }
2115621331 }
21332 return block.addBitCast(dest_ty, operand_coerced);
21333 }
2115721334
21158 if (ptr_align > 1) {
21159 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());
21160 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
21161 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
21162 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
21335 const len = dest_ty.vectorLen(mod);
21336 if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) {
21337 for (0..len) |i| {
21338 const idx_ref = try mod.intRef(Type.usize, i);
21339 const elem_coerced = try block.addBinOp(.array_elem_val, operand_coerced, idx_ref);
21340 if (!ptr_ty.isAllowzeroPtr(mod)) {
21341 const is_non_zero = try block.addBinOp(.cmp_neq, elem_coerced, .zero_usize);
21342 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
21343 }
21344 if (ptr_align > 1) {
21345 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, ptr_align - 1)).toIntern());
21346 const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);
21347 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
21348 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
21349 }
2116321350 }
2116421351 }
21165 return block.addBitCast(ptr_ty, operand_coerced);
21352
21353 const new_elems = try sema.arena.alloc(Air.Inst.Ref, len);
21354 for (new_elems, 0..) |*new_elem, i| {
21355 const idx_ref = try mod.intRef(Type.usize, i);
21356 const old_elem = try block.addBinOp(.array_elem_val, operand_coerced, idx_ref);
21357 new_elem.* = try block.addBitCast(ptr_ty, old_elem);
21358 }
21359 return block.addAggregateInit(dest_ty, new_elems);
21360}
21361
21362fn ptrFromIntVal(sema: *Sema, block: *Block, operand_src: LazySrcLoc, operand_val: Value, ptr_ty: Type, ptr_align: u32) !Value {
21363 const mod = sema.mod;
21364 const addr = operand_val.toUnsignedInt(mod);
21365 if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
21366 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});
21367 if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0)
21368 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
21369
21370 return switch (ptr_ty.zigTypeTag(mod)) {
21371 .Optional => (try mod.intern(.{ .opt = .{
21372 .ty = ptr_ty.toIntern(),
21373 .val = if (addr == 0) .none else (try mod.ptrIntValue(ptr_ty.childType(mod), addr)).toIntern(),
21374 } })).toValue(),
21375 .Pointer => try mod.ptrIntValue(ptr_ty, addr),
21376 else => unreachable,
21377 };
2116621378}
2116721379
2116821380fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
test/behavior/cast.zig+129-1
......@@ -609,7 +609,7 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
609609 try expect(mem.eql(u8, std.mem.sliceTo(@as([*:0]const u8, @ptrCast(x[0].?)), 0), "window name"));
610610}
611611
612test "vector casts" {
612test "@intCast on vector" {
613613 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
614614 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
615615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -2366,3 +2366,131 @@ test "cast builtins can wrap result in error union and optional" {
23662366 try S.doTheTest();
23672367 try comptime S.doTheTest();
23682368}
2369
2370test "@floatCast on vector" {
2371 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2372 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2373 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2374 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2375 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2376 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2377
2378 const S = struct {
2379 fn doTheTest() !void {
2380 var a: @Vector(3, f64) = .{ 1.5, 2.5, 3.5 };
2381 const b: @Vector(3, f32) = @floatCast(a);
2382 try expectEqual(@Vector(3, f32){ 1.5, 2.5, 3.5 }, b);
2383 }
2384 };
2385
2386 try S.doTheTest();
2387 try comptime S.doTheTest();
2388}
2389
2390test "@ptrFromInt on vector" {
2391 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2392 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2394 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2395 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2396 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2397
2398 const S = struct {
2399 fn doTheTest() !void {
2400 var a: @Vector(3, usize) = .{ 0x1000, 0x2000, 0x3000 };
2401 const b: @Vector(3, *anyopaque) = @ptrFromInt(a);
2402 try expectEqual(@Vector(3, *anyopaque){
2403 @ptrFromInt(0x1000),
2404 @ptrFromInt(0x2000),
2405 @ptrFromInt(0x3000),
2406 }, b);
2407 }
2408 };
2409
2410 try S.doTheTest();
2411 try comptime S.doTheTest();
2412}
2413
2414test "@intFromPtr on vector" {
2415 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2416 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2420 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2421
2422 const S = struct {
2423 fn doTheTest() !void {
2424 var a: @Vector(3, *anyopaque) = .{
2425 @ptrFromInt(0x1000),
2426 @ptrFromInt(0x2000),
2427 @ptrFromInt(0x3000),
2428 };
2429 const b: @Vector(3, usize) = @intFromPtr(a);
2430 try expectEqual(@Vector(3, usize){ 0x1000, 0x2000, 0x3000 }, b);
2431 }
2432 };
2433
2434 try S.doTheTest();
2435 try comptime S.doTheTest();
2436}
2437
2438test "@floatFromInt on vector" {
2439 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2440 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2441 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2442 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2444 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2445
2446 const S = struct {
2447 fn doTheTest() !void {
2448 var a: @Vector(3, u32) = .{ 10, 20, 30 };
2449 const b: @Vector(3, f32) = @floatFromInt(a);
2450 try expectEqual(@Vector(3, f32){ 10.0, 20.0, 30.0 }, b);
2451 }
2452 };
2453
2454 try S.doTheTest();
2455 try comptime S.doTheTest();
2456}
2457
2458test "@intFromFloat on vector" {
2459 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2460 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2461 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2462 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2463 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2464 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2465
2466 const S = struct {
2467 fn doTheTest() !void {
2468 var a: @Vector(3, f32) = .{ 10.3, 20.5, 30.7 };
2469 const b: @Vector(3, u32) = @intFromFloat(a);
2470 try expectEqual(@Vector(3, u32){ 10, 20, 30 }, b);
2471 }
2472 };
2473
2474 try S.doTheTest();
2475 try comptime S.doTheTest();
2476}
2477
2478test "@intFromBool on vector" {
2479 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2480 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2481 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2483 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2484 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2485
2486 const S = struct {
2487 fn doTheTest() !void {
2488 var a: @Vector(3, bool) = .{ false, true, false };
2489 const b: @Vector(3, u1) = @intFromBool(a);
2490 try expectEqual(@Vector(3, u1){ 0, 1, 0 }, b);
2491 }
2492 };
2493
2494 try S.doTheTest();
2495 try comptime S.doTheTest();
2496}
test/cases/compile_errors/invalid_float_casts.zig+1-1
......@@ -22,4 +22,4 @@ export fn qux() void {
2222// :3:40: error: unable to cast runtime value to 'comptime_float'
2323// :7:18: error: expected integer type, found 'f32'
2424// :11:32: error: expected integer type, found 'f32'
25// :15:29: error: expected float type, found 'u32'
25// :15:29: error: expected float or vector type, found 'u32'