aboutsummaryrefslogtreecommitdiff
path: root/src/arch/wasm/CodeGen.zig
diff options
context:
space:
mode:
authorAlex Rønne Petersen <alex@alexrp.com>2025-01-22 02:56:53 +0100
committerAlex Rønne Petersen <alex@alexrp.com>2025-01-22 20:56:28 +0100
commitea1502974dd991c0ed4c58dd54fb96cf7080f293 (patch)
tree00d3b226ba78e1c2864df26e038512c03708668b /src/arch/wasm/CodeGen.zig
parent280ced66eb712f5c74835b10fa6ba0bd915ee96b (diff)
downloadzig-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.zig71
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;
}