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" {
76737673 {#see_also|@shlExact|@shlWithOverflow#}
76747674 {#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
76767713 {#header_open|@sizeOf#}
76777714 <pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre>
76787715 <p>
src/all_types.hpp+12-1
......@@ -1351,7 +1351,7 @@ struct ZigTypeBoundFn {
13511351};
13521352
13531353struct ZigTypeVector {
1354 // The type must be a pointer, integer, or float
1354 // The type must be a pointer, integer, bool, or float
13551355 ZigType *elem_type;
13561356 uint32_t len;
13571357};
......@@ -1611,6 +1611,7 @@ enum BuiltinFnId {
16111611 BuiltinFnIdIntToEnum,
16121612 BuiltinFnIdIntType,
16131613 BuiltinFnIdVectorType,
1614 BuiltinFnIdShuffle,
16141615 BuiltinFnIdSetCold,
16151616 BuiltinFnIdSetRuntimeSafety,
16161617 BuiltinFnIdSetFloatMode,
......@@ -2428,6 +2429,7 @@ enum IrInstructionId {
24282429 IrInstructionIdBoolToInt,
24292430 IrInstructionIdIntType,
24302431 IrInstructionIdVectorType,
2432 IrInstructionIdShuffleVector,
24312433 IrInstructionIdBoolNot,
24322434 IrInstructionIdMemset,
24332435 IrInstructionIdMemcpy,
......@@ -3669,6 +3671,15 @@ struct IrInstructionVectorToArray {
36693671 IrInstruction *result_loc;
36703672};
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
36723683struct IrInstructionAssertZero {
36733684 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) {
47084708bool is_valid_vector_elem_type(ZigType *elem_type) {
47094709 return elem_type->id == ZigTypeIdInt ||
47104710 elem_type->id == ZigTypeIdFloat ||
4711 elem_type->id == ZigTypeIdBool ||
47114712 get_codegen_ptr_type(elem_type) != nullptr;
47124713}
47134714
......@@ -4727,7 +4728,7 @@ ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) {
47274728
47284729 ZigType *entry = new_type_table_entry(ZigTypeIdVector);
47294730 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
47314732 // llvm type refs. pointers we will use usize instead.
47324733 LLVMTypeRef example_vector_llvm_type;
47334734 if (elem_type->id == ZigTypeIdPointer) {
src/codegen.cpp+84-10
......@@ -4581,6 +4581,36 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru
45814581 return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int);
45824582}
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
45844614static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {
45854615 ZigType *int_type = instruction->op->value.type;
45864616 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
55495579 assert(handle_is_ptr(array_type));
55505580 LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
55515581 LLVMValueRef vector = ir_llvm_value(g, instruction->vector);
5552 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc,
5553 LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), "");
5554 uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type);
5555 gen_store_untyped(g, vector, casted_ptr, alignment, false);
5582
5583 ZigType *elem_type = array_type->data.array.child_type;
5584 bool bitcast_ok = (elem_type->size_in_bits * 8) == elem_type->abi_size;
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 }
55565605 return result_loc;
55575606}
55585607
......@@ -5563,12 +5612,34 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
55635612 assert(vector_type->id == ZigTypeIdVector);
55645613 assert(!handle_is_ptr(vector_type));
55655614 LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
5566 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,
5567 LLVMPointerType(get_llvm_type(g, vector_type), 0), "");
5568 ZigType *array_type = instruction->array->value.type;
5569 assert(array_type->id == ZigTypeIdArray);
5570 uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type);
5571 return gen_load_untyped(g, casted_ptr, alignment, false, "");
5615 LLVMTypeRef vector_type_ref = get_llvm_type(g, vector_type);
5616
5617 ZigType *elem_type = vector_type->data.vector.elem_type;
5618 bool bitcast_ok = (elem_type->size_in_bits * 8) == elem_type->abi_size;
5619 if (bitcast_ok) {
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 }
55725643}
55735644
55745645static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,
......@@ -6054,6 +6125,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
60546125 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);
60556126 case IrInstructionIdSpillEnd:
60566127 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);
6128 case IrInstructionIdShuffleVector:
6129 return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction);
60576130 }
60586131 zig_unreachable();
60596132}
......@@ -7744,6 +7817,7 @@ static void define_builtin_fns(CodeGen *g) {
77447817 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
77457818 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
77467819 create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);
7820 create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4);
77477821 create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
77487822 create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
77497823 create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);
src/ir.cpp+338-52
......@@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) {
717717 return IrInstructionIdVectorType;
718718}
719719
720static constexpr IrInstructionId ir_instruction_id(IrInstructionShuffleVector *) {
721 return IrInstructionIdShuffleVector;
722}
723
720724static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
721725 return IrInstructionIdBoolNot;
722726}
......@@ -2277,6 +2281,25 @@ static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode
22772281 return &instruction->base;
22782282}
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
22802303static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
22812304 IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node);
22822305 instruction->value = value;
......@@ -4936,6 +4959,32 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
49364959 IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value);
49374960 return ir_lval_wrap(irb, scope, vector_type, lval, result_loc);
49384961 }
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 }
49394988 case BuiltinFnIdMemcpy:
49404989 {
49414990 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) {
1100011049 return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val);
1100111050}
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
1100311065static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) {
1100411066 ZigType *ty = ir_resolve_type(ira, type_value);
1100511067 if (type_is_invalid(ty))
......@@ -13092,6 +13154,59 @@ static bool optional_value_is_null(ConstExprValue *val) {
1309213154 }
1309313155}
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
1309513210// Returns ErrorNotLazy when the value cannot be determined
1309613211static Error lazy_cmp_zero(AstNode *source_node, ConstExprValue *val, Cmp *result) {
1309713212 Error err;
......@@ -13477,51 +13592,22 @@ never_mind_just_calculate_it_normally:
1347713592 ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad);
1347813593 if (op2_val == nullptr)
1347913594 return ira->codegen->invalid_instruction;
13480
13481 if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {
13482 if (float_is_nan(op1_val) || float_is_nan(op2_val)) {
13483 return ir_const_bool(ira, &bin_op_instruction->base, op_id == IrBinOpCmpNotEq);
13484 }
13485 Cmp cmp_result = float_cmp(op1_val, op2_val);
13486 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13487 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13488 } else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {
13489 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
13490 bool answer = resolve_cmp_op_id(op_id, cmp_result);
13491 return ir_const_bool(ira, &bin_op_instruction->base, answer);
13492 } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
13493 if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
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);
13595 if (resolved_type->id != ZigTypeIdVector)
13596 return ir_evaluate_bin_op_cmp(ira, resolved_type, op1_val, op2_val, bin_op_instruction, op_id, one_possible_value);
13597 IrInstruction *result = ir_const(ira, &bin_op_instruction->base,
13598 get_vector_type(ira->codegen, resolved_type->data.vector.len, ira->codegen->builtin_types.entry_bool));
13599 result->value.data.x_array.data.s_none.elements =
13600 create_const_vals(resolved_type->data.vector.len);
13601
13602 expand_undef_array(ira->codegen, &result->value);
13603 for (size_t i = 0;i < resolved_type->data.vector.len;i++) {
13604 IrInstruction *cur_res = ir_evaluate_bin_op_cmp(ira, resolved_type->data.vector.elem_type,
13605 &op1_val->data.x_array.data.s_none.elements[i],
13606 &op2_val->data.x_array.data.s_none.elements[i],
13607 bin_op_instruction, op_id, one_possible_value);
13608 copy_const_val(&result->value.data.x_array.data.s_none.elements[i], &cur_res->value, false);
1352413609 }
13610 return result;
1352513611 }
1352613612
1352713613 // some comparisons with unsigned numbers can be evaluated
......@@ -13564,7 +13650,12 @@ never_mind_just_calculate_it_normally:
1356413650 IrInstruction *result = ir_build_bin_op(&ira->new_irb,
1356513651 bin_op_instruction->base.scope, bin_op_instruction->base.source_node,
1356613652 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 }
1356813659 return result;
1356913660}
1357013661
......@@ -22018,20 +22109,212 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr
2201822109 if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len))
2201922110 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);
2202222113 if (type_is_invalid(elem_type))
2202322114 return ira->codegen->invalid_instruction;
2202422115
22025 if (!is_valid_vector_elem_type(elem_type)) {
22026 ir_add_error(ira, instruction->elem_type,
22027 buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid",
22028 buf_ptr(&elem_type->name)));
22116 ZigType *vector_type = get_vector_type(ira->codegen, len, elem_type);
22117
22118 return ir_const_type(ira, &instruction->base, vector_type);
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)));
2202922136 return ira->codegen->invalid_instruction;
2203022137 }
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);
2203522318}
2203622319
2203722320static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {
......@@ -25578,6 +25861,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2557825861 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
2557925862 case IrInstructionIdVectorType:
2558025863 return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction);
25864 case IrInstructionIdShuffleVector:
25865 return ir_analyze_instruction_shuffle_vector(ira, (IrInstructionShuffleVector *)instruction);
2558125866 case IrInstructionIdBoolNot:
2558225867 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
2558325868 case IrInstructionIdMemset:
......@@ -25913,6 +26198,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2591326198 case IrInstructionIdTruncate:
2591426199 case IrInstructionIdIntType:
2591526200 case IrInstructionIdVectorType:
26201 case IrInstructionIdShuffleVector:
2591626202 case IrInstructionIdBoolNot:
2591726203 case IrInstructionIdSliceSrc:
2591826204 case IrInstructionIdMemberCount:
src/ir_print.cpp+17
......@@ -42,6 +42,8 @@ static const char* ir_instruction_type_str(IrInstruction* instruction) {
4242 switch (instruction->id) {
4343 case IrInstructionIdInvalid:
4444 return "Invalid";
45 case IrInstructionIdShuffleVector:
46 return "Shuffle";
4547 case IrInstructionIdDeclVarSrc:
4648 return "DeclVarSrc";
4749 case IrInstructionIdDeclVarGen:
......@@ -1208,6 +1210,18 @@ static void ir_print_vector_type(IrPrint *irp, IrInstructionVectorType *instruct
12081210 fprintf(irp->f, ")");
12091211}
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
12111225static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) {
12121226 fprintf(irp->f, "! ");
12131227 ir_print_other_instruction(irp, instruction->value);
......@@ -2143,6 +2157,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool
21432157 case IrInstructionIdVectorType:
21442158 ir_print_vector_type(irp, (IrInstructionVectorType *)instruction);
21452159 break;
2160 case IrInstructionIdShuffleVector:
2161 ir_print_shuffle_vector(irp, (IrInstructionShuffleVector *)instruction);
2162 break;
21462163 case IrInstructionIdBoolNot:
21472164 ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction);
21482165 break;
std/hash/auto_hash.zig+6-3
......@@ -116,7 +116,7 @@ pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void {
116116 // Otherwise, hash every element.
117117 // TODO remove the copy to an array once field access is done.
118118 const array: [info.len]info.child = key;
119 comptime var i: u32 = 0;
119 comptime var i = 0;
120120 inline while (i < info.len) : (i += 1) {
121121 hash(hasher, array[i], strat);
122122 }
......@@ -357,10 +357,13 @@ test "testHash union" {
357357test "testHash vector" {
358358 const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 };
359359 const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 };
360 const c: @Vector(4, u31) = [_]u31{ 1, 2, 3, 4 };
361360 testing.expect(testHash(a) == testHash(a));
362361 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));
364367}
365368
366369test "testHash error union" {
test/compile_errors.zig+14-1
......@@ -6484,6 +6484,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
64846484 "tmp.zig:7:23: error: unable to evaluate constant expression",
64856485 );
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
64876500 cases.addTest(
64886501 "nested vectors",
64896502 \\export fn entry() void {
......@@ -6491,7 +6504,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
64916504 \\ var v: V = undefined;
64926505 \\}
64936506 ,
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",
64956508 );
64966509
64976510 cases.add("compileLog of tagged enum doesn't crash the compiler",
test/stage1/behavior.zig+1
......@@ -80,6 +80,7 @@ comptime {
8080 _ = @import("behavior/pub_enum.zig");
8181 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
8282 _ = @import("behavior/reflection.zig");
83 _ = @import("behavior/shuffle.zig");
8384 _ = @import("behavior/sizeof_and_typeof.zig");
8485 _ = @import("behavior/slice.zig");
8586 _ = @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");
22const mem = std.mem;
33const 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
517test "vector wrap operators" {
618 const S = struct {
719 fn doTheTest() void {
......@@ -18,6 +30,23 @@ test "vector wrap operators" {
1830 comptime S.doTheTest();
1931}
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
2150test "vector int operators" {
2251 const S = struct {
2352 fn doTheTest() void {
......@@ -80,3 +109,32 @@ test "array to vector" {
80109 var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
81110 var vec: @Vector(4, f32) = arr;
82111}
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}