| author | |
| committer | |
| log | 1eb33966b100c34f9a432d76d45dd86176996936 |
| tree | b03cf7256bc6c77b79bffecbe83cd384b5e9db91 |
| parent | 0048bcbd71b9139203d7acee120d524d38e22a0e |
| parent | 28c7fe60b6de6e3c32e082a0abfb5a7bac8fc45a |
| signature |
This is the commit from Shawn's SIMD patchset regarding `@splat`,
plus my fixups.7 files changed, 229 insertions(+), 21 deletions(-)
doc/langref.html.in+30-6| ... | ... | @@ -5864,7 +5864,7 @@ volatile ( |
| 5864 | 5864 | : [number] "{rax}" (number), |
| 5865 | 5865 | [arg1] "{rdi}" (arg1) |
| 5866 | 5866 | // Next is the list of clobbers. These declare a set of registers whose |
| 5867 | // values will not be preserved by the execution of this assembly code. | |
| 5867 | // values will not be preserved by the execution of this assembly code. | |
| 5868 | 5868 | // These do not include output or input registers. The special clobber |
| 5869 | 5869 | // value of "memory" means that the assembly writes to arbitrary undeclared |
| 5870 | 5870 | // memory locations - not only the memory pointed to by a declared indirect |
| ... | ... | @@ -5885,7 +5885,7 @@ volatile ( |
| 5885 | 5885 | </p> |
| 5886 | 5886 | {#header_open|Output Constraints#} |
| 5887 | 5887 | <p> |
| 5888 | Output constraints are still considered to be unstable in Zig, and | |
| 5888 | Output constraints are still considered to be unstable in Zig, and | |
| 5889 | 5889 | so |
| 5890 | 5890 | <a href="http://releases.llvm.org/8.0.0/docs/LangRef.html#inline-asm-constraint-string">LLVM documentation</a> |
| 5891 | 5891 | and |
| ... | ... | @@ -5900,7 +5900,7 @@ volatile ( |
| 5900 | 5900 | |
| 5901 | 5901 | {#header_open|Input Constraints#} |
| 5902 | 5902 | <p> |
| 5903 | Input constraints are still considered to be unstable in Zig, and | |
| 5903 | Input constraints are still considered to be unstable in Zig, and | |
| 5904 | 5904 | so |
| 5905 | 5905 | <a href="http://releases.llvm.org/8.0.0/docs/LangRef.html#inline-asm-constraint-string">LLVM documentation</a> |
| 5906 | 5906 | and |
| ... | ... | @@ -5919,7 +5919,7 @@ volatile ( |
| 5919 | 5919 | the assembly code. These do not include output or input registers. The special clobber |
| 5920 | 5920 | value of {#syntax#}"memory"{#endsyntax#} means that the assembly causes writes to |
| 5921 | 5921 | arbitrary undeclared memory locations - not only the memory pointed to by a declared |
| 5922 | indirect output. | |
| 5922 | indirect output. | |
| 5923 | 5923 | </p> |
| 5924 | 5924 | <p> |
| 5925 | 5925 | Failure to declare the full set of clobbers for a given inline assembly |
| ... | ... | @@ -7746,6 +7746,30 @@ test "@setRuntimeSafety" { |
| 7746 | 7746 | </p> |
| 7747 | 7747 | {#header_close#} |
| 7748 | 7748 | |
| 7749 | {#header_open|@splat#} | |
| 7750 | <pre>{#syntax#}@splat(comptime len: u32, scalar: var) @Vector(len, @typeOf(scalar)){#endsyntax#}</pre> | |
| 7751 | <p> | |
| 7752 | Produces a vector of length {#syntax#}len{#endsyntax#} where each element is the value | |
| 7753 | {#syntax#}scalar{#endsyntax#}: | |
| 7754 | </p> | |
| 7755 | {#code_begin|test#} | |
| 7756 | const std = @import("std"); | |
| 7757 | const assert = std.debug.assert; | |
| 7758 | ||
| 7759 | test "vector @splat" { | |
| 7760 | const scalar: u32 = 5; | |
| 7761 | const result = @splat(4, scalar); | |
| 7762 | comptime assert(@typeOf(result) == @Vector(4, u32)); | |
| 7763 | assert(std.mem.eql(u32, ([4]u32)(result), [_]u32{ 5, 5, 5, 5 })); | |
| 7764 | } | |
| 7765 | {#code_end#} | |
| 7766 | <p> | |
| 7767 | {#syntax#}scalar{#endsyntax#} must be an {#link|integer|Integers#}, {#link|bool|Primitive Types#}, | |
| 7768 | {#link|float|Floats#}, or {#link|pointer|Pointers#}. | |
| 7769 | </p> | |
| 7770 | {#see_also|Vectors|@shuffle#} | |
| 7771 | {#header_close#} | |
| 7772 | ||
| 7749 | 7773 | {#header_open|@sqrt#} |
| 7750 | 7774 | <pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre> |
| 7751 | 7775 | <p> |
| ... | ... | @@ -9456,8 +9480,8 @@ const c = @cImport({ |
| 9456 | 9480 | <li>Does not support Zig-only pointer attributes such as alignment. Use normal {#link|Pointers#} |
| 9457 | 9481 | please!</li> |
| 9458 | 9482 | </ul> |
| 9459 | <p>When a C pointer is pointing to a single struct (not an array), deference the C pointer to | |
| 9460 | access to the struct's fields or member data. That syntax looks like | |
| 9483 | <p>When a C pointer is pointing to a single struct (not an array), deference the C pointer to | |
| 9484 | access to the struct's fields or member data. That syntax looks like | |
| 9461 | 9485 | this: </p> |
| 9462 | 9486 | <p>{#syntax#}ptr_to_struct.*.struct_member{#endsyntax#}</p> |
| 9463 | 9487 | <p>This is comparable to doing {#syntax#}->{#endsyntax#} in C.</p> |
src/all_types.hpp+16| ... | ... | @@ -1612,6 +1612,7 @@ enum BuiltinFnId { |
| 1612 | 1612 | BuiltinFnIdIntType, |
| 1613 | 1613 | BuiltinFnIdVectorType, |
| 1614 | 1614 | BuiltinFnIdShuffle, |
| 1615 | BuiltinFnIdSplat, | |
| 1615 | 1616 | BuiltinFnIdSetCold, |
| 1616 | 1617 | BuiltinFnIdSetRuntimeSafety, |
| 1617 | 1618 | BuiltinFnIdSetFloatMode, |
| ... | ... | @@ -2431,6 +2432,8 @@ enum IrInstructionId { |
| 2431 | 2432 | IrInstructionIdIntType, |
| 2432 | 2433 | IrInstructionIdVectorType, |
| 2433 | 2434 | IrInstructionIdShuffleVector, |
| 2435 | IrInstructionIdSplatSrc, | |
| 2436 | IrInstructionIdSplatGen, | |
| 2434 | 2437 | IrInstructionIdBoolNot, |
| 2435 | 2438 | IrInstructionIdMemset, |
| 2436 | 2439 | IrInstructionIdMemcpy, |
| ... | ... | @@ -3681,6 +3684,19 @@ struct IrInstructionShuffleVector { |
| 3681 | 3684 | IrInstruction *mask; // This is in zig-format, not llvm format |
| 3682 | 3685 | }; |
| 3683 | 3686 | |
| 3687 | struct IrInstructionSplatSrc { | |
| 3688 | IrInstruction base; | |
| 3689 | ||
| 3690 | IrInstruction *len; | |
| 3691 | IrInstruction *scalar; | |
| 3692 | }; | |
| 3693 | ||
| 3694 | struct IrInstructionSplatGen { | |
| 3695 | IrInstruction base; | |
| 3696 | ||
| 3697 | IrInstruction *scalar; | |
| 3698 | }; | |
| 3699 | ||
| 3684 | 3700 | struct IrInstructionAssertZero { |
| 3685 | 3701 | IrInstruction base; |
| 3686 | 3702 |
src/codegen.cpp+16| ... | ... | @@ -4619,6 +4619,18 @@ static LLVMValueRef ir_render_shuffle_vector(CodeGen *g, IrExecutable *executabl |
| 4619 | 4619 | llvm_mask_value, ""); |
| 4620 | 4620 | } |
| 4621 | 4621 | |
| 4622 | static LLVMValueRef ir_render_splat(CodeGen *g, IrExecutable *executable, IrInstructionSplatGen *instruction) { | |
| 4623 | ZigType *result_type = instruction->base.value.type; | |
| 4624 | src_assert(result_type->id == ZigTypeIdVector, instruction->base.source_node); | |
| 4625 | uint32_t len = result_type->data.vector.len; | |
| 4626 | LLVMTypeRef op_llvm_type = LLVMVectorType(get_llvm_type(g, instruction->scalar->value.type), 1); | |
| 4627 | LLVMTypeRef mask_llvm_type = LLVMVectorType(LLVMInt32Type(), len); | |
| 4628 | LLVMValueRef undef_vector = LLVMGetUndef(op_llvm_type); | |
| 4629 | LLVMValueRef op_vector = LLVMBuildInsertElement(g->builder, undef_vector, | |
| 4630 | ir_llvm_value(g, instruction->scalar), LLVMConstInt(LLVMInt32Type(), 0, false), ""); | |
| 4631 | return LLVMBuildShuffleVector(g->builder, op_vector, undef_vector, LLVMConstNull(mask_llvm_type), ""); | |
| 4632 | } | |
| 4633 | ||
| 4622 | 4634 | static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) { |
| 4623 | 4635 | ZigType *int_type = instruction->op->value.type; |
| 4624 | 4636 | LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount); |
| ... | ... | @@ -5986,6 +5998,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5986 | 5998 | case IrInstructionIdFrameSizeSrc: |
| 5987 | 5999 | case IrInstructionIdAllocaGen: |
| 5988 | 6000 | case IrInstructionIdAwaitSrc: |
| 6001 | case IrInstructionIdSplatSrc: | |
| 5989 | 6002 | zig_unreachable(); |
| 5990 | 6003 | |
| 5991 | 6004 | case IrInstructionIdDeclVarGen: |
| ... | ... | @@ -6146,6 +6159,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 6146 | 6159 | return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction); |
| 6147 | 6160 | case IrInstructionIdShuffleVector: |
| 6148 | 6161 | return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction); |
| 6162 | case IrInstructionIdSplatGen: | |
| 6163 | return ir_render_splat(g, executable, (IrInstructionSplatGen *) instruction); | |
| 6149 | 6164 | } |
| 6150 | 6165 | zig_unreachable(); |
| 6151 | 6166 | } |
| ... | ... | @@ -7837,6 +7852,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 7837 | 7852 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int |
| 7838 | 7853 | create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); |
| 7839 | 7854 | create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4); |
| 7855 | create_builtin_fn(g, BuiltinFnIdSplat, "splat", 2); | |
| 7840 | 7856 | create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); |
| 7841 | 7857 | create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); |
| 7842 | 7858 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); |
src/ir.cpp+106-5| ... | ... | @@ -721,6 +721,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionShuffleVector *) |
| 721 | 721 | return IrInstructionIdShuffleVector; |
| 722 | 722 | } |
| 723 | 723 | |
| 724 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSplatSrc *) { | |
| 725 | return IrInstructionIdSplatSrc; | |
| 726 | } | |
| 727 | ||
| 728 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSplatGen *) { | |
| 729 | return IrInstructionIdSplatGen; | |
| 730 | } | |
| 731 | ||
| 724 | 732 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { |
| 725 | 733 | return IrInstructionIdBoolNot; |
| 726 | 734 | } |
| ... | ... | @@ -2300,6 +2308,19 @@ static IrInstruction *ir_build_shuffle_vector(IrBuilder *irb, Scope *scope, AstN |
| 2300 | 2308 | return &instruction->base; |
| 2301 | 2309 | } |
| 2302 | 2310 | |
| 2311 | static IrInstruction *ir_build_splat_src(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2312 | IrInstruction *len, IrInstruction *scalar) | |
| 2313 | { | |
| 2314 | IrInstructionSplatSrc *instruction = ir_build_instruction<IrInstructionSplatSrc>(irb, scope, source_node); | |
| 2315 | instruction->len = len; | |
| 2316 | instruction->scalar = scalar; | |
| 2317 | ||
| 2318 | ir_ref_instruction(len, irb->current_basic_block); | |
| 2319 | ir_ref_instruction(scalar, irb->current_basic_block); | |
| 2320 | ||
| 2321 | return &instruction->base; | |
| 2322 | } | |
| 2323 | ||
| 2303 | 2324 | static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 2304 | 2325 | IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node); |
| 2305 | 2326 | instruction->value = value; |
| ... | ... | @@ -2356,6 +2377,19 @@ static IrInstruction *ir_build_slice_src(IrBuilder *irb, Scope *scope, AstNode * |
| 2356 | 2377 | return &instruction->base; |
| 2357 | 2378 | } |
| 2358 | 2379 | |
| 2380 | static IrInstruction *ir_build_splat_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_type, | |
| 2381 | IrInstruction *scalar) | |
| 2382 | { | |
| 2383 | IrInstructionSplatGen *instruction = ir_build_instruction<IrInstructionSplatGen>( | |
| 2384 | &ira->new_irb, source_instruction->scope, source_instruction->source_node); | |
| 2385 | instruction->base.value.type = result_type; | |
| 2386 | instruction->scalar = scalar; | |
| 2387 | ||
| 2388 | ir_ref_instruction(scalar, ira->new_irb.current_basic_block); | |
| 2389 | ||
| 2390 | return &instruction->base; | |
| 2391 | } | |
| 2392 | ||
| 2359 | 2393 | static IrInstruction *ir_build_slice_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *slice_type, |
| 2360 | 2394 | IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, IrInstruction *result_loc) |
| 2361 | 2395 | { |
| ... | ... | @@ -4985,6 +5019,22 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4985 | 5019 | arg0_value, arg1_value, arg2_value, arg3_value); |
| 4986 | 5020 | return ir_lval_wrap(irb, scope, shuffle_vector, lval, result_loc); |
| 4987 | 5021 | } |
| 5022 | case BuiltinFnIdSplat: | |
| 5023 | { | |
| 5024 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 5025 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 5026 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 5027 | return arg0_value; | |
| 5028 | ||
| 5029 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | |
| 5030 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | |
| 5031 | if (arg1_value == irb->codegen->invalid_instruction) | |
| 5032 | return arg1_value; | |
| 5033 | ||
| 5034 | IrInstruction *splat = ir_build_splat_src(irb, scope, node, | |
| 5035 | arg0_value, arg1_value); | |
| 5036 | return ir_lval_wrap(irb, scope, splat, lval, result_loc); | |
| 5037 | } | |
| 4988 | 5038 | case BuiltinFnIdMemcpy: |
| 4989 | 5039 | { |
| 4990 | 5040 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | ... | @@ -11049,16 +11099,23 @@ static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { |
| 11049 | 11099 | return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val); |
| 11050 | 11100 | } |
| 11051 | 11101 | |
| 11102 | static Error ir_validate_vector_elem_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *elem_type) { | |
| 11103 | if (!is_valid_vector_elem_type(elem_type)) { | |
| 11104 | ir_add_error(ira, source_instr, | |
| 11105 | buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid", | |
| 11106 | buf_ptr(&elem_type->name))); | |
| 11107 | return ErrorSemanticAnalyzeFail; | |
| 11108 | } | |
| 11109 | return ErrorNone; | |
| 11110 | } | |
| 11111 | ||
| 11052 | 11112 | static ZigType *ir_resolve_vector_elem_type(IrAnalyze *ira, IrInstruction *elem_type_value) { |
| 11113 | Error err; | |
| 11053 | 11114 | ZigType *elem_type = ir_resolve_type(ira, elem_type_value); |
| 11054 | 11115 | if (type_is_invalid(elem_type)) |
| 11055 | 11116 | 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))); | |
| 11117 | if ((err = ir_validate_vector_elem_type(ira, elem_type_value, elem_type))) | |
| 11060 | 11118 | return ira->codegen->builtin_types.entry_invalid; |
| 11061 | } | |
| 11062 | 11119 | return elem_type; |
| 11063 | 11120 | } |
| 11064 | 11121 | |
| ... | ... | @@ -22324,6 +22381,45 @@ static IrInstruction *ir_analyze_instruction_shuffle_vector(IrAnalyze *ira, IrIn |
| 22324 | 22381 | return ir_analyze_shuffle_vector(ira, &instruction->base, scalar_type, a, b, mask); |
| 22325 | 22382 | } |
| 22326 | 22383 | |
| 22384 | static IrInstruction *ir_analyze_instruction_splat(IrAnalyze *ira, IrInstructionSplatSrc *instruction) { | |
| 22385 | Error err; | |
| 22386 | ||
| 22387 | IrInstruction *len = instruction->len->child; | |
| 22388 | if (type_is_invalid(len->value.type)) | |
| 22389 | return ira->codegen->invalid_instruction; | |
| 22390 | ||
| 22391 | IrInstruction *scalar = instruction->scalar->child; | |
| 22392 | if (type_is_invalid(scalar->value.type)) | |
| 22393 | return ira->codegen->invalid_instruction; | |
| 22394 | ||
| 22395 | uint64_t len_u64; | |
| 22396 | if (!ir_resolve_unsigned(ira, len, ira->codegen->builtin_types.entry_u32, &len_u64)) | |
| 22397 | return ira->codegen->invalid_instruction; | |
| 22398 | uint32_t len_int = len_u64; | |
| 22399 | ||
| 22400 | if ((err = ir_validate_vector_elem_type(ira, scalar, scalar->value.type))) | |
| 22401 | return ira->codegen->invalid_instruction; | |
| 22402 | ||
| 22403 | ZigType *return_type = get_vector_type(ira->codegen, len_int, scalar->value.type); | |
| 22404 | ||
| 22405 | if (instr_is_comptime(scalar)) { | |
| 22406 | ConstExprValue *scalar_val = ir_resolve_const(ira, scalar, UndefOk); | |
| 22407 | if (scalar_val == nullptr) | |
| 22408 | return ira->codegen->invalid_instruction; | |
| 22409 | if (scalar_val->special == ConstValSpecialUndef) | |
| 22410 | return ir_const_undef(ira, &instruction->base, return_type); | |
| 22411 | ||
| 22412 | IrInstruction *result = ir_const(ira, &instruction->base, return_type); | |
| 22413 | result->value.data.x_array.data.s_none.elements = create_const_vals(len_int); | |
| 22414 | for (uint32_t i = 0; i < len_int; i += 1) { | |
| 22415 | copy_const_val(&result->value.data.x_array.data.s_none.elements[i], scalar_val, false); | |
| 22416 | } | |
| 22417 | return result; | |
| 22418 | } | |
| 22419 | ||
| 22420 | return ir_build_splat_gen(ira, &instruction->base, return_type, scalar); | |
| 22421 | } | |
| 22422 | ||
| 22327 | 22423 | static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { |
| 22328 | 22424 | IrInstruction *value = instruction->value->child; |
| 22329 | 22425 | if (type_is_invalid(value->value.type)) |
| ... | ... | @@ -25778,6 +25874,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25778 | 25874 | case IrInstructionIdTestErrGen: |
| 25779 | 25875 | case IrInstructionIdFrameSizeGen: |
| 25780 | 25876 | case IrInstructionIdAwaitGen: |
| 25877 | case IrInstructionIdSplatGen: | |
| 25781 | 25878 | zig_unreachable(); |
| 25782 | 25879 | |
| 25783 | 25880 | case IrInstructionIdReturn: |
| ... | ... | @@ -25908,6 +26005,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25908 | 26005 | return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); |
| 25909 | 26006 | case IrInstructionIdShuffleVector: |
| 25910 | 26007 | return ir_analyze_instruction_shuffle_vector(ira, (IrInstructionShuffleVector *)instruction); |
| 26008 | case IrInstructionIdSplatSrc: | |
| 26009 | return ir_analyze_instruction_splat(ira, (IrInstructionSplatSrc *)instruction); | |
| 25911 | 26010 | case IrInstructionIdBoolNot: |
| 25912 | 26011 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); |
| 25913 | 26012 | case IrInstructionIdMemset: |
| ... | ... | @@ -26244,6 +26343,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 26244 | 26343 | case IrInstructionIdIntType: |
| 26245 | 26344 | case IrInstructionIdVectorType: |
| 26246 | 26345 | case IrInstructionIdShuffleVector: |
| 26346 | case IrInstructionIdSplatSrc: | |
| 26347 | case IrInstructionIdSplatGen: | |
| 26247 | 26348 | case IrInstructionIdBoolNot: |
| 26248 | 26349 | case IrInstructionIdSliceSrc: |
| 26249 | 26350 | case IrInstructionIdMemberCount: |
src/ir_print.cpp+24| ... | ... | @@ -44,6 +44,10 @@ static const char* ir_instruction_type_str(IrInstruction* instruction) { |
| 44 | 44 | return "Invalid"; |
| 45 | 45 | case IrInstructionIdShuffleVector: |
| 46 | 46 | return "Shuffle"; |
| 47 | case IrInstructionIdSplatSrc: | |
| 48 | return "SplatSrc"; | |
| 49 | case IrInstructionIdSplatGen: | |
| 50 | return "SplatGen"; | |
| 47 | 51 | case IrInstructionIdDeclVarSrc: |
| 48 | 52 | return "DeclVarSrc"; |
| 49 | 53 | case IrInstructionIdDeclVarGen: |
| ... | ... | @@ -1222,6 +1226,20 @@ static void ir_print_shuffle_vector(IrPrint *irp, IrInstructionShuffleVector *in |
| 1222 | 1226 | fprintf(irp->f, ")"); |
| 1223 | 1227 | } |
| 1224 | 1228 | |
| 1229 | static void ir_print_splat_src(IrPrint *irp, IrInstructionSplatSrc *instruction) { | |
| 1230 | fprintf(irp->f, "@splat("); | |
| 1231 | ir_print_other_instruction(irp, instruction->len); | |
| 1232 | fprintf(irp->f, ", "); | |
| 1233 | ir_print_other_instruction(irp, instruction->scalar); | |
| 1234 | fprintf(irp->f, ")"); | |
| 1235 | } | |
| 1236 | ||
| 1237 | static void ir_print_splat_gen(IrPrint *irp, IrInstructionSplatGen *instruction) { | |
| 1238 | fprintf(irp->f, "@splat("); | |
| 1239 | ir_print_other_instruction(irp, instruction->scalar); | |
| 1240 | fprintf(irp->f, ")"); | |
| 1241 | } | |
| 1242 | ||
| 1225 | 1243 | static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { |
| 1226 | 1244 | fprintf(irp->f, "! "); |
| 1227 | 1245 | ir_print_other_instruction(irp, instruction->value); |
| ... | ... | @@ -2160,6 +2178,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2160 | 2178 | case IrInstructionIdShuffleVector: |
| 2161 | 2179 | ir_print_shuffle_vector(irp, (IrInstructionShuffleVector *)instruction); |
| 2162 | 2180 | break; |
| 2181 | case IrInstructionIdSplatSrc: | |
| 2182 | ir_print_splat_src(irp, (IrInstructionSplatSrc *)instruction); | |
| 2183 | break; | |
| 2184 | case IrInstructionIdSplatGen: | |
| 2185 | ir_print_splat_gen(irp, (IrInstructionSplatGen *)instruction); | |
| 2186 | break; | |
| 2163 | 2187 | case IrInstructionIdBoolNot: |
| 2164 | 2188 | ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); |
| 2165 | 2189 | break; |
test/compile_errors.zig+10| ... | ... | @@ -6507,6 +6507,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 6507 | 6507 | "tmp.zig:2:26: error: vector element type must be integer, float, bool, or pointer; '@Vector(4, u8)' is invalid", |
| 6508 | 6508 | ); |
| 6509 | 6509 | |
| 6510 | cases.addTest( | |
| 6511 | "bad @splat type", | |
| 6512 | \\export fn entry() void { | |
| 6513 | \\ const c = 4; | |
| 6514 | \\ var v = @splat(4, c); | |
| 6515 | \\} | |
| 6516 | , | |
| 6517 | "tmp.zig:3:23: error: vector element type must be integer, float, bool, or pointer; 'comptime_int' is invalid", | |
| 6518 | ); | |
| 6519 | ||
| 6510 | 6520 | cases.add("compileLog of tagged enum doesn't crash the compiler", |
| 6511 | 6521 | \\const Bar = union(enum(u32)) { |
| 6512 | 6522 | \\ X: i32 = 1 |
test/stage1/behavior/vector.zig+27-10| ... | ... | @@ -35,12 +35,12 @@ test "vector bin compares with mem.eql" { |
| 35 | 35 | fn doTheTest() void { |
| 36 | 36 | var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; |
| 37 | 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})); | |
| 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 | 44 | } |
| 45 | 45 | }; |
| 46 | 46 | S.doTheTest(); |
| ... | ... | @@ -114,22 +114,22 @@ test "vector casts of sizes not divisable by 8" { |
| 114 | 114 | const S = struct { |
| 115 | 115 | fn doTheTest() void { |
| 116 | 116 | { |
| 117 | var v: @Vector(4, u3) = [4]u3{ 5, 2, 3, 0}; | |
| 117 | var v: @Vector(4, u3) = [4]u3{ 5, 2, 3, 0 }; | |
| 118 | 118 | var x: [4]u3 = v; |
| 119 | 119 | expect(mem.eql(u3, x, ([4]u3)(v))); |
| 120 | 120 | } |
| 121 | 121 | { |
| 122 | var v: @Vector(4, u2) = [4]u2{ 1, 2, 3, 0}; | |
| 122 | var v: @Vector(4, u2) = [4]u2{ 1, 2, 3, 0 }; | |
| 123 | 123 | var x: [4]u2 = v; |
| 124 | 124 | expect(mem.eql(u2, x, ([4]u2)(v))); |
| 125 | 125 | } |
| 126 | 126 | { |
| 127 | var v: @Vector(4, u1) = [4]u1{ 1, 0, 1, 0}; | |
| 127 | var v: @Vector(4, u1) = [4]u1{ 1, 0, 1, 0 }; | |
| 128 | 128 | var x: [4]u1 = v; |
| 129 | 129 | expect(mem.eql(u1, x, ([4]u1)(v))); |
| 130 | 130 | } |
| 131 | 131 | { |
| 132 | var v: @Vector(4, bool) = [4]bool{ false, false, true, false}; | |
| 132 | var v: @Vector(4, bool) = [4]bool{ false, false, true, false }; | |
| 133 | 133 | var x: [4]bool = v; |
| 134 | 134 | expect(mem.eql(bool, x, ([4]bool)(v))); |
| 135 | 135 | } |
| ... | ... | @@ -138,3 +138,20 @@ test "vector casts of sizes not divisable by 8" { |
| 138 | 138 | S.doTheTest(); |
| 139 | 139 | comptime S.doTheTest(); |
| 140 | 140 | } |
| 141 | ||
| 142 | test "vector @splat" { | |
| 143 | const S = struct { | |
| 144 | fn doTheTest() void { | |
| 145 | var v: u32 = 5; | |
| 146 | var x = @splat(4, v); | |
| 147 | expect(@typeOf(x) == @Vector(4, u32)); | |
| 148 | var array_x: [4]u32 = x; | |
| 149 | expect(array_x[0] == 5); | |
| 150 | expect(array_x[1] == 5); | |
| 151 | expect(array_x[2] == 5); | |
| 152 | expect(array_x[3] == 5); | |
| 153 | } | |
| 154 | }; | |
| 155 | S.doTheTest(); | |
| 156 | comptime S.doTheTest(); | |
| 157 | } |