authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-18 16:35:57-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-18 16:35:57-04:00
log86209e1a9259dca40803e56d612beacf5a35855c
tree21e2b617a7cd424f82e040b94014b1c176dcf63b
parent914ad1ec2eff4ea9061804ad0da9cde7dd6543b6
parentef0f3ba905e992556a60f935cbb7cb30cf1f27db
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'merge-shawnl-simd5'

This is the first 3 commits of #2945, plus my fixups.

11 files changed, 626 insertions(+), 68 deletions(-)

doc/langref.html.in+37
...@@ -7673,6 +7673,43 @@ test "@setRuntimeSafety" {...@@ -7673,6 +7673,43 @@ test "@setRuntimeSafety" {
7673 {#see_also|@shlExact|@shlWithOverflow#}7673 {#see_also|@shlExact|@shlWithOverflow#}
7674 {#header_close#}7674 {#header_close#}
76757675
7676 {#header_open|@shuffle#}
7677 <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>
7678 <p>
7679 Constructs a new {#link|vector|Vectors#} by selecting elements from {#syntax#}a{#endsyntax#} and
7680 {#syntax#}b{#endsyntax#} based on {#syntax#}mask{#endsyntax#}.
7681 </p>
7682 <p>
7683 Each element in {#syntax#}mask{#endsyntax#} selects an element from either {#syntax#}a{#endsyntax#} or
7684 {#syntax#}b{#endsyntax#}. Positive numbers select from {#syntax#}a{#endsyntax#} starting at 0.
7685 Negative values select from {#syntax#}b{#endsyntax#}, starting at {#syntax#}-1{#endsyntax#} and going down.
7686 It is recommended to use the {#syntax#}~{#endsyntax#} operator from indexes from {#syntax#}b{#endsyntax#}
7687 so that both indexes can start from {#syntax#}0{#endsyntax#} (i.e. {#syntax#}~i32(0){#endsyntax#} is
7688 {#syntax#}-1{#endsyntax#}).
7689 </p>
7690 <p>
7691 For each element of {#syntax#}mask{#endsyntax#}, if it or the selected value from
7692 {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} is {#syntax#}undefined{#endsyntax#},
7693 then the resulting element is {#syntax#}undefined{#endsyntax#}.
7694 </p>
7695 <p>
7696 {#syntax#}a_len{#endsyntax#} and {#syntax#}b_len{#endsyntax#} may differ in length. Out-of-bounds element
7697 indexes in {#syntax#}mask{#endsyntax#} result in compile errors.
7698 </p>
7699 <p>
7700 If {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} is {#syntax#}undefined{#endsyntax#}, it
7701 is equivalent to a vector of all {#syntax#}undefined{#endsyntax#} with the same length as the other vector.
7702 If both vectors are {#syntax#}undefined{#endsyntax#}, {#syntax#}@shuffle{#endsyntax#} returns
7703 a vector with all elements {#syntax#}undefined{#endsyntax#}.
7704 </p>
7705 <p>
7706 {#syntax#}E{#endsyntax#} must be an {#link|integer|Integers#}, {#link|float|Floats#},
7707 {#link|pointer|Pointers#}, or {#syntax#}bool{#endsyntax#}. The mask may be any vector length, and its
7708 length determines the result length.
7709 </p>
7710 {#see_also|SIMD#}
7711 {#header_close#}
7712
7676 {#header_open|@sizeOf#}7713 {#header_open|@sizeOf#}
7677 <pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre>7714 <pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre>
7678 <p>7715 <p>
src/all_types.hpp+12-1
...@@ -1351,7 +1351,7 @@ struct ZigTypeBoundFn {...@@ -1351,7 +1351,7 @@ struct ZigTypeBoundFn {
1351};1351};
13521352
1353struct ZigTypeVector {1353struct ZigTypeVector {
1354 // The type must be a pointer, integer, or float1354 // 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,7 @@ enum BuiltinFnId {...@@ -1611,6 +1611,7 @@ enum BuiltinFnId {
1611 BuiltinFnIdIntToEnum,1611 BuiltinFnIdIntToEnum,
1612 BuiltinFnIdIntType,1612 BuiltinFnIdIntType,
1613 BuiltinFnIdVectorType,1613 BuiltinFnIdVectorType,
1614 BuiltinFnIdShuffle,
1614 BuiltinFnIdSetCold,1615 BuiltinFnIdSetCold,
1615 BuiltinFnIdSetRuntimeSafety,1616 BuiltinFnIdSetRuntimeSafety,
1616 BuiltinFnIdSetFloatMode,1617 BuiltinFnIdSetFloatMode,
...@@ -2428,6 +2429,7 @@ enum IrInstructionId {...@@ -2428,6 +2429,7 @@ enum IrInstructionId {
2428 IrInstructionIdBoolToInt,2429 IrInstructionIdBoolToInt,
2429 IrInstructionIdIntType,2430 IrInstructionIdIntType,
2430 IrInstructionIdVectorType,2431 IrInstructionIdVectorType,
2432 IrInstructionIdShuffleVector,
2431 IrInstructionIdBoolNot,2433 IrInstructionIdBoolNot,
2432 IrInstructionIdMemset,2434 IrInstructionIdMemset,
2433 IrInstructionIdMemcpy,2435 IrInstructionIdMemcpy,
...@@ -3669,6 +3671,15 @@ struct IrInstructionVectorToArray {...@@ -3669,6 +3671,15 @@ struct IrInstructionVectorToArray {
3669 IrInstruction *result_loc;3671 IrInstruction *result_loc;
3670};3672};
36713673
3674struct IrInstructionShuffleVector {
3675 IrInstruction base;
3676
3677 IrInstruction *scalar_type;
3678 IrInstruction *a;
3679 IrInstruction *b;
3680 IrInstruction *mask; // This is in zig-format, not llvm format
3681};
3682
3672struct IrInstructionAssertZero {3683struct IrInstructionAssertZero {
3673 IrInstruction base;3684 IrInstruction base;
36743685
src/analyze.cpp+2-1
...@@ -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) {
4708bool is_valid_vector_elem_type(ZigType *elem_type) {4708bool 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}
47134714
...@@ -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) {
47274728
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 resolvable4731 // 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) {
src/codegen.cpp+84-10
...@@ -4581,6 +4581,36 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru...@@ -4581,6 +4581,36 @@ 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);4581 return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
4582}4582}
45834583
4584static LLVMValueRef ir_render_shuffle_vector(CodeGen *g, IrExecutable *executable, IrInstructionShuffleVector *instruction) {
4585 uint64_t len_a = instruction->a->value.type->data.vector.len;
4586 uint64_t len_mask = instruction->mask->value.type->data.vector.len;
4587
4588 // LLVM uses integers larger than the length of the first array to
4589 // index into the second array. This was deemed unnecessarily fragile
4590 // when changing code, so Zig uses negative numbers to index the
4591 // second vector. These start at -1 and go down, and are easiest to use
4592 // with the ~ operator. Here we convert between the two formats.
4593 IrInstruction *mask = instruction->mask;
4594 LLVMValueRef *values = allocate<LLVMValueRef>(len_mask);
4595 for (uint64_t i = 0; i < len_mask; i++) {
4596 if (mask->value.data.x_array.data.s_none.elements[i].special == ConstValSpecialUndef) {
4597 values[i] = LLVMGetUndef(LLVMInt32Type());
4598 } else {
4599 int32_t v = bigint_as_signed(&mask->value.data.x_array.data.s_none.elements[i].data.x_bigint);
4600 uint32_t index_val = (v >= 0) ? (uint32_t)v : (uint32_t)~v + (uint32_t)len_a;
4601 values[i] = LLVMConstInt(LLVMInt32Type(), index_val, false);
4602 }
4603 }
4604
4605 LLVMValueRef llvm_mask_value = LLVMConstVector(values, len_mask);
4606 free(values);
4607
4608 return LLVMBuildShuffleVector(g->builder,
4609 ir_llvm_value(g, instruction->a),
4610 ir_llvm_value(g, instruction->b),
4611 llvm_mask_value, "");
4612}
4613
4584static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {4614static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {
4585 ZigType *int_type = instruction->op->value.type;4615 ZigType *int_type = instruction->op->value.type;
4586 LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);4616 LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);
...@@ -5549,10 +5579,29 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab...@@ -5549,10 +5579,29 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab
5549 assert(handle_is_ptr(array_type));5579 assert(handle_is_ptr(array_type));
5550 LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);5580 LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
5551 LLVMValueRef vector = ir_llvm_value(g, instruction->vector);5581 LLVMValueRef vector = ir_llvm_value(g, instruction->vector);
5552 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc,5582
5553 LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), "");5583 ZigType *elem_type = array_type->data.array.child_type;
5554 uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type);5584 bool bitcast_ok = (elem_type->size_in_bits * 8) == elem_type->abi_size;
5555 gen_store_untyped(g, vector, casted_ptr, alignment, false);5585 if (bitcast_ok) {
5586 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc,
5587 LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), "");
5588 uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type);
5589 gen_store_untyped(g, vector, casted_ptr, alignment, false);
5590 } else {
5591 // If the ABI size of the element type is not evenly divisible by size_in_bits, a simple bitcast
5592 // will not work, and we fall back to extractelement.
5593 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5594 LLVMTypeRef u32_type_ref = LLVMInt32Type();
5595 LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false);
5596 for (uintptr_t i = 0; i < instruction->vector->value.type->data.vector.len; i++) {
5597 LLVMValueRef index_usize = LLVMConstInt(usize_type_ref, i, false);
5598 LLVMValueRef index_u32 = LLVMConstInt(u32_type_ref, i, false);
5599 LLVMValueRef indexes[] = { zero, index_usize };
5600 LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, result_loc, indexes, 2, "");
5601 LLVMValueRef elem = LLVMBuildExtractElement(g->builder, vector, index_u32, "");
5602 LLVMBuildStore(g->builder, elem, elem_ptr);
5603 }
5604 }
5556 return result_loc;5605 return result_loc;
5557}5606}
55585607
...@@ -5563,12 +5612,34 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab...@@ -5563,12 +5612,34 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
5563 assert(vector_type->id == ZigTypeIdVector);5612 assert(vector_type->id == ZigTypeIdVector);
5564 assert(!handle_is_ptr(vector_type));5613 assert(!handle_is_ptr(vector_type));
5565 LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);5614 LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
5566 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,5615 LLVMTypeRef vector_type_ref = get_llvm_type(g, vector_type);
5567 LLVMPointerType(get_llvm_type(g, vector_type), 0), "");5616
5568 ZigType *array_type = instruction->array->value.type;5617 ZigType *elem_type = vector_type->data.vector.elem_type;
5569 assert(array_type->id == ZigTypeIdArray);5618 bool bitcast_ok = (elem_type->size_in_bits * 8) == elem_type->abi_size;
5570 uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type);5619 if (bitcast_ok) {
5571 return gen_load_untyped(g, casted_ptr, alignment, false, "");5620 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,
5621 LLVMPointerType(vector_type_ref, 0), "");
5622 ZigType *array_type = instruction->array->value.type;
5623 assert(array_type->id == ZigTypeIdArray);
5624 uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type);
5625 return gen_load_untyped(g, casted_ptr, alignment, false, "");
5626 } else {
5627 // If the ABI size of the element type is not evenly divisible by size_in_bits, a simple bitcast
5628 // will not work, and we fall back to insertelement.
5629 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5630 LLVMTypeRef u32_type_ref = LLVMInt32Type();
5631 LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false);
5632 LLVMValueRef vector = LLVMGetUndef(vector_type_ref);
5633 for (uintptr_t i = 0; i < instruction->base.value.type->data.vector.len; i++) {
5634 LLVMValueRef index_usize = LLVMConstInt(usize_type_ref, i, false);
5635 LLVMValueRef index_u32 = LLVMConstInt(u32_type_ref, i, false);
5636 LLVMValueRef indexes[] = { zero, index_usize };
5637 LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indexes, 2, "");
5638 LLVMValueRef elem = LLVMBuildLoad(g->builder, elem_ptr, "");
5639 vector = LLVMBuildInsertElement(g->builder, vector, elem, index_u32, "");
5640 }
5641 return vector;
5642 }
5572}5643}
55735644
5574static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,5645static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,
...@@ -6054,6 +6125,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -6054,6 +6125,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
6054 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);6125 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);
6055 case IrInstructionIdSpillEnd:6126 case IrInstructionIdSpillEnd:
6056 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);6127 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);
6128 case IrInstructionIdShuffleVector:
6129 return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction);
6057 }6130 }
6058 zig_unreachable();6131 zig_unreachable();
6059}6132}
...@@ -7744,6 +7817,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7744,6 +7817,7 @@ static void define_builtin_fns(CodeGen *g) {
7744 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);7817 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
7745 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int7818 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
7746 create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);7819 create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);
7820 create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4);
7747 create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);7821 create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
7748 create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);7822 create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
7749 create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);7823 create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);
src/ir.cpp+338-52
...@@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) {...@@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) {
717 return IrInstructionIdVectorType;717 return IrInstructionIdVectorType;
718}718}
719719
720static constexpr IrInstructionId ir_instruction_id(IrInstructionShuffleVector *) {
721 return IrInstructionIdShuffleVector;
722}
723
720static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {724static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
721 return IrInstructionIdBoolNot;725 return IrInstructionIdBoolNot;
722}726}
...@@ -2277,6 +2281,25 @@ static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode...@@ -2277,6 +2281,25 @@ static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode
2277 return &instruction->base;2281 return &instruction->base;
2278}2282}
22792283
2284static IrInstruction *ir_build_shuffle_vector(IrBuilder *irb, Scope *scope, AstNode *source_node,
2285 IrInstruction *scalar_type, IrInstruction *a, IrInstruction *b, IrInstruction *mask)
2286{
2287 IrInstructionShuffleVector *instruction = ir_build_instruction<IrInstructionShuffleVector>(irb, scope, source_node);
2288 instruction->scalar_type = scalar_type;
2289 instruction->a = a;
2290 instruction->b = b;
2291 instruction->mask = mask;
2292
2293 if (scalar_type != nullptr) {
2294 ir_ref_instruction(scalar_type, irb->current_basic_block);
2295 }
2296 ir_ref_instruction(a, irb->current_basic_block);
2297 ir_ref_instruction(b, irb->current_basic_block);
2298 ir_ref_instruction(mask, irb->current_basic_block);
2299
2300 return &instruction->base;
2301}
2302
2280static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {2303static 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);2304 IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node);
2282 instruction->value = value;2305 instruction->value = value;
...@@ -4936,6 +4959,32 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4936,6 +4959,32 @@ 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);4959 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);4960 return ir_lval_wrap(irb, scope, vector_type, lval, result_loc);
4938 }4961 }
4962 case BuiltinFnIdShuffle:
4963 {
4964 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4965 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4966 if (arg0_value == irb->codegen->invalid_instruction)
4967 return arg0_value;
4968
4969 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4970 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4971 if (arg1_value == irb->codegen->invalid_instruction)
4972 return arg1_value;
4973
4974 AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
4975 IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
4976 if (arg2_value == irb->codegen->invalid_instruction)
4977 return arg2_value;
4978
4979 AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
4980 IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
4981 if (arg3_value == irb->codegen->invalid_instruction)
4982 return arg3_value;
4983
4984 IrInstruction *shuffle_vector = ir_build_shuffle_vector(irb, scope, node,
4985 arg0_value, arg1_value, arg2_value, arg3_value);
4986 return ir_lval_wrap(irb, scope, shuffle_vector, lval, result_loc);
4987 }
4939 case BuiltinFnIdMemcpy:4988 case BuiltinFnIdMemcpy:
4940 {4989 {
4941 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);4990 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
...@@ -11000,6 +11049,19 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {...@@ -11000,6 +11049,19 @@ 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);11049 return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val);
11001}11050}
1100211051
11052static ZigType *ir_resolve_vector_elem_type(IrAnalyze *ira, IrInstruction *elem_type_value) {
11053 ZigType *elem_type = ir_resolve_type(ira, elem_type_value);
11054 if (type_is_invalid(elem_type))
11055 return ira->codegen->builtin_types.entry_invalid;
11056 if (!is_valid_vector_elem_type(elem_type)) {
11057 ir_add_error(ira, elem_type_value,
11058 buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid",
11059 buf_ptr(&elem_type->name)));
11060 return ira->codegen->builtin_types.entry_invalid;
11061 }
11062 return elem_type;
11063}
11064
11003static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) {11065static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) {
11004 ZigType *ty = ir_resolve_type(ira, type_value);11066 ZigType *ty = ir_resolve_type(ira, type_value);
11005 if (type_is_invalid(ty))11067 if (type_is_invalid(ty))
...@@ -13092,6 +13154,59 @@ static bool optional_value_is_null(ConstExprValue *val) {...@@ -13092,6 +13154,59 @@ static bool optional_value_is_null(ConstExprValue *val) {
13092 }13154 }
13093}13155}
1309413156
13157static IrInstruction *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type,
13158 ConstExprValue *op1_val, ConstExprValue *op2_val, IrInstructionBinOp *bin_op_instruction, IrBinOp op_id,
13159 bool one_possible_value) {
13160 if (op1_val->special == ConstValSpecialUndef ||
13161 op2_val->special == ConstValSpecialUndef)
13162 return ir_const_undef(ira, &bin_op_instruction->base, resolved_type);
13163 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {
13164 if (float_is_nan(op1_val) || float_is_nan(op2_val)) {
13165 return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq);
13166 }
13167 Cmp cmp_result = float_cmp(op1_val, op2_val);
13168 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13169 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13170 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {
13171 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
13172 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13173 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13174 } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
13175 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
13176 op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&
13177 (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
13178 op2_val->data.x_ptr.special == ConstPtrSpecialNull))
13179 {
13180 uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ?
13181 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr;
13182 uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ?
13183 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr;
13184 Cmp cmp_result;
13185 if (op1_addr > op2_addr) {
13186 cmp_result = CmpGT;
13187 } else if (op1_addr < op2_addr) {
13188 cmp_result = CmpLT;
13189 } else {
13190 cmp_result = CmpEQ;
13191 }
13192 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13193 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13194 }
13195 } else {
13196 bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);
13197 bool answer;
13198 if (op_id == IrBinOpCmpEq) {
13199 answer = are_equal;
13200 } else if (op_id == IrBinOpCmpNotEq) {
13201 answer = !are_equal;
13202 } else {
13203 zig_unreachable();
13204 }
13205 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13206 }
13207 zig_unreachable();
13208}
13209
13095// Returns ErrorNotLazy when the value cannot be determined13210// Returns ErrorNotLazy when the value cannot be determined
13096static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) {13211static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) {
13097 Error err;13212 Error err;
...@@ -13477,51 +13592,22 @@ never_mind_just_calculate_it_normally:...@@ -13477,51 +13592,22 @@ never_mind_just_calculate_it_normally:
13477 ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad);13592 ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad);
13478 if (op2_val == nullptr)13593 if (op2_val == nullptr)
13479 return ira->codegen->invalid_instruction;13594 return ira->codegen->invalid_instruction;
1348013595 if (resolved_type->id != ZigTypeIdVector)
13481 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {13596 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)) {13597 IrInstruction *result = ir_const(ira, &bin_op_instruction->base,
13483 return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq);13598 get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool));
13484 }13599 result->value.data.x_array.data.s_none.elements =
13485 Cmp cmp_result = float_cmp(op1_val, op2_val);13600 create_const_vals(resolved_type->data.vector.len);
13486 bool answer = resolve_cmp_op_id(op_id, cmp_result);13601
13487 return ir_const_bool(ira, &bin_op_instruction->base, answer);13602 expand_undef_array(ira->codegen, &result->value);
13488 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {13603 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);13604 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);13605 &op1_val->data.x_array.data.s_none.elements[i],
13491 return ir_const_bool(ira, &bin_op_instruction->base, answer);13606 &op2_val->data.x_array.data.s_none.elements[i],
13492 } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {13607 bin_op_instruction, op_id, one_possible_value);
13493 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||13608 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 }13609 }
13610 return result;
13525 }13611 }
1352613612
13527 // some comparisons with unsigned numbers can be evaluated13613 // some comparisons with unsigned numbers can be evaluated
...@@ -13564,7 +13650,12 @@ never_mind_just_calculate_it_normally:...@@ -13564,7 +13650,12 @@ never_mind_just_calculate_it_normally:
13564 IrInstruction *result = ir_build_bin_op(&ira->new_irb,13650 IrInstruction *result = ir_build_bin_op(&ira->new_irb,
13565 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,13651 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,
13566 op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on);13652 op_id, casted_op1, casted_op2, bin_op_instruction->safety_check_on);
13567 result->value.type = ira->codegen->builtin_types.entry_bool;13653 if (resolved_type->id == ZigTypeIdVector) {
13654 result->value.type = get_vector_type(ira->codegen, resolved_type->data.vector.len,
13655 ira->codegen->builtin_types.entry_bool);
13656 } else {
13657 result->value.type = ira->codegen->builtin_types.entry_bool;
13658 }
13568 return result;13659 return result;
13569}13660}
1357013661
...@@ -22018,20 +22109,212 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr...@@ -22018,20 +22109,212 @@ 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))22109 if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len))
22019 return ira->codegen->invalid_instruction;22110 return ira->codegen->invalid_instruction;
2202022111
22021 ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child);22112 ZigType *elem_type = ir_resolve_vector_elem_type(ira, instruction->elem_type->child);
22022 if (type_is_invalid(elem_type))22113 if (type_is_invalid(elem_type))
22023 return ira->codegen->invalid_instruction;22114 return ira->codegen->invalid_instruction;
2202422115
22025 if (!is_valid_vector_elem_type(elem_type)) {22116 ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type);
22026 ir_add_error(ira, instruction->elem_type,22117
22027 buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid",22118 return ir_const_type(ira, &instruction->base, vector_type);
22028 buf_ptr(&elem_type->name)));22119}
22120
22121static IrInstruction *ir_analyze_shuffle_vector(IrAnalyze *ira, IrInstruction *source_instr,
22122 ZigType *scalar_type, IrInstruction *a, IrInstruction *b, IrInstruction *mask)
22123{
22124 ir_assert(source_instr && scalar_type && a && b && mask, source_instr);
22125 ir_assert(is_valid_vector_elem_type(scalar_type), source_instr);
22126
22127 uint32_t len_mask;
22128 if (mask->value.type->id == ZigTypeIdVector) {
22129 len_mask = mask->value.type->data.vector.len;
22130 } else if (mask->value.type->id == ZigTypeIdArray) {
22131 len_mask = mask->value.type->data.array.len;
22132 } else {
22133 ir_add_error(ira, mask,
22134 buf_sprintf("expected vector or array, found '%s'",
22135 buf_ptr(&mask->value.type->name)));
22029 return ira->codegen->invalid_instruction;22136 return ira->codegen->invalid_instruction;
22030 }22137 }
22138 mask = ir_implicit_cast(ira, mask, get_vector_type(ira->codegen, len_mask,
22139 ira->codegen->builtin_types.entry_i32));
22140 if (type_is_invalid(mask->value.type))
22141 return ira->codegen->invalid_instruction;
2203122142
22032 ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type);22143 uint32_t len_a;
22144 if (a->value.type->id == ZigTypeIdVector) {
22145 len_a = a->value.type->data.vector.len;
22146 } else if (a->value.type->id == ZigTypeIdArray) {
22147 len_a = a->value.type->data.array.len;
22148 } else if (a->value.type->id == ZigTypeIdUndefined) {
22149 len_a = UINT32_MAX;
22150 } else {
22151 ir_add_error(ira, a,
22152 buf_sprintf("expected vector or array with element type '%s', found '%s'",
22153 buf_ptr(&scalar_type->name),
22154 buf_ptr(&a->value.type->name)));
22155 return ira->codegen->invalid_instruction;
22156 }
2203322157
22034 return ir_const_type(ira, &instruction->base, vector_type);22158 uint32_t len_b;
22159 if (b->value.type->id == ZigTypeIdVector) {
22160 len_b = b->value.type->data.vector.len;
22161 } else if (b->value.type->id == ZigTypeIdArray) {
22162 len_b = b->value.type->data.array.len;
22163 } else if (b->value.type->id == ZigTypeIdUndefined) {
22164 len_b = UINT32_MAX;
22165 } else {
22166 ir_add_error(ira, b,
22167 buf_sprintf("expected vector or array with element type '%s', found '%s'",
22168 buf_ptr(&scalar_type->name),
22169 buf_ptr(&b->value.type->name)));
22170 return ira->codegen->invalid_instruction;
22171 }
22172
22173 if (len_a == UINT32_MAX && len_b == UINT32_MAX) {
22174 return ir_const_undef(ira, a, get_vector_type(ira->codegen, len_mask, scalar_type));
22175 }
22176
22177 if (len_a == UINT32_MAX) {
22178 len_a = len_b;
22179 a = ir_const_undef(ira, a, get_vector_type(ira->codegen, len_a, scalar_type));
22180 } else {
22181 a = ir_implicit_cast(ira, a, get_vector_type(ira->codegen, len_a, scalar_type));
22182 if (type_is_invalid(a->value.type))
22183 return ira->codegen->invalid_instruction;
22184 }
22185
22186 if (len_b == UINT32_MAX) {
22187 len_b = len_a;
22188 b = ir_const_undef(ira, b, get_vector_type(ira->codegen, len_b, scalar_type));
22189 } else {
22190 b = ir_implicit_cast(ira, b, get_vector_type(ira->codegen, len_b, scalar_type));
22191 if (type_is_invalid(b->value.type))
22192 return ira->codegen->invalid_instruction;
22193 }
22194
22195 ConstExprValue *mask_val = ir_resolve_const(ira, mask, UndefOk);
22196 if (mask_val == nullptr)
22197 return ira->codegen->invalid_instruction;
22198
22199 expand_undef_array(ira->codegen, mask_val);
22200
22201 for (uint32_t i = 0; i < len_mask; i += 1) {
22202 ConstExprValue *mask_elem_val = &mask_val->data.x_array.data.s_none.elements[i];
22203 if (mask_elem_val->special == ConstValSpecialUndef)
22204 continue;
22205 int32_t v_i32 = bigint_as_signed(&mask_elem_val->data.x_bigint);
22206 uint32_t v;
22207 IrInstruction *chosen_operand;
22208 if (v_i32 >= 0) {
22209 v = (uint32_t)v_i32;
22210 chosen_operand = a;
22211 } else {
22212 v = (uint32_t)~v_i32;
22213 chosen_operand = b;
22214 }
22215 if (v >= chosen_operand->value.type->data.vector.len) {
22216 ErrorMsg *msg = ir_add_error(ira, mask,
22217 buf_sprintf("mask index '%u' has out-of-bounds selection", i));
22218 add_error_note(ira->codegen, msg, chosen_operand->source_node,
22219 buf_sprintf("selected index '%u' out of bounds of %s", v,
22220 buf_ptr(&chosen_operand->value.type->name)));
22221 if (chosen_operand == a && v < len_a + len_b) {
22222 add_error_note(ira->codegen, msg, b->source_node,
22223 buf_create_from_str("selections from the second vector are specified with negative numbers"));
22224 }
22225 return ira->codegen->invalid_instruction;
22226 }
22227 }
22228
22229 ZigType *result_type = get_vector_type(ira->codegen, len_mask, scalar_type);
22230 if (instr_is_comptime(a) && instr_is_comptime(b)) {
22231 ConstExprValue *a_val = ir_resolve_const(ira, a, UndefOk);
22232 if (a_val == nullptr)
22233 return ira->codegen->invalid_instruction;
22234
22235 ConstExprValue *b_val = ir_resolve_const(ira, b, UndefOk);
22236 if (b_val == nullptr)
22237 return ira->codegen->invalid_instruction;
22238
22239 expand_undef_array(ira->codegen, a_val);
22240 expand_undef_array(ira->codegen, b_val);
22241
22242 IrInstruction *result = ir_const(ira, source_instr, result_type);
22243 result->value.data.x_array.data.s_none.elements = create_const_vals(len_mask);
22244 for (uint32_t i = 0; i < mask_val->type->data.vector.len; i += 1) {
22245 ConstExprValue *mask_elem_val = &mask_val->data.x_array.data.s_none.elements[i];
22246 ConstExprValue *result_elem_val = &result->value.data.x_array.data.s_none.elements[i];
22247 if (mask_elem_val->special == ConstValSpecialUndef) {
22248 result_elem_val->special = ConstValSpecialUndef;
22249 continue;
22250 }
22251 int32_t v = bigint_as_signed(&mask_elem_val->data.x_bigint);
22252 // We've already checked for and emitted compile errors for index out of bounds here.
22253 ConstExprValue *src_elem_val = (v >= 0) ?
22254 &a->value.data.x_array.data.s_none.elements[v] :
22255 &b->value.data.x_array.data.s_none.elements[~v];
22256 copy_const_val(result_elem_val, src_elem_val, false);
22257
22258 ir_assert(result_elem_val->special == ConstValSpecialStatic, source_instr);
22259 }
22260 result->value.special = ConstValSpecialStatic;
22261 return result;
22262 }
22263
22264 // All static analysis passed, and not comptime.
22265 // For runtime codegen, vectors a and b must be the same length. Here we
22266 // recursively @shuffle the smaller vector to append undefined elements
22267 // to it up to the length of the longer vector. This recursion terminates
22268 // in 1 call because these calls to ir_analyze_shuffle_vector guarantee
22269 // len_a == len_b.
22270 if (len_a != len_b) {
22271 uint32_t len_min = min(len_a, len_b);
22272 uint32_t len_max = max(len_a, len_b);
22273
22274 IrInstruction *expand_mask = ir_const(ira, mask,
22275 get_vector_type(ira->codegen, len_max, ira->codegen->builtin_types.entry_i32));
22276 expand_mask->value.data.x_array.data.s_none.elements = create_const_vals(len_max);
22277 uint32_t i = 0;
22278 for (; i < len_min; i += 1)
22279 bigint_init_unsigned(&expand_mask->value.data.x_array.data.s_none.elements[i].data.x_bigint, i);
22280 for (; i < len_max; i += 1)
22281 bigint_init_signed(&expand_mask->value.data.x_array.data.s_none.elements[i].data.x_bigint, -1);
22282
22283 IrInstruction *undef = ir_const_undef(ira, source_instr,
22284 get_vector_type(ira->codegen, len_min, scalar_type));
22285
22286 if (len_b < len_a) {
22287 b = ir_analyze_shuffle_vector(ira, source_instr, scalar_type, b, undef, expand_mask);
22288 } else {
22289 a = ir_analyze_shuffle_vector(ira, source_instr, scalar_type, a, undef, expand_mask);
22290 }
22291 }
22292
22293 IrInstruction *result = ir_build_shuffle_vector(&ira->new_irb,
22294 source_instr->scope, source_instr->source_node,
22295 nullptr, a, b, mask);
22296 result->value.type = result_type;
22297 return result;
22298}
22299
22300static IrInstruction *ir_analyze_instruction_shuffle_vector(IrAnalyze *ira, IrInstructionShuffleVector *instruction) {
22301 ZigType *scalar_type = ir_resolve_vector_elem_type(ira, instruction->scalar_type);
22302 if (type_is_invalid(scalar_type))
22303 return ira->codegen->invalid_instruction;
22304
22305 IrInstruction *a = instruction->a->child;
22306 if (type_is_invalid(a->value.type))
22307 return ira->codegen->invalid_instruction;
22308
22309 IrInstruction *b = instruction->b->child;
22310 if (type_is_invalid(b->value.type))
22311 return ira->codegen->invalid_instruction;
22312
22313 IrInstruction *mask = instruction->mask->child;
22314 if (type_is_invalid(mask->value.type))
22315 return ira->codegen->invalid_instruction;
22316
22317 return ir_analyze_shuffle_vector(ira, &instruction->base, scalar_type, a, b, mask);
22035}22318}
2203622319
22037static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {22320static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {
...@@ -25578,6 +25861,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25578,6 +25861,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25578 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);25861 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
25579 case IrInstructionIdVectorType:25862 case IrInstructionIdVectorType:
25580 return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction);25863 return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction);
25864 case IrInstructionIdShuffleVector:
25865 return ir_analyze_instruction_shuffle_vector(ira, (IrInstructionShuffleVector *)instruction);
25581 case IrInstructionIdBoolNot:25866 case IrInstructionIdBoolNot:
25582 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);25867 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
25583 case IrInstructionIdMemset:25868 case IrInstructionIdMemset:
...@@ -25913,6 +26198,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25913,6 +26198,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25913 case IrInstructionIdTruncate:26198 case IrInstructionIdTruncate:
25914 case IrInstructionIdIntType:26199 case IrInstructionIdIntType:
25915 case IrInstructionIdVectorType:26200 case IrInstructionIdVectorType:
26201 case IrInstructionIdShuffleVector:
25916 case IrInstructionIdBoolNot:26202 case IrInstructionIdBoolNot:
25917 case IrInstructionIdSliceSrc:26203 case IrInstructionIdSliceSrc:
25918 case IrInstructionIdMemberCount:26204 case IrInstructionIdMemberCount:
src/ir_print.cpp+17
...@@ -42,6 +42,8 @@ static const char* ir_instruction_type_str(IrInstruction* instruction) {...@@ -42,6 +42,8 @@ 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";
45 case IrInstructionIdDeclVarSrc:47 case IrInstructionIdDeclVarSrc:
46 return "DeclVarSrc";48 return "DeclVarSrc";
47 case IrInstructionIdDeclVarGen:49 case IrInstructionIdDeclVarGen:
...@@ -1208,6 +1210,18 @@ static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruct...@@ -1208,6 +1210,18 @@ static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruct
1208 fprintf(irp->f, ")");1210 fprintf(irp->f, ")");
1209}1211}
12101212
1213static void ir_print_shuffle_vector(IrPrint *irp, IrInstructionShuffleVector *instruction) {
1214 fprintf(irp->f, "@shuffle(");
1215 ir_print_other_instruction(irp, instruction->scalar_type);
1216 fprintf(irp->f, ", ");
1217 ir_print_other_instruction(irp, instruction->a);
1218 fprintf(irp->f, ", ");
1219 ir_print_other_instruction(irp, instruction->b);
1220 fprintf(irp->f, ", ");
1221 ir_print_other_instruction(irp, instruction->mask);
1222 fprintf(irp->f, ")");
1223}
1224
1211static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {1225static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {
1212 fprintf(irp->f, "! ");1226 fprintf(irp->f, "! ");
1213 ir_print_other_instruction(irp, instruction->value);1227 ir_print_other_instruction(irp, instruction->value);
...@@ -2143,6 +2157,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool...@@ -2143,6 +2157,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool
2143 case IrInstructionIdVectorType:2157 case IrInstructionIdVectorType:
2144 ir_print_vector_type(irp, (IrInstructionVectorType *)instruction);2158 ir_print_vector_type(irp, (IrInstructionVectorType *)instruction);
2145 break;2159 break;
2160 case IrInstructionIdShuffleVector:
2161 ir_print_shuffle_vector(irp, (IrInstructionShuffleVector *)instruction);
2162 break;
2146 case IrInstructionIdBoolNot:2163 case IrInstructionIdBoolNot:
2147 ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);2164 ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);
2148 break;2165 break;
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" {
357test "testHash vector" {357test "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}
365368
366test "testHash error union" {369test "testHash error union" {
test/compile_errors.zig+14-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 );
64866486
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,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -6491,7 +6504,7 @@ 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",
6495 );6508 );
64966509
6497 cases.add("compileLog of tagged enum doesn't crash the compiler",6510 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/shuffle.zig created+57
...@@ -0,0 +1,57 @@
1const std = @import("std");
2const mem = std.mem;
3const expect = std.testing.expect;
4
5test "@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+58
...@@ -2,6 +2,18 @@ const std = @import("std");...@@ -2,6 +2,18 @@ const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "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
5test "vector wrap operators" {17test "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}
2032
33test "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
21test "vector int operators" {50test "vector int operators" {
22 const S = struct {51 const S = struct {
23 fn doTheTest() void {52 fn doTheTest() void {
...@@ -80,3 +109,32 @@ test "array to vector" {...@@ -80,3 +109,32 @@ 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
113test "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}