| author | |
| committer | |
| log | 01577a3af480cff02c5f78864f8056487b3d3b44 |
| tree | 9d029218b191a5c3f5701153fd1784eafae08e3f |
| parent | 0048bcbd71b9139203d7acee120d524d38e22a0e |
| signature |
6 files changed, 157 insertions(+), 10 deletions(-)
src/all_types.hpp+9| ... | ... | @@ -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,7 @@ enum IrInstructionId { |
| 2431 | 2432 | IrInstructionIdIntType, |
| 2432 | 2433 | IrInstructionIdVectorType, |
| 2433 | 2434 | IrInstructionIdShuffleVector, |
| 2435 | IrInstructionIdSplat, | |
| 2434 | 2436 | IrInstructionIdBoolNot, |
| 2435 | 2437 | IrInstructionIdMemset, |
| 2436 | 2438 | IrInstructionIdMemcpy, |
| ... | ... | @@ -3681,6 +3683,13 @@ struct IrInstructionShuffleVector { |
| 3681 | 3683 | IrInstruction *mask; // This is in zig-format, not llvm format |
| 3682 | 3684 | }; |
| 3683 | 3685 | |
| 3686 | struct IrInstructionSplat { | |
| 3687 | IrInstruction base; | |
| 3688 | ||
| 3689 | IrInstruction *len; | |
| 3690 | IrInstruction *scalar; | |
| 3691 | }; | |
| 3692 | ||
| 3684 | 3693 | struct IrInstructionAssertZero { |
| 3685 | 3694 | IrInstruction base; |
| 3686 | 3695 |
src/codegen.cpp+17| ... | ... | @@ -4619,6 +4619,20 @@ 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, IrInstructionSplat *instruction) { | |
| 4623 | uint64_t len = bigint_as_u64(&instruction->len->value.data.x_bigint); | |
| 4624 | LLVMValueRef wrapped_scalar_undef = LLVMGetUndef(instruction->base.value.type->llvm_type); | |
| 4625 | LLVMValueRef wrapped_scalar = LLVMBuildInsertElement(g->builder, wrapped_scalar_undef, | |
| 4626 | ir_llvm_value(g, instruction->scalar), | |
| 4627 | LLVMConstInt(LLVMInt32Type(), 0, false), | |
| 4628 | ""); | |
| 4629 | return LLVMBuildShuffleVector(g->builder, | |
| 4630 | wrapped_scalar, | |
| 4631 | wrapped_scalar_undef, | |
| 4632 | LLVMConstNull(LLVMVectorType(g->builtin_types.entry_u32->llvm_type, (uint32_t)len)), | |
| 4633 | ""); | |
| 4634 | } | |
| 4635 | ||
| 4622 | 4636 | static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) { |
| 4623 | 4637 | ZigType *int_type = instruction->op->value.type; |
| 4624 | 4638 | LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount); |
| ... | ... | @@ -6146,6 +6160,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 6146 | 6160 | return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction); |
| 6147 | 6161 | case IrInstructionIdShuffleVector: |
| 6148 | 6162 | return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction); |
| 6163 | case IrInstructionIdSplat: | |
| 6164 | return ir_render_splat(g, executable, (IrInstructionSplat *) instruction); | |
| 6149 | 6165 | } |
| 6150 | 6166 | zig_unreachable(); |
| 6151 | 6167 | } |
| ... | ... | @@ -7837,6 +7853,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 7837 | 7853 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int |
| 7838 | 7854 | create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); |
| 7839 | 7855 | create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4); |
| 7856 | create_builtin_fn(g, BuiltinFnIdSplat, "splat", 2); | |
| 7840 | 7857 | create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1); |
| 7841 | 7858 | create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1); |
| 7842 | 7859 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1); |
src/ir.cpp+82| ... | ... | @@ -721,6 +721,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionShuffleVector *) |
| 721 | 721 | return IrInstructionIdShuffleVector; |
| 722 | 722 | } |
| 723 | 723 | |
| 724 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSplat *) { | |
| 725 | return IrInstructionIdSplat; | |
| 726 | } | |
| 727 | ||
| 724 | 728 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { |
| 725 | 729 | return IrInstructionIdBoolNot; |
| 726 | 730 | } |
| ... | ... | @@ -2300,6 +2304,19 @@ static IrInstruction *ir_build_shuffle_vector(IrBuilder *irb, Scope *scope, AstN |
| 2300 | 2304 | return &instruction->base; |
| 2301 | 2305 | } |
| 2302 | 2306 | |
| 2307 | static IrInstruction *ir_build_splat(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2308 | IrInstruction *len, IrInstruction *scalar) | |
| 2309 | { | |
| 2310 | IrInstructionSplat *instruction = ir_build_instruction<IrInstructionSplat>(irb, scope, source_node); | |
| 2311 | instruction->len = len; | |
| 2312 | instruction->scalar = scalar; | |
| 2313 | ||
| 2314 | ir_ref_instruction(len, irb->current_basic_block); | |
| 2315 | ir_ref_instruction(scalar, irb->current_basic_block); | |
| 2316 | ||
| 2317 | return &instruction->base; | |
| 2318 | } | |
| 2319 | ||
| 2303 | 2320 | static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 2304 | 2321 | IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node); |
| 2305 | 2322 | instruction->value = value; |
| ... | ... | @@ -4985,6 +5002,22 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4985 | 5002 | arg0_value, arg1_value, arg2_value, arg3_value); |
| 4986 | 5003 | return ir_lval_wrap(irb, scope, shuffle_vector, lval, result_loc); |
| 4987 | 5004 | } |
| 5005 | case BuiltinFnIdSplat: | |
| 5006 | { | |
| 5007 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 5008 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 5009 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 5010 | return arg0_value; | |
| 5011 | ||
| 5012 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | |
| 5013 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | |
| 5014 | if (arg1_value == irb->codegen->invalid_instruction) | |
| 5015 | return arg1_value; | |
| 5016 | ||
| 5017 | IrInstruction *splat = ir_build_splat(irb, scope, node, | |
| 5018 | arg0_value, arg1_value); | |
| 5019 | return ir_lval_wrap(irb, scope, splat, lval, result_loc); | |
| 5020 | } | |
| 4988 | 5021 | case BuiltinFnIdMemcpy: |
| 4989 | 5022 | { |
| 4990 | 5023 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | ... | @@ -22324,6 +22357,52 @@ static IrInstruction *ir_analyze_instruction_shuffle_vector(IrAnalyze *ira, IrIn |
| 22324 | 22357 | return ir_analyze_shuffle_vector(ira, &instruction->base, scalar_type, a, b, mask); |
| 22325 | 22358 | } |
| 22326 | 22359 | |
| 22360 | static IrInstruction *ir_analyze_instruction_splat(IrAnalyze *ira, IrInstructionSplat *instruction) { | |
| 22361 | IrInstruction *len = instruction->len->child; | |
| 22362 | if (type_is_invalid(len->value.type)) | |
| 22363 | return ira->codegen->invalid_instruction; | |
| 22364 | ||
| 22365 | IrInstruction *scalar = instruction->scalar->child; | |
| 22366 | if (type_is_invalid(scalar->value.type)) | |
| 22367 | return ira->codegen->invalid_instruction; | |
| 22368 | ||
| 22369 | uint64_t len_int; | |
| 22370 | if (!ir_resolve_unsigned(ira, len, ira->codegen->builtin_types.entry_u32, &len_int)) { | |
| 22371 | ir_add_error(ira, len, | |
| 22372 | buf_sprintf("splat length must be comptime")); | |
| 22373 | return ira->codegen->invalid_instruction; | |
| 22374 | } | |
| 22375 | ||
| 22376 | if (!is_valid_vector_elem_type(scalar->value.type)) { | |
| 22377 | ir_add_error(ira, len, | |
| 22378 | buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid", | |
| 22379 | buf_ptr(&scalar->value.type->name))); | |
| 22380 | return ira->codegen->invalid_instruction; | |
| 22381 | } | |
| 22382 | ||
| 22383 | ZigType *return_type = get_vector_type(ira->codegen, len_int, scalar->value.type); | |
| 22384 | ||
| 22385 | if (instr_is_comptime(scalar)) { | |
| 22386 | IrInstruction *result = ir_const_undef(ira, scalar, return_type); | |
| 22387 | result->value.data.x_array.data.s_none.elements = | |
| 22388 | allocate<ConstExprValue>(len_int); | |
| 22389 | for (uint32_t i = 0; i < len_int; i++) { | |
| 22390 | result->value.data.x_array.data.s_none.elements[i] = | |
| 22391 | scalar->value; | |
| 22392 | } | |
| 22393 | result->value.type = return_type; | |
| 22394 | result->value.special = ConstValSpecialStatic; | |
| 22395 | return result; | |
| 22396 | } | |
| 22397 | ||
| 22398 | IrInstruction *result = ir_build_splat(&ira->new_irb, | |
| 22399 | instruction->base.scope, instruction->base.source_node, | |
| 22400 | instruction->len->child, instruction->scalar->child); | |
| 22401 | result->value.type = return_type; | |
| 22402 | result->value.special = ConstValSpecialRuntime; | |
| 22403 | return result; | |
| 22404 | } | |
| 22405 | ||
| 22327 | 22406 | static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { |
| 22328 | 22407 | IrInstruction *value = instruction->value->child; |
| 22329 | 22408 | if (type_is_invalid(value->value.type)) |
| ... | ... | @@ -25908,6 +25987,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25908 | 25987 | return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); |
| 25909 | 25988 | case IrInstructionIdShuffleVector: |
| 25910 | 25989 | return ir_analyze_instruction_shuffle_vector(ira, (IrInstructionShuffleVector *)instruction); |
| 25990 | case IrInstructionIdSplat: | |
| 25991 | return ir_analyze_instruction_splat(ira, (IrInstructionSplat *)instruction); | |
| 25911 | 25992 | case IrInstructionIdBoolNot: |
| 25912 | 25993 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); |
| 25913 | 25994 | case IrInstructionIdMemset: |
| ... | ... | @@ -26244,6 +26325,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 26244 | 26325 | case IrInstructionIdIntType: |
| 26245 | 26326 | case IrInstructionIdVectorType: |
| 26246 | 26327 | case IrInstructionIdShuffleVector: |
| 26328 | case IrInstructionIdSplat: | |
| 26247 | 26329 | case IrInstructionIdBoolNot: |
| 26248 | 26330 | case IrInstructionIdSliceSrc: |
| 26249 | 26331 | case IrInstructionIdMemberCount: |
src/ir_print.cpp+13| ... | ... | @@ -44,6 +44,8 @@ static const char* ir_instruction_type_str(IrInstruction* instruction) { |
| 44 | 44 | return "Invalid"; |
| 45 | 45 | case IrInstructionIdShuffleVector: |
| 46 | 46 | return "Shuffle"; |
| 47 | case IrInstructionIdSplat: | |
| 48 | return "Splat"; | |
| 47 | 49 | case IrInstructionIdDeclVarSrc: |
| 48 | 50 | return "DeclVarSrc"; |
| 49 | 51 | case IrInstructionIdDeclVarGen: |
| ... | ... | @@ -1222,6 +1224,14 @@ static void ir_print_shuffle_vector(IrPrint *irp, IrInstructionShuffleVector *in |
| 1222 | 1224 | fprintf(irp->f, ")"); |
| 1223 | 1225 | } |
| 1224 | 1226 | |
| 1227 | static void ir_print_splat(IrPrint *irp, IrInstructionSplat *instruction) { | |
| 1228 | fprintf(irp->f, "@splat("); | |
| 1229 | ir_print_other_instruction(irp, instruction->len); | |
| 1230 | fprintf(irp->f, ", "); | |
| 1231 | ir_print_other_instruction(irp, instruction->scalar); | |
| 1232 | fprintf(irp->f, ")"); | |
| 1233 | } | |
| 1234 | ||
| 1225 | 1235 | static void ir_print_bool_not(IrPrint *irp, IrInstructionBoolNot *instruction) { |
| 1226 | 1236 | fprintf(irp->f, "! "); |
| 1227 | 1237 | ir_print_other_instruction(irp, instruction->value); |
| ... | ... | @@ -2160,6 +2170,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2160 | 2170 | case IrInstructionIdShuffleVector: |
| 2161 | 2171 | ir_print_shuffle_vector(irp, (IrInstructionShuffleVector *)instruction); |
| 2162 | 2172 | break; |
| 2173 | case IrInstructionIdSplat: | |
| 2174 | ir_print_splat(irp, (IrInstructionSplat *)instruction); | |
| 2175 | break; | |
| 2163 | 2176 | case IrInstructionIdBoolNot: |
| 2164 | 2177 | ir_print_bool_not(irp, (IrInstructionBoolNot *)instruction); |
| 2165 | 2178 | 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:20: 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+26-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,19 @@ 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 | expect(x[0] == 5); | |
| 149 | expect(x[1] == 5); | |
| 150 | expect(x[2] == 5); | |
| 151 | expect(x[3] == 5); | |
| 152 | } | |
| 153 | }; | |
| 154 | S.doTheTest(); | |
| 155 | comptime S.doTheTest(); | |
| 156 | } |