authorgravatar for shawn@git.icuShawn Landden <shawn@git.icu> 2019-06-29 11:32:26-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-18 11:26:45-04:00
log193604c837df75ab0c3fa5860f8b234263fe5b50
treed96c52e9fd95d3e964fcc298505effc6bf3bffb3
parent9e4065fa738f040dd338c613409fc1089cc33580
signaturelock-open Commit is signed but in an unrecognized format.

stage1: add @shuffle() shufflevector support

I change the semantics of the mask operand, to make it a little more flexible. There is no real danger in this because it is a compile-error if you do it the LLVM way (and there is an appropiate error to tell you this). v2: avoid problems with double-free

7 files changed, 426 insertions(+), 0 deletions(-)

doc/langref.html.in+22
...@@ -8226,6 +8226,28 @@ fn foo(comptime T: type, ptr: *T) T {...@@ -8226,6 +8226,28 @@ fn foo(comptime T: type, ptr: *T) T {
8226 {#link|pointer|Pointers#}.8226 {#link|pointer|Pointers#}.
8227 </p>8227 </p>
8228 {#header_close#}8228 {#header_close#}
8229
8230 {#header_open|@shuffle#}
8231 <pre>{#syntax#}@shuffle(comptime ElemType: type, a: @Vector(_, ElemType), b: @Vector(_, ElemType), comptime mask: @Vector(_, u32)) @Vector(mask.len, ElemType){#endsyntax#}</pre>
8232 <p>
8233 Does the {#syntax#}shufflevector{#endsyntax#} instruction. Each element in {#syntax#}comptime{#endsyntax#}
8234 (and always {#syntax#}i32{#endsyntax#}) {#syntax#}mask{#endsyntax#} selects a element from either {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#}.
8235 Positive numbers select from {#syntax#}a{#endsyntax#} (starting at 0), while negative values select
8236 from {#syntax#}b{#endsyntax#} (starting at -1 and going down). It is recommended to use the {#syntax#}~{#endsyntax#}
8237 operator from indexes from b so that both indexes can start from 0 (i.e. ~0 is -1). If either the {#syntax#}mask{#endsyntax#}
8238 value or the value from {#syntax#}a{#endsyntax#} or {#syntax#}b{#endsyntax#} that it selects are {#syntax#}undefined{#endsyntax#}
8239 then the resulting value is {#syntax#}undefined{#endsyntax#}. Also see {#link|SIMD#} and
8240 the relevent <a href="https://llvm.org/docs/LangRef.html#i-shufflevector">LLVM Documentation on
8241 {#syntax#}shufflevector{#endsyntax#}</a>, although note that the mask values are interpreted differently than in LLVM-IR.
8242 Also, unlike LLVM-IR, the number of elements in {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} do not have to match.
8243 The {#syntax#}undefined{#endsyntax#} identifier can be selected from up to the length of the other vector,
8244 and yields {#syntax#}undefined{#endsyntax#}. If both vectors are {#syntax#}undefined{#endsyntax#}, yields an
8245 {#syntax#}undefined{#endsyntax#} {#syntax#}ElemType{#endsyntax#} vector with length of {#syntax#}mask{#endsyntax#}.</p>
8246 <p>
8247 {#syntax#}ElemType{#endsyntax#} must be an {#link|integer|Integers#}, a {#link|float|Floats#}, or a
8248 {#link|pointer|Pointers#}. The mask may be any vector length that the target supports, and its' length determines the result length.
8249 </p>
8250 {#header_close#}
8229 {#header_close#}8251 {#header_close#}
82308252
8231 {#header_open|Build Mode#}8253 {#header_open|Build Mode#}
src/all_types.hpp+11
...@@ -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/codegen.cpp+32
...@@ -4581,6 +4581,35 @@ static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstru...@@ -4581,6 +4581,35 @@ 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_c = 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_c);
4595 for (uint64_t i = 0;i < len_c;i++) {
4596 if (mask->value.data.x_array.data.s_none.elements[i].special == ConstValSpecialUndef) {
4597 values[i] = LLVMGetUndef(LLVMInt32Type());
4598 } else {
4599 int64_t v = bigint_as_signed(&mask->value.data.x_array.data.s_none.elements[i].data.x_bigint);
4600 if (v < 0)
4601 v = (uint32_t)~v + (uint32_t)len_a;
4602 values[i] = LLVMConstInt(LLVMInt32Type(), v, false);
4603 }
4604 }
4605
4606 return LLVMBuildShuffleVector(g->builder,
4607 ir_llvm_value(g, instruction->a),
4608 ir_llvm_value(g, instruction->b),
4609 LLVMConstVector(values, len_c),
4610 "");
4611}
4612
4584static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {4613static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {
4585 ZigType *int_type = instruction->op->value.type;4614 ZigType *int_type = instruction->op->value.type;
4586 LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);4615 LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);
...@@ -6095,6 +6124,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -6095,6 +6124,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
6095 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);6124 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);
6096 case IrInstructionIdSpillEnd:6125 case IrInstructionIdSpillEnd:
6097 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);6126 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);
6127 case IrInstructionIdShuffleVector:
6128 return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction);
6098 }6129 }
6099 zig_unreachable();6130 zig_unreachable();
6100}6131}
...@@ -7785,6 +7816,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7785,6 +7816,7 @@ static void define_builtin_fns(CodeGen *g) {
7785 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);7816 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
7786 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int7817 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
7787 create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);7818 create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);
7819 create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4);
7788 create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);7820 create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
7789 create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);7821 create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
7790 create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);7822 create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);
src/ir.cpp+274
...@@ -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);
...@@ -22063,6 +22112,228 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr...@@ -22063,6 +22112,228 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr
22063 return ir_const_type(ira, &instruction->base, vector_type);22112 return ir_const_type(ira, &instruction->base, vector_type);
22064}22113}
2206522114
22115static IrInstruction *ir_analyze_shuffle_vector(IrAnalyze *ira, IrInstruction *source_instr,
22116 ZigType *scalar_type, IrInstruction *a, IrInstruction *b, IrInstruction *mask) {
22117 assert(source_instr && scalar_type && a && b && mask);
22118 assert(scalar_type->id == ZigTypeIdBool ||
22119 scalar_type->id == ZigTypeIdInt ||
22120 scalar_type->id == ZigTypeIdFloat ||
22121 scalar_type->id == ZigTypeIdPointer);
22122
22123 ZigType *mask_type = mask->value.type;
22124 if (type_is_invalid(mask_type))
22125 return ira->codegen->invalid_instruction;
22126
22127 const char *shuffle_mask_fail_fmt = "@shuffle mask operand must be a vector of signed 32-bit integers, got '%s'";
22128
22129 if (mask_type->id == ZigTypeIdArray) {
22130 ZigType *vector_type = get_vector_type(ira->codegen, mask_type->data.array.len, mask_type->data.array.child_type);
22131 mask = ir_analyze_array_to_vector(ira, mask, mask, vector_type);
22132 if (!mask)
22133 return ira->codegen->invalid_instruction;
22134 mask_type = vector_type;
22135 }
22136
22137 if (mask_type->id != ZigTypeIdVector) {
22138 ir_add_error(ira, mask,
22139 buf_sprintf(shuffle_mask_fail_fmt, buf_ptr(&mask->value.type->name)));
22140 return ira->codegen->invalid_instruction;
22141 }
22142
22143 ZigType *mask_scalar_type = mask_type->data.array.child_type;
22144 if (mask_scalar_type->id != ZigTypeIdInt) {
22145 ir_add_error(ira, mask,
22146 buf_sprintf(shuffle_mask_fail_fmt, buf_ptr(&mask->value.type->name)));
22147 return ira->codegen->invalid_instruction;
22148 }
22149
22150 if (mask_scalar_type->data.integral.bit_count != 32 ||
22151 mask_scalar_type->data.integral.is_signed == false) {
22152 ir_add_error(ira, mask,
22153 buf_sprintf(shuffle_mask_fail_fmt, buf_ptr(&mask->value.type->name)));
22154 return ira->codegen->invalid_instruction;
22155 }
22156
22157 uint64_t len_a, len_b, len_c = mask->value.type->data.vector.len;
22158 if (a->value.type->id != ZigTypeIdVector) {
22159 if (a->value.type->id != ZigTypeIdUndefined) {
22160 ir_add_error(ira, a,
22161 buf_sprintf("expected vector of element type '%s' got '%s'",
22162 buf_ptr(&scalar_type->name),
22163 buf_ptr(&a->value.type->name)));
22164 return ira->codegen->invalid_instruction;
22165 }
22166 } else {
22167 len_a = a->value.type->data.vector.len;
22168 }
22169
22170 if (b->value.type->id != ZigTypeIdVector) {
22171 if (b->value.type->id != ZigTypeIdUndefined) {
22172 ir_add_error(ira, b,
22173 buf_sprintf("expected vector of element type '%s' got '%s'",
22174 buf_ptr(&scalar_type->name),
22175 buf_ptr(&b->value.type->name)));
22176 return ira->codegen->invalid_instruction;
22177 }
22178 } else {
22179 len_b = b->value.type->data.vector.len;
22180 }
22181
22182 if (a->value.type->id == ZigTypeIdUndefined && b->value.type->id == ZigTypeIdUndefined) {
22183 return ir_const_undef(ira, a, get_vector_type(ira->codegen, len_c, scalar_type));
22184 }
22185
22186 // undefined is a vector up to length of the other vector.
22187 if (a->value.type->id == ZigTypeIdUndefined) {
22188 a = ir_const_undef(ira, a, b->value.type);
22189 len_a = b->value.type->data.vector.len;
22190 } else if (b->value.type->id == ZigTypeIdUndefined) {
22191 b = ir_const_undef(ira, b, a->value.type);
22192 len_b = a->value.type->data.vector.len;
22193 }
22194
22195 // FIXME I think this needs to be more sophisticated
22196 if (a->value.type->data.vector.elem_type != scalar_type) {
22197 ir_add_error(ira, a,
22198 buf_sprintf("element type '%s' does not match '%s'",
22199 buf_ptr(&a->value.type->data.vector.elem_type->name),
22200 buf_ptr(&scalar_type->name)));
22201 return ira->codegen->invalid_instruction;
22202 }
22203 if (b->value.type->data.vector.elem_type != scalar_type) {
22204 ir_add_error(ira, b,
22205 buf_sprintf("element type '%s' does not match '%s'",
22206 buf_ptr(&b->value.type->data.vector.elem_type->name),
22207 buf_ptr(&scalar_type->name)));
22208 return ira->codegen->invalid_instruction;
22209 }
22210
22211 if (a->value.type != b->value.type) {
22212 assert(len_a != len_b);
22213 uint32_t len_max = max(len_a, len_b), len_min = min(len_a, len_b);
22214 bool expand_b = len_b < len_a;
22215 IrInstruction *expand_mask = ir_const(ira, mask,
22216 get_vector_type(ira->codegen, len_max, ira->codegen->builtin_types.entry_i32));
22217 expand_mask->value.data.x_array.data.s_none.elements = create_const_vals(len_max);
22218 uint32_t i = 0;
22219 for (; i < len_min; i++)
22220 bigint_init_unsigned(&expand_mask->value.data.x_array.data.s_none.elements[i].data.x_bigint, i);
22221 for (; i < len_max; i++)
22222 bigint_init_signed(&expand_mask->value.data.x_array.data.s_none.elements[i].data.x_bigint, -1);
22223 IrInstruction *undef = ir_const_undef(ira, source_instr,
22224 get_vector_type(ira->codegen, len_min, scalar_type));
22225 if (expand_b) {
22226 if (instr_is_comptime(b)) {
22227 ConstExprValue *old = b->value.data.x_array.data.s_none.elements;
22228 b->value.data.x_array.data.s_none.elements =
22229 allocate<ConstExprValue>(len_a);
22230 memcpy(b->value.data.x_array.data.s_none.elements, old,
22231 b->value.type->data.vector.len * sizeof(ConstExprValue));
22232 } else {
22233 b = ir_build_shuffle_vector(&ira->new_irb,
22234 source_instr->scope, source_instr->source_node,
22235 nullptr, b, undef, expand_mask);
22236 b->value.special = ConstValSpecialRuntime;
22237 }
22238 b->value.type = get_vector_type(ira->codegen, len_max, scalar_type);
22239 } else {
22240 if (instr_is_comptime(a)) {
22241 ConstExprValue *old = a->value.data.x_array.data.s_none.elements;
22242 a->value.data.x_array.data.s_none.elements =
22243 allocate<ConstExprValue>(len_b);
22244 memcpy(a->value.data.x_array.data.s_none.elements, old,
22245 a->value.type->data.vector.len * sizeof(ConstExprValue));
22246 } else {
22247 a = ir_build_shuffle_vector(&ira->new_irb,
22248 source_instr->scope, source_instr->source_node,
22249 nullptr, a, undef, expand_mask);
22250 a->value.special = ConstValSpecialRuntime;
22251 }
22252 a->value.type = get_vector_type(ira->codegen, len_max, scalar_type);
22253 }
22254 }
22255 ConstExprValue *mask_val = ir_resolve_const(ira, mask, UndefOk);
22256 if (!mask_val) {
22257 ir_add_error(ira, mask,
22258 buf_sprintf("mask must be comptime"));
22259 return ira->codegen->invalid_instruction;
22260 }
22261 for (uint32_t i = 0;i < mask->value.type->data.vector.len;i++) {
22262 if (mask->value.data.x_array.data.s_none.elements[i].special == ConstValSpecialUndef)
22263 continue;
22264 int64_t v = bigint_as_signed(&mask->value.data.x_array.data.s_none.elements[i].data.x_bigint);
22265 if (v >= 0 && (uint64_t)v + 1 > len_a) {
22266 ErrorMsg *msg = ir_add_error(ira, mask,
22267 buf_sprintf("mask index out of bounds"));
22268 add_error_note(ira->codegen, msg, mask->source_node,
22269 buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, (uintptr_t)i));
22270 if ((uint64_t)v <= len_a + len_b)
22271 add_error_note(ira->codegen, msg, mask->source_node,
22272 buf_sprintf("selections from the second vector are specified with negative numbers"));
22273 } else if (v < 0 && (uint64_t)~v + 1 > len_b) {
22274 ErrorMsg *msg = ir_add_error(ira, mask,
22275 buf_sprintf("mask index out of bounds"));
22276 add_error_note(ira->codegen, msg, mask->source_node,
22277 buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, (uintptr_t)i));
22278 }
22279 else
22280 continue;
22281 return ira->codegen->invalid_instruction;
22282 }
22283
22284 ZigType *result_type = get_vector_type(ira->codegen, len_c, scalar_type);
22285 if (instr_is_comptime(a) &&
22286 instr_is_comptime(b)) {
22287 IrInstruction *result = ir_const(ira, source_instr, result_type);
22288 result->value.data.x_array.data.s_none.elements = create_const_vals(len_c);
22289 for (uint32_t i = 0;i < mask->value.type->data.vector.len;i++) {
22290 if (mask->value.data.x_array.data.s_none.elements[i].special == ConstValSpecialUndef)
22291 result->value.data.x_array.data.s_none.elements[i].special =
22292 ConstValSpecialUndef;
22293 int64_t v = bigint_as_signed(&mask->value.data.x_array.data.s_none.elements[i].data.x_bigint);
22294 if (v >= 0)
22295 result->value.data.x_array.data.s_none.elements[i] =
22296 a->value.data.x_array.data.s_none.elements[v];
22297 else if (v < 0)
22298 result->value.data.x_array.data.s_none.elements[i] =
22299 b->value.data.x_array.data.s_none.elements[~v];
22300 else
22301 zig_unreachable();
22302 result->value.data.x_array.data.s_none.elements[i].special =
22303 ConstValSpecialStatic;
22304 }
22305 result->value.special = ConstValSpecialStatic;
22306 return result;
22307 }
22308
22309 // All static analysis passed, and not comptime
22310 IrInstruction *result = ir_build_shuffle_vector(&ira->new_irb,
22311 source_instr->scope, source_instr->source_node,
22312 nullptr, a, b, mask);
22313 result->value.type = result_type;
22314 result->value.special = ConstValSpecialRuntime;
22315 return result;
22316}
22317
22318static IrInstruction *ir_analyze_instruction_shuffle_vector(IrAnalyze *ira, IrInstructionShuffleVector *instruction) {
22319 ZigType *scalar_type = ir_resolve_type(ira, instruction->scalar_type);
22320 assert(scalar_type);
22321 if (type_is_invalid(scalar_type))
22322 return ira->codegen->invalid_instruction;
22323
22324 if (scalar_type->id != ZigTypeIdBool &&
22325 scalar_type->id != ZigTypeIdInt &&
22326 scalar_type->id != ZigTypeIdFloat &&
22327 scalar_type->id != ZigTypeIdPointer) {
22328 ir_add_error(ira, instruction->scalar_type,
22329 buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid",
22330 buf_ptr(&scalar_type->name)));
22331 return ira->codegen->invalid_instruction;
22332 }
22333
22334 return ir_analyze_shuffle_vector(ira, &instruction->base, scalar_type, instruction->a->child, instruction->b->child, instruction->mask->child);
22335}
22336
22066static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {22337static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {
22067 IrInstruction *value = instruction->value->child;22338 IrInstruction *value = instruction->value->child;
22068 if (type_is_invalid(value->value.type))22339 if (type_is_invalid(value->value.type))
...@@ -25607,6 +25878,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25607,6 +25878,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25607 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);25878 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
25608 case IrInstructionIdVectorType:25879 case IrInstructionIdVectorType:
25609 return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction);25880 return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction);
25881 case IrInstructionIdShuffleVector:
25882 return ir_analyze_instruction_shuffle_vector(ira, (IrInstructionShuffleVector *)instruction);
25610 case IrInstructionIdBoolNot:25883 case IrInstructionIdBoolNot:
25611 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);25884 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
25612 case IrInstructionIdMemset:25885 case IrInstructionIdMemset:
...@@ -25942,6 +26215,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25942,6 +26215,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25942 case IrInstructionIdTruncate:26215 case IrInstructionIdTruncate:
25943 case IrInstructionIdIntType:26216 case IrInstructionIdIntType:
25944 case IrInstructionIdVectorType:26217 case IrInstructionIdVectorType:
26218 case IrInstructionIdShuffleVector:
25945 case IrInstructionIdBoolNot:26219 case IrInstructionIdBoolNot:
25946 case IrInstructionIdSliceSrc:26220 case IrInstructionIdSliceSrc:
25947 case IrInstructionIdMemberCount:26221 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;
test/compile_errors.zig+13
...@@ -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 "using LLVM syntax for @shuffle",
6489 \\export fn entry() void {
6490 \\ const v: @Vector(4, u32) = [4]u32{0, 1, 2, 3};
6491 \\ const x: @Vector(4, u32) = [4]u32{4, 5, 6, 7};
6492 \\ var z = @shuffle(u32, v, x, [8]i32{0, 1, 2, 3, 4, 5, 6, 7});
6493 \\}
6494 ,
6495 "tmp.zig:4:39: error: mask index out of bounds",
6496 "tmp.zig:4:39: note: when computing vector element at index 4",
6497 "tmp.zig:4:39: 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 {
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 // FIXME re-enable when LLVM codegen is fixed
45 // https://bugs.llvm.org/show_bug.cgi?id=42803
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}