[llvm] [MemCpyOpt] Forward `memcpy` based on the actual copy memory location. (PR #87190)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 9 07:50:08 PDT 2024
================
@@ -0,0 +1,205 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=memcpyopt -S -verify-memoryssa | FileCheck %s
+
+%buf = type [9 x i8]
+
+; We can forward `memcpy` because the copy location are the same,
+define void @forward_offset(ptr %src, ptr %dest) {
+; CHECK-LABEL: define void @forward_offset(
+; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {
+; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 1 [[SRC]], i64 7, i1 false)
+; CHECK-NEXT: [[SRC_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 1
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 1
+; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 6, i1 false)
+; CHECK-NEXT: ret void
+;
+ %cpy_tmp = alloca %buf, align 1
+ call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 1 %src, i64 7, i1 false)
+ %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 1
+ call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)
+ ret void
+}
+
+; We need to update the align value of the source of `memcpy` when forwarding.
+define void @forward_offset_align(ptr %src, ptr %dest) {
+; CHECK-LABEL: define void @forward_offset_align(
+; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {
+; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 4 [[SRC]], i64 9, i1 false)
+; CHECK-NEXT: [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 3
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 3
+; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 1 [[TMP1]], i64 5, i1 false)
+; CHECK-NEXT: ret void
+;
+ %cpy_tmp = alloca %buf, align 1
+ call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 4 %src, i64 9, i1 false)
+ %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 3
+ call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 5, i1 false)
+ ret void
+}
+
+; We can change the align value to 2 when forwarding.
+define void @forward_offset_align_2(ptr %src, ptr %dest) {
+; CHECK-LABEL: define void @forward_offset_align_2(
+; CHECK-SAME: ptr [[SRC:%.*]], ptr [[DEST:%.*]]) {
+; CHECK-NEXT: [[DEP_DEST:%.*]] = alloca [9 x i8], align 1
+; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 [[DEP_DEST]], ptr align 4 [[SRC]], i64 9, i1 false)
+; CHECK-NEXT: [[TMP_OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DEP_DEST]], i64 2
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i64 2
+; CHECK-NEXT: call void @llvm.memmove.p0.p0.i64(ptr align 1 [[DEST]], ptr align 2 [[TMP1]], i64 6, i1 false)
+; CHECK-NEXT: ret void
+;
+ %cpy_tmp = alloca %buf, align 1
+ call void @llvm.memcpy.p0.p0.i64(ptr align 1 %cpy_tmp, ptr align 4 %src, i64 9, i1 false)
+ %cpy_tmp_offset = getelementptr inbounds i8, ptr %cpy_tmp, i64 2
+ call void @llvm.memcpy.p0.p0.i64(ptr align 1 %dest, ptr align 1 %cpy_tmp_offset, i64 6, i1 false)
+ ret void
+}
+
+; If the copy destination can be used as the copy source, we don't need to create a GEP instruction.
+; FIXME: We can directly remove memcpy here.
----------------
DianQK wrote:
This introduces a new scenario similar to https://llvm.godbolt.org/z/obo4j4G6x, where the copy source and destination are the same. I can address it in this PR or in the next one.
https://github.com/llvm/llvm-project/pull/87190
More information about the llvm-commits
mailing list