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
signature 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 {
82268226 {#link|pointer|Pointers#}.
82278227 </p>
82288228 {#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#}
82298251 {#header_close#}
82308252
82318253 {#header_open|Build Mode#}
src/all_types.hpp+11
......@@ -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/codegen.cpp+32
......@@ -4581,6 +4581,35 @@ 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_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
45844613static LLVMValueRef ir_render_pop_count(CodeGen *g, IrExecutable *executable, IrInstructionPopCount *instruction) {
45854614 ZigType *int_type = instruction->op->value.type;
45864615 LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdPopCount);
......@@ -6095,6 +6124,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
60956124 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);
60966125 case IrInstructionIdSpillEnd:
60976126 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);
6127 case IrInstructionIdShuffleVector:
6128 return ir_render_shuffle_vector(g, executable, (IrInstructionShuffleVector *) instruction);
60986129 }
60996130 zig_unreachable();
61006131}
......@@ -7785,6 +7816,7 @@ static void define_builtin_fns(CodeGen *g) {
77857816 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
77867817 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
77877818 create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2);
7819 create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4);
77887820 create_builtin_fn(g, BuiltinFnIdSetCold, "setCold", 1);
77897821 create_builtin_fn(g, BuiltinFnIdSetRuntimeSafety, "setRuntimeSafety", 1);
77907822 create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 1);
src/ir.cpp+274
......@@ -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);
......@@ -22063,6 +22112,228 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr
2206322112 return ir_const_type(ira, &instruction->base, vector_type);
2206422113}
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
2206622337static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) {
2206722338 IrInstruction *value = instruction->value->child;
2206822339 if (type_is_invalid(value->value.type))
......@@ -25607,6 +25878,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2560725878 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
2560825879 case IrInstructionIdVectorType:
2560925880 return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction);
25881 case IrInstructionIdShuffleVector:
25882 return ir_analyze_instruction_shuffle_vector(ira, (IrInstructionShuffleVector *)instruction);
2561025883 case IrInstructionIdBoolNot:
2561125884 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
2561225885 case IrInstructionIdMemset:
......@@ -25942,6 +26215,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2594226215 case IrInstructionIdTruncate:
2594326216 case IrInstructionIdIntType:
2594426217 case IrInstructionIdVectorType:
26218 case IrInstructionIdShuffleVector:
2594526219 case IrInstructionIdBoolNot:
2594626220 case IrInstructionIdSliceSrc:
2594726221 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;
test/compile_errors.zig+13
......@@ -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 "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
64876500 cases.addTest(
64886501 "nested vectors",
64896502 \\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}