From 0e3ca4c63ecb8e43af8261020d21bc6888d18fc0 Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Thu, 25 Jul 2019 11:11:37 -0500 Subject: [PATCH] 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. --- src/analyze.cpp | 3 ++- src/codegen.cpp | 28 ++++++++++++++-------- src/ir.cpp | 2 +- test/compile_errors.zig | 2 +- test/stage1/behavior/vector.zig | 41 +++++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index d5d8745018..ac70d5646f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 4799c0a28f..1b86f95433 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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, diff --git a/src/ir.cpp b/src/ir.cpp index ea9039a1b6..56866340c4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -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; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 6365ca64cb..9d96d6f948 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -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", diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig index 431e3fe272..94d3aa1a45 100644 --- a/test/stage1/behavior/vector.zig +++ b/test/stage1/behavior/vector.zig @@ -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(); +}