| author | |
| committer | |
| log | e572063f92ddd497c5bb6a067358bdbae1c16aab |
| tree | 25315d5cdeb5f0ced3b49007de2f9eae91bdcceb |
| parent | c8bb44618a9c3c7bfff4a9f672a451fdeda1bb02 |
This makes writing code that is generic over scalar and vector
types easier. In particular, this helps when multiplying a generic
argument by a constant, or passing a generic arugment alongside a
scalar value to a function or builtin such as `@mulAdd`.
This also has the side benefit of making the implicit splat for
some binary operations as suggested by @SpexGuy in #35376 simpler
to implement for inplace arithmetic operations.
part of #353765 files changed, 36 insertions(+), 18 deletions(-)
doc/langref.html.in+1-1| ... | ... | @@ -5582,7 +5582,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 5582 | 5582 | <p> |
| 5583 | 5583 | Produces an array or vector where each element is the value |
| 5584 | 5584 | {#syntax#}element{#endsyntax#}. The return type, including the number of |
| 5585 | elements, is inferred. | |
| 5585 | elements, is inferred. If the result type is a scalar, `element` is returned. | |
| 5586 | 5586 | </p> |
| 5587 | 5587 | {#code|test_splat_builtin.zig#} |
| 5588 | 5588 | {#see_also|Vectors|Arrays|@shuffle#} |
doc/langref/test_splat_builtin.zig+7| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expectEqualSlices = std.testing.expectEqualSlices; |
| 3 | const expectEqual = std.testing.expectEqual; | |
| 3 | 4 | |
| 4 | 5 | test "vector @splat" { |
| 5 | 6 | const scalar: u32 = 5; |
| ... | ... | @@ -13,4 +14,10 @@ test "array @splat" { |
| 13 | 14 | try expectEqualSlices(u32, &[_]u32{ 5, 5, 5, 5 }, &@as([4]u32, result)); |
| 14 | 15 | } |
| 15 | 16 | |
| 17 | test "scalar @splat" { | |
| 18 | const scalar: u32 = 5; | |
| 19 | const result: u32 = @splat(scalar); | |
| 20 | try expectEqual(5, result); | |
| 21 | } | |
| 22 | ||
| 16 | 23 | // test |
src/Sema.zig+9-10| ... | ... | @@ -7515,13 +7515,12 @@ fn zirSplatOpResultType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil |
| 7515 | 7515 | const un_node = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; |
| 7516 | 7516 | |
| 7517 | 7517 | const raw_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, un_node.operand) orelse return .generic_poison_type; |
| 7518 | const vec_ty = raw_ty.optEuBaseType(zcu); | |
| 7518 | const base_ty = raw_ty.optEuBaseType(zcu); | |
| 7519 | 7519 | |
| 7520 | switch (vec_ty.zigTypeTag(zcu)) { | |
| 7521 | .array, .vector => {}, | |
| 7522 | else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{f}'", .{vec_ty.fmt(zcu)}), | |
| 7520 | switch (base_ty.zigTypeTag(zcu)) { | |
| 7521 | .array, .vector => return Air.internedToRef(base_ty.childType(zcu).toIntern()), | |
| 7522 | else => return Air.internedToRef(base_ty.toIntern()), | |
| 7523 | 7523 | } |
| 7524 | return Air.internedToRef(vec_ty.childType(zcu).toIntern()); | |
| 7525 | 7524 | } |
| 7526 | 7525 | |
| 7527 | 7526 | fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -23314,17 +23313,17 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 23314 | 23313 | const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; |
| 23315 | 23314 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 23316 | 23315 | const src = block.nodeOffset(inst_data.src_node); |
| 23317 | const scalar_src = block.builtinCallArgSrc(inst_data.src_node, 0); | |
| 23316 | const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); | |
| 23318 | 23317 | const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@splat"); |
| 23318 | const operand = sema.resolveInst(extra.rhs); | |
| 23319 | 23319 | |
| 23320 | 23320 | switch (dest_ty.zigTypeTag(zcu)) { |
| 23321 | 23321 | .array, .vector => {}, |
| 23322 | else => return sema.fail(block, src, "expected array or vector type, found '{f}'", .{dest_ty.fmt(zcu)}), | |
| 23322 | else => return sema.coerce(block, dest_ty, operand, operand_src), | |
| 23323 | 23323 | } |
| 23324 | 23324 | |
| 23325 | const operand = sema.resolveInst(extra.rhs); | |
| 23326 | 23325 | const scalar_ty = dest_ty.childType(zcu); |
| 23327 | const scalar = try sema.coerce(block, scalar_ty, operand, scalar_src); | |
| 23326 | const scalar = try sema.coerce(block, scalar_ty, operand, operand_src); | |
| 23328 | 23327 | |
| 23329 | 23328 | const len = try sema.usizeCast(block, src, dest_ty.arrayLen(zcu)); |
| 23330 | 23329 | |
| ... | ... | @@ -23348,7 +23347,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 23348 | 23347 | return .fromValue(try pt.aggregateSplatValue(dest_ty, scalar_val)); |
| 23349 | 23348 | } |
| 23350 | 23349 | |
| 23351 | try sema.requireRuntimeBlock(block, src, scalar_src); | |
| 23350 | try sema.requireRuntimeBlock(block, src, operand_src); | |
| 23352 | 23351 | |
| 23353 | 23352 | switch (dest_ty.zigTypeTag(zcu)) { |
| 23354 | 23353 | .vector, .array => return block.addTyOp(.splat, dest_ty, scalar), |
test/behavior/splat.zig+19| ... | ... | @@ -160,3 +160,22 @@ test "vector @splat" { |
| 160 | 160 | try S.doTheTest(); |
| 161 | 161 | try comptime S.doTheTest(); |
| 162 | 162 | } |
| 163 | ||
| 164 | test "scalar @splat" { | |
| 165 | const S = struct { | |
| 166 | fn testForTypes(R: type, result: R, Op: type, op: Op) !void { | |
| 167 | try expect(@as(R, result) == @as(Op, @splat(op))); | |
| 168 | } | |
| 169 | fn doTheTest() !void { | |
| 170 | try testForTypes(comptime_float, 3.1415, comptime_float, 3.1415); | |
| 171 | try testForTypes(f32, 3.1415, comptime_float, 3.1415); | |
| 172 | try testForTypes(f32, 3.1415, f32, 3.1415); | |
| 173 | try testForTypes(u8, 31, u8, 31); | |
| 174 | try testForTypes(u8, 31, u16, 31); | |
| 175 | try testForTypes(i16, 31, i16, 31); | |
| 176 | try testForTypes(i16, 31, i8, 31); | |
| 177 | } | |
| 178 | }; | |
| 179 | try S.doTheTest(); | |
| 180 | try comptime S.doTheTest(); | |
| 181 | } |
test/cases/compile_errors/splat_bad_result_type.zig deleted-7| ... | ... | @@ -1,7 +0,0 @@ |
| 1 | export fn f() void { | |
| 2 | _ = @as(u32, @splat(5)); | |
| 3 | } | |
| 4 | ||
| 5 | // error | |
| 6 | // | |
| 7 | // :2:18: error: expected array or vector type, found 'u32' |