diff options
| author | Xavier Bouchoux <xavierb@gmail.com> | 2023-07-28 08:15:20 +0200 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-08-10 16:10:59 -0700 |
| commit | 77dd64b5f449982bda1bf1871e214a68c535f4c5 (patch) | |
| tree | 7c19c7440c7015a57d1ad7cf315d138aa7d344d2 /src/Sema.zig | |
| parent | 9959319d5395a668867c90f63b5f82eb03f0ac9f (diff) | |
| download | zig-77dd64b5f449982bda1bf1871e214a68c535f4c5.tar.gz zig-77dd64b5f449982bda1bf1871e214a68c535f4c5.zip | |
Sema: fix coerceArrayLike() for vectors with padding
as explainded at https://llvm.org/docs/LangRef.html#vector-type :
"In general vector elements are laid out in memory in the same way as array types.
Such an analogy works fine as long as the vector elements are byte sized.
However, when the elements of the vector aren’t byte sized it gets a bit more complicated.
One way to describe the layout is by describing what happens when a vector such
as <N x iM> is bitcasted to an integer type with N*M bits, and then following the
rules for storing such an integer to memory."
"When <N*M> isn’t evenly divisible by the byte size the exact memory layout
is unspecified (just like it is for an integral type of the same size)."
Diffstat (limited to 'src/Sema.zig')
| -rw-r--r-- | src/Sema.zig | 71 |
1 files changed, 58 insertions, 13 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 0494b2a09c..b80f4d72db 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -28315,6 +28315,50 @@ fn coerceInMemoryAllowed( return .ok; } + // Arrays <-> Vectors + if ((dest_tag == .Vector and src_tag == .Array) or + (dest_tag == .Array and src_tag == .Vector)) + { + const dest_len = dest_ty.arrayLen(mod); + const src_len = src_ty.arrayLen(mod); + if (dest_len != src_len) { + return InMemoryCoercionResult{ .array_len = .{ + .actual = src_len, + .wanted = dest_len, + } }; + } + + const dest_elem_ty = dest_ty.childType(mod); + const src_elem_ty = src_ty.childType(mod); + const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); + if (child != .ok) { + return InMemoryCoercionResult{ .array_elem = .{ + .child = try child.dupe(sema.arena), + .actual = src_elem_ty, + .wanted = dest_elem_ty, + } }; + } + + if (dest_tag == .Array) { + const dest_info = dest_ty.arrayInfo(mod); + if (dest_info.sentinel != null) { + return InMemoryCoercionResult{ .array_sentinel = .{ + .actual = Value.@"unreachable", + .wanted = dest_info.sentinel.?, + .ty = dest_info.elem_type, + } }; + } + } + + // The memory layout of @Vector(N, iM) is the same as the integer type i(N*M), + // that is to say, the padding bits are not in the same place as the array [N]iM. + // If there's no padding, the bitcast is possible. + const elem_bit_size = dest_elem_ty.bitSize(mod); + const elem_abi_byte_size = dest_elem_ty.abiSize(mod); + if (elem_abi_byte_size * 8 == elem_bit_size) + return .ok; + } + // Optionals if (dest_tag == .Optional and src_tag == .Optional) { if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { @@ -30205,10 +30249,22 @@ fn coerceArrayLike( ) !Air.Inst.Ref { const mod = sema.mod; const inst_ty = sema.typeOf(inst); - const inst_len = inst_ty.arrayLen(mod); - const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(mod)); const target = mod.getTarget(); + // try coercion of the whole array + const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); + if (in_memory_result == .ok) { + if (try sema.resolveMaybeUndefVal(inst)) |inst_val| { + // These types share the same comptime value representation. + return sema.coerceInMemory(inst_val, dest_ty); + } + try sema.requireRuntimeBlock(block, inst_src, null); + return block.addBitCast(dest_ty, inst); + } + + // otherwise, try element by element + const inst_len = inst_ty.arrayLen(mod); + const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(mod)); if (dest_len != inst_len) { const msg = msg: { const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ @@ -30223,17 +30279,6 @@ fn coerceArrayLike( } const dest_elem_ty = dest_ty.childType(mod); - const inst_elem_ty = inst_ty.childType(mod); - const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src); - if (in_memory_result == .ok) { - if (try sema.resolveMaybeUndefVal(inst)) |inst_val| { - // These types share the same comptime value representation. - return sema.coerceInMemory(inst_val, dest_ty); - } - try sema.requireRuntimeBlock(block, inst_src, null); - return block.addBitCast(dest_ty, inst); - } - const element_vals = try sema.arena.alloc(InternPool.Index, dest_len); const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len); var runtime_src: ?LazySrcLoc = null; |
