Fix array->vector and vector->array for many types. Allow vector of bool.

Vectors do not have the same packing as arrays, and just bitcasting
is not the correct way to convert them.
This commit is contained in:
Shawn Landden 2019-07-25 11:11:37 -05:00 committed by Andrew Kelley
parent 914ad1ec2e
commit 0e3ca4c63e
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
5 changed files with 63 additions and 13 deletions

View File

@ -4708,6 +4708,7 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
bool is_valid_vector_elem_type(ZigType *elem_type) {
return elem_type->id == ZigTypeIdInt ||
elem_type->id == ZigTypeIdFloat ||
elem_type->id == ZigTypeIdBool ||
get_codegen_ptr_type(elem_type) != nullptr;
}
@ -4727,7 +4728,7 @@ ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) {
ZigType *entry = new_type_table_entry(ZigTypeIdVector);
if ((len != 0) && type_has_bits(elem_type)) {
// Vectors can only be ints, floats, or pointers. ints and floats have trivially resolvable
// Vectors can only be ints, floats, bools, or pointers. ints (inc. bools) and floats have trivially resolvable
// llvm type refs. pointers we will use usize instead.
LLVMTypeRef example_vector_llvm_type;
if (elem_type->id == ZigTypeIdPointer) {

View File

@ -5549,10 +5549,14 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab
assert(handle_is_ptr(array_type));
LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
LLVMValueRef vector = ir_llvm_value(g, instruction->vector);
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc,
LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), "");
uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type);
gen_store_untyped(g, vector, casted_ptr, alignment, false);
LLVMValueRef array = LLVMGetUndef(get_llvm_type(g, array_type));
for (uintptr_t i = 0; i < instruction->vector->value.type->data.vector.len; i++) {
LLVMValueRef index = LLVMConstInt(g->builtin_types.entry_u32->llvm_type, i, false);
LLVMValueRef elem = LLVMBuildExtractElement(g->builder, vector,
index, "vector_to_array");
array = LLVMBuildInsertValue(g->builder, array, elem, i, "");
}
LLVMBuildStore(g->builder, array, result_loc);
return result_loc;
}
@ -5563,12 +5567,16 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
assert(vector_type->id == ZigTypeIdVector);
assert(!handle_is_ptr(vector_type));
LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,
LLVMPointerType(get_llvm_type(g, vector_type), 0), "");
ZigType *array_type = instruction->array->value.type;
assert(array_type->id == ZigTypeIdArray);
uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type);
return gen_load_untyped(g, casted_ptr, alignment, false, "");
LLVMValueRef array = LLVMBuildLoad2(g->builder, get_llvm_type(g, instruction->array->value.type),
array_ptr, "");
LLVMValueRef vector = LLVMGetUndef(get_llvm_type(g, vector_type));
for (uintptr_t i = 0; i < instruction->base.value.type->data.vector.len; i++) {
LLVMValueRef index = LLVMConstInt(g->builtin_types.entry_u32->llvm_type, i, false);
LLVMValueRef elem = LLVMBuildExtractValue(g->builder, array,
i, "vector_to_array");
vector = LLVMBuildInsertElement(g->builder, vector, elem, index, "");
}
return vector;
}
static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,

View File

@ -22024,7 +22024,7 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr
if (!is_valid_vector_elem_type(elem_type)) {
ir_add_error(ira, instruction->elem_type,
buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid",
buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid",
buf_ptr(&elem_type->name)));
return ira->codegen->invalid_instruction;
}

View File

@ -6491,7 +6491,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var v: V = undefined;
\\}
,
"tmp.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid",
"tmp.zig:2:26: error: vector element type must be integer, float, bool, or pointer; '@Vector(4, u8)' is invalid",
);
cases.add("compileLog of tagged enum doesn't crash the compiler",

View File

@ -2,6 +2,18 @@ const std = @import("std");
const mem = std.mem;
const expect = std.testing.expect;
test "implicit cast vector to array - bool" {
const S = struct {
fn doTheTest() void {
const a: @Vector(4, bool) = [_]bool{ true, false, true, false };
const result_array: [4]bool = a;
expect(mem.eql(bool, result_array, [4]bool{ true, false, true, false }));
}
};
S.doTheTest();
comptime S.doTheTest();
}
test "vector wrap operators" {
const S = struct {
fn doTheTest() void {
@ -80,3 +92,32 @@ test "array to vector" {
var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
var vec: @Vector(4, f32) = arr;
}
test "vector casts of sizes not divisable by 8" {
const S = struct {
fn doTheTest() void {
{
var v: @Vector(4, u3) = [4]u3{ 5, 2, 3, 0};
var x: [4]u3 = v;
expect(mem.eql(u3, x, ([4]u3)(v)));
}
{
var v: @Vector(4, u2) = [4]u2{ 1, 2, 3, 0};
var x: [4]u2 = v;
expect(mem.eql(u2, x, ([4]u2)(v)));
}
{
var v: @Vector(4, u1) = [4]u1{ 1, 0, 1, 0};
var x: [4]u1 = v;
expect(mem.eql(u1, x, ([4]u1)(v)));
}
{
var v: @Vector(4, bool) = [4]bool{ false, false, true, false};
var x: [4]bool = v;
expect(mem.eql(bool, x, ([4]bool)(v)));
}
}
};
S.doTheTest();
comptime S.doTheTest();
}