From 8a0a6b7387fcd0017db85de14793abfd6ec7f6e5 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 15 Dec 2022 20:34:26 +0200 Subject: [PATCH] port packed vector elem ptr logic from stage1 Closes #12812 Closes #13925 --- src/Air.zig | 10 +++ src/Liveness.zig | 15 ++++ src/Sema.zig | 64 +++++++++++--- src/arch/aarch64/CodeGen.zig | 1 + src/arch/arm/CodeGen.zig | 1 + src/arch/riscv64/CodeGen.zig | 1 + src/arch/sparc64/CodeGen.zig | 1 + src/arch/wasm/CodeGen.zig | 2 + src/arch/x86_64/CodeGen.zig | 1 + src/codegen/c.zig | 1 + src/codegen/llvm.zig | 85 ++++++++++++++++--- src/print_air.zig | 12 +++ src/type.zig | 30 ++++++- test/behavior/vector.zig | 27 ++++++ ...tor_pointer_with_unknown_runtime_index.zig | 17 ++++ ...tor_pointer_with_unknown_runtime_index.zig | 17 ---- ...tor_pointer_with_unknown_runtime_index.zig | 16 ---- ...tor_pointer_with_unknown_runtime_index.zig | 16 ++++ 18 files changed, 257 insertions(+), 60 deletions(-) create mode 100644 test/cases/compile_errors/load_vector_pointer_with_unknown_runtime_index.zig delete mode 100644 test/cases/compile_errors/stage1/obj/load_vector_pointer_with_unknown_runtime_index.zig delete mode 100644 test/cases/compile_errors/stage1/obj/store_vector_pointer_with_unknown_runtime_index.zig create mode 100644 test/cases/compile_errors/store_vector_pointer_with_unknown_runtime_index.zig diff --git a/src/Air.zig b/src/Air.zig index 3bcbdb8e98ab..707e700f0830 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -737,6 +737,10 @@ pub const Inst = struct { /// Uses the `ty_pl` field. save_err_return_trace_index, + /// Store an element to a vector pointer at an index. + /// Uses the `vector_store_elem` field. + vector_store_elem, + pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag { switch (op) { .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt, @@ -814,6 +818,11 @@ pub const Inst = struct { operand: Ref, operation: std.builtin.ReduceOp, }, + vector_store_elem: struct { + vector_ptr: Ref, + // Index into a different array. + payload: u32, + }, // Make sure we don't accidentally add a field to make this union // bigger than expected. Note that in Debug builds, Zig is allowed @@ -1177,6 +1186,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .set_union_tag, .prefetch, .set_err_return_trace, + .vector_store_elem, => return Type.void, .ptrtoint, diff --git a/src/Liveness.zig b/src/Liveness.zig index 7b2f2fd40dda..d129dc01bfb6 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -212,6 +212,15 @@ pub fn categorizeOperand( return .write; }, + .vector_store_elem => { + const o = air_datas[inst].vector_store_elem; + const extra = air.extraData(Air.Bin, o.payload).data; + if (o.vector_ptr == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write); + if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); + if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 2, .none); + return .write; + }, + .arg, .alloc, .ret_ptr, @@ -824,6 +833,12 @@ fn analyzeInst( return trackOperands(a, new_set, inst, main_tomb, .{ o.lhs, o.rhs, .none }); }, + .vector_store_elem => { + const o = inst_datas[inst].vector_store_elem; + const extra = a.air.extraData(Air.Bin, o.payload).data; + return trackOperands(a, new_set, inst, main_tomb, .{ o.vector_ptr, extra.lhs, extra.rhs }); + }, + .arg, .alloc, .ret_ptr, diff --git a/src/Sema.zig b/src/Sema.zig index 8c7c8b0dd712..e67965271a53 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -25952,6 +25952,30 @@ fn storePtr2( try sema.requireRuntimeBlock(block, src, runtime_src); try sema.queueFullTypeResolution(elem_ty); + + if (ptr_ty.ptrInfo().data.vector_index == .runtime) { + const ptr_inst = Air.refToIndex(ptr).?; + const air_tags = sema.air_instructions.items(.tag); + if (air_tags[ptr_inst] == .ptr_elem_ptr) { + const ty_pl = sema.air_instructions.items(.data)[ptr_inst].ty_pl; + const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data; + _ = try block.addInst(.{ + .tag = .vector_store_elem, + .data = .{ .vector_store_elem = .{ + .vector_ptr = bin_op.lhs, + .payload = try block.sema.addExtra(Air.Bin{ + .lhs = bin_op.rhs, + .rhs = operand, + }), + } }, + }); + return; + } + return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{ + ptr_ty.fmt(sema.mod), + }); + } + if (is_ret) { _ = try block.addBinOp(.store, ptr, operand); } else { @@ -27827,6 +27851,19 @@ fn analyzeLoad( } } + if (ptr_ty.ptrInfo().data.vector_index == .runtime) { + const ptr_inst = Air.refToIndex(ptr).?; + const air_tags = sema.air_instructions.items(.tag); + if (air_tags[ptr_inst] == .ptr_elem_ptr) { + const ty_pl = sema.air_instructions.items(.data)[ptr_inst].ty_pl; + const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data; + return block.addBinOp(.ptr_elem_val, bin_op.lhs, bin_op.rhs); + } + return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{ + ptr_ty.fmt(sema.mod), + }); + } + return block.addTyOp(.load, elem_ty, ptr); } @@ -32697,23 +32734,24 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { const target = sema.mod.getTarget(); const parent_ty = ptr_ty.childType(); + const VI = Type.Payload.Pointer.Data.VectorIndex; + const vector_info: struct { - host_size: u16, - bit_offset: u16, - alignment: u32, + host_size: u16 = 0, + alignment: u32 = 0, + vector_index: VI = .none, } = if (parent_ty.tag() == .vector) blk: { const elem_bits = elem_ty.bitSize(target); - const is_packed = elem_bits != 0 and (elem_bits & (elem_bits - 1)) != 0; - // TODO: runtime-known index - assert(!is_packed or offset != null); - const is_packed_with_offset = is_packed and offset != null and offset.? != 0; - const target_offset = if (is_packed_with_offset) (if (target.cpu.arch.endian() == .Big) (parent_ty.vectorLen() - 1 - offset.?) else offset.?) else 0; + if (elem_bits == 0) break :blk .{}; + const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits); + if (!is_packed) break :blk .{}; + break :blk .{ - .host_size = if (is_packed_with_offset) @intCast(u16, parent_ty.abiSize(target)) else 0, - .bit_offset = if (is_packed_with_offset) @intCast(u16, elem_bits * target_offset) else 0, - .alignment = if (is_packed_with_offset) @intCast(u16, parent_ty.abiAlignment(target)) else 0, + .host_size = @intCast(u16, parent_ty.arrayLen()), + .alignment = @intCast(u16, parent_ty.abiAlignment(target)), + .vector_index = if (offset) |some| @intToEnum(VI, some) else .runtime, }; - } else .{ .host_size = 0, .bit_offset = 0, .alignment = 0 }; + } else .{}; const alignment: u32 = a: { // Calculate the new pointer alignment. @@ -32741,6 +32779,6 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { .@"volatile" = ptr_info.@"volatile", .@"align" = alignment, .host_size = vector_info.host_size, - .bit_offset = vector_info.bit_offset, + .vector_index = vector_info.vector_index, }); } diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index e09664598a74..8c87a005d551 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -873,6 +873,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), + .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), .wasm_memory_size => unreachable, .wasm_memory_grow => unreachable, diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 8197d85b4808..9d6d18d5c9b6 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -783,6 +783,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), + .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), .wasm_memory_size => unreachable, .wasm_memory_grow => unreachable, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 58661926bbec..24e24076f7e8 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -697,6 +697,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), + .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), .wasm_memory_size => unreachable, .wasm_memory_grow => unreachable, diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 6eac6ba4fc4e..1672547f5802 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -714,6 +714,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => @panic("TODO implement is_named_enum_value"), .error_set_has_value => @panic("TODO implement error_set_has_value"), + .vector_store_elem => @panic("TODO implement vector_store_elem"), .wasm_memory_size => unreachable, .wasm_memory_grow => unreachable, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 99c0facb1ad6..70a2aea3c9d1 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1971,6 +1971,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .is_named_enum_value, .error_set_has_value, .addrspace_cast, + .vector_store_elem, => |tag| return func.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), .add_optimized, @@ -2213,6 +2214,7 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ptr_ty = func.air.typeOf(bin_op.lhs); const ptr_info = ptr_ty.ptrInfo().data; const ty = ptr_ty.childType(); + if (ptr_info.host_size == 0) { try func.store(lhs, rhs, ty, 0); } else { diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index bfb60bf74a7b..d0599150bd5b 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -785,6 +785,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}), .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}), + .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}), .wasm_memory_size => unreachable, .wasm_memory_grow => unreachable, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 55b9cd4b770e..97f67d3eec2b 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -2908,6 +2908,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}), .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}), + .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}), // zig fmt: on }; if (result_value == .local) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 7d70a5166664..670efa6d0c83 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1572,6 +1572,7 @@ pub const Object = struct { ptr_info.@"addrspace" != .generic or ptr_info.bit_offset != 0 or ptr_info.host_size != 0 or + ptr_info.vector_index != .none or ptr_info.@"allowzero" or !ptr_info.mutable or ptr_info.@"volatile" or @@ -4660,6 +4661,8 @@ pub const FuncGen = struct { .wasm_memory_size => try self.airWasmMemorySize(inst), .wasm_memory_grow => try self.airWasmMemoryGrow(inst), + .vector_store_elem => try self.airVectorStoreElem(inst), + .constant => unreachable, .const_ty => unreachable, .unreach => self.airUnreach(inst), @@ -5022,7 +5025,7 @@ pub const FuncGen = struct { .data = ret_ty, }; const ptr_ty = Type.initPayload(&ptr_ty_payload.base); - self.store(ret_ptr, ptr_ty, operand, .NotAtomic); + try self.store(ret_ptr, ptr_ty, operand, .NotAtomic); _ = self.builder.buildRetVoid(); return null; } @@ -5779,6 +5782,10 @@ pub const FuncGen = struct { const base_ptr = try self.resolveInst(bin_op.lhs); const rhs = try self.resolveInst(bin_op.rhs); + + const elem_ptr = self.air.getRefType(ty_pl.ty); + if (elem_ptr.ptrInfo().data.vector_index != .none) return base_ptr; + const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); if (ptr_ty.isSinglePointer()) { // If this is a single-item pointer to an array, we need another index in the GEP. @@ -6803,7 +6810,7 @@ pub const FuncGen = struct { .data = payload_ty, }; const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); - self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); + try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, ""); _ = self.builder.buildStore(non_null_bit, non_null_ptr); return optional_ptr; @@ -6839,7 +6846,7 @@ pub const FuncGen = struct { .data = payload_ty, }; const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); - self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); + try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); return result_ptr; } @@ -6908,6 +6915,28 @@ pub const FuncGen = struct { return self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); } + fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { + const data = self.air.instructions.items(.data)[inst].vector_store_elem; + const extra = self.air.extraData(Air.Bin, data.payload).data; + + const vector_ptr = try self.resolveInst(data.vector_ptr); + const vector_ptr_ty = self.air.typeOf(data.vector_ptr); + const index = try self.resolveInst(extra.lhs); + const operand = try self.resolveInst(extra.rhs); + + const loaded_vector = blk: { + const elem_llvm_ty = try self.dg.lowerType(vector_ptr_ty.elemType2()); + const load_inst = self.builder.buildLoad(elem_llvm_ty, vector_ptr, ""); + const target = self.dg.module.getTarget(); + load_inst.setAlignment(vector_ptr_ty.ptrAlignment(target)); + load_inst.setVolatile(llvm.Bool.fromBool(vector_ptr_ty.isVolatilePtr())); + break :blk load_inst; + }; + const modified_vector = self.builder.buildInsertElement(loaded_vector, operand, index, ""); + try self.store(vector_ptr, vector_ptr_ty, modified_vector, .NotAtomic); + return null; + } + fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { if (self.liveness.isUnused(inst)) return null; @@ -8135,7 +8164,7 @@ pub const FuncGen = struct { } } else { const src_operand = try self.resolveInst(bin_op.rhs); - self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic); + try self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic); } return null; } @@ -8385,7 +8414,7 @@ pub const FuncGen = struct { element = self.builder.buildZExt(element, abi_ty, ""); } } - self.store(ptr, ptr_ty, element, ordering); + try self.store(ptr, ptr_ty, element, ordering); return null; } @@ -9178,7 +9207,7 @@ pub const FuncGen = struct { }, }; const field_ptr_ty = Type.initPayload(&field_ptr_payload.base); - self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic); + try self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic); } return alloca_inst; @@ -9216,7 +9245,7 @@ pub const FuncGen = struct { }; const elem_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, ""); const llvm_elem = try self.resolveInst(elem); - self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic); + try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic); } if (array_info.sentinel) |sent_val| { const indices: [2]*llvm.Value = .{ @@ -9229,7 +9258,7 @@ pub const FuncGen = struct { .val = sent_val, }); - self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic); + try self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic); } return alloca_inst; @@ -9352,7 +9381,7 @@ pub const FuncGen = struct { }; const len: c_uint = if (field_size == layout.payload_size) 2 else 3; const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, casted_ptr, &indices, len, ""); - self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic); + try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic); return result_ptr; } @@ -9364,7 +9393,7 @@ pub const FuncGen = struct { }; const len: c_uint = if (field_size == layout.payload_size) 2 else 3; const field_ptr = self.builder.buildInBoundsGEP(llvm_union_ty, casted_ptr, &indices, len, ""); - self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic); + try self.store(field_ptr, field_ptr_ty, llvm_payload, .NotAtomic); } { const indices: [2]*llvm.Value = .{ @@ -9693,6 +9722,20 @@ pub const FuncGen = struct { const target = self.dg.module.getTarget(); const ptr_alignment = info.alignment(target); const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr()); + + assert(info.vector_index != .runtime); + if (info.vector_index != .none) { + const index_u32 = self.dg.context.intType(32).constInt(@enumToInt(info.vector_index), .False); + const vec_elem_ty = try self.dg.lowerType(info.pointee_type); + const vec_ty = vec_elem_ty.vectorType(info.host_size); + + const loaded_vector = self.builder.buildLoad(vec_ty, ptr, ""); + loaded_vector.setAlignment(ptr_alignment); + loaded_vector.setVolatile(ptr_volatile); + + return self.builder.buildExtractElement(loaded_vector, index_u32, ""); + } + if (info.host_size == 0) { if (isByRef(info.pointee_type)) { return self.loadByRef(ptr, info.pointee_type, ptr_alignment, info.@"volatile"); @@ -9748,7 +9791,7 @@ pub const FuncGen = struct { ptr_ty: Type, elem: *llvm.Value, ordering: llvm.AtomicOrdering, - ) void { + ) !void { const info = ptr_ty.ptrInfo().data; const elem_ty = info.pointee_type; if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { @@ -9757,6 +9800,26 @@ pub const FuncGen = struct { const target = self.dg.module.getTarget(); const ptr_alignment = ptr_ty.ptrAlignment(target); const ptr_volatile = llvm.Bool.fromBool(info.@"volatile"); + + assert(info.vector_index != .runtime); + if (info.vector_index != .none) { + const index_u32 = self.dg.context.intType(32).constInt(@enumToInt(info.vector_index), .False); + const vec_elem_ty = try self.dg.lowerType(elem_ty); + const vec_ty = vec_elem_ty.vectorType(info.host_size); + + const loaded_vector = self.builder.buildLoad(vec_ty, ptr, ""); + loaded_vector.setAlignment(ptr_alignment); + loaded_vector.setVolatile(ptr_volatile); + + const modified_vector = self.builder.buildInsertElement(loaded_vector, elem, index_u32, ""); + + const store_inst = self.builder.buildStore(modified_vector, ptr); + assert(ordering == .NotAtomic); + store_inst.setAlignment(ptr_alignment); + store_inst.setVolatile(ptr_volatile); + return; + } + if (info.host_size != 0) { const int_elem_ty = self.context.intType(info.host_size * 8); const int_ptr = self.builder.buildBitCast(ptr, int_elem_ty.pointerType(0), ""); diff --git a/src/print_air.zig b/src/print_air.zig index 671f781e5ed7..0344595a9192 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -306,6 +306,7 @@ const Writer = struct { .shuffle => try w.writeShuffle(s, inst), .reduce, .reduce_optimized => try w.writeReduce(s, inst), .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst), + .vector_store_elem => try w.writeVectorStoreElem(s, inst), .dbg_block_begin, .dbg_block_end => {}, } @@ -478,6 +479,17 @@ const Writer = struct { try w.writeOperand(s, inst, 1, extra.rhs); } + fn writeVectorStoreElem(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const data = w.air.instructions.items(.data)[inst].vector_store_elem; + const extra = w.air.extraData(Air.VectorCmp, data.payload).data; + + try w.writeOperand(s, inst, 0, data.vector_ptr); + try s.writeAll(", "); + try w.writeOperand(s, inst, 1, extra.lhs); + try s.writeAll(", "); + try w.writeOperand(s, inst, 2, extra.rhs); + } + fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const atomic_order = w.air.instructions.items(.data)[inst].fence; diff --git a/src/type.zig b/src/type.zig index 53aee5051a4c..64702509dc78 100644 --- a/src/type.zig +++ b/src/type.zig @@ -748,6 +748,8 @@ pub const Type = extern union { return false; if (info_a.host_size != info_b.host_size) return false; + if (info_a.vector_index != info_b.vector_index) + return false; if (info_a.@"allowzero" != info_b.@"allowzero") return false; if (info_a.mutable != info_b.mutable) @@ -1126,6 +1128,7 @@ pub const Type = extern union { std.hash.autoHash(hasher, info.@"addrspace"); std.hash.autoHash(hasher, info.bit_offset); std.hash.autoHash(hasher, info.host_size); + std.hash.autoHash(hasher, info.vector_index); std.hash.autoHash(hasher, info.@"allowzero"); std.hash.autoHash(hasher, info.mutable); std.hash.autoHash(hasher, info.@"volatile"); @@ -1467,6 +1470,7 @@ pub const Type = extern union { .@"addrspace" = payload.@"addrspace", .bit_offset = payload.bit_offset, .host_size = payload.host_size, + .vector_index = payload.vector_index, .@"allowzero" = payload.@"allowzero", .mutable = payload.mutable, .@"volatile" = payload.@"volatile", @@ -1855,12 +1859,17 @@ pub const Type = extern union { .C => try writer.writeAll("[*c]"), .Slice => try writer.writeAll("[]"), } - if (payload.@"align" != 0 or payload.host_size != 0) { + if (payload.@"align" != 0 or payload.host_size != 0 or payload.vector_index != .none) { try writer.print("align({d}", .{payload.@"align"}); if (payload.bit_offset != 0 or payload.host_size != 0) { try writer.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size }); } + if (payload.vector_index == .runtime) { + try writer.writeAll(":?"); + } else if (payload.vector_index != .none) { + try writer.print(":{d}", .{@enumToInt(payload.vector_index)}); + } try writer.writeAll(") "); } if (payload.@"addrspace" != .generic) { @@ -2185,12 +2194,17 @@ pub const Type = extern union { .C => try writer.writeAll("[*c]"), .Slice => try writer.writeAll("[]"), } - if (info.@"align" != 0 or info.host_size != 0) { + if (info.@"align" != 0 or info.host_size != 0 or info.vector_index != .none) { try writer.print("align({d}", .{info.@"align"}); if (info.bit_offset != 0 or info.host_size != 0) { try writer.print(":{d}:{d}", .{ info.bit_offset, info.host_size }); } + if (info.vector_index == .runtime) { + try writer.writeAll(":?"); + } else if (info.vector_index != .none) { + try writer.print(":{d}", .{@enumToInt(info.vector_index)}); + } try writer.writeAll(") "); } if (info.@"addrspace" != .generic) { @@ -3865,6 +3879,7 @@ pub const Type = extern union { payload.@"addrspace" != .generic or payload.bit_offset != 0 or payload.host_size != 0 or + payload.vector_index != .none or payload.@"allowzero" or payload.@"volatile") { @@ -3877,6 +3892,7 @@ pub const Type = extern union { .@"addrspace" = payload.@"addrspace", .bit_offset = payload.bit_offset, .host_size = payload.host_size, + .vector_index = payload.vector_index, .@"allowzero" = payload.@"allowzero", .mutable = payload.mutable, .@"volatile" = payload.@"volatile", @@ -6365,11 +6381,18 @@ pub const Type = extern union { /// When host_size=pointee_abi_size and bit_offset=0, this must be /// represented with host_size=0 instead. host_size: u16 = 0, + vector_index: VectorIndex = .none, @"allowzero": bool = false, mutable: bool = true, // TODO rename this to const, not mutable @"volatile": bool = false, size: std.builtin.Type.Pointer.Size = .One, + pub const VectorIndex = enum(u32) { + none = std.math.maxInt(u32), + runtime = std.math.maxInt(u32) - 1, + _, + }; + pub fn alignment(data: Data, target: Target) u32 { if (data.@"align" != 0) return data.@"align"; return abiAlignment(data.pointee_type, target); @@ -6524,7 +6547,8 @@ pub const Type = extern union { } if (d.@"align" == 0 and d.@"addrspace" == .generic and - d.bit_offset == 0 and d.host_size == 0 and !d.@"allowzero" and !d.@"volatile") + d.bit_offset == 0 and d.host_size == 0 and d.vector_index == .none and + !d.@"allowzero" and !d.@"volatile") { if (d.sentinel) |sent| { if (!d.mutable and d.pointee_type.eql(Type.u8, mod)) { diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 9bcc5f9b9e25..322142d8fceb 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -1234,3 +1234,30 @@ test "array operands to shuffle are coerced to vectors" { var b = @shuffle(u32, a, @splat(5, @as(u24, 0)), mask); try expectEqual([_]u32{ 0, 3, 5, 7, 9 }, b); } + +test "load packed vector element" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + var x: @Vector(2, u15) = .{ 1, 4 }; + try expect((&x[0]).* == 1); + try expect((&x[1]).* == 4); +} + +test "store packed vector element" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + var v = @Vector(4, u1){ 1, 1, 1, 1 }; + try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v); + v[0] = 0; + try expectEqual(@Vector(4, u1){ 0, 1, 1, 1 }, v); +} diff --git a/test/cases/compile_errors/load_vector_pointer_with_unknown_runtime_index.zig b/test/cases/compile_errors/load_vector_pointer_with_unknown_runtime_index.zig new file mode 100644 index 000000000000..d2182d8ad03e --- /dev/null +++ b/test/cases/compile_errors/load_vector_pointer_with_unknown_runtime_index.zig @@ -0,0 +1,17 @@ +export fn entry() void { + var v: @Vector(4, i31) = [_]i31{ 1, 5, 3, undefined }; + + var i: u32 = 0; + var x = loadv(&v[i]); + _ = x; +} + +fn loadv(ptr: anytype) i31 { + return ptr.*; +} + +// error +// backend=llvm +// target=native +// +// :10:15: error: unable to determine vector element index of type '*align(16:0:4:?) i31' diff --git a/test/cases/compile_errors/stage1/obj/load_vector_pointer_with_unknown_runtime_index.zig b/test/cases/compile_errors/stage1/obj/load_vector_pointer_with_unknown_runtime_index.zig deleted file mode 100644 index 8d703b09e6c6..000000000000 --- a/test/cases/compile_errors/stage1/obj/load_vector_pointer_with_unknown_runtime_index.zig +++ /dev/null @@ -1,17 +0,0 @@ -export fn entry() void { - var v: @import("std").meta.Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; - - var i: u32 = 0; - var x = loadv(&v[i]); - _ = x; -} - -fn loadv(ptr: anytype) i32 { - return ptr.*; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:10:12: error: unable to determine vector element index of type '*align(16:0:4:?) i32 diff --git a/test/cases/compile_errors/stage1/obj/store_vector_pointer_with_unknown_runtime_index.zig b/test/cases/compile_errors/stage1/obj/store_vector_pointer_with_unknown_runtime_index.zig deleted file mode 100644 index 57e91631b117..000000000000 --- a/test/cases/compile_errors/stage1/obj/store_vector_pointer_with_unknown_runtime_index.zig +++ /dev/null @@ -1,16 +0,0 @@ -export fn entry() void { - var v: @import("std").meta.Vector(4, i32) = [_]i32{ 1, 5, 3, undefined }; - - var i: u32 = 0; - storev(&v[i], 42); -} - -fn storev(ptr: anytype, val: i32) void { - ptr.* = val; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:9:8: error: unable to determine vector element index of type '*align(16:0:4:?) i32 diff --git a/test/cases/compile_errors/store_vector_pointer_with_unknown_runtime_index.zig b/test/cases/compile_errors/store_vector_pointer_with_unknown_runtime_index.zig new file mode 100644 index 000000000000..0007ff13277a --- /dev/null +++ b/test/cases/compile_errors/store_vector_pointer_with_unknown_runtime_index.zig @@ -0,0 +1,16 @@ +export fn entry() void { + var v: @Vector(4, i31) = [_]i31{ 1, 5, 3, undefined }; + + var i: u32 = 0; + storev(&v[i], 42); +} + +fn storev(ptr: anytype, val: i31) void { + ptr.* = val; +} + +// error +// backend=llvm +// target=native +// +// :9:8: error: unable to determine vector element index of type '*align(16:0:4:?) i31'