aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib
diff options
context:
space:
mode:
authorDerek Schuff <dschuff@chromium.org>2025-10-14 22:00:25 +0000
committerGitHub <noreply@github.com>2025-10-14 22:00:25 +0000
commit19a58a520820a0678e767abdf418f101cfd5ca1a (patch)
treea14712b6637bb6cc32f8ac56b2a6928379801c7d /llvm/lib
parent511c1f9f151e22757cdac0b291022bf1cccbfc1d (diff)
downloadllvm-19a58a520820a0678e767abdf418f101cfd5ca1a.zip
llvm-19a58a520820a0678e767abdf418f101cfd5ca1a.tar.gz
llvm-19a58a520820a0678e767abdf418f101cfd5ca1a.tar.bz2
[WebAssembly] Optimize lowering of constant-sized memcpy and memset (#163294)
We currently emit a check that the size operand isn't zero, to avoid executing the wasm memory.copy instruction when it would trap. But this isn't necessary if the operand is a constant. Fixes #163245
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp45
1 files changed, 45 insertions, 0 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 47c24fc..f973949 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -601,6 +601,29 @@ static MachineBasicBlock *LowerMemcpy(MachineInstr &MI, DebugLoc DL,
MachineOperand Src = MI.getOperand(3);
MachineOperand Len = MI.getOperand(4);
+ // If the length is a constant, we don't actually need the check.
+ if (MachineInstr *Def = MRI.getVRegDef(Len.getReg())) {
+ if (Def->getOpcode() == WebAssembly::CONST_I32 ||
+ Def->getOpcode() == WebAssembly::CONST_I64) {
+ if (Def->getOperand(1).getImm() == 0) {
+ // A zero-length memcpy is a no-op.
+ MI.eraseFromParent();
+ return BB;
+ }
+ // A non-zero-length memcpy doesn't need a zero check.
+ unsigned MemoryCopy =
+ Int64 ? WebAssembly::MEMORY_COPY_A64 : WebAssembly::MEMORY_COPY_A32;
+ BuildMI(*BB, MI, DL, TII.get(MemoryCopy))
+ .add(DstMem)
+ .add(SrcMem)
+ .add(Dst)
+ .add(Src)
+ .add(Len);
+ MI.eraseFromParent();
+ return BB;
+ }
+ }
+
// We're going to add an extra use to `Len` to test if it's zero; that
// use shouldn't be a kill, even if the original use is.
MachineOperand NoKillLen = Len;
@@ -669,6 +692,28 @@ static MachineBasicBlock *LowerMemset(MachineInstr &MI, DebugLoc DL,
MachineOperand Val = MI.getOperand(2);
MachineOperand Len = MI.getOperand(3);
+ // If the length is a constant, we don't actually need the check.
+ if (MachineInstr *Def = MRI.getVRegDef(Len.getReg())) {
+ if (Def->getOpcode() == WebAssembly::CONST_I32 ||
+ Def->getOpcode() == WebAssembly::CONST_I64) {
+ if (Def->getOperand(1).getImm() == 0) {
+ // A zero-length memset is a no-op.
+ MI.eraseFromParent();
+ return BB;
+ }
+ // A non-zero-length memset doesn't need a zero check.
+ unsigned MemoryFill =
+ Int64 ? WebAssembly::MEMORY_FILL_A64 : WebAssembly::MEMORY_FILL_A32;
+ BuildMI(*BB, MI, DL, TII.get(MemoryFill))
+ .add(Mem)
+ .add(Dst)
+ .add(Val)
+ .add(Len);
+ MI.eraseFromParent();
+ return BB;
+ }
+ }
+
// We're going to add an extra use to `Len` to test if it's zero; that
// use shouldn't be a kill, even if the original use is.
MachineOperand NoKillLen = Len;