Skip to content

Commit ea15029

Browse files
committed
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.
1 parent 280ced6 commit ea15029

File tree

5 files changed

+62
-32
lines changed

5 files changed

+62
-32
lines changed

build.zig

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -598,9 +598,10 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
598598
.optimize = .ReleaseSmall,
599599
.target = b.resolveTargetQuery(std.Target.Query.parse(.{
600600
.arch_os_abi = "wasm32-wasi",
601-
// `extended_const` is not supported by the `wasm-opt` version in CI.
602-
// `nontrapping_fptoint` is not supported by `wasm2c`.
603-
.cpu_features = "baseline-extended_const-nontrapping_fptoint",
601+
// * `extended_const` is not supported by the `wasm-opt` version in CI.
602+
// * `nontrapping_fptoint` is not supported by `wasm2c`.
603+
// * `nontrapping_bulk_memory_len0` is supported by `wasm2c`.
604+
.cpu_features = "baseline-extended_const-nontrapping_fptoint+nontrapping_bulk_memory_len0",
604605
}) catch unreachable),
605606
});
606607

lib/std/Target/wasm.zig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub const Feature = enum {
1313
multimemory,
1414
multivalue,
1515
mutable_globals,
16+
nontrapping_bulk_memory_len0,
1617
nontrapping_fptoint,
1718
reference_types,
1819
relaxed_simd,
@@ -70,6 +71,13 @@ pub const all_features = blk: {
7071
.description = "Enable mutable globals",
7172
.dependencies = featureSet(&[_]Feature{}),
7273
};
74+
result[@intFromEnum(Feature.nontrapping_bulk_memory_len0)] = .{
75+
.llvm_name = null,
76+
.description = "Bulk memory operations with a zero length do not trap",
77+
.dependencies = featureSet(&[_]Feature{
78+
.bulk_memory,
79+
}),
80+
};
7381
result[@intFromEnum(Feature.nontrapping_fptoint)] = .{
7482
.llvm_name = "nontrapping-fptoint",
7583
.description = "Enable non-trapping float-to-int conversion operators",

src/arch/wasm/CodeGen.zig

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,27 +1591,34 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {
15911591
// When bulk_memory is enabled, we lower it to wasm's memcpy instruction.
15921592
// If not, we lower it ourselves manually
15931593
if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory)) {
1594-
try cg.startBlock(.block, .empty);
1595-
1596-
// Even if `len` is zero, the spec requires an implementation to trap if `src + len` or
1597-
// `dst + len` are out of memory bounds. This can easily happen in Zig in a case such as:
1598-
//
1599-
// const dst: [*]u8 = undefined;
1600-
// const src: [*]u8 = undefined;
1601-
// var len: usize = runtime_zero();
1602-
// @memcpy(dst[0..len], src[0..len]);
1603-
//
1604-
// So explicitly avoid using `memory.copy` in the `len == 0` case. Lovely design.
1605-
try cg.emitWValue(len);
1606-
try cg.addTag(.i32_eqz);
1607-
try cg.addLabel(.br_if, 0);
1594+
const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0);
1595+
1596+
if (!len0_ok) {
1597+
try cg.startBlock(.block, .empty);
1598+
1599+
// Even if `len` is zero, the spec requires an implementation to trap if `src + len` or
1600+
// `dst + len` are out of memory bounds. This can easily happen in Zig in a case such
1601+
// as:
1602+
//
1603+
// const dst: [*]u8 = undefined;
1604+
// const src: [*]u8 = undefined;
1605+
// var len: usize = runtime_zero();
1606+
// @memcpy(dst[0..len], src[0..len]);
1607+
//
1608+
// So explicitly avoid using `memory.copy` in the `len == 0` case. Lovely design.
1609+
try cg.emitWValue(len);
1610+
try cg.addTag(.i32_eqz);
1611+
try cg.addLabel(.br_if, 0);
1612+
}
16081613

16091614
try cg.lowerToStack(dst);
16101615
try cg.lowerToStack(src);
16111616
try cg.emitWValue(len);
16121617
try cg.addExtended(.memory_copy);
16131618

1614-
try cg.endBlock();
1619+
if (!len0_ok) {
1620+
try cg.endBlock();
1621+
}
16151622

16161623
return;
16171624
}
@@ -4800,26 +4807,32 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)
48004807
// When bulk_memory is enabled, we lower it to wasm's memset instruction.
48014808
// If not, we lower it ourselves.
48024809
if (std.Target.wasm.featureSetHas(cg.target.cpu.features, .bulk_memory) and abi_size == 1) {
4803-
try cg.startBlock(.block, .empty);
4804-
4805-
// Even if `len` is zero, the spec requires an implementation to trap if `ptr + len` is
4806-
// out of memory bounds. This can easily happen in Zig in a case such as:
4807-
//
4808-
// const ptr: [*]u8 = undefined;
4809-
// var len: usize = runtime_zero();
4810-
// @memset(ptr[0..len], 42);
4811-
//
4812-
// So explicitly avoid using `memory.fill` in the `len == 0` case. Lovely design.
4813-
try cg.emitWValue(len);
4814-
try cg.addTag(.i32_eqz);
4815-
try cg.addLabel(.br_if, 0);
4810+
const len0_ok = std.Target.wasm.featureSetHas(cg.target.cpu.features, .nontrapping_bulk_memory_len0);
4811+
4812+
if (!len0_ok) {
4813+
try cg.startBlock(.block, .empty);
4814+
4815+
// Even if `len` is zero, the spec requires an implementation to trap if `ptr + len` is
4816+
// out of memory bounds. This can easily happen in Zig in a case such as:
4817+
//
4818+
// const ptr: [*]u8 = undefined;
4819+
// var len: usize = runtime_zero();
4820+
// @memset(ptr[0..len], 42);
4821+
//
4822+
// So explicitly avoid using `memory.fill` in the `len == 0` case. Lovely design.
4823+
try cg.emitWValue(len);
4824+
try cg.addTag(.i32_eqz);
4825+
try cg.addLabel(.br_if, 0);
4826+
}
48164827

48174828
try cg.lowerToStack(ptr);
48184829
try cg.emitWValue(value);
48194830
try cg.emitWValue(len);
48204831
try cg.addExtended(.memory_fill);
48214832

4822-
try cg.endBlock();
4833+
if (!len0_ok) {
4834+
try cg.endBlock();
4835+
}
48234836

48244837
return;
48254838
}

src/link/Wasm.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,6 +2826,7 @@ pub const Feature = packed struct(u8) {
28262826
multimemory,
28272827
multivalue,
28282828
@"mutable-globals",
2829+
@"nontrapping-bulk-memory-len0",
28292830
@"nontrapping-fptoint",
28302831
@"reference-types",
28312832
@"relaxed-simd",

tools/update_cpu_features.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,13 @@ const llvm_targets = [_]LlvmTarget{
10331033
.zig_name = "wasm",
10341034
.llvm_name = "WebAssembly",
10351035
.td_name = "WebAssembly.td",
1036+
.extra_features = &.{
1037+
.{
1038+
.zig_name = "nontrapping_bulk_memory_len0",
1039+
.desc = "Bulk memory operations with a zero length do not trap",
1040+
.deps = &.{"bulk_memory"},
1041+
},
1042+
},
10361043
.extra_cpus = &.{
10371044
.{
10381045
.llvm_name = null,

0 commit comments

Comments
 (0)