| ... | @@ -2483,23 +2483,86 @@ test "null terminated array" { | ... | @@ -2483,23 +2483,86 @@ test "null terminated array" { |
| 2483 | {#header_open|Vectors#} | 2483 | {#header_open|Vectors#} |
| 2484 | <p> | 2484 | <p> |
| 2485 | A vector is a group of booleans, {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on | 2485 | A vector is a group of booleans, {#link|Integers#}, {#link|Floats#}, or {#link|Pointers#} which are operated on |
| 2486 | in parallel using a single instruction ({#link|SIMD#}). Vector types are created with the builtin function {#link|@Type#}, | 2486 | in parallel using SIMD instructions. Vector types are created with the builtin function {#link|@Type#}, |
| 2487 | or using the shorthand as {#syntax#}std.meta.Vector{#endsyntax#}. | 2487 | or using the shorthand function {#syntax#}std.meta.Vector{#endsyntax#}. |
| 2488 | </p> | 2488 | </p> |
| 2489 | <p> | 2489 | <p> |
| 2490 | TODO talk about C ABI interop | 2490 | Vectors support the same builtin operators as their underlying base types. These operations are performed |
| | 2491 | element-wise, and return a vector of the same length as the input vectors. This includes: |
| | 2492 | <ul> |
| | 2493 | <li>Arithmetic ({#syntax#}+{#endsyntax#}, {#syntax#}-{#endsyntax#}, {#syntax#}/{#endsyntax#}, {#syntax#}*{#endsyntax#}, |
| | 2494 | {#syntax#}@divFloor{#endsyntax#}, {#syntax#}@sqrt{#endsyntax#}, {#syntax#}@ceil{#endsyntax#}, |
| | 2495 | {#syntax#}@log{#endsyntax#}, etc.)</li> |
| | 2496 | <li>Bitwise operators ({#syntax#}>>{#endsyntax#}, {#syntax#}<<{#endsyntax#}, {#syntax#}&{#endsyntax#}, |
| | 2497 | {#syntax#}|{#endsyntax#}, {#syntax#}~{#endsyntax#}, etc.)</li> |
| | 2498 | <li>Comparison operators ({#syntax#}<{#endsyntax#}, {#syntax#}>{#endsyntax#}, {#syntax#}=={#endsyntax#}, etc.)</li> |
| | 2499 | </ul> |
| 2491 | </p> | 2500 | </p> |
| 2492 | {#header_open|SIMD#} | | |
| 2493 | <p> | 2501 | <p> |
| 2494 | TODO Zig's SIMD abilities are just beginning to be fleshed out. Here are some talking points to update the | 2502 | It is prohibited to use a math operator on a mixture of scalars (individual numbers) and vectors. |
| 2495 | docs with: | 2503 | Zig provides the {#link|@splat#} builtin to easily convert from scalars to vectors, and it supports {#link|@reduce#} |
| 2496 | * What kind of operations can you do? All the operations on integers and floats? What about mixing scalar and vector? | 2504 | and array indexing syntax to convert from vectors to scalars. Vectors also support assignment to and from |
| 2497 | * How to convert to/from vectors/arrays | 2505 | fixed-length arrays with comptime known length. |
| 2498 | * How to access individual elements from vectors, how to loop over the elements | | |
| 2499 | * "shuffle" | | |
| 2500 | * Advice on writing high perf software, how to abstract the best way | | |
| 2501 | </p> | 2506 | </p> |
| 2502 | {#header_close#} | 2507 | <p> |
| | 2508 | For rearranging elements within and between vectors, Zig provides the {#link|@shuffle#} and {#link|@select#} functions. |
| | 2509 | </p> |
| | 2510 | <p> |
| | 2511 | Operations on vectors shorter than the target machine's native SIMD size will typically compile to single SIMD |
| | 2512 | instructions, while vectors longer than the target machine's native SIMD size will compile to multiple SIMD |
| | 2513 | instructions. If a given operation doesn't have SIMD support on the target architecture, the compiler will default |
| | 2514 | to operating on each vector element one at a time. Zig supports any comptime-known vector length up to 2^32-1, |
| | 2515 | although small powers of two (2-64) are most typical. Note that excessively long vector lengths (e.g. 2^20) may |
| | 2516 | result in compiler crashes on current versions of Zig. |
| | 2517 | </p> |
| | 2518 | {#code_begin|test|vector_example#} |
| | 2519 | const std = @import("std"); |
| | 2520 | const Vector = std.meta.Vector; |
| | 2521 | const expectEqual = std.testing.expectEqual; |
| | 2522 | |
| | 2523 | test "Basic vector usage" { |
| | 2524 | // Vectors have a compile-time known length and base type, |
| | 2525 | // and can be assigned to using array literal syntax |
| | 2526 | const a: Vector(4, i32) = [_]i32{ 1, 2, 3, 4 }; |
| | 2527 | const b: Vector(4, i32) = [_]i32{ 5, 6, 7, 8 }; |
| | 2528 | |
| | 2529 | // Math operations take place element-wise |
| | 2530 | const c = a + b; |
| | 2531 | |
| | 2532 | // Individual vector elements can be accessed using array indexing syntax. |
| | 2533 | try expectEqual(6, c[0]); |
| | 2534 | try expectEqual(8, c[1]); |
| | 2535 | try expectEqual(10, c[2]); |
| | 2536 | try expectEqual(12, c[3]); |
| | 2537 | } |
| | 2538 | |
| | 2539 | test "Conversion between vectors, arrays, and slices" { |
| | 2540 | // Vectors and fixed-length arrays can be automatically assigned back and forth |
| | 2541 | var arr1: [4]f32 = [_]f32{ 1.1, 3.2, 4.5, 5.6 }; |
| | 2542 | var vec: Vector(4, f32) = arr1; |
| | 2543 | var arr2: [4]f32 = vec; |
| | 2544 | try expectEqual(arr1, arr2); |
| | 2545 | |
| | 2546 | // You can also assign from a slice with comptime-known length to a vector using .* |
| | 2547 | const vec2: Vector(2, f32) = arr1[1..3].*; |
| | 2548 | |
| | 2549 | var slice: []const f32 = &arr1; |
| | 2550 | var offset: u32 = 1; |
| | 2551 | // To extract a comptime-known length from a runtime-known offset, |
| | 2552 | // first extract a new slice from the starting offset, then an array of |
| | 2553 | // comptime known length |
| | 2554 | const vec3: Vector(2, f32) = slice[offset..][0..2].*; |
| | 2555 | try expectEqual(slice[offset], vec2[0]); |
| | 2556 | try expectEqual(slice[offset + 1], vec2[1]); |
| | 2557 | try expectEqual(vec2, vec3); |
| | 2558 | } |
| | 2559 | {#code_end#} |
| | 2560 | <p> |
| | 2561 | TODO talk about C ABI interop<br> |
| | 2562 | TODO consider suggesting std.MultiArrayList |
| | 2563 | </p> |
| | 2564 | {#see_also|@splat|@shuffle|@select|@reduce#} |
| | 2565 | |
| 2503 | {#header_close#} | 2566 | {#header_close#} |
| 2504 | | 2567 | |
| 2505 | {#header_open|Pointers#} | 2568 | {#header_open|Pointers#} |
| ... | @@ -8525,7 +8588,7 @@ test "@hasDecl" { | ... | @@ -8525,7 +8588,7 @@ test "@hasDecl" { |
| 8525 | <p> | 8588 | <p> |
| 8526 | NaNs are handled as follows: if one of the operands of a (pairwise) operation is NaN, the other operand is returned. If both operands are NaN, NaN is returned. | 8589 | NaNs are handled as follows: if one of the operands of a (pairwise) operation is NaN, the other operand is returned. If both operands are NaN, NaN is returned. |
| 8527 | </p> | 8590 | </p> |
| 8528 | {#see_also|@minimum|SIMD|Vectors#} | 8591 | {#see_also|@minimum|Vectors#} |
| 8529 | {#header_close#} | 8592 | {#header_close#} |
| 8530 | | 8593 | |
| 8531 | {#header_open|@memcpy#} | 8594 | {#header_open|@memcpy#} |
| ... | @@ -8573,7 +8636,7 @@ mem.set(u8, dest, c);{#endsyntax#}</pre> | ... | @@ -8573,7 +8636,7 @@ mem.set(u8, dest, c);{#endsyntax#}</pre> |
| 8573 | <p> | 8636 | <p> |
| 8574 | NaNs are handled as follows: if one of the operands of a (pairwise) operation is NaN, the other operand is returned. If both operands are NaN, NaN is returned. | 8637 | NaNs are handled as follows: if one of the operands of a (pairwise) operation is NaN, the other operand is returned. If both operands are NaN, NaN is returned. |
| 8575 | </p> | 8638 | </p> |
| 8576 | {#see_also|@maximum|SIMD|Vectors#} | 8639 | {#see_also|@maximum|Vectors#} |
| 8577 | {#header_close#} | 8640 | {#header_close#} |
| 8578 | | 8641 | |
| 8579 | {#header_open|@wasmMemorySize#} | 8642 | {#header_open|@wasmMemorySize#} |
| ... | @@ -8779,7 +8842,7 @@ pub const PrefetchOptions = struct { | ... | @@ -8779,7 +8842,7 @@ pub const PrefetchOptions = struct { |
| 8779 | <p> | 8842 | <p> |
| 8780 | Selects values element-wise from {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} based on {#syntax#}pred{#endsyntax#}. If {#syntax#}pred[i]{#endsyntax#} is {#syntax#}true{#endsyntax#}, the corresponding element in the result will be {#syntax#}a[i]{#endsyntax#} and otherwise {#syntax#}b[i]{#endsyntax#}. | 8843 | Selects values element-wise from {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} based on {#syntax#}pred{#endsyntax#}. If {#syntax#}pred[i]{#endsyntax#} is {#syntax#}true{#endsyntax#}, the corresponding element in the result will be {#syntax#}a[i]{#endsyntax#} and otherwise {#syntax#}b[i]{#endsyntax#}. |
| 8781 | </p> | 8844 | </p> |
| 8782 | {#see_also|SIMD|Vectors#} | 8845 | {#see_also|Vectors#} |
| 8783 | {#header_close#} | 8846 | {#header_close#} |
| 8784 | | 8847 | |
| 8785 | {#header_open|@setAlignStack#} | 8848 | {#header_open|@setAlignStack#} |
| ... | @@ -8976,7 +9039,28 @@ test "@setRuntimeSafety" { | ... | @@ -8976,7 +9039,28 @@ test "@setRuntimeSafety" { |
| 8976 | {#link|pointer|Pointers#}, or {#syntax#}bool{#endsyntax#}. The mask may be any vector length, and its | 9039 | {#link|pointer|Pointers#}, or {#syntax#}bool{#endsyntax#}. The mask may be any vector length, and its |
| 8977 | length determines the result length. | 9040 | length determines the result length. |
| 8978 | </p> | 9041 | </p> |
| 8979 | {#see_also|SIMD#} | 9042 | {#code_begin|test|vector_shuffle#} |
| | 9043 | const std = @import("std"); |
| | 9044 | const Vector = std.meta.Vector; |
| | 9045 | const expect = std.testing.expect; |
| | 9046 | |
| | 9047 | test "vector @shuffle" { |
| | 9048 | const a: Vector(7, u8) = [_]u8{ 'o', 'l', 'h', 'e', 'r', 'z', 'w' }; |
| | 9049 | const b: Vector(4, u8) = [_]u8{ 'w', 'd', '!', 'x' }; |
| | 9050 | |
| | 9051 | // To shuffle within a single vector, pass undefined as the second argument. |
| | 9052 | // Notice that we can re-order, duplicate, or omit elements of the input vector |
| | 9053 | const mask1: Vector(5, i32) = [_]i32{ 2, 3, 1, 1, 0 }; |
| | 9054 | const res1: Vector(5, u8) = @shuffle(u8, a, undefined, mask1); |
| | 9055 | try expect(std.mem.eql(u8, &@as([5]u8, res1), "hello")); |
| | 9056 | |
| | 9057 | // Combining two vectors |
| | 9058 | const mask2: Vector(6, i32) = [_]i32{ -1, 0, 4, 1, -2, -3 }; |
| | 9059 | const res2: Vector(6, u8) = @shuffle(u8, a, b, mask2); |
| | 9060 | try expect(std.mem.eql(u8, &@as([6]u8, res2), "world!")); |
| | 9061 | } |
| | 9062 | {#code_end#} |
| | 9063 | {#see_also|Vectors#} |
| 8980 | {#header_close#} | 9064 | {#header_close#} |
| 8981 | | 9065 | |
| 8982 | {#header_open|@sizeOf#} | 9066 | {#header_open|@sizeOf#} |