[llvm] [SelectionDAG] zext/trunc size of memory libcalls to target pointer size (PR #226672)

via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 26 03:23:12 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: Mitch Briles (MitchBriles)

<details>
<summary>Changes</summary>

Fixes #<!-- -->226666 

For `memcpy`, `memmove`, and `memset`, the value for the number of bytes for the operation ("Size") used the type of the intrinsic. When the type of Size was narrower than that of the "length" parameter of the libcall, the value would be widened with ANY_EXTEND.  On RISC-V, this can materialize as a sign extension, which leads to writing `2^33` times as many bytes.

Changes
- Zero-extends or truncates the Size to the target pointer width (Note that GISel already does this correctly).
- Added new RISC-V/AArch64 tests, and updated existing ones.

Note that this also fixed an AArch64 crash. With `-mattr=+mops`, SD crashed with any non-constant i32 length argument to one of these libcalls with "unimplemented reg-to-reg copy"

cc @<!-- -->RKSimon to assign, please, and thanks!

---

Patch is 30.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/226672.diff


7 Files Affected:

- (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (+3) 
- (modified) llvm/test/CodeGen/AArch64/aarch64-mops.ll (+194) 
- (modified) llvm/test/CodeGen/AArch64/func-argpassing.ll (+2-2) 
- (modified) llvm/test/CodeGen/AArch64/streaming-compatible-memory-ops.ll (+156) 
- (modified) llvm/test/CodeGen/RISCV/memcpy.ll (+96-2) 
- (modified) llvm/test/CodeGen/RISCV/memmove.ll (+74) 
- (added) llvm/test/CodeGen/RISCV/memset.ll (+125) 


``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 8c67b0449ddb6..70592b73ba43b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -10123,6 +10123,7 @@ SDValue SelectionDAG::getMemcpy(
     const CallInst *CI, std::optional<bool> OverrideTailCall,
     MachinePointerInfo DstPtrInfo, MachinePointerInfo SrcPtrInfo,
     const AAMDNodes &AAInfo, BatchAAResults *BatchAA) {
+  Size = getZExtOrTrunc(Size, dl, TLI->getPointerTy(getDataLayout()));
   // Check to see if we should lower the memcpy to loads and stores first.
   // For cases within the target-specified limits, this is the best choice.
   const MDNode *DstMemCacheHint =
@@ -10254,6 +10255,7 @@ SDValue SelectionDAG::getMemmove(SDValue Chain, const SDLoc &dl, SDValue Dst,
                                  MachinePointerInfo SrcPtrInfo,
                                  const AAMDNodes &AAInfo,
                                  BatchAAResults *BatchAA) {
+  Size = getZExtOrTrunc(Size, dl, TLI->getPointerTy(getDataLayout()));
   // Check to see if we should lower the memmove to loads and stores first.
   // For cases within the target-specified limits, this is the best choice.
   ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
@@ -10365,6 +10367,7 @@ SDValue SelectionDAG::getMemset(SDValue Chain, const SDLoc &dl, SDValue Dst,
                                 const CallInst *CI,
                                 MachinePointerInfo DstPtrInfo,
                                 const AAMDNodes &AAInfo) {
+  Size = getZExtOrTrunc(Size, dl, TLI->getPointerTy(getDataLayout()));
   // Check to see if we should lower the memset to stores first.
   // For cases within the target-specified limits, this is the best choice.
   ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
diff --git a/llvm/test/CodeGen/AArch64/aarch64-mops.ll b/llvm/test/CodeGen/AArch64/aarch64-mops.ll
index 02eb780596494..f673c9b68800f 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-mops.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-mops.ll
@@ -2838,3 +2838,197 @@ entry:
   call void @llvm.memmove.inline.p0.p0.i64(ptr align 1 %dst, ptr align 1 %src, i64 300, i1 true)
   ret void
 }
+
+define void @memset_size_i32(ptr %dst, i32 %size, i32 %value) {
+; GISel-WITHOUT-MOPS-O0-LABEL: memset_size_i32:
+; GISel-WITHOUT-MOPS-O0:       // %bb.0: // %entry
+; GISel-WITHOUT-MOPS-O0-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISel-WITHOUT-MOPS-O0-NEXT:    .cfi_def_cfa_offset 16
+; GISel-WITHOUT-MOPS-O0-NEXT:    .cfi_offset w30, -16
+; GISel-WITHOUT-MOPS-O0-NEXT:    mov w8, w1
+; GISel-WITHOUT-MOPS-O0-NEXT:    mov w1, w2
+; GISel-WITHOUT-MOPS-O0-NEXT:    mov w8, w8
+; GISel-WITHOUT-MOPS-O0-NEXT:    mov w2, w8
+; GISel-WITHOUT-MOPS-O0-NEXT:    bl memset
+; GISel-WITHOUT-MOPS-O0-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISel-WITHOUT-MOPS-O0-NEXT:    ret
+;
+; GISel-WITHOUT-MOPS-O3-LABEL: memset_size_i32:
+; GISel-WITHOUT-MOPS-O3:       // %bb.0: // %entry
+; GISel-WITHOUT-MOPS-O3-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISel-WITHOUT-MOPS-O3-NEXT:    .cfi_def_cfa_offset 16
+; GISel-WITHOUT-MOPS-O3-NEXT:    .cfi_offset w30, -16
+; GISel-WITHOUT-MOPS-O3-NEXT:    mov w3, w2
+; GISel-WITHOUT-MOPS-O3-NEXT:    mov w2, w1
+; GISel-WITHOUT-MOPS-O3-NEXT:    mov w1, w3
+; GISel-WITHOUT-MOPS-O3-NEXT:    bl memset
+; GISel-WITHOUT-MOPS-O3-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISel-WITHOUT-MOPS-O3-NEXT:    ret
+;
+; GISel-MOPS-O0-LABEL: memset_size_i32:
+; GISel-MOPS-O0:       // %bb.0: // %entry
+; GISel-MOPS-O0-NEXT:    mov w8, w1
+; GISel-MOPS-O0-NEXT:    // kill: def $x8 killed $w8
+; GISel-MOPS-O0-NEXT:    // implicit-def: $x9
+; GISel-MOPS-O0-NEXT:    mov w9, w2
+; GISel-MOPS-O0-NEXT:    setp [x0]!, x8!, x9
+; GISel-MOPS-O0-NEXT:    setm [x0]!, x8!, x9
+; GISel-MOPS-O0-NEXT:    sete [x0]!, x8!, x9
+; GISel-MOPS-O0-NEXT:    ret
+;
+; GISel-MOPS-O3-LABEL: memset_size_i32:
+; GISel-MOPS-O3:       // %bb.0: // %entry
+; GISel-MOPS-O3-NEXT:    mov w8, w1
+; GISel-MOPS-O3-NEXT:    // kill: def $w2 killed $w2 def $x2
+; GISel-MOPS-O3-NEXT:    setp [x0]!, x8!, x2
+; GISel-MOPS-O3-NEXT:    setm [x0]!, x8!, x2
+; GISel-MOPS-O3-NEXT:    sete [x0]!, x8!, x2
+; GISel-MOPS-O3-NEXT:    ret
+;
+; SDAG-WITHOUT-MOPS-O2-LABEL: memset_size_i32:
+; SDAG-WITHOUT-MOPS-O2:       // %bb.0: // %entry
+; SDAG-WITHOUT-MOPS-O2-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; SDAG-WITHOUT-MOPS-O2-NEXT:    .cfi_def_cfa_offset 16
+; SDAG-WITHOUT-MOPS-O2-NEXT:    .cfi_offset w30, -16
+; SDAG-WITHOUT-MOPS-O2-NEXT:    mov w8, w2
+; SDAG-WITHOUT-MOPS-O2-NEXT:    mov w2, w1
+; SDAG-WITHOUT-MOPS-O2-NEXT:    mov w1, w8
+; SDAG-WITHOUT-MOPS-O2-NEXT:    bl memset
+; SDAG-WITHOUT-MOPS-O2-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; SDAG-WITHOUT-MOPS-O2-NEXT:    ret
+;
+; SDAG-MOPS-O2-LABEL: memset_size_i32:
+; SDAG-MOPS-O2:       // %bb.0: // %entry
+; SDAG-MOPS-O2-NEXT:    mov w8, w1
+; SDAG-MOPS-O2-NEXT:    // kill: def $w2 killed $w2 def $x2
+; SDAG-MOPS-O2-NEXT:    setp [x0]!, x8!, x2
+; SDAG-MOPS-O2-NEXT:    setm [x0]!, x8!, x2
+; SDAG-MOPS-O2-NEXT:    sete [x0]!, x8!, x2
+; SDAG-MOPS-O2-NEXT:    ret
+entry:
+  %value_trunc = trunc i32 %value to i8
+  call void @llvm.memset.p0.i32(ptr align 1 %dst, i8 %value_trunc, i32 %size, i1 false)
+  ret void
+}
+
+define void @memcpy_n_i32(ptr %dst, ptr %src, i32 %size) {
+; GISel-WITHOUT-MOPS-O0-LABEL: memcpy_n_i32:
+; GISel-WITHOUT-MOPS-O0:       // %bb.0: // %entry
+; GISel-WITHOUT-MOPS-O0-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISel-WITHOUT-MOPS-O0-NEXT:    .cfi_def_cfa_offset 16
+; GISel-WITHOUT-MOPS-O0-NEXT:    .cfi_offset w30, -16
+; GISel-WITHOUT-MOPS-O0-NEXT:    mov w8, w2
+; GISel-WITHOUT-MOPS-O0-NEXT:    mov w2, w8
+; GISel-WITHOUT-MOPS-O0-NEXT:    bl memcpy
+; GISel-WITHOUT-MOPS-O0-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISel-WITHOUT-MOPS-O0-NEXT:    ret
+;
+; GISel-WITHOUT-MOPS-O3-LABEL: memcpy_n_i32:
+; GISel-WITHOUT-MOPS-O3:       // %bb.0: // %entry
+; GISel-WITHOUT-MOPS-O3-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISel-WITHOUT-MOPS-O3-NEXT:    .cfi_def_cfa_offset 16
+; GISel-WITHOUT-MOPS-O3-NEXT:    .cfi_offset w30, -16
+; GISel-WITHOUT-MOPS-O3-NEXT:    mov w2, w2
+; GISel-WITHOUT-MOPS-O3-NEXT:    bl memcpy
+; GISel-WITHOUT-MOPS-O3-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISel-WITHOUT-MOPS-O3-NEXT:    ret
+;
+; GISel-MOPS-O0-LABEL: memcpy_n_i32:
+; GISel-MOPS-O0:       // %bb.0: // %entry
+; GISel-MOPS-O0-NEXT:    mov w8, w2
+; GISel-MOPS-O0-NEXT:    // kill: def $x8 killed $w8
+; GISel-MOPS-O0-NEXT:    cpyfp [x0]!, [x1]!, x8!
+; GISel-MOPS-O0-NEXT:    cpyfm [x0]!, [x1]!, x8!
+; GISel-MOPS-O0-NEXT:    cpyfe [x0]!, [x1]!, x8!
+; GISel-MOPS-O0-NEXT:    ret
+;
+; GISel-MOPS-O3-LABEL: memcpy_n_i32:
+; GISel-MOPS-O3:       // %bb.0: // %entry
+; GISel-MOPS-O3-NEXT:    mov w8, w2
+; GISel-MOPS-O3-NEXT:    cpyfp [x0]!, [x1]!, x8!
+; GISel-MOPS-O3-NEXT:    cpyfm [x0]!, [x1]!, x8!
+; GISel-MOPS-O3-NEXT:    cpyfe [x0]!, [x1]!, x8!
+; GISel-MOPS-O3-NEXT:    ret
+;
+; SDAG-WITHOUT-MOPS-O2-LABEL: memcpy_n_i32:
+; SDAG-WITHOUT-MOPS-O2:       // %bb.0: // %entry
+; SDAG-WITHOUT-MOPS-O2-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; SDAG-WITHOUT-MOPS-O2-NEXT:    .cfi_def_cfa_offset 16
+; SDAG-WITHOUT-MOPS-O2-NEXT:    .cfi_offset w30, -16
+; SDAG-WITHOUT-MOPS-O2-NEXT:    mov w2, w2
+; SDAG-WITHOUT-MOPS-O2-NEXT:    bl memcpy
+; SDAG-WITHOUT-MOPS-O2-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; SDAG-WITHOUT-MOPS-O2-NEXT:    ret
+;
+; SDAG-MOPS-O2-LABEL: memcpy_n_i32:
+; SDAG-MOPS-O2:       // %bb.0: // %entry
+; SDAG-MOPS-O2-NEXT:    mov w8, w2
+; SDAG-MOPS-O2-NEXT:    cpyfp [x0]!, [x1]!, x8!
+; SDAG-MOPS-O2-NEXT:    cpyfm [x0]!, [x1]!, x8!
+; SDAG-MOPS-O2-NEXT:    cpyfe [x0]!, [x1]!, x8!
+; SDAG-MOPS-O2-NEXT:    ret
+entry:
+  call void @llvm.memcpy.p0.p0.i32(ptr align 1 %dst, ptr align 1 %src, i32 %size, i1 false)
+  ret void
+}
+
+define void @memmove_n_i32(ptr %dst, ptr %src, i32 %size) {
+; GISel-WITHOUT-MOPS-O0-LABEL: memmove_n_i32:
+; GISel-WITHOUT-MOPS-O0:       // %bb.0: // %entry
+; GISel-WITHOUT-MOPS-O0-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISel-WITHOUT-MOPS-O0-NEXT:    .cfi_def_cfa_offset 16
+; GISel-WITHOUT-MOPS-O0-NEXT:    .cfi_offset w30, -16
+; GISel-WITHOUT-MOPS-O0-NEXT:    mov w8, w2
+; GISel-WITHOUT-MOPS-O0-NEXT:    mov w2, w8
+; GISel-WITHOUT-MOPS-O0-NEXT:    bl memmove
+; GISel-WITHOUT-MOPS-O0-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISel-WITHOUT-MOPS-O0-NEXT:    ret
+;
+; GISel-WITHOUT-MOPS-O3-LABEL: memmove_n_i32:
+; GISel-WITHOUT-MOPS-O3:       // %bb.0: // %entry
+; GISel-WITHOUT-MOPS-O3-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISel-WITHOUT-MOPS-O3-NEXT:    .cfi_def_cfa_offset 16
+; GISel-WITHOUT-MOPS-O3-NEXT:    .cfi_offset w30, -16
+; GISel-WITHOUT-MOPS-O3-NEXT:    mov w2, w2
+; GISel-WITHOUT-MOPS-O3-NEXT:    bl memmove
+; GISel-WITHOUT-MOPS-O3-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISel-WITHOUT-MOPS-O3-NEXT:    ret
+;
+; GISel-MOPS-O0-LABEL: memmove_n_i32:
+; GISel-MOPS-O0:       // %bb.0: // %entry
+; GISel-MOPS-O0-NEXT:    mov w8, w2
+; GISel-MOPS-O0-NEXT:    // kill: def $x8 killed $w8
+; GISel-MOPS-O0-NEXT:    cpyp [x0]!, [x1]!, x8!
+; GISel-MOPS-O0-NEXT:    cpym [x0]!, [x1]!, x8!
+; GISel-MOPS-O0-NEXT:    cpye [x0]!, [x1]!, x8!
+; GISel-MOPS-O0-NEXT:    ret
+;
+; GISel-MOPS-O3-LABEL: memmove_n_i32:
+; GISel-MOPS-O3:       // %bb.0: // %entry
+; GISel-MOPS-O3-NEXT:    mov w8, w2
+; GISel-MOPS-O3-NEXT:    cpyp [x0]!, [x1]!, x8!
+; GISel-MOPS-O3-NEXT:    cpym [x0]!, [x1]!, x8!
+; GISel-MOPS-O3-NEXT:    cpye [x0]!, [x1]!, x8!
+; GISel-MOPS-O3-NEXT:    ret
+;
+; SDAG-WITHOUT-MOPS-O2-LABEL: memmove_n_i32:
+; SDAG-WITHOUT-MOPS-O2:       // %bb.0: // %entry
+; SDAG-WITHOUT-MOPS-O2-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; SDAG-WITHOUT-MOPS-O2-NEXT:    .cfi_def_cfa_offset 16
+; SDAG-WITHOUT-MOPS-O2-NEXT:    .cfi_offset w30, -16
+; SDAG-WITHOUT-MOPS-O2-NEXT:    mov w2, w2
+; SDAG-WITHOUT-MOPS-O2-NEXT:    bl memmove
+; SDAG-WITHOUT-MOPS-O2-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; SDAG-WITHOUT-MOPS-O2-NEXT:    ret
+;
+; SDAG-MOPS-O2-LABEL: memmove_n_i32:
+; SDAG-MOPS-O2:       // %bb.0: // %entry
+; SDAG-MOPS-O2-NEXT:    mov w8, w2
+; SDAG-MOPS-O2-NEXT:    cpyp [x0]!, [x1]!, x8!
+; SDAG-MOPS-O2-NEXT:    cpym [x0]!, [x1]!, x8!
+; SDAG-MOPS-O2-NEXT:    cpye [x0]!, [x1]!, x8!
+; SDAG-MOPS-O2-NEXT:    ret
+entry:
+  call void @llvm.memmove.p0.p0.i32(ptr align 1 %dst, ptr align 1 %src, i32 %size, i1 false)
+  ret void
+}
diff --git a/llvm/test/CodeGen/AArch64/func-argpassing.ll b/llvm/test/CodeGen/AArch64/func-argpassing.ll
index 9d10f6cb23583..d75aae86a1650 100644
--- a/llvm/test/CodeGen/AArch64/func-argpassing.ll
+++ b/llvm/test/CodeGen/AArch64/func-argpassing.ll
@@ -183,9 +183,9 @@ define dso_local void @check_i128_stackalign(i32 %val0, i32 %val1, i32 %val2, i3
 
 declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1)
 
-define dso_local i32 @test_extern() {
+define dso_local i32 @test_extern(ptr %dst, ptr %src, i32 %size) {
 ; CHECK-LABEL: test_extern:
-  call void @llvm.memcpy.p0.p0.i32(ptr align 4 undef, ptr align 4 undef, i32 undef, i1 0)
+  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %dst, ptr align 4 %src, i32 %size, i1 0)
 ; CHECK: bl memcpy
   ret i32 0
 }
diff --git a/llvm/test/CodeGen/AArch64/streaming-compatible-memory-ops.ll b/llvm/test/CodeGen/AArch64/streaming-compatible-memory-ops.ll
index 895271d8bfdc8..84916e0aae190 100644
--- a/llvm/test/CodeGen/AArch64/streaming-compatible-memory-ops.ll
+++ b/llvm/test/CodeGen/AArch64/streaming-compatible-memory-ops.ll
@@ -446,6 +446,162 @@ entry:
   ret void
 }
 
+define void @se_memcpy_i32(i32 %n) "aarch64_pstate_sm_enabled" nounwind {
+; CHECK-LABEL: se_memcpy_i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT:    adrp x8, :got:dst
+; CHECK-NEXT:    adrp x1, :got:src
+; CHECK-NEXT:    mov w2, w0
+; CHECK-NEXT:    ldr x8, [x8, :got_lo12:dst]
+; CHECK-NEXT:    ldr x1, [x1, :got_lo12:src]
+; CHECK-NEXT:    mov x0, x8
+; CHECK-NEXT:    bl __arm_sc_memcpy
+; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT:    ret
+;
+; CHECK-NO-SME-ROUTINES-LABEL: se_memcpy_i32:
+; CHECK-NO-SME-ROUTINES:       // %bb.0: // %entry
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d15, d14, [sp, #-80]! // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d13, d12, [sp, #16] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    adrp x8, :got:dst
+; CHECK-NO-SME-ROUTINES-NEXT:    adrp x1, :got:src
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d11, d10, [sp, #32] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    mov w2, w0
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d9, d8, [sp, #48] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    str x30, [sp, #64] // 8-byte Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    ldr x8, [x8, :got_lo12:dst]
+; CHECK-NO-SME-ROUTINES-NEXT:    ldr x1, [x1, :got_lo12:src]
+; CHECK-NO-SME-ROUTINES-NEXT:    smstop sm
+; CHECK-NO-SME-ROUTINES-NEXT:    mov x0, x8
+; CHECK-NO-SME-ROUTINES-NEXT:    bl memcpy
+; CHECK-NO-SME-ROUTINES-NEXT:    smstart sm
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d9, d8, [sp, #48] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldr x30, [sp, #64] // 8-byte Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d11, d10, [sp, #32] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d13, d12, [sp, #16] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d15, d14, [sp], #80 // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ret
+;
+; CHECK-MOPS-LABEL: se_memcpy_i32:
+; CHECK-MOPS:       // %bb.0: // %entry
+; CHECK-MOPS-NEXT:    adrp x8, :got:src
+; CHECK-MOPS-NEXT:    adrp x9, :got:dst
+; CHECK-MOPS-NEXT:    mov w10, w0
+; CHECK-MOPS-NEXT:    ldr x8, [x8, :got_lo12:src]
+; CHECK-MOPS-NEXT:    ldr x9, [x9, :got_lo12:dst]
+; CHECK-MOPS-NEXT:    cpyfp [x9]!, [x8]!, x10!
+; CHECK-MOPS-NEXT:    cpyfm [x9]!, [x8]!, x10!
+; CHECK-MOPS-NEXT:    cpyfe [x9]!, [x8]!, x10!
+; CHECK-MOPS-NEXT:    ret
+entry:
+  tail call void @llvm.memcpy.p0.p0.i32(ptr align 1 @dst, ptr nonnull align 1 @src, i32 %n, i1 false)
+  ret void
+}
+
+define void @se_memset_i32(i32 %n) "aarch64_pstate_sm_enabled" nounwind {
+; CHECK-LABEL: se_memset_i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT:    adrp x8, :got:dst
+; CHECK-NEXT:    mov w2, w0
+; CHECK-NEXT:    mov w1, #2 // =0x2
+; CHECK-NEXT:    ldr x8, [x8, :got_lo12:dst]
+; CHECK-NEXT:    mov x0, x8
+; CHECK-NEXT:    bl __arm_sc_memset
+; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT:    ret
+;
+; CHECK-NO-SME-ROUTINES-LABEL: se_memset_i32:
+; CHECK-NO-SME-ROUTINES:       // %bb.0: // %entry
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d15, d14, [sp, #-80]! // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d13, d12, [sp, #16] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    adrp x8, :got:dst
+; CHECK-NO-SME-ROUTINES-NEXT:    mov w2, w0
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d11, d10, [sp, #32] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d9, d8, [sp, #48] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    str x30, [sp, #64] // 8-byte Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    ldr x8, [x8, :got_lo12:dst]
+; CHECK-NO-SME-ROUTINES-NEXT:    smstop sm
+; CHECK-NO-SME-ROUTINES-NEXT:    mov x0, x8
+; CHECK-NO-SME-ROUTINES-NEXT:    mov w1, #2 // =0x2
+; CHECK-NO-SME-ROUTINES-NEXT:    bl memset
+; CHECK-NO-SME-ROUTINES-NEXT:    smstart sm
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d9, d8, [sp, #48] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldr x30, [sp, #64] // 8-byte Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d11, d10, [sp, #32] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d13, d12, [sp, #16] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d15, d14, [sp], #80 // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ret
+;
+; CHECK-MOPS-LABEL: se_memset_i32:
+; CHECK-MOPS:       // %bb.0: // %entry
+; CHECK-MOPS-NEXT:    adrp x8, :got:dst
+; CHECK-MOPS-NEXT:    mov w9, w0
+; CHECK-MOPS-NEXT:    mov w10, #2 // =0x2
+; CHECK-MOPS-NEXT:    ldr x8, [x8, :got_lo12:dst]
+; CHECK-MOPS-NEXT:    setp [x8]!, x9!, x10
+; CHECK-MOPS-NEXT:    setm [x8]!, x9!, x10
+; CHECK-MOPS-NEXT:    sete [x8]!, x9!, x10
+; CHECK-MOPS-NEXT:    ret
+entry:
+  tail call void @llvm.memset.p0.i32(ptr align 1 @dst, i8 2, i32 %n, i1 false)
+  ret void
+}
+
+define void @se_memmove_i32(i32 %n) "aarch64_pstate_sm_enabled" nounwind {
+; CHECK-LABEL: se_memmove_i32:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT:    adrp x8, :got:dst
+; CHECK-NEXT:    adrp x1, :got:src
+; CHECK-NEXT:    mov w2, w0
+; CHECK-NEXT:    ldr x8, [x8, :got_lo12:dst]
+; CHECK-NEXT:    ldr x1, [x1, :got_lo12:src]
+; CHECK-NEXT:    mov x0, x8
+; CHECK-NEXT:    bl __arm_sc_memmove
+; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT:    ret
+;
+; CHECK-NO-SME-ROUTINES-LABEL: se_memmove_i32:
+; CHECK-NO-SME-ROUTINES:       // %bb.0: // %entry
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d15, d14, [sp, #-80]! // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d13, d12, [sp, #16] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    adrp x8, :got:dst
+; CHECK-NO-SME-ROUTINES-NEXT:    adrp x1, :got:src
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d11, d10, [sp, #32] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    mov w2, w0
+; CHECK-NO-SME-ROUTINES-NEXT:    stp d9, d8, [sp, #48] // 16-byte Folded Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    str x30, [sp, #64] // 8-byte Spill
+; CHECK-NO-SME-ROUTINES-NEXT:    ldr x8, [x8, :got_lo12:dst]
+; CHECK-NO-SME-ROUTINES-NEXT:    ldr x1, [x1, :got_lo12:src]
+; CHECK-NO-SME-ROUTINES-NEXT:    smstop sm
+; CHECK-NO-SME-ROUTINES-NEXT:    mov x0, x8
+; CHECK-NO-SME-ROUTINES-NEXT:    bl memmove
+; CHECK-NO-SME-ROUTINES-NEXT:    smstart sm
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d9, d8, [sp, #48] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldr x30, [sp, #64] // 8-byte Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d11, d10, [sp, #32] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d13, d12, [sp, #16] // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ldp d15, d14, [sp], #80 // 16-byte Folded Reload
+; CHECK-NO-SME-ROUTINES-NEXT:    ret
+;
+; CHECK-MOPS-LABEL: se_memmove_i32:
+; CHECK-MOPS:       // %bb.0: // %entry
+; CHECK-MOPS-NEXT:    adrp x8, :got:src
+; CHECK-MOPS-NEXT:    adrp x9, :got:dst
+; CHECK-MOPS-NEXT:    mov w10, w0
+; CHECK-MOPS-NEXT:    ldr x8, [x8, :got_lo12:src]
+; CHECK-MOPS-NEXT:    ldr x9, [x9, :got_lo12:dst]
+; CHECK-MOPS-NEXT:    cpyp [x9]!, [x8]!, x10!
+; CHECK-MOPS-NEXT:    cpym [x9]!, [x8]!, x10!
+; CHECK-MOPS-NEXT:    cpye [x9]!, [x8]!, x10!
+; CHECK-MOPS-NEXT:    ret
+entry:
+  tail call void @llvm.memmove.p0.p0.i32(ptr align 1 @dst, ptr nonnull align 1 @src, i32 %n, i1 false)
+  ret void
+}
+
 declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg)
 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1 immarg)
 declare void @llvm.memmove.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1 immarg)
diff --git a/llvm/test/CodeGen/RISCV/memcpy.ll b/llvm/test/CodeGen/RISCV/memcpy.ll
index 859d1039527ce..e2b1d0a6957a1 100644
--- a/llvm/test/CodeGen/RISCV/memcpy.ll
+++ b/llvm/test/CodeGen/RISCV/memcpy.ll
@@ -8,9 +8,9 @@
 ; RUN: llc < %s -mtriple=riscv32 -mcpu=andes-a45 -mtune=rocket \
 ; RUN:   | FileCheck %s --check-prefixes=RV32-BOTH,RV32-FAST
 ; RUN: llc < %s -mtriple=riscv64 -mattr=+unaligned-scalar-mem \
-; RUN:   | FileCheck %s --check-prefixes=RV64-BOTH,RV64-FAST
+; RUN:   | FileCheck %s --check-prefixes=RV64-BOTH,RV64-FAST,RV64-UNALIGNED
 ; RUN: llc < %s -mtriple=riscv64 -mcpu=andes-ax45 -mtune=rocket \
-; RUN:   | FileCheck %s --check-prefixes=RV64-BOTH,RV64-FAST
+; RUN:   | FileCheck %s --check-prefixes=RV64-BOTH,RV64-FAST,RV64-ANDES
 
 ; ----------------------------------------------------------------------
 ; Fully unaligned cases
@@ -768,3 +768,97 @@ entry:
   ret i32 0
 }
 
+define void @memcpy_i32_var(ptr %de...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/226672


More information about the llvm-commits mailing list