@@ -1591,27 +1591,34 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void {
1591
1591
// When bulk_memory is enabled, we lower it to wasm's memcpy instruction.
1592
1592
// If not, we lower it ourselves manually
1593
1593
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
+ }
1608
1613
1609
1614
try cg .lowerToStack (dst );
1610
1615
try cg .lowerToStack (src );
1611
1616
try cg .emitWValue (len );
1612
1617
try cg .addExtended (.memory_copy );
1613
1618
1614
- try cg .endBlock ();
1619
+ if (! len0_ok ) {
1620
+ try cg .endBlock ();
1621
+ }
1615
1622
1616
1623
return ;
1617
1624
}
@@ -4800,26 +4807,32 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)
4800
4807
// When bulk_memory is enabled, we lower it to wasm's memset instruction.
4801
4808
// If not, we lower it ourselves.
4802
4809
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
+ }
4816
4827
4817
4828
try cg .lowerToStack (ptr );
4818
4829
try cg .emitWValue (value );
4819
4830
try cg .emitWValue (len );
4820
4831
try cg .addExtended (.memory_fill );
4821
4832
4822
- try cg .endBlock ();
4833
+ if (! len0_ok ) {
4834
+ try cg .endBlock ();
4835
+ }
4823
4836
4824
4837
return ;
4825
4838
}
0 commit comments