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 {