diff --git a/doc/langref.html.in b/doc/langref.html.in index 7ae0ee7c1c16..04763f64e40f 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -7857,7 +7857,7 @@ fn List(comptime T: type) type { {#header_open|@truncate#}
{#syntax#}@truncate(comptime T: type, integer: var) T{#endsyntax#}

- This function truncates bits from an integer type, resulting in a smaller + This function truncates bits from an integer type (or the integers of a vector), resulting in a smaller or same-sized integer type.

diff --git a/src/codegen.cpp b/src/codegen.cpp index 706e0a64d24e..592594ff36dc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1389,11 +1389,22 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMPositionBuilderAtEnd(g->builder, ok_block); } -static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *int_type) { - LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, int_type)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); +static LLVMValueRef gen_assert_zero(CodeGen *g, LLVMValueRef expr_val, ZigType *type) { + assert(type->id == ZigTypeIdInt || type->id == ZigTypeIdVector); + bool is_vector = type->id == ZigTypeIdVector; + LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, type)); + LLVMValueRef ok_bits = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, zero, ""); + LLVMValueRef ok_bit = ok_bits; LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); + if (is_vector) { + ok_bit = LLVMConstInt(g->builtin_types.entry_bool->llvm_type, 1, false); + for (size_t i = 0;i < type->data.vector.len;i++) { + LLVMValueRef i_val = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, i, false); + LLVMValueRef extract = LLVMBuildExtractElement(g->builder, ok_bits, i_val, ""); + ok_bit = LLVMBuildAnd(g->builder, ok_bit, extract, ""); + } + } LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -1407,29 +1418,45 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z ZigType *wanted_type, LLVMValueRef expr_val) { assert(actual_type->id == wanted_type->id); + bool is_vector = actual_type->id == ZigTypeIdVector; + ZigType *actual_scalar_type = is_vector ? actual_type->data.vector.elem_type : actual_type; + ZigType *wanted_scalar_type = is_vector ? wanted_type->data.vector.elem_type : wanted_type; + assert(actual_scalar_type->id == wanted_scalar_type->id); assert(expr_val != nullptr); + if (is_vector) { + assert(actual_type->data.vector.len == wanted_type->data.vector.len); + } uint64_t actual_bits; uint64_t wanted_bits; - if (actual_type->id == ZigTypeIdFloat) { - actual_bits = actual_type->data.floating.bit_count; - wanted_bits = wanted_type->data.floating.bit_count; - } else if (actual_type->id == ZigTypeIdInt) { - actual_bits = actual_type->data.integral.bit_count; - wanted_bits = wanted_type->data.integral.bit_count; + if (actual_scalar_type->id == ZigTypeIdFloat) { + actual_bits = actual_scalar_type->data.floating.bit_count; + wanted_bits = wanted_scalar_type->data.floating.bit_count; + } else if (actual_scalar_type->id == ZigTypeIdInt) { + actual_bits = actual_scalar_type->data.integral.bit_count; + wanted_bits = wanted_scalar_type->data.integral.bit_count; } else { zig_unreachable(); } - if (actual_type->id == ZigTypeIdInt && - !wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed && + if (actual_scalar_type->id == ZigTypeIdInt && + !wanted_scalar_type->data.integral.is_signed && actual_scalar_type->data.integral.is_signed && want_runtime_safety) { LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, actual_type)); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, ""); + LLVMValueRef ok_bits = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, ""); + LLVMValueRef ok_bit = ok_bits; LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastFail"); + if (is_vector) { + ok_bit = LLVMConstInt(g->builtin_types.entry_bool->llvm_type, 1, false); + for (size_t i = 0;i < wanted_type->data.vector.len;i++) { + LLVMValueRef i_val = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, i, false); + LLVMValueRef extract = LLVMBuildExtractElement(g->builder, ok_bits, i_val, ""); + ok_bit = LLVMBuildAnd(g->builder, ok_bit, extract, ""); + } + } LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); @@ -1441,9 +1468,9 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z if (actual_bits == wanted_bits) { return expr_val; } else if (actual_bits < wanted_bits) { - if (actual_type->id == ZigTypeIdFloat) { + if (actual_scalar_type->id == ZigTypeIdFloat) { return LLVMBuildFPExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else if (actual_type->id == ZigTypeIdInt) { + } else if (actual_scalar_type->id == ZigTypeIdInt) { if (actual_type->data.integral.is_signed) { return LLVMBuildSExt(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); } else { @@ -1453,9 +1480,9 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z zig_unreachable(); } } else if (actual_bits > wanted_bits) { - if (actual_type->id == ZigTypeIdFloat) { + if (actual_scalar_type->id == ZigTypeIdFloat) { return LLVMBuildFPTrunc(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - } else if (actual_type->id == ZigTypeIdInt) { + } else if (actual_scalar_type->id == ZigTypeIdInt) { if (wanted_bits == 0) { if (!want_runtime_safety) return nullptr; @@ -1467,14 +1494,23 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z return trunc_val; } LLVMValueRef orig_val; - if (wanted_type->data.integral.is_signed) { + if (wanted_scalar_type->data.integral.is_signed) { orig_val = LLVMBuildSExt(g->builder, trunc_val, get_llvm_type(g, actual_type), ""); } else { orig_val = LLVMBuildZExt(g->builder, trunc_val, get_llvm_type(g, actual_type), ""); } - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, ""); + LLVMValueRef ok_bits = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, ""); + LLVMValueRef ok_bit = ok_bits; LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk"); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail"); + if (is_vector) { + ok_bit = LLVMConstInt(g->builtin_types.entry_bool->llvm_type, 1, false); + for (size_t i = 0;i < wanted_type->data.vector.len;i++) { + LLVMValueRef i_val = LLVMConstInt(g->builtin_types.entry_i32->llvm_type, i, false); + LLVMValueRef extract = LLVMBuildExtractElement(g->builder, ok_bits, i_val, ""); + ok_bit = LLVMBuildAnd(g->builder, ok_bit, extract, ""); + } + } LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); diff --git a/src/ir.cpp b/src/ir.cpp index 3024e3240aa8..379969ca2622 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11693,34 +11693,90 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *wanted_type) { - assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdFloat); + bool is_vector = wanted_type->id == ZigTypeIdVector; + ZigType *wanted_scalar_type = is_vector ? wanted_type->data.vector.elem_type : wanted_type; + assert(wanted_scalar_type->id == ZigTypeIdInt || wanted_scalar_type->id == ZigTypeIdFloat); + assert((target->value.type->id == ZigTypeIdVector) == is_vector); + if (is_vector) { + assert(target->value.type->data.vector.len == wanted_type->data.vector.len); + } if (instr_is_comptime(target)) { - ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); + ConstExprValue *val = ir_resolve_const(ira, target, UndefOk); if (!val) return ira->codegen->invalid_instruction; - if (wanted_type->id == ZigTypeIdInt) { - if (bigint_cmp_zero(&val->data.x_bigint) == CmpLT && !wanted_type->data.integral.is_signed) { - ir_add_error(ira, source_instr, - buf_sprintf("attempt to cast negative value to unsigned integer")); - return ira->codegen->invalid_instruction; - } - if (!bigint_fits_in_bits(&val->data.x_bigint, wanted_type->data.integral.bit_count, - wanted_type->data.integral.is_signed)) - { - ir_add_error(ira, source_instr, - buf_sprintf("cast from '%s' to '%s' truncates bits", - buf_ptr(&target->value.type->name), buf_ptr(&wanted_type->name))); - return ira->codegen->invalid_instruction; - } - } IrInstruction *result = ir_const(ira, source_instr, wanted_type); - result->value.type = wanted_type; - if (wanted_type->id == ZigTypeIdInt) { - bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint); + if (wanted_scalar_type->id == ZigTypeIdInt || wanted_scalar_type->id == ZigTypeIdFloat) { + uint32_t i = 0; + uint32_t vector_len = 1; + ConstExprValue *sval = val; + if (is_vector) { + vector_len = val->type->data.vector.len; + expand_undef_array(ira->codegen, &result->value); + result->value.data.x_array.data.s_none.elements = + allocate(vector_len); + sval = &val->data.x_array.data.s_none.elements[0]; + } + while (i < vector_len) { + if (sval->special == ConstValSpecialUndef) { + if (is_vector) { + result->value.data.x_array.data.s_none.elements[i].special = ConstValSpecialUndef; + sval = &val->data.x_array.data.s_none.elements[++i]; + } else { + result->value.special = ConstValSpecialUndef; + } + continue; + } + if (wanted_scalar_type->id == ZigTypeIdInt) { + if (bigint_cmp_zero(&sval->data.x_bigint) == CmpLT && !wanted_scalar_type->data.integral.is_signed) { + ErrorMsg *msg = ir_add_error(ira, source_instr, + buf_sprintf("attempt to cast negative value to unsigned integer")); + if (is_vector) { + add_error_note(ira->codegen, msg, source_instr->source_node, + buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, (uintptr_t)i)); + } + return ira->codegen->invalid_instruction; + } + if (!bigint_fits_in_bits(&sval->data.x_bigint, wanted_scalar_type->data.integral.bit_count, + wanted_scalar_type->data.integral.is_signed)) + { + ErrorMsg *msg = ir_add_error(ira, source_instr, + buf_sprintf("cast from '%s' to '%s' truncates bits", + buf_ptr(&target->value.type->name), buf_ptr(&wanted_type->name))); + if (is_vector) { + add_error_note(ira->codegen, msg, source_instr->source_node, + buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, (uintptr_t)i)); + } + return ira->codegen->invalid_instruction; + } + } + if (is_vector) { + // float_init_float requires this to be set + result->value.data.x_array.data.s_none.elements[i].type = wanted_scalar_type; + if (wanted_scalar_type->id == ZigTypeIdInt) { + bigint_init_bigint(&result->value.data.x_array.data.s_none.elements[i].data.x_bigint, + &sval->data.x_bigint); + } else if (wanted_scalar_type->id == ZigTypeIdFloat) { + float_init_float(&result->value.data.x_array.data.s_none.elements[i], sval); + } else { + zig_unreachable(); + } + result->value.data.x_array.data.s_none.elements[i].special = ConstValSpecialStatic; + sval = &val->data.x_array.data.s_none.elements[++i]; + } else if (wanted_type->id == ZigTypeIdInt) { + bigint_init_bigint(&result->value.data.x_bigint, &sval->data.x_bigint); + break; + } else if (wanted_type->id == ZigTypeIdFloat) { + float_init_float(&result->value, sval); + break; + } else { + zig_unreachable(); + } + } } else { - float_init_float(&result->value, val); + zig_unreachable(); } + result->value.type = wanted_type; return result; } @@ -11728,10 +11784,23 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction // zero. However, we still want to emit a runtime safety check to make sure // the target is zero. if (!type_has_bits(wanted_type)) { - assert(wanted_type->id == ZigTypeIdInt); + assert(wanted_scalar_type->id == ZigTypeIdInt); assert(type_has_bits(target->value.type)); ir_build_assert_zero(ira, source_instr, target); - IrInstruction *result = ir_const_unsigned(ira, source_instr, 0); + IrInstruction *result; + if (is_vector) { + result = ir_const_type(ira, source_instr, wanted_type); + result->value.data.x_array.data.s_none.elements = + allocate(wanted_type->data.vector.len); + for (uint32_t i = 0; i < wanted_type->data.vector.len; i++) { + ConstExprValue *cur = &result->value.data.x_array.data.s_none.elements[i]; + bigint_init_unsigned(&cur->data.x_bigint, 0); + cur->special = ConstValSpecialStatic; + cur->type = wanted_scalar_type; + } + } else { + result = ir_const_unsigned(ira, source_instr, 0); + } result->value.type = wanted_type; return result; } @@ -12233,6 +12302,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ira->codegen->invalid_instruction; } + bool actual_is_vector = actual_type->id == ZigTypeIdVector; + bool wanted_is_vector = wanted_type->id == ZigTypeIdVector; + ZigType *actual_scalar_type = actual_is_vector ? actual_type->data.vector.elem_type : actual_type; + ZigType *wanted_scalar_type = wanted_is_vector ? wanted_type->data.vector.elem_type : wanted_type; + // perfect match or non-const to const ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type, source_node, false); @@ -12403,6 +12477,30 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); } + // widening of vectors + // These are separate (while identical) as I am still not sure if this should not implicitely cast, + // but only explicitely cast. (i.e. with @cast, or @as, or @Vector(4, i32)(foo)), + // as they are more expensive than scalar zext/sext/fext operations. + if (wanted_is_vector && + actual_is_vector) { + if (wanted_scalar_type->id == ZigTypeIdInt && + actual_scalar_type->id == ZigTypeIdInt) { + if (wanted_scalar_type->data.integral.is_signed == actual_scalar_type->data.integral.is_signed && + wanted_scalar_type->data.integral.bit_count >= actual_scalar_type->data.integral.bit_count) { + return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); + } + if (wanted_scalar_type->data.integral.is_signed && + !actual_scalar_type->data.integral.is_signed && + wanted_scalar_type->data.integral.bit_count > actual_scalar_type->data.integral.bit_count) { + return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); + } + } + if (wanted_scalar_type->id == ZigTypeIdFloat && + actual_scalar_type->id == ZigTypeIdFloat && + wanted_scalar_type->data.floating.bit_count >= actual_scalar_type->data.floating.bit_count) { + return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); + } + } // cast from [N]T to []const T // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this @@ -21789,8 +21887,12 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdInt && - dest_type->id != ZigTypeIdComptimeInt) + bool dest_is_vector = dest_type->id == ZigTypeIdVector; + ZigType *dest_scalar_type = dest_is_vector ? dest_type->data.vector.elem_type : dest_type; + + if (!(dest_type->id == ZigTypeIdInt || + dest_type->id == ZigTypeIdComptimeInt || + (dest_is_vector && dest_scalar_type->id == ZigTypeIdInt))) { ir_add_error(ira, dest_type_value, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; @@ -21801,13 +21903,27 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct if (type_is_invalid(src_type)) return ira->codegen->invalid_instruction; - if (src_type->id != ZigTypeIdInt && - src_type->id != ZigTypeIdComptimeInt) + bool src_is_vector = src_type->id == ZigTypeIdVector; + ZigType *src_scalar_type = src_is_vector ? src_type->data.vector.elem_type : src_type; + + if (!(src_type->id == ZigTypeIdInt || + src_type->id == ZigTypeIdComptimeInt || + (src_is_vector && src_scalar_type->id == ZigTypeIdInt))) { ir_add_error(ira, target, buf_sprintf("expected integer type, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } + bool is_vector = src_is_vector; + if ((dest_is_vector != src_is_vector) || + (is_vector && + dest_type->data.vector.len != src_type->data.vector.len)) + { + ir_add_error(ira, target, buf_sprintf("incompatible vector conversion from '%s' to '%s'", + buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + if (dest_type->id == ZigTypeIdComptimeInt) { return ir_implicit_cast(ira, target, dest_type); } @@ -21818,22 +21934,49 @@ static IrInstruction *ir_analyze_instruction_truncate(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; IrInstruction *result = ir_const(ira, &instruction->base, dest_type); - bigint_truncate(&result->value.data.x_bigint, &val->data.x_bigint, - dest_type->data.integral.bit_count, dest_type->data.integral.is_signed); + if (is_vector) { + result->value.data.x_array.data.s_none.elements = + allocate(dest_type->data.vector.len); + for (uint32_t i = 0; i < dest_type->data.vector.len; i++) { + ConstExprValue *val = &target->value.data.x_array.data.s_none.elements[i]; + ConstExprValue *result_val = &result->value.data.x_array.data.s_none.elements[i]; + bigint_truncate(&result_val->data.x_bigint, + &val->data.x_bigint, + dest_scalar_type->data.integral.bit_count, + dest_scalar_type->data.integral.is_signed); + result_val->special = ConstValSpecialStatic; + result_val->type = dest_scalar_type; + } + } else { + bigint_truncate(&result->value.data.x_bigint, &val->data.x_bigint, + dest_type->data.integral.bit_count, dest_type->data.integral.is_signed); + } return result; } - if (src_type->data.integral.bit_count == 0 || dest_type->data.integral.bit_count == 0) { + if (src_scalar_type->data.integral.bit_count == 0 || dest_scalar_type->data.integral.bit_count == 0) { IrInstruction *result = ir_const(ira, &instruction->base, dest_type); - bigint_init_unsigned(&result->value.data.x_bigint, 0); + if (is_vector) { + result->value.data.x_array.data.s_none.elements = + allocate(dest_type->data.vector.len); + for (uint32_t i = 0; i < dest_type->data.vector.len; i++) { + ConstExprValue *result_val = &result->value.data.x_array.data.s_none.elements[i]; + bigint_init_unsigned(&result_val->data.x_bigint, 0); + result_val->special = ConstValSpecialStatic; + result_val->type = dest_scalar_type; + } + } else { + bigint_init_unsigned(&result->value.data.x_bigint, 0); + } return result; } - if (src_type->data.integral.is_signed != dest_type->data.integral.is_signed) { + if (src_scalar_type->data.integral.is_signed != dest_scalar_type->data.integral.is_signed) { const char *sign_str = dest_type->data.integral.is_signed ? "signed" : "unsigned"; - ir_add_error(ira, target, buf_sprintf("expected %s integer type, found '%s'", sign_str, buf_ptr(&src_type->name))); + const char *vector_str = is_vector ? "vector" : "integer"; + ir_add_error(ira, target, buf_sprintf("expected %s %s type, found '%s'", sign_str, vector_str, buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; - } else if (src_type->data.integral.bit_count < dest_type->data.integral.bit_count) { + } else if (src_scalar_type->data.integral.bit_count < dest_scalar_type->data.integral.bit_count) { ir_add_error(ira, target, buf_sprintf("type '%s' has fewer bits than destination type '%s'", buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; @@ -21850,7 +21993,10 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - if (dest_type->id != ZigTypeIdInt && dest_type->id != ZigTypeIdComptimeInt) { + bool dest_is_vector = dest_type->id == ZigTypeIdVector; + ZigType *scalar_dest_type = dest_is_vector ? dest_type->data.vector.elem_type : dest_type; + + if (scalar_dest_type->id != ZigTypeIdInt && scalar_dest_type->id != ZigTypeIdComptimeInt) { ir_add_error(ira, instruction->dest_type, buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; } @@ -21859,14 +22005,37 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; - if (target->value.type->id != ZigTypeIdInt && target->value.type->id != ZigTypeIdComptimeInt) { + bool is_vector = target->value.type->id == ZigTypeIdVector; + ZigType *scalar_type = is_vector ? target->value.type->data.vector.elem_type : target->value.type; + + if (dest_is_vector && !is_vector) { + ir_add_error(ira, target, + buf_sprintf("cannot cast from scalar to vector")); + return ira->codegen->invalid_instruction; + } + + if (dest_is_vector && dest_type->data.vector.len != target->value.type->data.vector.len) { + ir_add_error(ira, target, + buf_sprintf("length mis-match; expected %" PRIu32 ", got %" PRIu32, + dest_type->data.vector.len, + target->value.type->data.vector.len)); + return ira->codegen->invalid_instruction; + } + + if (scalar_type->id != ZigTypeIdInt && + target->value.type->id != ZigTypeIdComptimeInt) { ir_add_error(ira, instruction->target, buf_sprintf("expected integer type, found '%s'", buf_ptr(&target->value.type->name))); return ira->codegen->invalid_instruction; } + ZigType *wanted_type = dest_type; + if (is_vector && !dest_is_vector) { + wanted_type = get_vector_type(ira->codegen, target->value.type->data.vector.len, wanted_type); + } + if (instr_is_comptime(target)) { - return ir_implicit_cast(ira, target, dest_type); + return ir_implicit_cast(ira, target, wanted_type); } if (dest_type->id == ZigTypeIdComptimeInt) { @@ -21875,7 +22044,7 @@ static IrInstruction *ir_analyze_instruction_int_cast(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; } - return ir_analyze_widen_or_shorten(ira, &instruction->base, target, dest_type); + return ir_analyze_widen_or_shorten(ira, &instruction->base, target, wanted_type); } static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstructionFloatCast *instruction) { diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 04c7fa606f45..435e216a642e 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -327,6 +327,24 @@ test "@intCast comptime_int" { expect(result == 1234); } +test "@intCast of vector" { + var v: @Vector(8, u8) = [_]u8{0, 1, 2, 3, 4, 5, 6, 7}; + var w = @intCast(u16, v); + comptime var i: usize = 0; + inline while (i < 8) : (i += 1) { + expect(w[i] == i); + } +} + +test "@floatCast of vector" { + var v: @Vector(8, f16) = [_]f16{0, 1, 2, 3, 4, 5, 6, 7}; + var w = @floatCast(f32, v); + comptime var i: usize = 0; + inline while (i < 8) : (i += 1) { + expect(w[i] == i); + } +} + test "@floatCast comptime_int and comptime_float" { { const result = @floatCast(f16, 1234); diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index 4c24cab25493..07225a736e85 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -110,6 +110,56 @@ test "array to vector" { var vec: @Vector(4, f32) = arr; } +test "vector upcast" { + const S = struct { + fn doTheTest() void { + { + const v: @Vector(4, i16) = [4]i16{ 21, -2, 30, 40}; + const x: @Vector(4, i32) = @Vector(4, i32)(v); + expect(x[0] == 21); + expect(x[1] == -2); + expect(x[2] == 30); + expect(x[3] == 40); + } + + { + const v: @Vector(4, u16) = [4]u16{ 21, 2, 30, 40}; + const x: @Vector(4, u32) = @Vector(4, u32)(v); + expect(x[0] == 21); + expect(x[1] == 2); + expect(x[2] == 30); + expect(x[3] == 40); + } + + { + const v: @Vector(4, f16) = [4]f16{ 21, -2, 30, 40}; + const x: @Vector(4, f32) = @Vector(4, f32)(v); + expect(x[0] == 21); + expect(x[1] == -2); + expect(x[2] == 30); + expect(x[3] == 40); + } + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "vector truncate" { + const S = struct { + fn doTheTest() void { + const v: @Vector(4, i32) = [4]i32{ 21, -2, 30, 40}; + const x: @Vector(4, i16) = @truncate(@Vector(4, i16), v); + expect(x[0] == 21); + expect(x[1] == -2); + expect(x[2] == 30); + expect(x[3] == 40); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + test "vector casts of sizes not divisable by 8" { const S = struct { fn doTheTest() void {