| author | |
| committer | |
| log | 8a30edcde82dfcd36c3eec2fb7bcd5af549325cf |
| tree | 9d45053a816d85e72daee5c168a20259be585871 |
| parent | 5e34fb35972b8ff2ec0a420779b689229d05c659 |
| parent | 925ffbce7f424548be9eb42eb3914d5035066003 |
| signature |
23 files changed, 1200 insertions(+), 180 deletions(-)
doc/langref.html.in+79-9| ... | @@ -5864,7 +5864,7 @@ volatile ( | ... | @@ -5864,7 +5864,7 @@ volatile ( |
| 5864 | : [number] "{rax}" (number), | 5864 | : [number] "{rax}" (number), |
| 5865 | [arg1] "{rdi}" (arg1) | 5865 | [arg1] "{rdi}" (arg1) |
| 5866 | // Next is the list of clobbers. These declare a set of registers whose | 5866 | // Next is the list of clobbers. These declare a set of registers whose |
| 5867 | // values will not be preserved by the execution of this assembly code. | 5867 | // values will not be preserved by the execution of this assembly code. |
| 5868 | // These do not include output or input registers. The special clobber | 5868 | // These do not include output or input registers. The special clobber |
| 5869 | // value of "memory" means that the assembly writes to arbitrary undeclared | 5869 | // value of "memory" means that the assembly writes to arbitrary undeclared |
| 5870 | // memory locations - not only the memory pointed to by a declared indirect | 5870 | // memory locations - not only the memory pointed to by a declared indirect |
| ... | @@ -5885,7 +5885,7 @@ volatile ( | ... | @@ -5885,7 +5885,7 @@ volatile ( |
| 5885 | </p> | 5885 | </p> |
| 5886 | {#header_open|Output Constraints#} | 5886 | {#header_open|Output Constraints#} |
| 5887 | <p> | 5887 | <p> |
| 5888 | Output constraints are still considered to be unstable in Zig, and | 5888 | Output constraints are still considered to be unstable in Zig, and |
| 5889 | so | 5889 | so |
| 5890 | <a href="http://releases.llvm.org/8.0.0/docs/LangRef.html#inline-asm-constraint-string">LLVM documentation</a> | 5890 | <a href="http://releases.llvm.org/8.0.0/docs/LangRef.html#inline-asm-constraint-string">LLVM documentation</a> |
| 5891 | and | 5891 | and |
| ... | @@ -5900,7 +5900,7 @@ volatile ( | ... | @@ -5900,7 +5900,7 @@ volatile ( |
| 5900 | 5900 | ||
| 5901 | {#header_open|Input Constraints#} | 5901 | {#header_open|Input Constraints#} |
| 5902 | <p> | 5902 | <p> |
| 5903 | Input constraints are still considered to be unstable in Zig, and | 5903 | Input constraints are still considered to be unstable in Zig, and |
| 5904 | so | 5904 | so |
| 5905 | <a href="http://releases.llvm.org/8.0.0/docs/LangRef.html#inline-asm-constraint-string">LLVM documentation</a> | 5905 | <a href="http://releases.llvm.org/8.0.0/docs/LangRef.html#inline-asm-constraint-string">LLVM documentation</a> |
| 5906 | and | 5906 | and |
| ... | @@ -5919,7 +5919,7 @@ volatile ( | ... | @@ -5919,7 +5919,7 @@ volatile ( |
| 5919 | the assembly code. These do not include output or input registers. The special clobber | 5919 | the assembly code. These do not include output or input registers. The special clobber |
| 5920 | value of {#syntax#}"memory"{#endsyntax#} means that the assembly causes writes to | 5920 | value of {#syntax#}"memory"{#endsyntax#} means that the assembly causes writes to |
| 5921 | arbitrary undeclared memory locations - not only the memory pointed to by a declared | 5921 | arbitrary undeclared memory locations - not only the memory pointed to by a declared |
| 5922 | indirect output. | 5922 | indirect output. |
| 5923 | </p> | 5923 | </p> |
| 5924 | <p> | 5924 | <p> |
| 5925 | Failure to declare the full set of clobbers for a given inline assembly | 5925 | Failure to declare the full set of clobbers for a given inline assembly |
| ... | @@ -6542,12 +6542,21 @@ async fn func(y: *i32) void { | ... | @@ -6542,12 +6542,21 @@ async fn func(y: *i32) void { |
| 6542 | {#header_close#} | 6542 | {#header_close#} |
| 6543 | 6543 | ||
| 6544 | {#header_open|@byteSwap#} | 6544 | {#header_open|@byteSwap#} |
| 6545 | <pre>{#syntax#}@byteSwap(comptime T: type, integer: T) T{#endsyntax#}</pre> | 6545 | <pre>{#syntax#}@byteSwap(comptime T: type, operand: T) T{#endsyntax#}</pre> |
| 6546 | <p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p> | 6546 | <p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p> |
| 6547 | <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p> | ||
| 6547 | <p> | 6548 | <p> |
| 6548 | Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, | 6549 | Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, |
| 6549 | and converts a little endian integer to a big endian integer. | 6550 | and converts a little endian integer to a big endian integer. |
| 6550 | </p> | 6551 | </p> |
| 6552 | <p> | ||
| 6553 | Note that for the purposes of memory layout with respect to endianness, the integer type should be | ||
| 6554 | related to the number of bytes reported by {#link|@sizeOf#} bytes. This is demonstrated with | ||
| 6555 | {#syntax#}u24{#endsyntax#}. {#syntax#}@sizeOf(u24) == 4{#endsyntax#}, which means that a | ||
| 6556 | {#syntax#}u24{#endsyntax#} stored in memory takes 4 bytes, and those 4 bytes are what are swapped on | ||
| 6557 | a little vs big endian system. On the other hand, if {#syntax#}T{#endsyntax#} is specified to | ||
| 6558 | be {#syntax#}u24{#endsyntax#}, then only 3 bytes are reversed. | ||
| 6559 | </p> | ||
| 6551 | {#header_close#} | 6560 | {#header_close#} |
| 6552 | 6561 | ||
| 6553 | {#header_open|@bitReverse#} | 6562 | {#header_open|@bitReverse#} |
| ... | @@ -6641,7 +6650,7 @@ async fn func(y: *i32) void { | ... | @@ -6641,7 +6650,7 @@ async fn func(y: *i32) void { |
| 6641 | {#header_open|@clz#} | 6650 | {#header_open|@clz#} |
| 6642 | <pre>{#syntax#}@clz(comptime T: type, integer: T){#endsyntax#}</pre> | 6651 | <pre>{#syntax#}@clz(comptime T: type, integer: T){#endsyntax#}</pre> |
| 6643 | <p> | 6652 | <p> |
| 6644 | This function counts the number of leading zeroes in {#syntax#}integer{#endsyntax#}. | 6653 | This function counts the number of most-significant (leading in a big-Endian sense) zeroes in {#syntax#}integer{#endsyntax#}. |
| 6645 | </p> | 6654 | </p> |
| 6646 | <p> | 6655 | <p> |
| 6647 | If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#}, | 6656 | If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#}, |
| ... | @@ -6783,7 +6792,7 @@ test "main" { | ... | @@ -6783,7 +6792,7 @@ test "main" { |
| 6783 | {#header_open|@ctz#} | 6792 | {#header_open|@ctz#} |
| 6784 | <pre>{#syntax#}@ctz(comptime T: type, integer: T){#endsyntax#}</pre> | 6793 | <pre>{#syntax#}@ctz(comptime T: type, integer: T){#endsyntax#}</pre> |
| 6785 | <p> | 6794 | <p> |
| 6786 | This function counts the number of trailing zeroes in {#syntax#}integer{#endsyntax#}. | 6795 | This function counts the number of least-significant (trailing in a big-Endian sense) zeroes in {#syntax#}integer{#endsyntax#}. |
| 6787 | </p> | 6796 | </p> |
| 6788 | <p> | 6797 | <p> |
| 6789 | If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#}, | 6798 | If {#syntax#}integer{#endsyntax#} is known at {#link|comptime#}, |
| ... | @@ -7673,6 +7682,43 @@ test "@setRuntimeSafety" { | ... | @@ -7673,6 +7682,43 @@ test "@setRuntimeSafety" { |
| 7673 | {#see_also|@shlExact|@shlWithOverflow#} | 7682 | {#see_also|@shlExact|@shlWithOverflow#} |
| 7674 | {#header_close#} | 7683 | {#header_close#} |
| 7675 | 7684 | ||
| 7685 | {#header_open|@shuffle#} | ||
| 7686 | <pre>{#syntax#}@shuffle(comptime E: type, a: @Vector(a_len, E), b: @Vector(b_len, E), comptime mask: @Vector(mask_len, i32)) @Vector(mask_len, E){#endsyntax#}</pre> | ||
| 7687 | <p> | ||
| 7688 | Constructs a new {#link|vector|Vectors#} by selecting elements from {#syntax#}a{#endsyntax#} and | ||
| 7689 | {#syntax#}b{#endsyntax#} based on {#syntax#}mask{#endsyntax#}. | ||
| 7690 | </p> | ||
| 7691 | <p> | ||
| 7692 | Each element in {#syntax#}mask{#endsyntax#} selects an element from either {#syntax#}a{#endsyntax#} or | ||
| 7693 | {#syntax#}b{#endsyntax#}. Positive numbers select from {#syntax#}a{#endsyntax#} starting at 0. | ||
| 7694 | Negative values select from {#syntax#}b{#endsyntax#}, starting at {#syntax#}-1{#endsyntax#} and going down. | ||
| 7695 | It is recommended to use the {#syntax#}~{#endsyntax#} operator from indexes from {#syntax#}b{#endsyntax#} | ||
| 7696 | so that both indexes can start from {#syntax#}0{#endsyntax#} (i.e. {#syntax#}~i32(0){#endsyntax#} is | ||
| 7697 | {#syntax#}-1{#endsyntax#}). | ||
| 7698 | </p> | ||
| 7699 | <p> | ||
| 7700 | For each element of {#syntax#}mask{#endsyntax#}, if it or the selected value from | ||
| 7701 | {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} is {#syntax#}undefined{#endsyntax#}, | ||
| 7702 | then the resulting element is {#syntax#}undefined{#endsyntax#}. | ||
| 7703 | </p> | ||
| 7704 | <p> | ||
| 7705 | {#syntax#}a_len{#endsyntax#} and {#syntax#}b_len{#endsyntax#} may differ in length. Out-of-bounds element | ||
| 7706 | indexes in {#syntax#}mask{#endsyntax#} result in compile errors. | ||
| 7707 | </p> | ||
| 7708 | <p> | ||
| 7709 | If {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} is {#syntax#}undefined{#endsyntax#}, it | ||
| 7710 | is equivalent to a vector of all {#syntax#}undefined{#endsyntax#} with the same length as the other vector. | ||
| 7711 | If both vectors are {#syntax#}undefined{#endsyntax#}, {#syntax#}@shuffle{#endsyntax#} returns | ||
| 7712 | a vector with all elements {#syntax#}undefined{#endsyntax#}. | ||
| 7713 | </p> | ||
| 7714 | <p> | ||
| 7715 | {#syntax#}E{#endsyntax#} must be an {#link|integer|Integers#}, {#link|float|Floats#}, | ||
| 7716 | {#link|pointer|Pointers#}, or {#syntax#}bool{#endsyntax#}. The mask may be any vector length, and its | ||
| 7717 | length determines the result length. | ||
| 7718 | </p> | ||
| 7719 | {#see_also|SIMD#} | ||
| 7720 | {#header_close#} | ||
| 7721 | |||
| 7676 | {#header_open|@sizeOf#} | 7722 | {#header_open|@sizeOf#} |
| 7677 | <pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre> | 7723 | <pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre> |
| 7678 | <p> | 7724 | <p> |
| ... | @@ -7700,6 +7746,30 @@ test "@setRuntimeSafety" { | ... | @@ -7700,6 +7746,30 @@ test "@setRuntimeSafety" { |
| 7700 | </p> | 7746 | </p> |
| 7701 | {#header_close#} | 7747 | {#header_close#} |
| 7702 | 7748 | ||
| 7749 | {#header_open|@splat#} | ||
| 7750 | <pre>{#syntax#}@splat(comptime len: u32, scalar: var) @Vector(len, @typeOf(scalar)){#endsyntax#}</pre> | ||
| 7751 | <p> | ||
| 7752 | Produces a vector of length {#syntax#}len{#endsyntax#} where each element is the value | ||
| 7753 | {#syntax#}scalar{#endsyntax#}: | ||
| 7754 | </p> | ||
| 7755 | {#code_begin|test#} | ||
| 7756 | const std = @import("std"); | ||
| 7757 | const assert = std.debug.assert; | ||
| 7758 | |||
| 7759 | test "vector @splat" { | ||
| 7760 | const scalar: u32 = 5; | ||
| 7761 | const result = @splat(4, scalar); | ||
| 7762 | comptime assert(@typeOf(result) == @Vector(4, u32)); | ||
| 7763 | assert(std.mem.eql(u32, ([4]u32)(result), [_]u32{ 5, 5, 5, 5 })); | ||
| 7764 | } | ||
| 7765 | {#code_end#} | ||
| 7766 | <p> | ||
| 7767 | {#syntax#}scalar{#endsyntax#} must be an {#link|integer|Integers#}, {#link|bool|Primitive Types#}, | ||
| 7768 | {#link|float|Floats#}, or {#link|pointer|Pointers#}. | ||
| 7769 | </p> | ||
| 7770 | {#see_also|Vectors|@shuffle#} | ||
| 7771 | {#header_close#} | ||
| 7772 | |||
| 7703 | {#header_open|@sqrt#} | 7773 | {#header_open|@sqrt#} |
| 7704 | <pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre> | 7774 | <pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre> |
| 7705 | <p> | 7775 | <p> |
| ... | @@ -9411,8 +9481,8 @@ const c = @cImport({ | ... | @@ -9411,8 +9481,8 @@ const c = @cImport({ |
| 9411 | <li>Does not support Zig-only pointer attributes such as alignment. Use normal {#link|Pointers#} | 9481 | <li>Does not support Zig-only pointer attributes such as alignment. Use normal {#link|Pointers#} |
| 9412 | please!</li> | 9482 | please!</li> |
| 9413 | </ul> | 9483 | </ul> |
| 9414 | <p>When a C pointer is pointing to a single struct (not an array), deference the C pointer to | 9484 | <p>When a C pointer is pointing to a single struct (not an array), deference the C pointer to |
| 9415 | access to the struct's fields or member data. That syntax looks like | 9485 | access to the struct's fields or member data. That syntax looks like |
| 9416 | this: </p> | 9486 | this: </p> |
| 9417 | <p>{#syntax#}ptr_to_struct.*.struct_member{#endsyntax#}</p> | 9487 | <p>{#syntax#}ptr_to_struct.*.struct_member{#endsyntax#}</p> |
| 9418 | <p>This is comparable to doing {#syntax#}->{#endsyntax#} in C.</p> | 9488 | <p>This is comparable to doing {#syntax#}->{#endsyntax#} in C.</p> |
src/all_types.hpp+29-1| ... | @@ -1351,7 +1351,7 @@ struct ZigTypeBoundFn { | ... | @@ -1351,7 +1351,7 @@ struct ZigTypeBoundFn { |
| 1351 | }; | 1351 | }; |
| 1352 | 1352 | ||
| 1353 | struct ZigTypeVector { | 1353 | struct ZigTypeVector { |
| 1354 | // The type must be a pointer, integer, or float | 1354 | // The type must be a pointer, integer, bool, or float |
| 1355 | ZigType *elem_type; | 1355 | ZigType *elem_type; |
| 1356 | uint32_t len; | 1356 | uint32_t len; |
| 1357 | }; | 1357 | }; |
| ... | @@ -1611,6 +1611,8 @@ enum BuiltinFnId { | ... | @@ -1611,6 +1611,8 @@ enum BuiltinFnId { |
| 1611 | BuiltinFnIdIntToEnum, | 1611 | BuiltinFnIdIntToEnum, |
| 1612 | BuiltinFnIdIntType, | 1612 | BuiltinFnIdIntType, |
| 1613 | BuiltinFnIdVectorType, | 1613 | BuiltinFnIdVectorType, |
| 1614 | BuiltinFnIdShuffle, | ||
| 1615 | BuiltinFnIdSplat, | ||
| 1614 | BuiltinFnIdSetCold, | 1616 | BuiltinFnIdSetCold, |
| 1615 | BuiltinFnIdSetRuntimeSafety, | 1617 | BuiltinFnIdSetRuntimeSafety, |
| 1616 | BuiltinFnIdSetFloatMode, | 1618 | BuiltinFnIdSetFloatMode, |
| ... | @@ -1770,6 +1772,7 @@ struct ZigLLVMFnKey { | ... | @@ -1770,6 +1772,7 @@ struct ZigLLVMFnKey { |
| 1770 | } overflow_arithmetic; | 1772 | } overflow_arithmetic; |
| 1771 | struct { | 1773 | struct { |
| 1772 | uint32_t bit_count; | 1774 | uint32_t bit_count; |
| 1775 | uint32_t vector_len; // 0 means not a vector | ||
| 1773 | } bswap; | 1776 | } bswap; |
| 1774 | struct { | 1777 | struct { |
| 1775 | uint32_t bit_count; | 1778 | uint32_t bit_count; |
| ... | @@ -2428,6 +2431,9 @@ enum IrInstructionId { | ... | @@ -2428,6 +2431,9 @@ enum IrInstructionId { |
| 2428 | IrInstructionIdBoolToInt, | 2431 | IrInstructionIdBoolToInt, |
| 2429 | IrInstructionIdIntType, | 2432 | IrInstructionIdIntType, |
| 2430 | IrInstructionIdVectorType, | 2433 | IrInstructionIdVectorType, |
| 2434 | IrInstructionIdShuffleVector, | ||
| 2435 | IrInstructionIdSplatSrc, | ||
| 2436 | IrInstructionIdSplatGen, | ||
| 2431 | IrInstructionIdBoolNot, | 2437 | IrInstructionIdBoolNot, |
| 2432 | IrInstructionIdMemset, | 2438 | IrInstructionIdMemset, |
| 2433 | IrInstructionIdMemcpy, | 2439 | IrInstructionIdMemcpy, |
| ... | @@ -3669,6 +3675,28 @@ struct IrInstructionVectorToArray { | ... | @@ -3669,6 +3675,28 @@ struct IrInstructionVectorToArray { |
| 3669 | IrInstruction *result_loc; | 3675 | IrInstruction *result_loc; |
| 3670 | }; | 3676 | }; |
| 3671 | 3677 | ||
| 3678 | struct IrInstructionShuffleVector { | ||
| 3679 | IrInstruction base; | ||
| 3680 | |||
| 3681 | IrInstruction *scalar_type; | ||
| 3682 | IrInstruction *a; | ||
| 3683 | IrInstruction *b; | ||
| 3684 | IrInstruction *mask; // This is in zig-format, not llvm format | ||
| 3685 | }; | ||
| 3686 | |||
| 3687 | struct IrInstructionSplatSrc { | ||
| 3688 | IrInstruction base; | ||
| 3689 | |||
| 3690 | IrInstruction *len; | ||
| 3691 | IrInstruction *scalar; | ||
| 3692 | }; | ||
| 3693 | |||
| 3694 | struct IrInstructionSplatGen { | ||
| 3695 | IrInstruction base; | ||
| 3696 | |||
| 3697 | IrInstruction *scalar; | ||
| 3698 | }; | ||
| 3699 | |||
| 3672 | struct IrInstructionAssertZero { | 3700 | struct IrInstructionAssertZero { |
| 3673 | IrInstruction base; | 3701 | IrInstruction base; |
| 3674 | 3702 |
src/analyze.cpp+6-3| ... | @@ -4708,6 +4708,7 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { | ... | @@ -4708,6 +4708,7 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { |
| 4708 | bool is_valid_vector_elem_type(ZigType *elem_type) { | 4708 | bool is_valid_vector_elem_type(ZigType *elem_type) { |
| 4709 | return elem_type->id == ZigTypeIdInt || | 4709 | return elem_type->id == ZigTypeIdInt || |
| 4710 | elem_type->id == ZigTypeIdFloat || | 4710 | elem_type->id == ZigTypeIdFloat || |
| 4711 | elem_type->id == ZigTypeIdBool || | ||
| 4711 | get_codegen_ptr_type(elem_type) != nullptr; | 4712 | get_codegen_ptr_type(elem_type) != nullptr; |
| 4712 | } | 4713 | } |
| 4713 | 4714 | ||
| ... | @@ -4727,7 +4728,7 @@ ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { | ... | @@ -4727,7 +4728,7 @@ ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { |
| 4727 | 4728 | ||
| 4728 | ZigType *entry = new_type_table_entry(ZigTypeIdVector); | 4729 | ZigType *entry = new_type_table_entry(ZigTypeIdVector); |
| 4729 | if ((len != 0) && type_has_bits(elem_type)) { | 4730 | if ((len != 0) && type_has_bits(elem_type)) { |
| 4730 | // Vectors can only be ints, floats, or pointers. ints and floats have trivially resolvable | 4731 | // Vectors can only be ints, floats, bools, or pointers. ints (inc. bools) and floats have trivially resolvable |
| 4731 | // llvm type refs. pointers we will use usize instead. | 4732 | // llvm type refs. pointers we will use usize instead. |
| 4732 | LLVMTypeRef example_vector_llvm_type; | 4733 | LLVMTypeRef example_vector_llvm_type; |
| 4733 | if (elem_type->id == ZigTypeIdPointer) { | 4734 | if (elem_type->id == ZigTypeIdPointer) { |
| ... | @@ -6895,7 +6896,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { | ... | @@ -6895,7 +6896,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { |
| 6895 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + | 6896 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + |
| 6896 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); | 6897 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); |
| 6897 | case ZigLLVMFnIdBswap: | 6898 | case ZigLLVMFnIdBswap: |
| 6898 | return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; | 6899 | return (uint32_t)(x.data.bswap.bit_count) * ((uint32_t)3661994335) + |
| 6900 | (uint32_t)(x.data.bswap.vector_len) * (((uint32_t)x.id << 5) + 1025); | ||
| 6899 | case ZigLLVMFnIdBitReverse: | 6901 | case ZigLLVMFnIdBitReverse: |
| 6900 | return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; | 6902 | return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; |
| 6901 | case ZigLLVMFnIdOverflowArithmetic: | 6903 | case ZigLLVMFnIdOverflowArithmetic: |
| ... | @@ -6918,7 +6920,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { | ... | @@ -6918,7 +6920,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 6918 | case ZigLLVMFnIdPopCount: | 6920 | case ZigLLVMFnIdPopCount: |
| 6919 | return a.data.pop_count.bit_count == b.data.pop_count.bit_count; | 6921 | return a.data.pop_count.bit_count == b.data.pop_count.bit_count; |
| 6920 | case ZigLLVMFnIdBswap: | 6922 | case ZigLLVMFnIdBswap: |
| 6921 | return a.data.bswap.bit_count == b.data.bswap.bit_count; | 6923 | return a.data.bswap.bit_count == b.data.bswap.bit_count && |
| 6924 | a.data.bswap.vector_len == b.data.bswap.vector_len; | ||
| 6922 | case ZigLLVMFnIdBitReverse: | 6925 | case ZigLLVMFnIdBitReverse: |
| 6923 | return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; | 6926 | return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; |
| 6924 | case ZigLLVMFnIdFloatOp: | 6927 | case ZigLLVMFnIdFloatOp: |
src/codegen.cpp+131-20| ... | @@ -4505,7 +4505,11 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec | ... | @@ -4505,7 +4505,11 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec |
| 4505 | } | 4505 | } |
| 4506 | } | 4506 | } |
| 4507 | 4507 | ||
| 4508 | static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnId fn_id) { | 4508 | static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *expr_type, BuiltinFnId fn_id) { |
| 4509 | bool is_vector = expr_type->id == ZigTypeIdVector; | ||
| 4510 | ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; | ||
| 4511 | assert(int_type->id == ZigTypeIdInt); | ||
| 4512 | uint32_t vector_len = is_vector ? expr_type->data.vector.len : 0; | ||
| 4509 | ZigLLVMFnKey key = {}; | 4513 | ZigLLVMFnKey key = {}; |
| 4510 | const char *fn_name; | 4514 | const char *fn_name; |
| 4511 | uint32_t n_args; | 4515 | uint32_t n_args; |
| ... | @@ -4529,6 +4533,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI | ... | @@ -4529,6 +4533,7 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI |
| 4529 | n_args = 1; | 4533 | n_args = 1; |
| 4530 | key.id = ZigLLVMFnIdBswap; | 4534 | key.id = ZigLLVMFnIdBswap; |
| 4531 | key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; | 4535 | key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count; |
| 4536 | key.data.bswap.vector_len = vector_len; | ||
| 4532 | } else if (fn_id == BuiltinFnIdBitReverse) { | 4537 | } else if (fn_id == BuiltinFnIdBitReverse) { |
| 4533 | fn_name = "bitreverse"; | 4538 | fn_name = "bitreverse"; |
| 4534 | n_args = 1; | 4539 | n_args = 1; |
| ... | @@ -4543,12 +4548,15 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI | ... | @@ -4543,12 +4548,15 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI |
| 4543 | return existing_entry->value; | 4548 | return existing_entry->value; |
| 4544 | 4549 | ||
| 4545 | char llvm_name[64]; | 4550 | char llvm_name[64]; |
| 4546 | sprintf(llvm_name, "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count); | 4551 | if (is_vector) |
| 4552 | sprintf(llvm_name, "llvm.%s.v%" PRIu32 "i%" PRIu32, fn_name, vector_len, int_type->data.integral.bit_count); | ||
| 4553 | else | ||
| 4554 | sprintf(llvm_name, "llvm.%s.i%" PRIu32, fn_name, int_type->data.integral.bit_count); | ||
| 4547 | LLVMTypeRef param_types[] = { | 4555 | LLVMTypeRef param_types[] = { |
| 4548 | get_llvm_type(g, int_type), | 4556 | get_llvm_type(g, expr_type), |
| 4549 | LLVMInt1Type(), | 4557 | LLVMInt1Type(), |
| 4550 | }; | 4558 | }; |
| 4551 | LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, int_type), param_types, n_args, false); | 4559 | LLVMTypeRef fn_type = LLVMFunctionType(get_llvm_type(g, expr_type), param_types, n_args, false); |
| 4552 | LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type); | 4560 | LLVMValueRef fn_val = LLVMAddFunction(g->module, llvm_name, fn_type); |
| 4553 | assert(LLVMGetIntrinsicID(fn_val)); | 4561 | assert(LLVMGetIntrinsicID(fn_val)); |
| 4554 | 4562 | ||
| ... | @@ -4581,6 +4589,48 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru | ... | @@ -4581,6 +4589,48 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru |
| 4581 | return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int); | 4589 | return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int); |
| 4582 | } | 4590 | } |
| 4583 | 4591 | ||
| 4592 | static LLVMValueRef ir_render_shuffle_vector(CodeGen *g, IrExecutable *executable, IrInstructionShuffleVector *instruction) { | ||
| 4593 | uint64_t len_a = instruction->a->value.type->data.vector.len; | ||
| 4594 | uint64_t len_mask = instruction->mask->value.type->data.vector.len; | ||
| 4595 | |||
| 4596 | // LLVM uses integers larger than the length of the first array to | ||
| 4597 | // index into the second array. This was deemed unnecessarily fragile | ||
| 4598 | // when changing code, so Zig uses negative numbers to index the | ||
| 4599 | // second vector. These start at -1 and go down, and are easiest to use | ||
| 4600 | // with the ~ operator. Here we convert between the two formats. | ||
| 4601 | IrInstruction *mask = instruction->mask; | ||
| 4602 | LLVMValueRef *values = allocate<LLVMValueRef>(len_mask); | ||
| 4603 | for (uint64_t i = 0; i < len_mask; i++) { | ||
| 4604 | if (mask->value.data.x_array.data.s_none.elements[i].special == ConstValSpecialUndef) { | ||
| 4605 | values[i] = LLVMGetUndef(LLVMInt32Type()); | ||
| 4606 | } else { | ||
| 4607 | int32_t v = bigint_as_signed(&mask->value.data.x_array.data.s_none.elements[i].data.x_bigint); | ||
| 4608 | uint32_t index_val = (v >= 0) ? (uint32_t)v : (uint32_t)~v + (uint32_t)len_a; | ||
| 4609 | values[i] = LLVMConstInt(LLVMInt32Type(), index_val, false); | ||
| 4610 | } | ||
| 4611 | } | ||
| 4612 | |||
| 4613 | LLVMValueRef llvm_mask_value = LLVMConstVector(values, len_mask); | ||
| 4614 | free(values); | ||
| 4615 | |||
| 4616 | return LLVMBuildShuffleVector(g->builder, | ||
| 4617 | ir_llvm_value(g, instruction->a), | ||
| 4618 | ir_llvm_value(g, instruction->b), | ||
| 4619 | llvm_mask_value, ""); | ||
| 4620 | } | ||
| 4621 | |||
| 4622 | static LLVMValueRef ir_render_splat(CodeGen *g, IrExecutable *executable, IrInstructionSplatGen *instruction) { | ||
| 4623 | ZigType *result_type = instruction->base.value.type; | ||
| 4624 | src_assert(result_type->id == ZigTypeIdVector, instruction->base.source_node); | ||
| 4625 | uint32_t len = result_type->data.vector.len; | ||
| 4626 | LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value.type), 1); | ||
| 4627 | LLVMTypeRef mask_llvm_type = LLVMVectorType(LLVMInt32Type(), len); | ||
| 4628 | LLVMValueRef undef_vector = LLVMGetUndef(op_llvm_type); | ||
| 4629 | LLVMValueRef op_vector = LLVMBuildInsertElement(g->builder, undef_vector, | ||
| 4630 | ir_llvm_value(g, instruction->scalar), LLVMConstInt(LLVMInt32Type(), 0, false), ""); | ||
| 4631 | return LLVMBuildShuffleVector(g->builder, op_vector, undef_vector, LLVMConstNull(mask_llvm_type), ""); | ||
| 4632 | } | ||
| 4633 | |||
| 4584 | static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) { | 4634 | static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) { |
| 4585 | ZigType *int_type = instruction->op->value.type; | 4635 | ZigType *int_type = instruction->op->value.type; |
| 4586 | LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount); | 4636 | LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount); |
| ... | @@ -5512,25 +5562,36 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrIn | ... | @@ -5512,25 +5562,36 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrIn |
| 5512 | 5562 | ||
| 5513 | static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { | 5563 | static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { |
| 5514 | LLVMValueRef op = ir_llvm_value(g, instruction->op); | 5564 | LLVMValueRef op = ir_llvm_value(g, instruction->op); |
| 5515 | ZigType *int_type = instruction->base.value.type; | 5565 | ZigType *expr_type = instruction->base.value.type; |
| 5566 | bool is_vector = expr_type->id == ZigTypeIdVector; | ||
| 5567 | ZigType *int_type = is_vector ? expr_type->data.vector.elem_type : expr_type; | ||
| 5516 | assert(int_type->id == ZigTypeIdInt); | 5568 | assert(int_type->id == ZigTypeIdInt); |
| 5517 | if (int_type->data.integral.bit_count % 16 == 0) { | 5569 | if (int_type->data.integral.bit_count % 16 == 0) { |
| 5518 | LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap); | 5570 | LLVMValueRef fn_val = get_int_builtin_fn(g, expr_type, BuiltinFnIdBswap); |
| 5519 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); | 5571 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); |
| 5520 | } | 5572 | } |
| 5521 | // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate | 5573 | // Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate |
| 5522 | ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, | 5574 | ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed, |
| 5523 | int_type->data.integral.bit_count + 8); | 5575 | int_type->data.integral.bit_count + 8); |
| 5576 | LLVMValueRef shift_amt = LLVMConstInt(get_llvm_type(g, extended_type), 8, false); | ||
| 5577 | if (is_vector) { | ||
| 5578 | extended_type = get_vector_type(g, expr_type->data.vector.len, extended_type); | ||
| 5579 | LLVMValueRef *values = allocate_nonzero<LLVMValueRef>(expr_type->data.vector.len); | ||
| 5580 | for (uint32_t i = 0; i < expr_type->data.vector.len; i += 1) { | ||
| 5581 | values[i] = shift_amt; | ||
| 5582 | } | ||
| 5583 | shift_amt = LLVMConstVector(values, expr_type->data.vector.len); | ||
| 5584 | free(values); | ||
| 5585 | } | ||
| 5524 | // aabbcc | 5586 | // aabbcc |
| 5525 | LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), ""); | 5587 | LLVMValueRef extended = LLVMBuildZExt(g->builder, op, get_llvm_type(g, extended_type), ""); |
| 5526 | // 00aabbcc | 5588 | // 00aabbcc |
| 5527 | LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); | 5589 | LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap); |
| 5528 | LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, ""); | 5590 | LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, ""); |
| 5529 | // ccbbaa00 | 5591 | // ccbbaa00 |
| 5530 | LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, | 5592 | LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped, shift_amt, ""); |
| 5531 | LLVMConstInt(get_llvm_type(g, extended_type), 8, false), ""); | ||
| 5532 | // 00ccbbaa | 5593 | // 00ccbbaa |
| 5533 | return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, int_type), ""); | 5594 | return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), ""); |
| 5534 | } | 5595 | } |
| 5535 | 5596 | ||
| 5536 | static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) { | 5597 | static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) { |
| ... | @@ -5549,10 +5610,29 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab | ... | @@ -5549,10 +5610,29 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab |
| 5549 | assert(handle_is_ptr(array_type)); | 5610 | assert(handle_is_ptr(array_type)); |
| 5550 | LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); | 5611 | LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); |
| 5551 | LLVMValueRef vector = ir_llvm_value(g, instruction->vector); | 5612 | LLVMValueRef vector = ir_llvm_value(g, instruction->vector); |
| 5552 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, | 5613 | |
| 5553 | LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); | 5614 | ZigType *elem_type = array_type->data.array.child_type; |
| 5554 | uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type); | 5615 | bool bitcast_ok = elem_type->size_in_bits == elem_type->abi_size * 8; |
| 5555 | gen_store_untyped(g, vector, casted_ptr, alignment, false); | 5616 | if (bitcast_ok) { |
| 5617 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, | ||
| 5618 | LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); | ||
| 5619 | uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type); | ||
| 5620 | gen_store_untyped(g, vector, casted_ptr, alignment, false); | ||
| 5621 | } else { | ||
| 5622 | // If the ABI size of the element type is not evenly divisible by size_in_bits, a simple bitcast | ||
| 5623 | // will not work, and we fall back to extractelement. | ||
| 5624 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; | ||
| 5625 | LLVMTypeRef u32_type_ref = LLVMInt32Type(); | ||
| 5626 | LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false); | ||
| 5627 | for (uintptr_t i = 0; i < instruction->vector->value.type->data.vector.len; i++) { | ||
| 5628 | LLVMValueRef index_usize = LLVMConstInt(usize_type_ref, i, false); | ||
| 5629 | LLVMValueRef index_u32 = LLVMConstInt(u32_type_ref, i, false); | ||
| 5630 | LLVMValueRef indexes[] = { zero, index_usize }; | ||
| 5631 | LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, result_loc, indexes, 2, ""); | ||
| 5632 | LLVMValueRef elem = LLVMBuildExtractElement(g->builder, vector, index_u32, ""); | ||
| 5633 | LLVMBuildStore(g->builder, elem, elem_ptr); | ||
| 5634 | } | ||
| 5635 | } | ||
| 5556 | return result_loc; | 5636 | return result_loc; |
| 5557 | } | 5637 | } |
| 5558 | 5638 | ||
| ... | @@ -5563,12 +5643,34 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab | ... | @@ -5563,12 +5643,34 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab |
| 5563 | assert(vector_type->id == ZigTypeIdVector); | 5643 | assert(vector_type->id == ZigTypeIdVector); |
| 5564 | assert(!handle_is_ptr(vector_type)); | 5644 | assert(!handle_is_ptr(vector_type)); |
| 5565 | LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array); | 5645 | LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array); |
| 5566 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, | 5646 | LLVMTypeRef vector_type_ref = get_llvm_type(g, vector_type); |
| 5567 | LLVMPointerType(get_llvm_type(g, vector_type), 0), ""); | 5647 | |
| 5568 | ZigType *array_type = instruction->array->value.type; | 5648 | ZigType *elem_type = vector_type->data.vector.elem_type; |
| 5569 | assert(array_type->id == ZigTypeIdArray); | 5649 | bool bitcast_ok = elem_type->size_in_bits == elem_type->abi_size * 8; |
| 5570 | uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type); | 5650 | if (bitcast_ok) { |
| 5571 | return gen_load_untyped(g, casted_ptr, alignment, false, ""); | 5651 | LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr, |
| 5652 | LLVMPointerType(vector_type_ref, 0), ""); | ||
| 5653 | ZigType *array_type = instruction->array->value.type; | ||
| 5654 | assert(array_type->id == ZigTypeIdArray); | ||
| 5655 | uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type); | ||
| 5656 | return gen_load_untyped(g, casted_ptr, alignment, false, ""); | ||
| 5657 | } else { | ||
| 5658 | // If the ABI size of the element type is not evenly divisible by size_in_bits, a simple bitcast | ||
| 5659 | // will not work, and we fall back to insertelement. | ||
| 5660 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; | ||
| 5661 | LLVMTypeRef u32_type_ref = LLVMInt32Type(); | ||
| 5662 | LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false); | ||
| 5663 | LLVMValueRef vector = LLVMGetUndef(vector_type_ref); | ||
| 5664 | for (uintptr_t i = 0; i < instruction->base.value.type->data.vector.len; i++) { | ||
| 5665 | LLVMValueRef index_usize = LLVMConstInt(usize_type_ref, i, false); | ||
| 5666 | LLVMValueRef index_u32 = LLVMConstInt(u32_type_ref, i, false); | ||
| 5667 | LLVMValueRef indexes[] = { zero, index_usize }; | ||
| 5668 | LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indexes, 2, ""); | ||
| 5669 | LLVMValueRef elem = LLVMBuildLoad(g->builder, elem_ptr, ""); | ||
| 5670 | vector = LLVMBuildInsertElement(g->builder, vector, elem, index_u32, ""); | ||
| 5671 | } | ||
| 5672 | return vector; | ||
| 5673 | } | ||
| 5572 | } | 5674 | } |
| 5573 | 5675 | ||
| 5574 | static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable, | 5676 | static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable, |
| ... | @@ -5896,6 +5998,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5896,6 +5998,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5896 | case IrInstructionIdFrameSizeSrc: | 5998 | case IrInstructionIdFrameSizeSrc: |
| 5897 | case IrInstructionIdAllocaGen: | 5999 | case IrInstructionIdAllocaGen: |
| 5898 | case IrInstructionIdAwaitSrc: | 6000 | case IrInstructionIdAwaitSrc: |
| 6001 | case IrInstructionIdSplatSrc: | ||
| 5899 | zig_unreachable(); | 6002 | zig_unreachable(); |
| 5900 | 6003 | ||
| 5901 | case IrInstructionIdDeclVarGen: | 6004 | case IrInstructionIdDeclVarGen: |
| ... | @@ -6054,6 +6157,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -6054,6 +6157,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 6054 | return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction); | 6157 | return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction); |
| 6055 | case IrInstructionIdSpillEnd: | 6158 | case IrInstructionIdSpillEnd: |
| 6056 | return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction); | 6159 | return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction); |
| 6160 | case IrInstructionIdShuffleVector: | ||
| 6161 | return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction); | ||
| 6162 | case IrInstructionIdSplatGen: | ||
| 6163 | return ir_render_splat(g, executable, (IrInstructionSplatGen *) instruction); | ||
| 6057 | } | 6164 | } |
| 6058 | zig_unreachable(); | 6165 | zig_unreachable(); |
| 6059 | } | 6166 | } |
| ... | @@ -7419,7 +7526,9 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -7419,7 +7526,9 @@ static void do_code_gen(CodeGen *g) { |
| 7419 | } | 7526 | } |
| 7420 | 7527 | ||
| 7421 | char *error = nullptr; | 7528 | char *error = nullptr; |
| 7422 | LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error); | 7529 | if (LLVMVerifyModule(g->module, LLVMReturnStatusAction, &error)) { |
| 7530 | zig_panic("broken LLVM module found: %s", error); | ||
| 7531 | } | ||
| 7423 | } | 7532 | } |
| 7424 | 7533 | ||
| 7425 | static void zig_llvm_emit_output(CodeGen *g) { | 7534 | static void zig_llvm_emit_output(CodeGen *g) { |
| ... | @@ -7744,6 +7853,8 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -7744,6 +7853,8 @@ static void define_builtin_fns(CodeGen *g) { |
| 7744 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); | 7853 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); |
| 7745 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int | 7854 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int |
| 7746 | create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); | 7855 | create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); |
| 7856 | create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4); | ||
| 7857 | create_builtin_fn(g, BuiltinFnIdSplat, "splat", 2); | ||
| 7747 | create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); | 7858 | create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); |
| 7748 | create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); | 7859 | create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); |
| 7749 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); | 7860 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); |
src/ir.cpp+499-67| ... | @@ -717,6 +717,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) { | ... | @@ -717,6 +717,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) { |
| 717 | return IrInstructionIdVectorType; | 717 | return IrInstructionIdVectorType; |
| 718 | } | 718 | } |
| 719 | 719 | ||
| 720 | static constexpr IrInstructionId ir_instruction_id(IrInstructionShuffleVector *) { | ||
| 721 | return IrInstructionIdShuffleVector; | ||
| 722 | } | ||
| 723 | |||
| 724 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSplatSrc *) { | ||
| 725 | return IrInstructionIdSplatSrc; | ||
| 726 | } | ||
| 727 | |||
| 728 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSplatGen *) { | ||
| 729 | return IrInstructionIdSplatGen; | ||
| 730 | } | ||
| 731 | |||
| 720 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { | 732 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { |
| 721 | return IrInstructionIdBoolNot; | 733 | return IrInstructionIdBoolNot; |
| 722 | } | 734 | } |
| ... | @@ -2277,6 +2289,38 @@ static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -2277,6 +2289,38 @@ static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode |
| 2277 | return &instruction->base; | 2289 | return &instruction->base; |
| 2278 | } | 2290 | } |
| 2279 | 2291 | ||
| 2292 | static IrInstruction *ir_build_shuffle_vector(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2293 | IrInstruction *scalar_type, IrInstruction *a, IrInstruction *b, IrInstruction *mask) | ||
| 2294 | { | ||
| 2295 | IrInstructionShuffleVector *instruction = ir_build_instruction<IrInstructionShuffleVector>(irb, scope, source_node); | ||
| 2296 | instruction->scalar_type = scalar_type; | ||
| 2297 | instruction->a = a; | ||
| 2298 | instruction->b = b; | ||
| 2299 | instruction->mask = mask; | ||
| 2300 | |||
| 2301 | if (scalar_type != nullptr) { | ||
| 2302 | ir_ref_instruction(scalar_type, irb->current_basic_block); | ||
| 2303 | } | ||
| 2304 | ir_ref_instruction(a, irb->current_basic_block); | ||
| 2305 | ir_ref_instruction(b, irb->current_basic_block); | ||
| 2306 | ir_ref_instruction(mask, irb->current_basic_block); | ||
| 2307 | |||
| 2308 | return &instruction->base; | ||
| 2309 | } | ||
| 2310 | |||
| 2311 | static IrInstruction *ir_build_splat_src(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2312 | IrInstruction *len, IrInstruction *scalar) | ||
| 2313 | { | ||
| 2314 | IrInstructionSplatSrc *instruction = ir_build_instruction<IrInstructionSplatSrc>(irb, scope, source_node); | ||
| 2315 | instruction->len = len; | ||
| 2316 | instruction->scalar = scalar; | ||
| 2317 | |||
| 2318 | ir_ref_instruction(len, irb->current_basic_block); | ||
| 2319 | ir_ref_instruction(scalar, irb->current_basic_block); | ||
| 2320 | |||
| 2321 | return &instruction->base; | ||
| 2322 | } | ||
| 2323 | |||
| 2280 | static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { | 2324 | static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 2281 | IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node); | 2325 | IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node); |
| 2282 | instruction->value = value; | 2326 | instruction->value = value; |
| ... | @@ -2333,6 +2377,19 @@ static IrInstruction *ir_build_slice_src(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -2333,6 +2377,19 @@ static IrInstruction *ir_build_slice_src(IrBuilder *irb, Scope *scope, AstNode * |
| 2333 | return &instruction->base; | 2377 | return &instruction->base; |
| 2334 | } | 2378 | } |
| 2335 | 2379 | ||
| 2380 | static IrInstruction *ir_build_splat_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_type, | ||
| 2381 | IrInstruction *scalar) | ||
| 2382 | { | ||
| 2383 | IrInstructionSplatGen *instruction = ir_build_instruction<IrInstructionSplatGen>( | ||
| 2384 | &ira->new_irb, source_instruction->scope, source_instruction->source_node); | ||
| 2385 | instruction->base.value.type = result_type; | ||
| 2386 | instruction->scalar = scalar; | ||
| 2387 | |||
| 2388 | ir_ref_instruction(scalar, ira->new_irb.current_basic_block); | ||
| 2389 | |||
| 2390 | return &instruction->base; | ||
| 2391 | } | ||
| 2392 | |||
| 2336 | static IrInstruction *ir_build_slice_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *slice_type, | 2393 | static IrInstruction *ir_build_slice_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *slice_type, |
| 2337 | IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, IrInstruction *result_loc) | 2394 | IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, IrInstruction *result_loc) |
| 2338 | { | 2395 | { |
| ... | @@ -4936,6 +4993,48 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4936,6 +4993,48 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4936 | IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); | 4993 | IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); |
| 4937 | return ir_lval_wrap(irb, scope, vector_type, lval, result_loc); | 4994 | return ir_lval_wrap(irb, scope, vector_type, lval, result_loc); |
| 4938 | } | 4995 | } |
| 4996 | case BuiltinFnIdShuffle: | ||
| 4997 | { | ||
| 4998 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4999 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 5000 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 5001 | return arg0_value; | ||
| 5002 | |||
| 5003 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 5004 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 5005 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 5006 | return arg1_value; | ||
| 5007 | |||
| 5008 | AstNode *arg2_node = node->data.fn_call_expr.params.at(2); | ||
| 5009 | IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); | ||
| 5010 | if (arg2_value == irb->codegen->invalid_instruction) | ||
| 5011 | return arg2_value; | ||
| 5012 | |||
| 5013 | AstNode *arg3_node = node->data.fn_call_expr.params.at(3); | ||
| 5014 | IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope); | ||
| 5015 | if (arg3_value == irb->codegen->invalid_instruction) | ||
| 5016 | return arg3_value; | ||
| 5017 | |||
| 5018 | IrInstruction *shuffle_vector = ir_build_shuffle_vector(irb, scope, node, | ||
| 5019 | arg0_value, arg1_value, arg2_value, arg3_value); | ||
| 5020 | return ir_lval_wrap(irb, scope, shuffle_vector, lval, result_loc); | ||
| 5021 | } | ||
| 5022 | case BuiltinFnIdSplat: | ||
| 5023 | { | ||
| 5024 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 5025 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 5026 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 5027 | return arg0_value; | ||
| 5028 | |||
| 5029 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 5030 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 5031 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 5032 | return arg1_value; | ||
| 5033 | |||
| 5034 | IrInstruction *splat = ir_build_splat_src(irb, scope, node, | ||
| 5035 | arg0_value, arg1_value); | ||
| 5036 | return ir_lval_wrap(irb, scope, splat, lval, result_loc); | ||
| 5037 | } | ||
| 4939 | case BuiltinFnIdMemcpy: | 5038 | case BuiltinFnIdMemcpy: |
| 4940 | { | 5039 | { |
| 4941 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 5040 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | @@ -11000,14 +11099,41 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { | ... | @@ -11000,14 +11099,41 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { |
| 11000 | return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val); | 11099 | return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val); |
| 11001 | } | 11100 | } |
| 11002 | 11101 | ||
| 11102 | static Error ir_validate_vector_elem_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *elem_type) { | ||
| 11103 | if (!is_valid_vector_elem_type(elem_type)) { | ||
| 11104 | ir_add_error(ira, source_instr, | ||
| 11105 | buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid", | ||
| 11106 | buf_ptr(&elem_type->name))); | ||
| 11107 | return ErrorSemanticAnalyzeFail; | ||
| 11108 | } | ||
| 11109 | return ErrorNone; | ||
| 11110 | } | ||
| 11111 | |||
| 11112 | static ZigType *ir_resolve_vector_elem_type(IrAnalyze *ira, IrInstruction *elem_type_value) { | ||
| 11113 | Error err; | ||
| 11114 | ZigType *elem_type = ir_resolve_type(ira, elem_type_value); | ||
| 11115 | if (type_is_invalid(elem_type)) | ||
| 11116 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11117 | if ((err = ir_validate_vector_elem_type(ira, elem_type_value, elem_type))) | ||
| 11118 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11119 | return elem_type; | ||
| 11120 | } | ||
| 11121 | |||
| 11003 | static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { | 11122 | static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { |
| 11004 | ZigType *ty = ir_resolve_type(ira, type_value); | 11123 | ZigType *ty = ir_resolve_type(ira, type_value); |
| 11005 | if (type_is_invalid(ty)) | 11124 | if (type_is_invalid(ty)) |
| 11006 | return ira->codegen->builtin_types.entry_invalid; | 11125 | return ira->codegen->builtin_types.entry_invalid; |
| 11007 | 11126 | ||
| 11008 | if (ty->id != ZigTypeIdInt) { | 11127 | if (ty->id != ZigTypeIdInt) { |
| 11009 | ir_add_error(ira, type_value, | 11128 | ErrorMsg *msg = ir_add_error(ira, type_value, |
| 11010 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&ty->name))); | 11129 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&ty->name))); |
| 11130 | if (ty->id == ZigTypeIdVector && | ||
| 11131 | ty->data.vector.elem_type->id == ZigTypeIdInt) | ||
| 11132 | { | ||
| 11133 | add_error_note(ira->codegen, msg, type_value->source_node, | ||
| 11134 | buf_sprintf("represent vectors with their element types, i.e. '%s'", | ||
| 11135 | buf_ptr(&ty->data.vector.elem_type->name))); | ||
| 11136 | } | ||
| 11011 | return ira->codegen->builtin_types.entry_invalid; | 11137 | return ira->codegen->builtin_types.entry_invalid; |
| 11012 | } | 11138 | } |
| 11013 | 11139 | ||
| ... | @@ -13092,6 +13218,59 @@ static bool optional_value_is_null(ConstExprValue *val) { | ... | @@ -13092,6 +13218,59 @@ static bool optional_value_is_null(ConstExprValue *val) { |
| 13092 | } | 13218 | } |
| 13093 | } | 13219 | } |
| 13094 | 13220 | ||
| 13221 | static IrInstruction *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type, | ||
| 13222 | ConstExprValue *op1_val, ConstExprValue *op2_val, IrInstructionBinOp *bin_op_instruction, IrBinOp op_id, | ||
| 13223 | bool one_possible_value) { | ||
| 13224 | if (op1_val->special == ConstValSpecialUndef || | ||
| 13225 | op2_val->special == ConstValSpecialUndef) | ||
| 13226 | return ir_const_undef(ira, &bin_op_instruction->base, resolved_type); | ||
| 13227 | if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) { | ||
| 13228 | if (float_is_nan(op1_val) || float_is_nan(op2_val)) { | ||
| 13229 | return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq); | ||
| 13230 | } | ||
| 13231 | Cmp cmp_result = float_cmp(op1_val, op2_val); | ||
| 13232 | bool answer = resolve_cmp_op_id(op_id, cmp_result); | ||
| 13233 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | ||
| 13234 | } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) { | ||
| 13235 | Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); | ||
| 13236 | bool answer = resolve_cmp_op_id(op_id, cmp_result); | ||
| 13237 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | ||
| 13238 | } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) { | ||
| 13239 | if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || | ||
| 13240 | op1_val->data.x_ptr.special == ConstPtrSpecialNull) && | ||
| 13241 | (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || | ||
| 13242 | op2_val->data.x_ptr.special == ConstPtrSpecialNull)) | ||
| 13243 | { | ||
| 13244 | uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ? | ||
| 13245 | 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; | ||
| 13246 | uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ? | ||
| 13247 | 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr; | ||
| 13248 | Cmp cmp_result; | ||
| 13249 | if (op1_addr > op2_addr) { | ||
| 13250 | cmp_result = CmpGT; | ||
| 13251 | } else if (op1_addr < op2_addr) { | ||
| 13252 | cmp_result = CmpLT; | ||
| 13253 | } else { | ||
| 13254 | cmp_result = CmpEQ; | ||
| 13255 | } | ||
| 13256 | bool answer = resolve_cmp_op_id(op_id, cmp_result); | ||
| 13257 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | ||
| 13258 | } | ||
| 13259 | } else { | ||
| 13260 | bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val); | ||
| 13261 | bool answer; | ||
| 13262 | if (op_id == IrBinOpCmpEq) { | ||
| 13263 | answer = are_equal; | ||
| 13264 | } else if (op_id == IrBinOpCmpNotEq) { | ||
| 13265 | answer = !are_equal; | ||
| 13266 | } else { | ||
| 13267 | zig_unreachable(); | ||
| 13268 | } | ||
| 13269 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | ||
| 13270 | } | ||
| 13271 | zig_unreachable(); | ||
| 13272 | } | ||
| 13273 | |||
| 13095 | // Returns ErrorNotLazy when the value cannot be determined | 13274 | // Returns ErrorNotLazy when the value cannot be determined |
| 13096 | static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) { | 13275 | static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) { |
| 13097 | Error err; | 13276 | Error err; |
| ... | @@ -13477,51 +13656,22 @@ never_mind_just_calculate_it_normally: | ... | @@ -13477,51 +13656,22 @@ never_mind_just_calculate_it_normally: |
| 13477 | ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad); | 13656 | ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad); |
| 13478 | if (op2_val == nullptr) | 13657 | if (op2_val == nullptr) |
| 13479 | return ira->codegen->invalid_instruction; | 13658 | return ira->codegen->invalid_instruction; |
| 13480 | 13659 | if (resolved_type->id != ZigTypeIdVector) | |
| 13481 | if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) { | 13660 | return ir_evaluate_bin_op_cmp(ira, resolved_type, op1_val, op2_val, bin_op_instruction, op_id, one_possible_value); |
| 13482 | if (float_is_nan(op1_val) || float_is_nan(op2_val)) { | 13661 | IrInstruction *result = ir_const(ira, &bin_op_instruction->base, |
| 13483 | return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq); | 13662 | get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool)); |
| 13484 | } | 13663 | result->value.data.x_array.data.s_none.elements = |
| 13485 | Cmp cmp_result = float_cmp(op1_val, op2_val); | 13664 | create_const_vals(resolved_type->data.vector.len); |
| 13486 | bool answer = resolve_cmp_op_id(op_id, cmp_result); | 13665 | |
| 13487 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | 13666 | expand_undef_array(ira->codegen, &result->value); |
| 13488 | } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) { | 13667 | for (size_t i = 0;i < resolved_type->data.vector.len;i++) { |
| 13489 | Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint); | 13668 | IrInstruction *cur_res = ir_evaluate_bin_op_cmp(ira, resolved_type->data.vector.elem_type, |
| 13490 | bool answer = resolve_cmp_op_id(op_id, cmp_result); | 13669 | &op1_val->data.x_array.data.s_none.elements[i], |
| 13491 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | 13670 | &op2_val->data.x_array.data.s_none.elements[i], |
| 13492 | } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) { | 13671 | bin_op_instruction, op_id, one_possible_value); |
| 13493 | if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || | 13672 | copy_const_val(&result->value.data.x_array.data.s_none.elements[i], &cur_res->value, false); |
| 13494 | op1_val->data.x_ptr.special == ConstPtrSpecialNull) && | ||
| 13495 | (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr || | ||
| 13496 | op2_val->data.x_ptr.special == ConstPtrSpecialNull)) | ||
| 13497 | { | ||
| 13498 | uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ? | ||
| 13499 | 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; | ||
| 13500 | uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ? | ||
| 13501 | 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr; | ||
| 13502 | Cmp cmp_result; | ||
| 13503 | if (op1_addr > op2_addr) { | ||
| 13504 | cmp_result = CmpGT; | ||
| 13505 | } else if (op1_addr < op2_addr) { | ||
| 13506 | cmp_result = CmpLT; | ||
| 13507 | } else { | ||
| 13508 | cmp_result = CmpEQ; | ||
| 13509 | } | ||
| 13510 | bool answer = resolve_cmp_op_id(op_id, cmp_result); | ||
| 13511 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | ||
| 13512 | } | ||
| 13513 | } else { | ||
| 13514 | bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val); | ||
| 13515 | bool answer; | ||
| 13516 | if (op_id == IrBinOpCmpEq) { | ||
| 13517 | answer = are_equal; | ||
| 13518 | } else if (op_id == IrBinOpCmpNotEq) { | ||
| 13519 | answer = !are_equal; | ||
| 13520 | } else { | ||
| 13521 | zig_unreachable(); | ||
| 13522 | } | ||
| 13523 | return ir_const_bool(ira, &bin_op_instruction->base, answer); | ||
| 13524 | } | 13673 | } |
| 13674 | return result; | ||
| 13525 | } | 13675 | } |
| 13526 | 13676 | ||
| 13527 | // some comparisons with unsigned numbers can be evaluated | 13677 | // some comparisons with unsigned numbers can be evaluated |
| ... | @@ -13564,7 +13714,12 @@ never_mind_just_calculate_it_normally: | ... | @@ -13564,7 +13714,12 @@ never_mind_just_calculate_it_normally: |
| 13564 | IrInstruction *result = ir_build_bin_op(&ira->new_irb, | 13714 | IrInstruction *result = ir_build_bin_op(&ira->new_irb, |
| 13565 | bin_op_instruction->base.scope, bin_op_instruction->base.source_node, | 13715 | bin_op_instruction->base.scope, bin_op_instruction->base.source_node, |
| 13566 | op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on); | 13716 | op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on); |
| 13567 | result->value.type = ira->codegen->builtin_types.entry_bool; | 13717 | if (resolved_type->id == ZigTypeIdVector) { |
| 13718 | result->value.type = get_vector_type(ira->codegen, resolved_type->data.vector.len, | ||
| 13719 | ira->codegen->builtin_types.entry_bool); | ||
| 13720 | } else { | ||
| 13721 | result->value.type = ira->codegen->builtin_types.entry_bool; | ||
| 13722 | } | ||
| 13568 | return result; | 13723 | return result; |
| 13569 | } | 13724 | } |
| 13570 | 13725 | ||
| ... | @@ -15198,7 +15353,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe | ... | @@ -15198,7 +15353,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe |
| 15198 | } | 15353 | } |
| 15199 | peer_parent->skipped = true; | 15354 | peer_parent->skipped = true; |
| 15200 | return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, | 15355 | return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, |
| 15201 | value_type, value, force_runtime, true, true); | 15356 | value_type, value, force_runtime || !is_comptime, true, true); |
| 15202 | } | 15357 | } |
| 15203 | 15358 | ||
| 15204 | if (peer_parent->resolved_type == nullptr) { | 15359 | if (peer_parent->resolved_type == nullptr) { |
| ... | @@ -22018,20 +22173,251 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr | ... | @@ -22018,20 +22173,251 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr |
| 22018 | if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len)) | 22173 | if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len)) |
| 22019 | return ira->codegen->invalid_instruction; | 22174 | return ira->codegen->invalid_instruction; |
| 22020 | 22175 | ||
| 22021 | ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child); | 22176 | ZigType *elem_type = ir_resolve_vector_elem_type(ira, instruction->elem_type->child); |
| 22022 | if (type_is_invalid(elem_type)) | 22177 | if (type_is_invalid(elem_type)) |
| 22023 | return ira->codegen->invalid_instruction; | 22178 | return ira->codegen->invalid_instruction; |
| 22024 | 22179 | ||
| 22025 | if (!is_valid_vector_elem_type(elem_type)) { | 22180 | ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type); |
| 22026 | ir_add_error(ira, instruction->elem_type, | 22181 | |
| 22027 | buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid", | 22182 | return ir_const_type(ira, &instruction->base, vector_type); |
| 22028 | buf_ptr(&elem_type->name))); | 22183 | } |
| 22184 | |||
| 22185 | static IrInstruction *ir_analyze_shuffle_vector(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 22186 | ZigType *scalar_type, IrInstruction *a, IrInstruction *b, IrInstruction *mask) | ||
| 22187 | { | ||
| 22188 | ir_assert(source_instr && scalar_type && a && b && mask, source_instr); | ||
| 22189 | ir_assert(is_valid_vector_elem_type(scalar_type), source_instr); | ||
| 22190 | |||
| 22191 | uint32_t len_mask; | ||
| 22192 | if (mask->value.type->id == ZigTypeIdVector) { | ||
| 22193 | len_mask = mask->value.type->data.vector.len; | ||
| 22194 | } else if (mask->value.type->id == ZigTypeIdArray) { | ||
| 22195 | len_mask = mask->value.type->data.array.len; | ||
| 22196 | } else { | ||
| 22197 | ir_add_error(ira, mask, | ||
| 22198 | buf_sprintf("expected vector or array, found '%s'", | ||
| 22199 | buf_ptr(&mask->value.type->name))); | ||
| 22029 | return ira->codegen->invalid_instruction; | 22200 | return ira->codegen->invalid_instruction; |
| 22030 | } | 22201 | } |
| 22202 | mask = ir_implicit_cast(ira, mask, get_vector_type(ira->codegen, len_mask, | ||
| 22203 | ira->codegen->builtin_types.entry_i32)); | ||
| 22204 | if (type_is_invalid(mask->value.type)) | ||
| 22205 | return ira->codegen->invalid_instruction; | ||
| 22031 | 22206 | ||
| 22032 | ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type); | 22207 | uint32_t len_a; |
| 22208 | if (a->value.type->id == ZigTypeIdVector) { | ||
| 22209 | len_a = a->value.type->data.vector.len; | ||
| 22210 | } else if (a->value.type->id == ZigTypeIdArray) { | ||
| 22211 | len_a = a->value.type->data.array.len; | ||
| 22212 | } else if (a->value.type->id == ZigTypeIdUndefined) { | ||
| 22213 | len_a = UINT32_MAX; | ||
| 22214 | } else { | ||
| 22215 | ir_add_error(ira, a, | ||
| 22216 | buf_sprintf("expected vector or array with element type '%s', found '%s'", | ||
| 22217 | buf_ptr(&scalar_type->name), | ||
| 22218 | buf_ptr(&a->value.type->name))); | ||
| 22219 | return ira->codegen->invalid_instruction; | ||
| 22220 | } | ||
| 22033 | 22221 | ||
| 22034 | return ir_const_type(ira, &instruction->base, vector_type); | 22222 | uint32_t len_b; |
| 22223 | if (b->value.type->id == ZigTypeIdVector) { | ||
| 22224 | len_b = b->value.type->data.vector.len; | ||
| 22225 | } else if (b->value.type->id == ZigTypeIdArray) { | ||
| 22226 | len_b = b->value.type->data.array.len; | ||
| 22227 | } else if (b->value.type->id == ZigTypeIdUndefined) { | ||
| 22228 | len_b = UINT32_MAX; | ||
| 22229 | } else { | ||
| 22230 | ir_add_error(ira, b, | ||
| 22231 | buf_sprintf("expected vector or array with element type '%s', found '%s'", | ||
| 22232 | buf_ptr(&scalar_type->name), | ||
| 22233 | buf_ptr(&b->value.type->name))); | ||
| 22234 | return ira->codegen->invalid_instruction; | ||
| 22235 | } | ||
| 22236 | |||
| 22237 | if (len_a == UINT32_MAX && len_b == UINT32_MAX) { | ||
| 22238 | return ir_const_undef(ira, a, get_vector_type(ira->codegen, len_mask, scalar_type)); | ||
| 22239 | } | ||
| 22240 | |||
| 22241 | if (len_a == UINT32_MAX) { | ||
| 22242 | len_a = len_b; | ||
| 22243 | a = ir_const_undef(ira, a, get_vector_type(ira->codegen, len_a, scalar_type)); | ||
| 22244 | } else { | ||
| 22245 | a = ir_implicit_cast(ira, a, get_vector_type(ira->codegen, len_a, scalar_type)); | ||
| 22246 | if (type_is_invalid(a->value.type)) | ||
| 22247 | return ira->codegen->invalid_instruction; | ||
| 22248 | } | ||
| 22249 | |||
| 22250 | if (len_b == UINT32_MAX) { | ||
| 22251 | len_b = len_a; | ||
| 22252 | b = ir_const_undef(ira, b, get_vector_type(ira->codegen, len_b, scalar_type)); | ||
| 22253 | } else { | ||
| 22254 | b = ir_implicit_cast(ira, b, get_vector_type(ira->codegen, len_b, scalar_type)); | ||
| 22255 | if (type_is_invalid(b->value.type)) | ||
| 22256 | return ira->codegen->invalid_instruction; | ||
| 22257 | } | ||
| 22258 | |||
| 22259 | ConstExprValue *mask_val = ir_resolve_const(ira, mask, UndefOk); | ||
| 22260 | if (mask_val == nullptr) | ||
| 22261 | return ira->codegen->invalid_instruction; | ||
| 22262 | |||
| 22263 | expand_undef_array(ira->codegen, mask_val); | ||
| 22264 | |||
| 22265 | for (uint32_t i = 0; i < len_mask; i += 1) { | ||
| 22266 | ConstExprValue *mask_elem_val = &mask_val->data.x_array.data.s_none.elements[i]; | ||
| 22267 | if (mask_elem_val->special == ConstValSpecialUndef) | ||
| 22268 | continue; | ||
| 22269 | int32_t v_i32 = bigint_as_signed(&mask_elem_val->data.x_bigint); | ||
| 22270 | uint32_t v; | ||
| 22271 | IrInstruction *chosen_operand; | ||
| 22272 | if (v_i32 >= 0) { | ||
| 22273 | v = (uint32_t)v_i32; | ||
| 22274 | chosen_operand = a; | ||
| 22275 | } else { | ||
| 22276 | v = (uint32_t)~v_i32; | ||
| 22277 | chosen_operand = b; | ||
| 22278 | } | ||
| 22279 | if (v >= chosen_operand->value.type->data.vector.len) { | ||
| 22280 | ErrorMsg *msg = ir_add_error(ira, mask, | ||
| 22281 | buf_sprintf("mask index '%u' has out-of-bounds selection", i)); | ||
| 22282 | add_error_note(ira->codegen, msg, chosen_operand->source_node, | ||
| 22283 | buf_sprintf("selected index '%u' out of bounds of %s", v, | ||
| 22284 | buf_ptr(&chosen_operand->value.type->name))); | ||
| 22285 | if (chosen_operand == a && v < len_a + len_b) { | ||
| 22286 | add_error_note(ira->codegen, msg, b->source_node, | ||
| 22287 | buf_create_from_str("selections from the second vector are specified with negative numbers")); | ||
| 22288 | } | ||
| 22289 | return ira->codegen->invalid_instruction; | ||
| 22290 | } | ||
| 22291 | } | ||
| 22292 | |||
| 22293 | ZigType *result_type = get_vector_type(ira->codegen, len_mask, scalar_type); | ||
| 22294 | if (instr_is_comptime(a) && instr_is_comptime(b)) { | ||
| 22295 | ConstExprValue *a_val = ir_resolve_const(ira, a, UndefOk); | ||
| 22296 | if (a_val == nullptr) | ||
| 22297 | return ira->codegen->invalid_instruction; | ||
| 22298 | |||
| 22299 | ConstExprValue *b_val = ir_resolve_const(ira, b, UndefOk); | ||
| 22300 | if (b_val == nullptr) | ||
| 22301 | return ira->codegen->invalid_instruction; | ||
| 22302 | |||
| 22303 | expand_undef_array(ira->codegen, a_val); | ||
| 22304 | expand_undef_array(ira->codegen, b_val); | ||
| 22305 | |||
| 22306 | IrInstruction *result = ir_const(ira, source_instr, result_type); | ||
| 22307 | result->value.data.x_array.data.s_none.elements = create_const_vals(len_mask); | ||
| 22308 | for (uint32_t i = 0; i < mask_val->type->data.vector.len; i += 1) { | ||
| 22309 | ConstExprValue *mask_elem_val = &mask_val->data.x_array.data.s_none.elements[i]; | ||
| 22310 | ConstExprValue *result_elem_val = &result->value.data.x_array.data.s_none.elements[i]; | ||
| 22311 | if (mask_elem_val->special == ConstValSpecialUndef) { | ||
| 22312 | result_elem_val->special = ConstValSpecialUndef; | ||
| 22313 | continue; | ||
| 22314 | } | ||
| 22315 | int32_t v = bigint_as_signed(&mask_elem_val->data.x_bigint); | ||
| 22316 | // We've already checked for and emitted compile errors for index out of bounds here. | ||
| 22317 | ConstExprValue *src_elem_val = (v >= 0) ? | ||
| 22318 | &a->value.data.x_array.data.s_none.elements[v] : | ||
| 22319 | &b->value.data.x_array.data.s_none.elements[~v]; | ||
| 22320 | copy_const_val(result_elem_val, src_elem_val, false); | ||
| 22321 | |||
| 22322 | ir_assert(result_elem_val->special == ConstValSpecialStatic, source_instr); | ||
| 22323 | } | ||
| 22324 | result->value.special = ConstValSpecialStatic; | ||
| 22325 | return result; | ||
| 22326 | } | ||
| 22327 | |||
| 22328 | // All static analysis passed, and not comptime. | ||
| 22329 | // For runtime codegen, vectors a and b must be the same length. Here we | ||
| 22330 | // recursively @shuffle the smaller vector to append undefined elements | ||
| 22331 | // to it up to the length of the longer vector. This recursion terminates | ||
| 22332 | // in 1 call because these calls to ir_analyze_shuffle_vector guarantee | ||
| 22333 | // len_a == len_b. | ||
| 22334 | if (len_a != len_b) { | ||
| 22335 | uint32_t len_min = min(len_a, len_b); | ||
| 22336 | uint32_t len_max = max(len_a, len_b); | ||
| 22337 | |||
| 22338 | IrInstruction *expand_mask = ir_const(ira, mask, | ||
| 22339 | get_vector_type(ira->codegen, len_max, ira->codegen->builtin_types.entry_i32)); | ||
| 22340 | expand_mask->value.data.x_array.data.s_none.elements = create_const_vals(len_max); | ||
| 22341 | uint32_t i = 0; | ||
| 22342 | for (; i < len_min; i += 1) | ||
| 22343 | bigint_init_unsigned(&expand_mask->value.data.x_array.data.s_none.elements[i].data.x_bigint, i); | ||
| 22344 | for (; i < len_max; i += 1) | ||
| 22345 | bigint_init_signed(&expand_mask->value.data.x_array.data.s_none.elements[i].data.x_bigint, -1); | ||
| 22346 | |||
| 22347 | IrInstruction *undef = ir_const_undef(ira, source_instr, | ||
| 22348 | get_vector_type(ira->codegen, len_min, scalar_type)); | ||
| 22349 | |||
| 22350 | if (len_b < len_a) { | ||
| 22351 | b = ir_analyze_shuffle_vector(ira, source_instr, scalar_type, b, undef, expand_mask); | ||
| 22352 | } else { | ||
| 22353 | a = ir_analyze_shuffle_vector(ira, source_instr, scalar_type, a, undef, expand_mask); | ||
| 22354 | } | ||
| 22355 | } | ||
| 22356 | |||
| 22357 | IrInstruction *result = ir_build_shuffle_vector(&ira->new_irb, | ||
| 22358 | source_instr->scope, source_instr->source_node, | ||
| 22359 | nullptr, a, b, mask); | ||
| 22360 | result->value.type = result_type; | ||
| 22361 | return result; | ||
| 22362 | } | ||
| 22363 | |||
| 22364 | static IrInstruction *ir_analyze_instruction_shuffle_vector(IrAnalyze *ira, IrInstructionShuffleVector *instruction) { | ||
| 22365 | ZigType *scalar_type = ir_resolve_vector_elem_type(ira, instruction->scalar_type); | ||
| 22366 | if (type_is_invalid(scalar_type)) | ||
| 22367 | return ira->codegen->invalid_instruction; | ||
| 22368 | |||
| 22369 | IrInstruction *a = instruction->a->child; | ||
| 22370 | if (type_is_invalid(a->value.type)) | ||
| 22371 | return ira->codegen->invalid_instruction; | ||
| 22372 | |||
| 22373 | IrInstruction *b = instruction->b->child; | ||
| 22374 | if (type_is_invalid(b->value.type)) | ||
| 22375 | return ira->codegen->invalid_instruction; | ||
| 22376 | |||
| 22377 | IrInstruction *mask = instruction->mask->child; | ||
| 22378 | if (type_is_invalid(mask->value.type)) | ||
| 22379 | return ira->codegen->invalid_instruction; | ||
| 22380 | |||
| 22381 | return ir_analyze_shuffle_vector(ira, &instruction->base, scalar_type, a, b, mask); | ||
| 22382 | } | ||
| 22383 | |||
| 22384 | static IrInstruction *ir_analyze_instruction_splat(IrAnalyze *ira, IrInstructionSplatSrc *instruction) { | ||
| 22385 | Error err; | ||
| 22386 | |||
| 22387 | IrInstruction *len = instruction->len->child; | ||
| 22388 | if (type_is_invalid(len->value.type)) | ||
| 22389 | return ira->codegen->invalid_instruction; | ||
| 22390 | |||
| 22391 | IrInstruction *scalar = instruction->scalar->child; | ||
| 22392 | if (type_is_invalid(scalar->value.type)) | ||
| 22393 | return ira->codegen->invalid_instruction; | ||
| 22394 | |||
| 22395 | uint64_t len_u64; | ||
| 22396 | if (!ir_resolve_unsigned(ira, len, ira->codegen->builtin_types.entry_u32, &len_u64)) | ||
| 22397 | return ira->codegen->invalid_instruction; | ||
| 22398 | uint32_t len_int = len_u64; | ||
| 22399 | |||
| 22400 | if ((err = ir_validate_vector_elem_type(ira, scalar, scalar->value.type))) | ||
| 22401 | return ira->codegen->invalid_instruction; | ||
| 22402 | |||
| 22403 | ZigType *return_type = get_vector_type(ira->codegen, len_int, scalar->value.type); | ||
| 22404 | |||
| 22405 | if (instr_is_comptime(scalar)) { | ||
| 22406 | ConstExprValue *scalar_val = ir_resolve_const(ira, scalar, UndefOk); | ||
| 22407 | if (scalar_val == nullptr) | ||
| 22408 | return ira->codegen->invalid_instruction; | ||
| 22409 | if (scalar_val->special == ConstValSpecialUndef) | ||
| 22410 | return ir_const_undef(ira, &instruction->base, return_type); | ||
| 22411 | |||
| 22412 | IrInstruction *result = ir_const(ira, &instruction->base, return_type); | ||
| 22413 | result->value.data.x_array.data.s_none.elements = create_const_vals(len_int); | ||
| 22414 | for (uint32_t i = 0; i < len_int; i += 1) { | ||
| 22415 | copy_const_val(&result->value.data.x_array.data.s_none.elements[i], scalar_val, false); | ||
| 22416 | } | ||
| 22417 | return result; | ||
| 22418 | } | ||
| 22419 | |||
| 22420 | return ir_build_splat_gen(ira, &instruction->base, return_type, scalar); | ||
| 22035 | } | 22421 | } |
| 22036 | 22422 | ||
| 22037 | static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { | 22423 | static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { |
| ... | @@ -24970,21 +25356,35 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct | ... | @@ -24970,21 +25356,35 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct |
| 24970 | } | 25356 | } |
| 24971 | 25357 | ||
| 24972 | static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { | 25358 | static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstructionBswap *instruction) { |
| 25359 | Error err; | ||
| 25360 | |||
| 24973 | ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); | 25361 | ZigType *int_type = ir_resolve_int_type(ira, instruction->type->child); |
| 24974 | if (type_is_invalid(int_type)) | 25362 | if (type_is_invalid(int_type)) |
| 24975 | return ira->codegen->invalid_instruction; | 25363 | return ira->codegen->invalid_instruction; |
| 24976 | 25364 | ||
| 24977 | IrInstruction *op = ir_implicit_cast(ira, instruction->op->child, int_type); | 25365 | IrInstruction *uncasted_op = instruction->op->child; |
| 24978 | if (type_is_invalid(op->value.type)) | 25366 | if (type_is_invalid(uncasted_op->value.type)) |
| 24979 | return ira->codegen->invalid_instruction; | 25367 | return ira->codegen->invalid_instruction; |
| 24980 | 25368 | ||
| 24981 | if (int_type->data.integral.bit_count == 0) { | 25369 | uint32_t vector_len; // UINT32_MAX means not a vector |
| 24982 | IrInstruction *result = ir_const(ira, &instruction->base, int_type); | 25370 | if (uncasted_op->value.type->id == ZigTypeIdArray && |
| 24983 | bigint_init_unsigned(&result->value.data.x_bigint, 0); | 25371 | is_valid_vector_elem_type(uncasted_op->value.type->data.array.child_type)) |
| 24984 | return result; | 25372 | { |
| 25373 | vector_len = uncasted_op->value.type->data.array.len; | ||
| 25374 | } else if (uncasted_op->value.type->id == ZigTypeIdVector) { | ||
| 25375 | vector_len = uncasted_op->value.type->data.vector.len; | ||
| 25376 | } else { | ||
| 25377 | vector_len = UINT32_MAX; | ||
| 24985 | } | 25378 | } |
| 24986 | 25379 | ||
| 24987 | if (int_type->data.integral.bit_count == 8) | 25380 | bool is_vector = (vector_len != UINT32_MAX); |
| 25381 | ZigType *op_type = is_vector ? get_vector_type(ira->codegen, vector_len, int_type) : int_type; | ||
| 25382 | |||
| 25383 | IrInstruction *op = ir_implicit_cast(ira, uncasted_op, op_type); | ||
| 25384 | if (type_is_invalid(op->value.type)) | ||
| 25385 | return ira->codegen->invalid_instruction; | ||
| 25386 | |||
| 25387 | if (int_type->data.integral.bit_count == 8 || int_type->data.integral.bit_count == 0) | ||
| 24988 | return op; | 25388 | return op; |
| 24989 | 25389 | ||
| 24990 | if (int_type->data.integral.bit_count % 8 != 0) { | 25390 | if (int_type->data.integral.bit_count % 8 != 0) { |
| ... | @@ -24999,20 +25399,44 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction | ... | @@ -24999,20 +25399,44 @@ static IrInstruction *ir_analyze_instruction_bswap(IrAnalyze *ira, IrInstruction |
| 24999 | if (val == nullptr) | 25399 | if (val == nullptr) |
| 25000 | return ira->codegen->invalid_instruction; | 25400 | return ira->codegen->invalid_instruction; |
| 25001 | if (val->special == ConstValSpecialUndef) | 25401 | if (val->special == ConstValSpecialUndef) |
| 25002 | return ir_const_undef(ira, &instruction->base, int_type); | 25402 | return ir_const_undef(ira, &instruction->base, op_type); |
| 25003 | 25403 | ||
| 25004 | IrInstruction *result = ir_const(ira, &instruction->base, int_type); | 25404 | IrInstruction *result = ir_const(ira, &instruction->base, op_type); |
| 25005 | size_t buf_size = int_type->data.integral.bit_count / 8; | 25405 | size_t buf_size = int_type->data.integral.bit_count / 8; |
| 25006 | uint8_t *buf = allocate_nonzero<uint8_t>(buf_size); | 25406 | uint8_t *buf = allocate_nonzero<uint8_t>(buf_size); |
| 25007 | bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); | 25407 | if (is_vector) { |
| 25008 | bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, | 25408 | expand_undef_array(ira->codegen, val); |
| 25009 | int_type->data.integral.is_signed); | 25409 | result->value.data.x_array.data.s_none.elements = create_const_vals(op_type->data.vector.len); |
| 25410 | for (unsigned i = 0; i < op_type->data.vector.len; i += 1) { | ||
| 25411 | ConstExprValue *op_elem_val = &val->data.x_array.data.s_none.elements[i]; | ||
| 25412 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, instruction->base.source_node, | ||
| 25413 | op_elem_val, UndefOk))) | ||
| 25414 | { | ||
| 25415 | return ira->codegen->invalid_instruction; | ||
| 25416 | } | ||
| 25417 | ConstExprValue *result_elem_val = &result->value.data.x_array.data.s_none.elements[i]; | ||
| 25418 | result_elem_val->type = int_type; | ||
| 25419 | result_elem_val->special = op_elem_val->special; | ||
| 25420 | if (op_elem_val->special == ConstValSpecialUndef) | ||
| 25421 | continue; | ||
| 25422 | |||
| 25423 | bigint_write_twos_complement(&op_elem_val->data.x_bigint, buf, int_type->data.integral.bit_count, true); | ||
| 25424 | bigint_read_twos_complement(&result->value.data.x_array.data.s_none.elements[i].data.x_bigint, | ||
| 25425 | buf, int_type->data.integral.bit_count, false, | ||
| 25426 | int_type->data.integral.is_signed); | ||
| 25427 | } | ||
| 25428 | } else { | ||
| 25429 | bigint_write_twos_complement(&val->data.x_bigint, buf, int_type->data.integral.bit_count, true); | ||
| 25430 | bigint_read_twos_complement(&result->value.data.x_bigint, buf, int_type->data.integral.bit_count, false, | ||
| 25431 | int_type->data.integral.is_signed); | ||
| 25432 | } | ||
| 25433 | free(buf); | ||
| 25010 | return result; | 25434 | return result; |
| 25011 | } | 25435 | } |
| 25012 | 25436 | ||
| 25013 | IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, | 25437 | IrInstruction *result = ir_build_bswap(&ira->new_irb, instruction->base.scope, |
| 25014 | instruction->base.source_node, nullptr, op); | 25438 | instruction->base.source_node, nullptr, op); |
| 25015 | result->value.type = int_type; | 25439 | result->value.type = op_type; |
| 25016 | return result; | 25440 | return result; |
| 25017 | } | 25441 | } |
| 25018 | 25442 | ||
| ... | @@ -25450,6 +25874,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction | ... | @@ -25450,6 +25874,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25450 | case IrInstructionIdTestErrGen: | 25874 | case IrInstructionIdTestErrGen: |
| 25451 | case IrInstructionIdFrameSizeGen: | 25875 | case IrInstructionIdFrameSizeGen: |
| 25452 | case IrInstructionIdAwaitGen: | 25876 | case IrInstructionIdAwaitGen: |
| 25877 | case IrInstructionIdSplatGen: | ||
| 25453 | zig_unreachable(); | 25878 | zig_unreachable(); |
| 25454 | 25879 | ||
| 25455 | case IrInstructionIdReturn: | 25880 | case IrInstructionIdReturn: |
| ... | @@ -25578,6 +26003,10 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction | ... | @@ -25578,6 +26003,10 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25578 | return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); | 26003 | return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); |
| 25579 | case IrInstructionIdVectorType: | 26004 | case IrInstructionIdVectorType: |
| 25580 | return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); | 26005 | return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); |
| 26006 | case IrInstructionIdShuffleVector: | ||
| 26007 | return ir_analyze_instruction_shuffle_vector(ira, (IrInstructionShuffleVector *)instruction); | ||
| 26008 | case IrInstructionIdSplatSrc: | ||
| 26009 | return ir_analyze_instruction_splat(ira, (IrInstructionSplatSrc *)instruction); | ||
| 25581 | case IrInstructionIdBoolNot: | 26010 | case IrInstructionIdBoolNot: |
| 25582 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); | 26011 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); |
| 25583 | case IrInstructionIdMemset: | 26012 | case IrInstructionIdMemset: |
| ... | @@ -25913,6 +26342,9 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -25913,6 +26342,9 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25913 | case IrInstructionIdTruncate: | 26342 | case IrInstructionIdTruncate: |
| 25914 | case IrInstructionIdIntType: | 26343 | case IrInstructionIdIntType: |
| 25915 | case IrInstructionIdVectorType: | 26344 | case IrInstructionIdVectorType: |
| 26345 | case IrInstructionIdShuffleVector: | ||
| 26346 | case IrInstructionIdSplatSrc: | ||
| 26347 | case IrInstructionIdSplatGen: | ||
| 25916 | case IrInstructionIdBoolNot: | 26348 | case IrInstructionIdBoolNot: |
| 25917 | case IrInstructionIdSliceSrc: | 26349 | case IrInstructionIdSliceSrc: |
| 25918 | case IrInstructionIdMemberCount: | 26350 | case IrInstructionIdMemberCount: |
src/ir_print.cpp+41| ... | @@ -42,6 +42,12 @@ static const char* ir_instruction_type_str(IrInstruction* instruction) { | ... | @@ -42,6 +42,12 @@ static const char* ir_instruction_type_str(IrInstruction* instruction) { |
| 42 | switch (instruction->id) { | 42 | switch (instruction->id) { |
| 43 | case IrInstructionIdInvalid: | 43 | case IrInstructionIdInvalid: |
| 44 | return "Invalid"; | 44 | return "Invalid"; |
| 45 | case IrInstructionIdShuffleVector: | ||
| 46 | return "Shuffle"; | ||
| 47 | case IrInstructionIdSplatSrc: | ||
| 48 | return "SplatSrc"; | ||
| 49 | case IrInstructionIdSplatGen: | ||
| 50 | return "SplatGen"; | ||
| 45 | case IrInstructionIdDeclVarSrc: | 51 | case IrInstructionIdDeclVarSrc: |
| 46 | return "DeclVarSrc"; | 52 | return "DeclVarSrc"; |
| 47 | case IrInstructionIdDeclVarGen: | 53 | case IrInstructionIdDeclVarGen: |
| ... | @@ -1208,6 +1214,32 @@ static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruct | ... | @@ -1208,6 +1214,32 @@ static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruct |
| 1208 | fprintf(irp->f, ")"); | 1214 | fprintf(irp->f, ")"); |
| 1209 | } | 1215 | } |
| 1210 | 1216 | ||
| 1217 | static void ir_print_shuffle_vector(IrPrint *irp, IrInstructionShuffleVector *instruction) { | ||
| 1218 | fprintf(irp->f, "@shuffle("); | ||
| 1219 | ir_print_other_instruction(irp, instruction->scalar_type); | ||
| 1220 | fprintf(irp->f, ", "); | ||
| 1221 | ir_print_other_instruction(irp, instruction->a); | ||
| 1222 | fprintf(irp->f, ", "); | ||
| 1223 | ir_print_other_instruction(irp, instruction->b); | ||
| 1224 | fprintf(irp->f, ", "); | ||
| 1225 | ir_print_other_instruction(irp, instruction->mask); | ||
| 1226 | fprintf(irp->f, ")"); | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | static void ir_print_splat_src(IrPrint *irp, IrInstructionSplatSrc *instruction) { | ||
| 1230 | fprintf(irp->f, "@splat("); | ||
| 1231 | ir_print_other_instruction(irp, instruction->len); | ||
| 1232 | fprintf(irp->f, ", "); | ||
| 1233 | ir_print_other_instruction(irp, instruction->scalar); | ||
| 1234 | fprintf(irp->f, ")"); | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | static void ir_print_splat_gen(IrPrint *irp, IrInstructionSplatGen *instruction) { | ||
| 1238 | fprintf(irp->f, "@splat("); | ||
| 1239 | ir_print_other_instruction(irp, instruction->scalar); | ||
| 1240 | fprintf(irp->f, ")"); | ||
| 1241 | } | ||
| 1242 | |||
| 1211 | static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { | 1243 | static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { |
| 1212 | fprintf(irp->f, "! "); | 1244 | fprintf(irp->f, "! "); |
| 1213 | ir_print_other_instruction(irp, instruction->value); | 1245 | ir_print_other_instruction(irp, instruction->value); |
| ... | @@ -2143,6 +2175,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool | ... | @@ -2143,6 +2175,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2143 | case IrInstructionIdVectorType: | 2175 | case IrInstructionIdVectorType: |
| 2144 | ir_print_vector_type(irp, (IrInstructionVectorType *)instruction); | 2176 | ir_print_vector_type(irp, (IrInstructionVectorType *)instruction); |
| 2145 | break; | 2177 | break; |
| 2178 | case IrInstructionIdShuffleVector: | ||
| 2179 | ir_print_shuffle_vector(irp, (IrInstructionShuffleVector *)instruction); | ||
| 2180 | break; | ||
| 2181 | case IrInstructionIdSplatSrc: | ||
| 2182 | ir_print_splat_src(irp, (IrInstructionSplatSrc *)instruction); | ||
| 2183 | break; | ||
| 2184 | case IrInstructionIdSplatGen: | ||
| 2185 | ir_print_splat_gen(irp, (IrInstructionSplatGen *)instruction); | ||
| 2186 | break; | ||
| 2146 | case IrInstructionIdBoolNot: | 2187 | case IrInstructionIdBoolNot: |
| 2147 | ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); | 2188 | ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); |
| 2148 | break; | 2189 | break; |
src/list.hpp+1-1| ... | @@ -15,7 +15,7 @@ struct ZigList { | ... | @@ -15,7 +15,7 @@ struct ZigList { |
| 15 | void deinit() { | 15 | void deinit() { |
| 16 | free(items); | 16 | free(items); |
| 17 | } | 17 | } |
| 18 | void append(T item) { | 18 | void append(const T& item) { |
| 19 | ensure_capacity(length + 1); | 19 | ensure_capacity(length + 1); |
| 20 | items[length++] = item; | 20 | items[length++] = item; |
| 21 | } | 21 | } |
src/main.cpp+1-1| ... | @@ -90,7 +90,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { | ... | @@ -90,7 +90,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { |
| 90 | " -mllvm [arg] (unsupported) forward an arg to LLVM's option processing\n" | 90 | " -mllvm [arg] (unsupported) forward an arg to LLVM's option processing\n" |
| 91 | " --override-std-dir [arg] override path to Zig standard library\n" | 91 | " --override-std-dir [arg] override path to Zig standard library\n" |
| 92 | " --override-lib-dir [arg] override path to Zig lib library\n" | 92 | " --override-lib-dir [arg] override path to Zig lib library\n" |
| 93 | " -ffunction-sections places each function in a seperate section\n" | 93 | " -ffunction-sections places each function in a separate section\n" |
| 94 | "\n" | 94 | "\n" |
| 95 | "Link Options:\n" | 95 | "Link Options:\n" |
| 96 | " --bundle-compiler-rt for static libraries, include compiler-rt symbols\n" | 96 | " --bundle-compiler-rt for static libraries, include compiler-rt symbols\n" |
std/event/channel.zig+2| ... | @@ -306,6 +306,8 @@ pub fn Channel(comptime T: type) type { | ... | @@ -306,6 +306,8 @@ pub fn Channel(comptime T: type) type { |
| 306 | test "std.event.Channel" { | 306 | test "std.event.Channel" { |
| 307 | // https://github.com/ziglang/zig/issues/1908 | 307 | // https://github.com/ziglang/zig/issues/1908 |
| 308 | if (builtin.single_threaded) return error.SkipZigTest; | 308 | if (builtin.single_threaded) return error.SkipZigTest; |
| 309 | // https://github.com/ziglang/zig/issues/3251 | ||
| 310 | if (std.os.freebsd.is_the_target) return error.SkipZigTest; | ||
| 309 | 311 | ||
| 310 | var loop: Loop = undefined; | 312 | var loop: Loop = undefined; |
| 311 | // TODO make a multi threaded test | 313 | // TODO make a multi threaded test |
std/event/future.zig+2| ... | @@ -85,6 +85,8 @@ pub fn Future(comptime T: type) type { | ... | @@ -85,6 +85,8 @@ pub fn Future(comptime T: type) type { |
| 85 | test "std.event.Future" { | 85 | test "std.event.Future" { |
| 86 | // https://github.com/ziglang/zig/issues/1908 | 86 | // https://github.com/ziglang/zig/issues/1908 |
| 87 | if (builtin.single_threaded) return error.SkipZigTest; | 87 | if (builtin.single_threaded) return error.SkipZigTest; |
| 88 | // https://github.com/ziglang/zig/issues/3251 | ||
| 89 | if (std.os.freebsd.is_the_target) return error.SkipZigTest; | ||
| 88 | 90 | ||
| 89 | const allocator = std.heap.direct_allocator; | 91 | const allocator = std.heap.direct_allocator; |
| 90 | 92 |
std/event/lock.zig+2| ... | @@ -118,6 +118,8 @@ pub const Lock = struct { | ... | @@ -118,6 +118,8 @@ pub const Lock = struct { |
| 118 | test "std.event.Lock" { | 118 | test "std.event.Lock" { |
| 119 | // TODO https://github.com/ziglang/zig/issues/1908 | 119 | // TODO https://github.com/ziglang/zig/issues/1908 |
| 120 | if (builtin.single_threaded) return error.SkipZigTest; | 120 | if (builtin.single_threaded) return error.SkipZigTest; |
| 121 | // TODO https://github.com/ziglang/zig/issues/3251 | ||
| 122 | if (std.os.freebsd.is_the_target) return error.SkipZigTest; | ||
| 121 | 123 | ||
| 122 | const allocator = std.heap.direct_allocator; | 124 | const allocator = std.heap.direct_allocator; |
| 123 | 125 |
std/hash/auto_hash.zig+6-3| ... | @@ -116,7 +116,7 @@ pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void { | ... | @@ -116,7 +116,7 @@ pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void { |
| 116 | // Otherwise, hash every element. | 116 | // Otherwise, hash every element. |
| 117 | // TODO remove the copy to an array once field access is done. | 117 | // TODO remove the copy to an array once field access is done. |
| 118 | const array: [info.len]info.child = key; | 118 | const array: [info.len]info.child = key; |
| 119 | comptime var i: u32 = 0; | 119 | comptime var i = 0; |
| 120 | inline while (i < info.len) : (i += 1) { | 120 | inline while (i < info.len) : (i += 1) { |
| 121 | hash(hasher, array[i], strat); | 121 | hash(hasher, array[i], strat); |
| 122 | } | 122 | } |
| ... | @@ -357,10 +357,13 @@ test "testHash union" { | ... | @@ -357,10 +357,13 @@ test "testHash union" { |
| 357 | test "testHash vector" { | 357 | test "testHash vector" { |
| 358 | const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 }; | 358 | const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 }; |
| 359 | const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 }; | 359 | const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 }; |
| 360 | const c: @Vector(4, u31) = [_]u31{ 1, 2, 3, 4 }; | ||
| 361 | testing.expect(testHash(a) == testHash(a)); | 360 | testing.expect(testHash(a) == testHash(a)); |
| 362 | testing.expect(testHash(a) != testHash(b)); | 361 | testing.expect(testHash(a) != testHash(b)); |
| 363 | testing.expect(testHash(a) != testHash(c)); | 362 | |
| 363 | const c: @Vector(4, u31) = [_]u31{ 1, 2, 3, 4 }; | ||
| 364 | const d: @Vector(4, u31) = [_]u31{ 1, 2, 3, 5 }; | ||
| 365 | testing.expect(testHash(c) == testHash(c)); | ||
| 366 | testing.expect(testHash(c) != testHash(d)); | ||
| 364 | } | 367 | } |
| 365 | 368 | ||
| 366 | test "testHash error union" { | 369 | test "testHash error union" { |
std/http/headers.zig+1-1| ... | @@ -299,7 +299,7 @@ pub const Headers = struct { | ... | @@ -299,7 +299,7 @@ pub const Headers = struct { |
| 299 | return buf; | 299 | return buf; |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | /// Returns all headers with the given name as a comma seperated string. | 302 | /// Returns all headers with the given name as a comma separated string. |
| 303 | /// | 303 | /// |
| 304 | /// Useful for HTTP headers that follow RFC-7230 section 3.2.2: | 304 | /// Useful for HTTP headers that follow RFC-7230 section 3.2.2: |
| 305 | /// A recipient MAY combine multiple header fields with the same field | 305 | /// A recipient MAY combine multiple header fields with the same field |
std/special/c.zig+2-7| ... | @@ -269,16 +269,11 @@ nakedcc fn clone() void { | ... | @@ -269,16 +269,11 @@ nakedcc fn clone() void { |
| 269 | \\ bx lr | 269 | \\ bx lr |
| 270 | \\ | 270 | \\ |
| 271 | \\1: mov r0,r6 | 271 | \\1: mov r0,r6 |
| 272 | \\ tst r5,#1 | 272 | \\ bl 3f |
| 273 | \\ bne 1f | ||
| 274 | \\ mov lr,pc | ||
| 275 | \\ mov pc,r5 | ||
| 276 | \\2: mov r7,#1 | 273 | \\2: mov r7,#1 |
| 277 | \\ svc 0 | 274 | \\ svc 0 |
| 278 | \\ | ||
| 279 | \\1: mov lr,pc | ||
| 280 | \\ bx r5 | ||
| 281 | \\ b 2b | 275 | \\ b 2b |
| 276 | \\3: bx r5 | ||
| 282 | ); | 277 | ); |
| 283 | } else { | 278 | } else { |
| 284 | @compileError("Implement clone() for this arch."); | 279 | @compileError("Implement clone() for this arch."); |
std/special/start.zig+1-1| ... | @@ -23,7 +23,7 @@ comptime { | ... | @@ -23,7 +23,7 @@ comptime { |
| 23 | } else if (builtin.os == .uefi) { | 23 | } else if (builtin.os == .uefi) { |
| 24 | @export("EfiMain", EfiMain, .Strong); | 24 | @export("EfiMain", EfiMain, .Strong); |
| 25 | } else { | 25 | } else { |
| 26 | @export("_start", _start, .Strong); | 26 | if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong); |
| 27 | } | 27 | } |
| 28 | } | 28 | } |
| 29 | 29 |
std/zig/ast.zig+40-40| ... | @@ -255,39 +255,39 @@ pub const Error = union(enum) { | ... | @@ -255,39 +255,39 @@ pub const Error = union(enum) { |
| 255 | } | 255 | } |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | pub const InvalidToken = SingleTokenError("Invalid token {}"); | 258 | pub const InvalidToken = SingleTokenError("Invalid token '{}'"); |
| 259 | pub const ExpectedContainerMembers = SingleTokenError("Expected test, comptime, var decl, or container field, found {}"); | 259 | pub const ExpectedContainerMembers = SingleTokenError("Expected test, comptime, var decl, or container field, found '{}'"); |
| 260 | pub const ExpectedStringLiteral = SingleTokenError("Expected string literal, found {}"); | 260 | pub const ExpectedStringLiteral = SingleTokenError("Expected string literal, found '{}'"); |
| 261 | pub const ExpectedIntegerLiteral = SingleTokenError("Expected integer literal, found {}"); | 261 | pub const ExpectedIntegerLiteral = SingleTokenError("Expected integer literal, found '{}'"); |
| 262 | pub const ExpectedIdentifier = SingleTokenError("Expected identifier, found {}"); | 262 | pub const ExpectedIdentifier = SingleTokenError("Expected identifier, found '{}'"); |
| 263 | pub const ExpectedStatement = SingleTokenError("Expected statement, found {}"); | 263 | pub const ExpectedStatement = SingleTokenError("Expected statement, found '{}'"); |
| 264 | pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found {}"); | 264 | pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found '{}'"); |
| 265 | pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found {}"); | 265 | pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'"); |
| 266 | pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found {}"); | 266 | pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'"); |
| 267 | pub const ExpectedAggregateKw = SingleTokenError("Expected " ++ @tagName(Token.Id.Keyword_struct) ++ ", " ++ @tagName(Token.Id.Keyword_union) ++ ", or " ++ @tagName(Token.Id.Keyword_enum) ++ ", found {}"); | 267 | pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', or '" ++ Token.Id.Keyword_enum.symbol() ++ "', found '{}'"); |
| 268 | pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found {}"); | 268 | pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'"); |
| 269 | pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found {}"); | 269 | pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{}'"); |
| 270 | pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found {}"); | 270 | pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{}'"); |
| 271 | pub const ExpectedLBrace = SingleTokenError("Expected '{{', found {}"); | 271 | pub const ExpectedLBrace = SingleTokenError("Expected '{{', found '{}'"); |
| 272 | pub const ExpectedLabelOrLBrace = SingleTokenError("Expected label or '{{', found {}"); | 272 | pub const ExpectedLabelOrLBrace = SingleTokenError("Expected label or '{{', found '{}'"); |
| 273 | pub const ExpectedColonOrRParen = SingleTokenError("Expected ':' or ')', found {}"); | 273 | pub const ExpectedColonOrRParen = SingleTokenError("Expected ':' or ')', found '{}'"); |
| 274 | pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found {}"); | 274 | pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found '{}'"); |
| 275 | pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found {}"); | 275 | pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found '{}'"); |
| 276 | pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or " ++ @tagName(Token.Id.Identifier) ++ ", found {}"); | 276 | pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or '" ++ Token.Id.Identifier.symbol() ++ "', found '{}'"); |
| 277 | pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found {}"); | 277 | pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found '{}'"); |
| 278 | pub const ExpectedTypeExpr = SingleTokenError("Expected type expression, found {}"); | 278 | pub const ExpectedTypeExpr = SingleTokenError("Expected type expression, found '{}'"); |
| 279 | pub const ExpectedPrimaryTypeExpr = SingleTokenError("Expected primary type expression, found {}"); | 279 | pub const ExpectedPrimaryTypeExpr = SingleTokenError("Expected primary type expression, found '{}'"); |
| 280 | pub const ExpectedExpr = SingleTokenError("Expected expression, found {}"); | 280 | pub const ExpectedExpr = SingleTokenError("Expected expression, found '{}'"); |
| 281 | pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found {}"); | 281 | pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found '{}'"); |
| 282 | pub const ExpectedParamList = SingleTokenError("Expected parameter list, found {}"); | 282 | pub const ExpectedParamList = SingleTokenError("Expected parameter list, found '{}'"); |
| 283 | pub const ExpectedPayload = SingleTokenError("Expected loop payload, found {}"); | 283 | pub const ExpectedPayload = SingleTokenError("Expected loop payload, found '{}'"); |
| 284 | pub const ExpectedBlockOrAssignment = SingleTokenError("Expected block or assignment, found {}"); | 284 | pub const ExpectedBlockOrAssignment = SingleTokenError("Expected block or assignment, found '{}'"); |
| 285 | pub const ExpectedBlockOrExpression = SingleTokenError("Expected block or expression, found {}"); | 285 | pub const ExpectedBlockOrExpression = SingleTokenError("Expected block or expression, found '{}'"); |
| 286 | pub const ExpectedExprOrAssignment = SingleTokenError("Expected expression or assignment, found {}"); | 286 | pub const ExpectedExprOrAssignment = SingleTokenError("Expected expression or assignment, found '{}'"); |
| 287 | pub const ExpectedPrefixExpr = SingleTokenError("Expected prefix expression, found {}"); | 287 | pub const ExpectedPrefixExpr = SingleTokenError("Expected prefix expression, found '{}'"); |
| 288 | pub const ExpectedLoopExpr = SingleTokenError("Expected loop expression, found {}"); | 288 | pub const ExpectedLoopExpr = SingleTokenError("Expected loop expression, found '{}'"); |
| 289 | pub const ExpectedDerefOrUnwrap = SingleTokenError("Expected pointer dereference or optional unwrap, found {}"); | 289 | pub const ExpectedDerefOrUnwrap = SingleTokenError("Expected pointer dereference or optional unwrap, found '{}'"); |
| 290 | pub const ExpectedSuffixOp = SingleTokenError("Expected pointer dereference, optional unwrap, or field access, found {}"); | 290 | pub const ExpectedSuffixOp = SingleTokenError("Expected pointer dereference, optional unwrap, or field access, found '{}'"); |
| 291 | 291 | ||
| 292 | pub const ExpectedParamType = SimpleError("Expected parameter type"); | 292 | pub const ExpectedParamType = SimpleError("Expected parameter type"); |
| 293 | pub const ExpectedPubItem = SimpleError("Pub must be followed by fn decl, var decl, or container member"); | 293 | pub const ExpectedPubItem = SimpleError("Pub must be followed by fn decl, var decl, or container member"); |
| ... | @@ -324,11 +324,11 @@ pub const Error = union(enum) { | ... | @@ -324,11 +324,11 @@ pub const Error = union(enum) { |
| 324 | return stream.print("`&&` is invalid. Note that `and` is boolean AND."); | 324 | return stream.print("`&&` is invalid. Note that `and` is boolean AND."); |
| 325 | }, | 325 | }, |
| 326 | .Invalid => { | 326 | .Invalid => { |
| 327 | return stream.print("expected {}, found invalid bytes", @tagName(self.expected_id)); | 327 | return stream.print("expected '{}', found invalid bytes", self.expected_id.symbol()); |
| 328 | }, | 328 | }, |
| 329 | else => { | 329 | else => { |
| 330 | const token_name = @tagName(found_token.id); | 330 | const token_name = found_token.id.symbol(); |
| 331 | return stream.print("expected {}, found {}", @tagName(self.expected_id), token_name); | 331 | return stream.print("expected '{}', found '{}'", self.expected_id.symbol(), token_name); |
| 332 | }, | 332 | }, |
| 333 | } | 333 | } |
| 334 | } | 334 | } |
| ... | @@ -339,8 +339,8 @@ pub const Error = union(enum) { | ... | @@ -339,8 +339,8 @@ pub const Error = union(enum) { |
| 339 | end_id: Token.Id, | 339 | end_id: Token.Id, |
| 340 | 340 | ||
| 341 | pub fn render(self: *const ExpectedCommaOrEnd, tokens: *Tree.TokenList, stream: var) !void { | 341 | pub fn render(self: *const ExpectedCommaOrEnd, tokens: *Tree.TokenList, stream: var) !void { |
| 342 | const token_name = @tagName(tokens.at(self.token).id); | 342 | const actual_token = tokens.at(self.token); |
| 343 | return stream.print("expected ',' or {}, found {}", @tagName(self.end_id), token_name); | 343 | return stream.print("expected ',' or '{}', found '{}'", self.end_id.symbol(), actual_token.id.symbol()); |
| 344 | } | 344 | } |
| 345 | }; | 345 | }; |
| 346 | 346 | ||
| ... | @@ -351,8 +351,8 @@ pub const Error = union(enum) { | ... | @@ -351,8 +351,8 @@ pub const Error = union(enum) { |
| 351 | token: TokenIndex, | 351 | token: TokenIndex, |
| 352 | 352 | ||
| 353 | pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void { | 353 | pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void { |
| 354 | const token_name = @tagName(tokens.at(self.token).id); | 354 | const actual_token = tokens.at(self.token); |
| 355 | return stream.print(msg, token_name); | 355 | return stream.print(msg, actual_token.id.symbol()); |
| 356 | } | 356 | } |
| 357 | }; | 357 | }; |
| 358 | } | 358 | } |
std/zig/tokenizer.zig+125| ... | @@ -196,6 +196,131 @@ pub const Token = struct { | ... | @@ -196,6 +196,131 @@ pub const Token = struct { |
| 196 | Keyword_var, | 196 | Keyword_var, |
| 197 | Keyword_volatile, | 197 | Keyword_volatile, |
| 198 | Keyword_while, | 198 | Keyword_while, |
| 199 | |||
| 200 | pub fn symbol(id: Id) []const u8 { | ||
| 201 | return switch (id) { | ||
| 202 | .Invalid => "Invalid", | ||
| 203 | .Invalid_ampersands => "&&", | ||
| 204 | .Identifier => "Identifier", | ||
| 205 | .StringLiteral => "StringLiteral", | ||
| 206 | .MultilineStringLiteralLine => "MultilineStringLiteralLine", | ||
| 207 | .CharLiteral => "CharLiteral", | ||
| 208 | .Eof => "Eof", | ||
| 209 | .Builtin => "Builtin", | ||
| 210 | .IntegerLiteral => "IntegerLiteral", | ||
| 211 | .FloatLiteral => "FloatLiteral", | ||
| 212 | .LineComment => "LineComment", | ||
| 213 | .DocComment => "DocComment", | ||
| 214 | .ShebangLine => "ShebangLine", | ||
| 215 | |||
| 216 | .Bang => "!", | ||
| 217 | .Pipe => "|", | ||
| 218 | .PipePipe => "||", | ||
| 219 | .PipeEqual => "|=", | ||
| 220 | .Equal => "=", | ||
| 221 | .EqualEqual => "==", | ||
| 222 | .EqualAngleBracketRight => "=>", | ||
| 223 | .BangEqual => "!=", | ||
| 224 | .LParen => "(", | ||
| 225 | .RParen => ")", | ||
| 226 | .Semicolon => ";", | ||
| 227 | .Percent => "%", | ||
| 228 | .PercentEqual => "%=", | ||
| 229 | .LBrace => "{", | ||
| 230 | .RBrace => "}", | ||
| 231 | .LBracket => "[", | ||
| 232 | .RBracket => "]", | ||
| 233 | .Period => ".", | ||
| 234 | .Ellipsis2 => "..", | ||
| 235 | .Ellipsis3 => "...", | ||
| 236 | .Caret => "^", | ||
| 237 | .CaretEqual => "^=", | ||
| 238 | .Plus => "+", | ||
| 239 | .PlusPlus => "++", | ||
| 240 | .PlusEqual => "+=", | ||
| 241 | .PlusPercent => "+%", | ||
| 242 | .PlusPercentEqual => "+%=", | ||
| 243 | .Minus => "-", | ||
| 244 | .MinusEqual => "-=", | ||
| 245 | .MinusPercent => "-%", | ||
| 246 | .MinusPercentEqual => "-%=", | ||
| 247 | .Asterisk => "*", | ||
| 248 | .AsteriskEqual => "*=", | ||
| 249 | .AsteriskAsterisk => "**", | ||
| 250 | .AsteriskPercent => "*%", | ||
| 251 | .AsteriskPercentEqual => "*%=", | ||
| 252 | .Arrow => "->", | ||
| 253 | .Colon => ":", | ||
| 254 | .Slash => "/", | ||
| 255 | .SlashEqual => "/=", | ||
| 256 | .Comma => ",", | ||
| 257 | .Ampersand => "&", | ||
| 258 | .AmpersandEqual => "&=", | ||
| 259 | .QuestionMark => "?", | ||
| 260 | .AngleBracketLeft => "<", | ||
| 261 | .AngleBracketLeftEqual => "<=", | ||
| 262 | .AngleBracketAngleBracketLeft => "<<", | ||
| 263 | .AngleBracketAngleBracketLeftEqual => "<<=", | ||
| 264 | .AngleBracketRight => ">", | ||
| 265 | .AngleBracketRightEqual => ">=", | ||
| 266 | .AngleBracketAngleBracketRight => ">>", | ||
| 267 | .AngleBracketAngleBracketRightEqual => ">>=", | ||
| 268 | .Tilde => "~", | ||
| 269 | .BracketStarBracket => "[*]", | ||
| 270 | .BracketStarCBracket => "[*c]", | ||
| 271 | .Keyword_align => "align", | ||
| 272 | .Keyword_allowzero => "allowzero", | ||
| 273 | .Keyword_and => "and", | ||
| 274 | .Keyword_anyframe => "anyframe", | ||
| 275 | .Keyword_asm => "asm", | ||
| 276 | .Keyword_async => "async", | ||
| 277 | .Keyword_await => "await", | ||
| 278 | .Keyword_break => "break", | ||
| 279 | .Keyword_catch => "catch", | ||
| 280 | .Keyword_comptime => "comptime", | ||
| 281 | .Keyword_const => "const", | ||
| 282 | .Keyword_continue => "continue", | ||
| 283 | .Keyword_defer => "defer", | ||
| 284 | .Keyword_else => "else", | ||
| 285 | .Keyword_enum => "enum", | ||
| 286 | .Keyword_errdefer => "errdefer", | ||
| 287 | .Keyword_error => "error", | ||
| 288 | .Keyword_export => "export", | ||
| 289 | .Keyword_extern => "extern", | ||
| 290 | .Keyword_false => "false", | ||
| 291 | .Keyword_fn => "fn", | ||
| 292 | .Keyword_for => "for", | ||
| 293 | .Keyword_if => "if", | ||
| 294 | .Keyword_inline => "inline", | ||
| 295 | .Keyword_nakedcc => "nakedcc", | ||
| 296 | .Keyword_noalias => "noalias", | ||
| 297 | .Keyword_noasync => "noasync", | ||
| 298 | .Keyword_noinline => "noinline", | ||
| 299 | .Keyword_null => "null", | ||
| 300 | .Keyword_or => "or", | ||
| 301 | .Keyword_orelse => "orelse", | ||
| 302 | .Keyword_packed => "packed", | ||
| 303 | .Keyword_pub => "pub", | ||
| 304 | .Keyword_resume => "resume", | ||
| 305 | .Keyword_return => "return", | ||
| 306 | .Keyword_linksection => "linksection", | ||
| 307 | .Keyword_stdcallcc => "stdcallcc", | ||
| 308 | .Keyword_struct => "struct", | ||
| 309 | .Keyword_suspend => "suspend", | ||
| 310 | .Keyword_switch => "switch", | ||
| 311 | .Keyword_test => "test", | ||
| 312 | .Keyword_threadlocal => "threadlocal", | ||
| 313 | .Keyword_true => "true", | ||
| 314 | .Keyword_try => "try", | ||
| 315 | .Keyword_undefined => "undefined", | ||
| 316 | .Keyword_union => "union", | ||
| 317 | .Keyword_unreachable => "unreachable", | ||
| 318 | .Keyword_usingnamespace => "usingnamespace", | ||
| 319 | .Keyword_var => "var", | ||
| 320 | .Keyword_volatile => "volatile", | ||
| 321 | .Keyword_while => "while", | ||
| 322 | }; | ||
| 323 | } | ||
| 199 | }; | 324 | }; |
| 200 | }; | 325 | }; |
| 201 | 326 |
test/compile_errors.zig+24-1| ... | @@ -6484,6 +6484,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -6484,6 +6484,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 6484 | "tmp.zig:7:23: error: unable to evaluate constant expression", | 6484 | "tmp.zig:7:23: error: unable to evaluate constant expression", |
| 6485 | ); | 6485 | ); |
| 6486 | 6486 | ||
| 6487 | cases.addTest( | ||
| 6488 | "@shuffle with selected index past first vector length", | ||
| 6489 | \\export fn entry() void { | ||
| 6490 | \\ const v: @Vector(4, u32) = [4]u32{ 10, 11, 12, 13 }; | ||
| 6491 | \\ const x: @Vector(4, u32) = [4]u32{ 14, 15, 16, 17 }; | ||
| 6492 | \\ var z = @shuffle(u32, v, x, [8]i32{ 0, 1, 2, 3, 7, 6, 5, 4 }); | ||
| 6493 | \\} | ||
| 6494 | , | ||
| 6495 | "tmp.zig:4:39: error: mask index '4' has out-of-bounds selection", | ||
| 6496 | "tmp.zig:4:27: note: selected index '7' out of bounds of @Vector(4, u32)", | ||
| 6497 | "tmp.zig:4:30: note: selections from the second vector are specified with negative numbers", | ||
| 6498 | ); | ||
| 6499 | |||
| 6487 | cases.addTest( | 6500 | cases.addTest( |
| 6488 | "nested vectors", | 6501 | "nested vectors", |
| 6489 | \\export fn entry() void { | 6502 | \\export fn entry() void { |
| ... | @@ -6491,7 +6504,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -6491,7 +6504,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 6491 | \\ var v: V = undefined; | 6504 | \\ var v: V = undefined; |
| 6492 | \\} | 6505 | \\} |
| 6493 | , | 6506 | , |
| 6494 | "tmp.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid", | 6507 | "tmp.zig:2:26: error: vector element type must be integer, float, bool, or pointer; '@Vector(4, u8)' is invalid", |
| 6508 | ); | ||
| 6509 | |||
| 6510 | cases.addTest( | ||
| 6511 | "bad @splat type", | ||
| 6512 | \\export fn entry() void { | ||
| 6513 | \\ const c = 4; | ||
| 6514 | \\ var v = @splat(4, c); | ||
| 6515 | \\} | ||
| 6516 | , | ||
| 6517 | "tmp.zig:3:23: error: vector element type must be integer, float, bool, or pointer; 'comptime_int' is invalid", | ||
| 6495 | ); | 6518 | ); |
| 6496 | 6519 | ||
| 6497 | cases.add("compileLog of tagged enum doesn't crash the compiler", | 6520 | cases.add("compileLog of tagged enum doesn't crash the compiler", |
test/stage1/behavior.zig+1| ... | @@ -80,6 +80,7 @@ comptime { | ... | @@ -80,6 +80,7 @@ comptime { |
| 80 | _ = @import("behavior/pub_enum.zig"); | 80 | _ = @import("behavior/pub_enum.zig"); |
| 81 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | 81 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); |
| 82 | _ = @import("behavior/reflection.zig"); | 82 | _ = @import("behavior/reflection.zig"); |
| 83 | _ = @import("behavior/shuffle.zig"); | ||
| 83 | _ = @import("behavior/sizeof_and_typeof.zig"); | 84 | _ = @import("behavior/sizeof_and_typeof.zig"); |
| 84 | _ = @import("behavior/slice.zig"); | 85 | _ = @import("behavior/slice.zig"); |
| 85 | _ = @import("behavior/slicetobytes.zig"); | 86 | _ = @import("behavior/slicetobytes.zig"); |
test/stage1/behavior/byteswap.zig+55-25| ... | @@ -1,32 +1,62 @@ | ... | @@ -1,32 +1,62 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | 3 | ||
| 4 | test "@byteSwap" { | 4 | test "@byteSwap integers" { |
| 5 | comptime testByteSwap(); | 5 | const ByteSwapIntTest = struct { |
| 6 | testByteSwap(); | 6 | fn run() void { |
| 7 | t(u0, 0, 0); | ||
| 8 | t(u8, 0x12, 0x12); | ||
| 9 | t(u16, 0x1234, 0x3412); | ||
| 10 | t(u24, 0x123456, 0x563412); | ||
| 11 | t(u32, 0x12345678, 0x78563412); | ||
| 12 | t(u40, 0x123456789a, 0x9a78563412); | ||
| 13 | t(i48, 0x123456789abc, @bitCast(i48, u48(0xbc9a78563412))); | ||
| 14 | t(u56, 0x123456789abcde, 0xdebc9a78563412); | ||
| 15 | t(u64, 0x123456789abcdef1, 0xf1debc9a78563412); | ||
| 16 | t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412); | ||
| 17 | |||
| 18 | t(u0, u0(0), 0); | ||
| 19 | t(i8, i8(-50), -50); | ||
| 20 | t(i16, @bitCast(i16, u16(0x1234)), @bitCast(i16, u16(0x3412))); | ||
| 21 | t(i24, @bitCast(i24, u24(0x123456)), @bitCast(i24, u24(0x563412))); | ||
| 22 | t(i32, @bitCast(i32, u32(0x12345678)), @bitCast(i32, u32(0x78563412))); | ||
| 23 | t(u40, @bitCast(i40, u40(0x123456789a)), u40(0x9a78563412)); | ||
| 24 | t(i48, @bitCast(i48, u48(0x123456789abc)), @bitCast(i48, u48(0xbc9a78563412))); | ||
| 25 | t(i56, @bitCast(i56, u56(0x123456789abcde)), @bitCast(i56, u56(0xdebc9a78563412))); | ||
| 26 | t(i64, @bitCast(i64, u64(0x123456789abcdef1)), @bitCast(i64, u64(0xf1debc9a78563412))); | ||
| 27 | t( | ||
| 28 | i128, | ||
| 29 | @bitCast(i128, u128(0x123456789abcdef11121314151617181)), | ||
| 30 | @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)), | ||
| 31 | ); | ||
| 32 | } | ||
| 33 | fn t(comptime I: type, input: I, expected_output: I) void { | ||
| 34 | std.testing.expectEqual(expected_output, @byteSwap(I, input)); | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | comptime ByteSwapIntTest.run(); | ||
| 38 | ByteSwapIntTest.run(); | ||
| 7 | } | 39 | } |
| 8 | 40 | ||
| 9 | fn testByteSwap() void { | 41 | test "@byteSwap vectors" { |
| 10 | expect(@byteSwap(u0, 0) == 0); | 42 | const ByteSwapVectorTest = struct { |
| 11 | expect(@byteSwap(u8, 0x12) == 0x12); | 43 | fn run() void { |
| 12 | expect(@byteSwap(u16, 0x1234) == 0x3412); | 44 | t(u8, 2, [_]u8{ 0x12, 0x13 }, [_]u8{ 0x12, 0x13 }); |
| 13 | expect(@byteSwap(u24, 0x123456) == 0x563412); | 45 | t(u16, 2, [_]u16{ 0x1234, 0x2345 }, [_]u16{ 0x3412, 0x4523 }); |
| 14 | expect(@byteSwap(u32, 0x12345678) == 0x78563412); | 46 | t(u24, 2, [_]u24{ 0x123456, 0x234567 }, [_]u24{ 0x563412, 0x674523 }); |
| 15 | expect(@byteSwap(u40, 0x123456789a) == 0x9a78563412); | 47 | } |
| 16 | expect(@byteSwap(i48, 0x123456789abc) == @bitCast(i48, u48(0xbc9a78563412))); | ||
| 17 | expect(@byteSwap(u56, 0x123456789abcde) == 0xdebc9a78563412); | ||
| 18 | expect(@byteSwap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412); | ||
| 19 | expect(@byteSwap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412); | ||
| 20 | 48 | ||
| 21 | expect(@byteSwap(u0, u0(0)) == 0); | 49 | fn t( |
| 22 | expect(@byteSwap(i8, i8(-50)) == -50); | 50 | comptime I: type, |
| 23 | expect(@byteSwap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412))); | 51 | comptime n: comptime_int, |
| 24 | expect(@byteSwap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412))); | 52 | input: @Vector(n, I), |
| 25 | expect(@byteSwap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412))); | 53 | expected_vector: @Vector(n, I), |
| 26 | expect(@byteSwap(u40, @bitCast(i40, u40(0x123456789a))) == u40(0x9a78563412)); | 54 | ) void { |
| 27 | expect(@byteSwap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412))); | 55 | const actual_output: [n]I = @byteSwap(I, input); |
| 28 | expect(@byteSwap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412))); | 56 | const expected_output: [n]I = expected_vector; |
| 29 | expect(@byteSwap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412))); | 57 | std.testing.expectEqual(expected_output, actual_output); |
| 30 | expect(@byteSwap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == | 58 | } |
| 31 | @bitCast(i128, u128(0x8171615141312111f1debc9a78563412))); | 59 | }; |
| 60 | comptime ByteSwapVectorTest.run(); | ||
| 61 | ByteSwapVectorTest.run(); | ||
| 32 | } | 62 | } |
test/stage1/behavior/misc.zig+20| ... | @@ -721,3 +721,23 @@ test "global variable assignment with optional unwrapping with var initialized t | ... | @@ -721,3 +721,23 @@ test "global variable assignment with optional unwrapping with var initialized t |
| 721 | }; | 721 | }; |
| 722 | expect(global_foo.* == 1234); | 722 | expect(global_foo.* == 1234); |
| 723 | } | 723 | } |
| 724 | |||
| 725 | test "peer result location with typed parent, runtime condition, comptime prongs" { | ||
| 726 | const S = struct { | ||
| 727 | fn doTheTest(arg: i32) i32 { | ||
| 728 | const st = Structy{ | ||
| 729 | .bleh = if (arg == 1) 1 else 1, | ||
| 730 | }; | ||
| 731 | |||
| 732 | if (st.bleh == 1) | ||
| 733 | return 1234; | ||
| 734 | return 0; | ||
| 735 | } | ||
| 736 | |||
| 737 | const Structy = struct { | ||
| 738 | bleh: i32, | ||
| 739 | }; | ||
| 740 | }; | ||
| 741 | expect(S.doTheTest(0) == 1234); | ||
| 742 | expect(S.doTheTest(1) == 1234); | ||
| 743 | } |
test/stage1/behavior/shuffle.zig created+57| ... | @@ -0,0 +1,57 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const expect = std.testing.expect; | ||
| 4 | |||
| 5 | test "@shuffle" { | ||
| 6 | const S = struct { | ||
| 7 | fn doTheTest() void { | ||
| 8 | var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 9 | var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; | ||
| 10 | const mask: @Vector(4, i32) = [4]i32{ 0, ~i32(2), 3, ~i32(3) }; | ||
| 11 | var res = @shuffle(i32, v, x, mask); | ||
| 12 | expect(mem.eql(i32, ([4]i32)(res), [4]i32{ 2147483647, 3, 40, 4 })); | ||
| 13 | |||
| 14 | // Implicit cast from array (of mask) | ||
| 15 | res = @shuffle(i32, v, x, [4]i32{ 0, ~i32(2), 3, ~i32(3) }); | ||
| 16 | expect(mem.eql(i32, ([4]i32)(res), [4]i32{ 2147483647, 3, 40, 4 })); | ||
| 17 | |||
| 18 | // Undefined | ||
| 19 | const mask2: @Vector(4, i32) = [4]i32{ 3, 1, 2, 0 }; | ||
| 20 | res = @shuffle(i32, v, undefined, mask2); | ||
| 21 | expect(mem.eql(i32, ([4]i32)(res), [4]i32{ 40, -2, 30, 2147483647 })); | ||
| 22 | |||
| 23 | // Upcasting of b | ||
| 24 | var v2: @Vector(2, i32) = [2]i32{ 2147483647, undefined }; | ||
| 25 | const mask3: @Vector(4, i32) = [4]i32{ ~i32(0), 2, ~i32(0), 3 }; | ||
| 26 | res = @shuffle(i32, x, v2, mask3); | ||
| 27 | expect(mem.eql(i32, ([4]i32)(res), [4]i32{ 2147483647, 3, 2147483647, 4 })); | ||
| 28 | |||
| 29 | // Upcasting of a | ||
| 30 | var v3: @Vector(2, i32) = [2]i32{ 2147483647, -2 }; | ||
| 31 | const mask4: @Vector(4, i32) = [4]i32{ 0, ~i32(2), 1, ~i32(3) }; | ||
| 32 | res = @shuffle(i32, v3, x, mask4); | ||
| 33 | expect(mem.eql(i32, ([4]i32)(res), [4]i32{ 2147483647, 3, -2, 4 })); | ||
| 34 | |||
| 35 | // bool | ||
| 36 | { | ||
| 37 | var x2: @Vector(4, bool) = [4]bool{ false, true, false, true }; | ||
| 38 | var v4: @Vector(2, bool) = [2]bool{ true, false }; | ||
| 39 | const mask5: @Vector(4, i32) = [4]i32{ 0, ~i32(1), 1, 2 }; | ||
| 40 | var res2 = @shuffle(bool, x2, v4, mask5); | ||
| 41 | expect(mem.eql(bool, ([4]bool)(res2), [4]bool{ false, false, true, false })); | ||
| 42 | } | ||
| 43 | |||
| 44 | // TODO re-enable when LLVM codegen is fixed | ||
| 45 | // https://github.com/ziglang/zig/issues/3246 | ||
| 46 | if (false) { | ||
| 47 | var x2: @Vector(3, bool) = [3]bool{ false, true, false }; | ||
| 48 | var v4: @Vector(2, bool) = [2]bool{ true, false }; | ||
| 49 | const mask5: @Vector(4, i32) = [4]i32{ 0, ~i32(1), 1, 2 }; | ||
| 50 | var res2 = @shuffle(bool, x2, v4, mask5); | ||
| 51 | expect(mem.eql(bool, ([4]bool)(res2), [4]bool{ false, false, true, false })); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | }; | ||
| 55 | S.doTheTest(); | ||
| 56 | comptime S.doTheTest(); | ||
| 57 | } | ||
test/stage1/behavior/vector.zig+75| ... | @@ -2,6 +2,18 @@ const std = @import("std"); | ... | @@ -2,6 +2,18 @@ const std = @import("std"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| 3 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 4 | 4 | ||
| 5 | test "implicit cast vector to array - bool" { | ||
| 6 | const S = struct { | ||
| 7 | fn doTheTest() void { | ||
| 8 | const a: @Vector(4, bool) = [_]bool{ true, false, true, false }; | ||
| 9 | const result_array: [4]bool = a; | ||
| 10 | expect(mem.eql(bool, result_array, [4]bool{ true, false, true, false })); | ||
| 11 | } | ||
| 12 | }; | ||
| 13 | S.doTheTest(); | ||
| 14 | comptime S.doTheTest(); | ||
| 15 | } | ||
| 16 | |||
| 5 | test "vector wrap operators" { | 17 | test "vector wrap operators" { |
| 6 | const S = struct { | 18 | const S = struct { |
| 7 | fn doTheTest() void { | 19 | fn doTheTest() void { |
| ... | @@ -18,6 +30,23 @@ test "vector wrap operators" { | ... | @@ -18,6 +30,23 @@ test "vector wrap operators" { |
| 18 | comptime S.doTheTest(); | 30 | comptime S.doTheTest(); |
| 19 | } | 31 | } |
| 20 | 32 | ||
| 33 | test "vector bin compares with mem.eql" { | ||
| 34 | const S = struct { | ||
| 35 | fn doTheTest() void { | ||
| 36 | var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 37 | var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 }; | ||
| 38 | expect(mem.eql(bool, ([4]bool)(v == x), [4]bool{ false, false, true, false })); | ||
| 39 | expect(mem.eql(bool, ([4]bool)(v != x), [4]bool{ true, true, false, true })); | ||
| 40 | expect(mem.eql(bool, ([4]bool)(v < x), [4]bool{ false, true, false, false })); | ||
| 41 | expect(mem.eql(bool, ([4]bool)(v > x), [4]bool{ true, false, false, true })); | ||
| 42 | expect(mem.eql(bool, ([4]bool)(v <= x), [4]bool{ false, true, true, false })); | ||
| 43 | expect(mem.eql(bool, ([4]bool)(v >= x), [4]bool{ true, false, true, true })); | ||
| 44 | } | ||
| 45 | }; | ||
| 46 | S.doTheTest(); | ||
| 47 | comptime S.doTheTest(); | ||
| 48 | } | ||
| 49 | |||
| 21 | test "vector int operators" { | 50 | test "vector int operators" { |
| 22 | const S = struct { | 51 | const S = struct { |
| 23 | fn doTheTest() void { | 52 | fn doTheTest() void { |
| ... | @@ -80,3 +109,49 @@ test "array to vector" { | ... | @@ -80,3 +109,49 @@ test "array to vector" { |
| 80 | var arr = [4]f32{ foo, 1.5, 0.0, 0.0 }; | 109 | var arr = [4]f32{ foo, 1.5, 0.0, 0.0 }; |
| 81 | var vec: @Vector(4, f32) = arr; | 110 | var vec: @Vector(4, f32) = arr; |
| 82 | } | 111 | } |
| 112 | |||
| 113 | test "vector casts of sizes not divisable by 8" { | ||
| 114 | const S = struct { | ||
| 115 | fn doTheTest() void { | ||
| 116 | { | ||
| 117 | var v: @Vector(4, u3) = [4]u3{ 5, 2, 3, 0 }; | ||
| 118 | var x: [4]u3 = v; | ||
| 119 | expect(mem.eql(u3, x, ([4]u3)(v))); | ||
| 120 | } | ||
| 121 | { | ||
| 122 | var v: @Vector(4, u2) = [4]u2{ 1, 2, 3, 0 }; | ||
| 123 | var x: [4]u2 = v; | ||
| 124 | expect(mem.eql(u2, x, ([4]u2)(v))); | ||
| 125 | } | ||
| 126 | { | ||
| 127 | var v: @Vector(4, u1) = [4]u1{ 1, 0, 1, 0 }; | ||
| 128 | var x: [4]u1 = v; | ||
| 129 | expect(mem.eql(u1, x, ([4]u1)(v))); | ||
| 130 | } | ||
| 131 | { | ||
| 132 | var v: @Vector(4, bool) = [4]bool{ false, false, true, false }; | ||
| 133 | var x: [4]bool = v; | ||
| 134 | expect(mem.eql(bool, x, ([4]bool)(v))); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | }; | ||
| 138 | S.doTheTest(); | ||
| 139 | comptime S.doTheTest(); | ||
| 140 | } | ||
| 141 | |||
| 142 | test "vector @splat" { | ||
| 143 | const S = struct { | ||
| 144 | fn doTheTest() void { | ||
| 145 | var v: u32 = 5; | ||
| 146 | var x = @splat(4, v); | ||
| 147 | expect(@typeOf(x) == @Vector(4, u32)); | ||
| 148 | var array_x: [4]u32 = x; | ||
| 149 | expect(array_x[0] == 5); | ||
| 150 | expect(array_x[1] == 5); | ||
| 151 | expect(array_x[2] == 5); | ||
| 152 | expect(array_x[3] == 5); | ||
| 153 | } | ||
| 154 | }; | ||
| 155 | S.doTheTest(); | ||
| 156 | comptime S.doTheTest(); | ||
| 157 | } |