diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2025-01-22 02:56:53 +0100 |
|---|---|---|
| committer | Alex Rønne Petersen <alex@alexrp.com> | 2025-01-22 20:56:28 +0100 |
| commit | ea1502974dd991c0ed4c58dd54fb96cf7080f293 (patch) | |
| tree | 00d3b226ba78e1c2864df26e038512c03708668b /src/arch/wasm/CodeGen.zig | |
| parent | 280ced66eb712f5c74835b10fa6ba0bd915ee96b (diff) | |
| download | zig-ea1502974dd991c0ed4c58dd54fb96cf7080f293.tar.gz zig-ea1502974dd991c0ed4c58dd54fb96cf7080f293.zip | |
wasm: Add a nontrapping_bulk_memory_len0 feature.
This will mainly be used when targeting our wasm2c implementation which has no
problem with zero-length bulk memory operations, as a non-standard extension.
Diffstat (limited to 'src/arch/wasm/CodeGen.zig')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 144c85bd9a..51019969f6 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1591,27 +1591,34 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { // When bulk_memory is enabled, we lower it to wasm's memcpy instruction. // If not, we lower it ourselves manually if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory)) { - try cg.startBlock(.block, .empty); - - // Even if `len` is zero, the spec requires an implementation to trap if `src + len` or - // `dst + len` are out of memory bounds. This can easily happen in Zig in a case such as: - // - // const dst: [*]u8 = undefined; - // const src: [*]u8 = undefined; - // var len: usize = runtime_zero(); - // @memcpy(dst[0..len], src[0..len]); - // - // So explicitly avoid using `memory.copy` in the `len == 0` case. Lovely design. - try cg.emitWValue(len); - try cg.addTag(.i32_eqz); - try cg.addLabel(.br_if, 0); + const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0); + + if (!len0_ok) { + try cg.startBlock(.block, .empty); + + // Even if `len` is zero, the spec requires an implementation to trap if `src + len` or + // `dst + len` are out of memory bounds. This can easily happen in Zig in a case such + // as: + // + // const dst: [*]u8 = undefined; + // const src: [*]u8 = undefined; + // var len: usize = runtime_zero(); + // @memcpy(dst[0..len], src[0..len]); + // + // So explicitly avoid using `memory.copy` in the `len == 0` case. Lovely design. + try cg.emitWValue(len); + try cg.addTag(.i32_eqz); + try cg.addLabel(.br_if, 0); + } try cg.lowerToStack(dst); try cg.lowerToStack(src); try cg.emitWValue(len); try cg.addExtended(.memory_copy); - try cg.endBlock(); + if (!len0_ok) { + try cg.endBlock(); + } return; } @@ -4800,26 +4807,32 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) // When bulk_memory is enabled, we lower it to wasm's memset instruction. // If not, we lower it ourselves. if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory) and abi_size == 1) { - try cg.startBlock(.block, .empty); - - // Even if `len` is zero, the spec requires an implementation to trap if `ptr + len` is - // out of memory bounds. This can easily happen in Zig in a case such as: - // - // const ptr: [*]u8 = undefined; - // var len: usize = runtime_zero(); - // @memset(ptr[0..len], 42); - // - // So explicitly avoid using `memory.fill` in the `len == 0` case. Lovely design. - try cg.emitWValue(len); - try cg.addTag(.i32_eqz); - try cg.addLabel(.br_if, 0); + const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0); + + if (!len0_ok) { + try cg.startBlock(.block, .empty); + + // Even if `len` is zero, the spec requires an implementation to trap if `ptr + len` is + // out of memory bounds. This can easily happen in Zig in a case such as: + // + // const ptr: [*]u8 = undefined; + // var len: usize = runtime_zero(); + // @memset(ptr[0..len], 42); + // + // So explicitly avoid using `memory.fill` in the `len == 0` case. Lovely design. + try cg.emitWValue(len); + try cg.addTag(.i32_eqz); + try cg.addLabel(.br_if, 0); + } try cg.lowerToStack(ptr); try cg.emitWValue(value); try cg.emitWValue(len); try cg.addExtended(.memory_fill); - try cg.endBlock(); + if (!len0_ok) { + try cg.endBlock(); + } return; } |
