| author | |
| committer | |
| log | 0e3ca4c63ecb8e43af8261020d21bc6888d18fc0 |
| tree | 7df095fa7a25c68d3648a3d87eaa937ce3ead5a4 |
| parent | 914ad1ec2eff4ea9061804ad0da9cde7dd6543b6 |
| signature |
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) { |
| 4708 | 4708 | bool is_valid_vector_elem_type(ZigType *elem_type) { |
| 4709 | 4709 | return elem_type->id == ZigTypeIdInt || |
| 4710 | 4710 | elem_type->id == ZigTypeIdFloat || |
| 4711 | elem_type->id == ZigTypeIdBool || | |
| 4711 | 4712 | get_codegen_ptr_type(elem_type) != nullptr; |
| 4712 | 4713 | } |
| 4713 | 4714 | |
| ... | ... | @@ -4727,7 +4728,7 @@ ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { |
| 4727 | 4728 | |
| 4728 | 4729 | ZigType *entry = new_type_table_entry(ZigTypeIdVector); |
| 4729 | 4730 | 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 | |
| 4731 | 4732 | // llvm type refs. pointers we will use usize instead. |
| 4732 | 4733 | LLVMTypeRef example_vector_llvm_type; |
| 4733 | 4734 | 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 |
| 5549 | 5549 | assert(handle_is_ptr(array_type)); |
| 5550 | 5550 | LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); |
| 5551 | 5551 | 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); | |
| 5556 | 5560 | return result_loc; |
| 5557 | 5561 | } |
| 5558 | 5562 | |
| ... | ... | @@ -5563,12 +5567,16 @@ static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executab |
| 5563 | 5567 | assert(vector_type->id == ZigTypeIdVector); |
| 5564 | 5568 | assert(!handle_is_ptr(vector_type)); |
| 5565 | 5569 | 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; | |
| 5572 | 5580 | } |
| 5573 | 5581 | |
| 5574 | 5582 | static 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 |
| 22024 | 22024 | |
| 22025 | 22025 | if (!is_valid_vector_elem_type(elem_type)) { |
| 22026 | 22026 | 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", | |
| 22028 | 22028 | buf_ptr(&elem_type->name))); |
| 22029 | 22029 | return ira->codegen->invalid_instruction; |
| 22030 | 22030 | } |
test/compile_errors.zig+1-1| ... | ... | @@ -6491,7 +6491,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 6491 | 6491 | \\ var v: V = undefined; |
| 6492 | 6492 | \\} |
| 6493 | 6493 | , |
| 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", | |
| 6495 | 6495 | ); |
| 6496 | 6496 | |
| 6497 | 6497 | 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"); |
| 2 | 2 | const mem = std.mem; |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | test "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 | ||
| 5 | 17 | test "vector wrap operators" { |
| 6 | 18 | const S = struct { |
| 7 | 19 | fn doTheTest() void { |
| ... | ... | @@ -80,3 +92,32 @@ test "array to vector" { |
| 80 | 92 | var arr = [4]f32{ foo, 1.5, 0.0, 0.0 }; |
| 81 | 93 | var vec: @Vector(4, f32) = arr; |
| 82 | 94 | } |
| 95 | ||
| 96 | test "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 | } |