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