Commit 0e3ca4c63e

Shawn Landden <shawn@git.icu>
2019-07-25 18:11:37
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.
1 parent 914ad1e
Changed files (5)
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) {
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,
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;
     }
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();
+}
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",