| ... | ... | @@ -717,6 +717,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionVectorType *) { |
| 717 | 717 | return IrInstructionIdVectorType; |
| 718 | 718 | } |
| 719 | 719 | |
| 720 | static constexpr IrInstructionId ir_instruction_id(IrInstructionShuffleVector *) { |
| 721 | return IrInstructionIdShuffleVector; |
| 722 | } |
| 723 | |
| 720 | 724 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { |
| 721 | 725 | return IrInstructionIdBoolNot; |
| 722 | 726 | } |
| ... | ... | @@ -2277,6 +2281,25 @@ static IrInstruction *ir_build_vector_type(IrBuilder *irb, Scope *scope, AstNode |
| 2277 | 2281 | return &instruction->base; |
| 2278 | 2282 | } |
| 2279 | 2283 | |
| 2284 | static 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 | |
| 2280 | 2303 | static IrInstruction *ir_build_bool_not(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { |
| 2281 | 2304 | IrInstructionBoolNot *instruction = ir_build_instruction<IrInstructionBoolNot>(irb, scope, source_node); |
| 2282 | 2305 | instruction->value = value; |
| ... | ... | @@ -4936,6 +4959,32 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4936 | 4959 | IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); |
| 4937 | 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 | 4988 | case BuiltinFnIdMemcpy: |
| 4940 | 4989 | { |
| 4941 | 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 | 22112 | return ir_const_type(ira, &instruction->base, vector_type); |
| 22064 | 22113 | } |
| 22065 | 22114 | |
| 22115 | static 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 | |
| 22318 | static 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 | |
| 22066 | 22337 | static IrInstruction *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstructionBoolNot *instruction) { |
| 22067 | 22338 | IrInstruction *value = instruction->value->child; |
| 22068 | 22339 | if (type_is_invalid(value->value.type)) |
| ... | ... | @@ -25607,6 +25878,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25607 | 25878 | return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); |
| 25608 | 25879 | case IrInstructionIdVectorType: |
| 25609 | 25880 | return ir_analyze_instruction_vector_type(ira, (IrInstructionVectorType *)instruction); |
| 25881 | case IrInstructionIdShuffleVector: |
| 25882 | return ir_analyze_instruction_shuffle_vector(ira, (IrInstructionShuffleVector *)instruction); |
| 25610 | 25883 | case IrInstructionIdBoolNot: |
| 25611 | 25884 | return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); |
| 25612 | 25885 | case IrInstructionIdMemset: |
| ... | ... | @@ -25942,6 +26215,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25942 | 26215 | case IrInstructionIdTruncate: |
| 25943 | 26216 | case IrInstructionIdIntType: |
| 25944 | 26217 | case IrInstructionIdVectorType: |
| 26218 | case IrInstructionIdShuffleVector: |
| 25945 | 26219 | case IrInstructionIdBoolNot: |
| 25946 | 26220 | case IrInstructionIdSliceSrc: |
| 25947 | 26221 | case IrInstructionIdMemberCount: |