| ... | ... | @@ -8511,6 +8511,14 @@ pub const FuncGen = struct { |
| 8511 | 8511 | const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty); |
| 8512 | 8512 | const is_volatile = ptr_ty.isVolatilePtr(mod); |
| 8513 | 8513 | |
| 8514 | // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless |
| 8515 | // of the length. This means we need to emit a check where we skip the memset when the length |
| 8516 | // is 0 as we allow for undefined pointers in 0-sized slices. |
| 8517 | const needs_wasm_safety_check = safety and |
| 8518 | o.target.isWasm() and |
| 8519 | ptr_ty.isSlice(mod) and |
| 8520 | std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory); |
| 8521 | |
| 8514 | 8522 | if (try self.air.value(bin_op.rhs, mod)) |elem_val| { |
| 8515 | 8523 | if (elem_val.isUndefDeep(mod)) { |
| 8516 | 8524 | // Even if safety is disabled, we still emit a memset to undefined since it conveys |
| ... | ... | @@ -8521,7 +8529,11 @@ pub const FuncGen = struct { |
| 8521 | 8529 | else |
| 8522 | 8530 | u8_llvm_ty.getUndef(); |
| 8523 | 8531 | const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8524 | | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8532 | if (needs_wasm_safety_check) { |
| 8533 | try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8534 | } else { |
| 8535 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8536 | } |
| 8525 | 8537 | |
| 8526 | 8538 | if (safety and mod.comp.bin_file.options.valgrind) { |
| 8527 | 8539 | self.valgrindMarkUndef(dest_ptr, len); |
| ... | ... | @@ -8539,7 +8551,12 @@ pub const FuncGen = struct { |
| 8539 | 8551 | .val = byte_val, |
| 8540 | 8552 | }); |
| 8541 | 8553 | const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8542 | | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8554 | |
| 8555 | if (needs_wasm_safety_check) { |
| 8556 | try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8557 | } else { |
| 8558 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8559 | } |
| 8543 | 8560 | return null; |
| 8544 | 8561 | } |
| 8545 | 8562 | } |
| ... | ... | @@ -8551,7 +8568,12 @@ pub const FuncGen = struct { |
| 8551 | 8568 | // In this case we can take advantage of LLVM's intrinsic. |
| 8552 | 8569 | const fill_byte = try self.bitCast(value, elem_ty, Type.u8); |
| 8553 | 8570 | const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8554 | | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8571 | |
| 8572 | if (needs_wasm_safety_check) { |
| 8573 | try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8574 | } else { |
| 8575 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8576 | } |
| 8555 | 8577 | return null; |
| 8556 | 8578 | } |
| 8557 | 8579 | |
| ... | ... | @@ -8622,6 +8644,29 @@ pub const FuncGen = struct { |
| 8622 | 8644 | return null; |
| 8623 | 8645 | } |
| 8624 | 8646 | |
| 8647 | fn safeWasmMemset( |
| 8648 | self: *FuncGen, |
| 8649 | dest_ptr: *llvm.Value, |
| 8650 | fill_byte: *llvm.Value, |
| 8651 | len: *llvm.Value, |
| 8652 | dest_ptr_align: u32, |
| 8653 | is_volatile: bool, |
| 8654 | ) !void { |
| 8655 | const parent_block = self.context.createBasicBlock("Block"); |
| 8656 | const llvm_usize_ty = self.context.intType(self.dg.object.target.ptrBitWidth()); |
| 8657 | const cond = try self.cmp(len, llvm_usize_ty.constInt(0, .False), Type.usize, .eq); |
| 8658 | const then_block = self.context.appendBasicBlock(self.llvm_func, "Then"); |
| 8659 | const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); |
| 8660 | _ = self.builder.buildCondBr(cond, then_block, else_block); |
| 8661 | self.builder.positionBuilderAtEnd(then_block); |
| 8662 | _ = self.builder.buildBr(parent_block); |
| 8663 | self.builder.positionBuilderAtEnd(else_block); |
| 8664 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8665 | _ = self.builder.buildBr(parent_block); |
| 8666 | self.llvm_func.appendExistingBasicBlock(parent_block); |
| 8667 | self.builder.positionBuilderAtEnd(parent_block); |
| 8668 | } |
| 8669 | |
| 8625 | 8670 | fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8626 | 8671 | const o = self.dg.object; |
| 8627 | 8672 | const mod = o.module; |