authorgravatar for shawn@git.icuShawn Landden <shawn@git.icu> 2019-07-25 11:11:37-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-18 09:52:58-04:00
log0e3ca4c63ecb8e43af8261020d21bc6888d18fc0
tree7df095fa7a25c68d3648a3d87eaa937ce3ead5a4
parent914ad1ec2eff4ea9061804ad0da9cde7dd6543b6
signaturelock-open Commit is signed but in an unrecognized format.

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.

5 files changed, 63 insertions(+), 13 deletions(-)

src/analyze.cpp+2-1
......@@ -4708,6 +4708,7 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
47084708bool is_valid_vector_elem_type(ZigType *elem_type) {
47094709 return elem_type->id == ZigTypeIdInt ||
47104710 elem_type->id == ZigTypeIdFloat ||
4711 elem_type->id == ZigTypeIdBool ||
47114712 get_codegen_ptr_type(elem_type) != nullptr;
47124713}
47134714
......@@ -4727,7 +4728,7 @@ ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) {
47274728
47284729 ZigType *entry = new_type_table_entry(ZigTypeIdVector);
47294730 if ((len != 0) && type_has_bits(elem_type)) {
4730 // Vectors can only be ints, floats, or pointers. ints and floats have trivially resolvable
4731 // Vectors can only be ints, floats, bools, or pointers. ints (inc. bools) and floats have trivially resolvable
47314732 // llvm type refs. pointers we will use usize instead.
47324733 LLVMTypeRef example_vector_llvm_type;
47334734 if (elem_type->id == ZigTypeIdPointer) {
src/codegen.cpp+18-10
......@@ -5549,10 +5549,14 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab
55495549 assert(handle_is_ptr(array_type));
55505550 LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc);
55515551 LLVMValueRef vector = ir_llvm_value(g, instruction->vector);
5552 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc,
5553 LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), "");
5554 uint32_t alignment = get_ptr_align(g, instruction->result_loc->value.type);
5555 gen_store_untyped(g, vector, casted_ptr, alignment, false);
5552 LLVMValueRef array = LLVMGetUndef(get_llvm_type(g, array_type));
5553 for (uintptr_t i = 0; i < instruction->vector->value.type->data.vector.len; i++) {
5554 LLVMValueRef index = LLVMConstInt(g->builtin_types.entry_u32->llvm_type, i, false);
5555 LLVMValueRef elem = LLVMBuildExtractElement(g->builder, vector,
5556 index, "vector_to_array");
5557 array = LLVMBuildInsertValue(g->builder, array, elem, i, "");
5558 }
5559 LLVMBuildStore(g->builder, array, result_loc);
55565560 return result_loc;
55575561}
55585562
......@@ -5563,12 +5567,16 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab
55635567 assert(vector_type->id == ZigTypeIdVector);
55645568 assert(!handle_is_ptr(vector_type));
55655569 LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
5566 LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, array_ptr,
5567 LLVMPointerType(get_llvm_type(g, vector_type), 0), "");
5568 ZigType *array_type = instruction->array->value.type;
5569 assert(array_type->id == ZigTypeIdArray);
5570 uint32_t alignment = get_abi_alignment(g, array_type->data.array.child_type);
5571 return gen_load_untyped(g, casted_ptr, alignment, false, "");
5570 LLVMValueRef array = LLVMBuildLoad2(g->builder, get_llvm_type(g, instruction->array->value.type),
5571 array_ptr, "");
5572 LLVMValueRef vector = LLVMGetUndef(get_llvm_type(g, vector_type));
5573 for (uintptr_t i = 0; i < instruction->base.value.type->data.vector.len; i++) {
5574 LLVMValueRef index = LLVMConstInt(g->builtin_types.entry_u32->llvm_type, i, false);
5575 LLVMValueRef elem = LLVMBuildExtractValue(g->builder, array,
5576 i, "vector_to_array");
5577 vector = LLVMBuildInsertElement(g->builder, vector, elem, index, "");
5578 }
5579 return vector;
55725580}
55735581
55745582static LLVMValueRef ir_render_assert_zero(CodeGen *g, IrExecutable *executable,
src/ir.cpp+1-1
......@@ -22024,7 +22024,7 @@ static IrInstruction *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstr
2202422024
2202522025 if (!is_valid_vector_elem_type(elem_type)) {
2202622026 ir_add_error(ira, instruction->elem_type,
22027 buf_sprintf("vector element type must be integer, float, or pointer; '%s' is invalid",
22027 buf_sprintf("vector element type must be integer, float, bool, or pointer; '%s' is invalid",
2202822028 buf_ptr(&elem_type->name)));
2202922029 return ira->codegen->invalid_instruction;
2203022030 }
test/compile_errors.zig+1-1
......@@ -6491,7 +6491,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
64916491 \\ var v: V = undefined;
64926492 \\}
64936493 ,
6494 "tmp.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid",
6494 "tmp.zig:2:26: error: vector element type must be integer, float, bool, or pointer; '@Vector(4, u8)' is invalid",
64956495 );
64966496
64976497 cases.add("compileLog of tagged enum doesn't crash the compiler",
test/stage1/behavior/vector.zig+41
......@@ -2,6 +2,18 @@ const std = @import("std");
22const mem = std.mem;
33const expect = std.testing.expect;
44
5test "implicit cast vector to array - bool" {
6 const S = struct {
7 fn doTheTest() void {
8 const a: @Vector(4, bool) = [_]bool{ true, false, true, false };
9 const result_array: [4]bool = a;
10 expect(mem.eql(bool, result_array, [4]bool{ true, false, true, false }));
11 }
12 };
13 S.doTheTest();
14 comptime S.doTheTest();
15}
16
517test "vector wrap operators" {
618 const S = struct {
719 fn doTheTest() void {
......@@ -80,3 +92,32 @@ test "array to vector" {
8092 var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
8193 var vec: @Vector(4, f32) = arr;
8294}
95
96test "vector casts of sizes not divisable by 8" {
97 const S = struct {
98 fn doTheTest() void {
99 {
100 var v: @Vector(4, u3) = [4]u3{ 5, 2, 3, 0};
101 var x: [4]u3 = v;
102 expect(mem.eql(u3, x, ([4]u3)(v)));
103 }
104 {
105 var v: @Vector(4, u2) = [4]u2{ 1, 2, 3, 0};
106 var x: [4]u2 = v;
107 expect(mem.eql(u2, x, ([4]u2)(v)));
108 }
109 {
110 var v: @Vector(4, u1) = [4]u1{ 1, 0, 1, 0};
111 var x: [4]u1 = v;
112 expect(mem.eql(u1, x, ([4]u1)(v)));
113 }
114 {
115 var v: @Vector(4, bool) = [4]bool{ false, false, true, false};
116 var x: [4]bool = v;
117 expect(mem.eql(bool, x, ([4]bool)(v)));
118 }
119 }
120 };
121 S.doTheTest();
122 comptime S.doTheTest();
123}