| ... | ... | @@ -1588,12 +1588,18 @@ fn toWasmBits(bits: u16) ?u16 { |
| 1588 | 1588 | /// Performs a copy of bytes for a given type. Copying all bytes |
| 1589 | 1589 | /// from rhs to lhs. |
| 1590 | 1590 | fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| 1591 | const len_known_neq_0 = switch (len) { |
| 1592 | .imm32 => |val| if (val != 0) true else return, |
| 1593 | .imm64 => |val| if (val != 0) true else return, |
| 1594 | else => false, |
| 1595 | }; |
| 1591 | 1596 | // When bulk_memory is enabled, we lower it to wasm's memcpy instruction. |
| 1592 | 1597 | // If not, we lower it ourselves manually |
| 1593 | 1598 | if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory)) { |
| 1594 | 1599 | const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0); |
| 1600 | const emit_check = !(len0_ok or len_known_neq_0); |
| 1595 | 1601 | |
| 1596 | | if (!len0_ok) { |
| 1602 | if (emit_check) { |
| 1597 | 1603 | try cg.startBlock(.block, .empty); |
| 1598 | 1604 | |
| 1599 | 1605 | // Even if `len` is zero, the spec requires an implementation to trap if `src + len` or |
| ... | ... | @@ -1616,7 +1622,7 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| 1616 | 1622 | try cg.emitWValue(len); |
| 1617 | 1623 | try cg.addExtended(.memory_copy); |
| 1618 | 1624 | |
| 1619 | | if (!len0_ok) { |
| 1625 | if (emit_check) { |
| 1620 | 1626 | try cg.endBlock(); |
| 1621 | 1627 | } |
| 1622 | 1628 | |
| ... | ... | @@ -5196,9 +5202,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5196 | 5202 | const result = try cg.allocStack(result_ty); |
| 5197 | 5203 | const elem_ty = result_ty.childType(zcu); |
| 5198 | 5204 | const elem_size = @as(u32, @intCast(elem_ty.abiSize(zcu))); |
| 5199 | | const sentinel = if (result_ty.sentinel(zcu)) |sent| blk: { |
| 5200 | | break :blk try cg.lowerConstant(sent, elem_ty); |
| 5201 | | } else null; |
| 5205 | const sentinel = result_ty.sentinel(zcu); |
| 5202 | 5206 | |
| 5203 | 5207 | // When the element type is by reference, we must copy the entire |
| 5204 | 5208 | // value. It is therefore safer to move the offset pointer and store |
| ... | ... | @@ -5211,12 +5215,13 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5211 | 5215 | const elem_val = try cg.resolveInst(elem); |
| 5212 | 5216 | try cg.store(offset, elem_val, elem_ty, 0); |
| 5213 | 5217 | |
| 5214 | | if (elem_index < elements.len - 1 and sentinel == null) { |
| 5218 | if (elem_index < elements.len - 1 or sentinel != null) { |
| 5215 | 5219 | _ = try cg.buildPointerOffset(offset, elem_size, .modify); |
| 5216 | 5220 | } |
| 5217 | 5221 | } |
| 5218 | | if (sentinel) |sent| { |
| 5219 | | try cg.store(offset, sent, elem_ty, 0); |
| 5222 | if (sentinel) |s| { |
| 5223 | const val = try cg.resolveInst(Air.internedToRef(s.toIntern())); |
| 5224 | try cg.store(offset, val, elem_ty, 0); |
| 5220 | 5225 | } |
| 5221 | 5226 | } else { |
| 5222 | 5227 | var offset: u32 = 0; |
| ... | ... | @@ -5225,8 +5230,9 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5225 | 5230 | try cg.store(result, elem_val, elem_ty, offset); |
| 5226 | 5231 | offset += elem_size; |
| 5227 | 5232 | } |
| 5228 | | if (sentinel) |sent| { |
| 5229 | | try cg.store(result, sent, elem_ty, offset); |
| 5233 | if (sentinel) |s| { |
| 5234 | const val = try cg.resolveInst(Air.internedToRef(s.toIntern())); |
| 5235 | try cg.store(result, val, elem_ty, offset); |
| 5230 | 5236 | } |
| 5231 | 5237 | } |
| 5232 | 5238 | break :result_value result; |