https://github.com/Fznamznon created 
https://github.com/llvm/llvm-project/pull/225845

These previously were lowered to a call to undefined memcpy function which 
caused link failures when compiled for AMDGPU since there it is never resolved 
to a library function.
cir.libc.memcpy is later lowered to llvm.memcpy intrinsic call which matches 
classic codegen.
This also adds alignment attributes to cir.libc.memcpy op so resulting LLVM IR 
also has them just like LLVM IR produced by the classic codegen

Assisted by: claude

>From 982af9a0559d051054316f3952db567c6465c8ae Mon Sep 17 00:00:00 2001
From: Mariya Podchishchaeva <[email protected]>
Date: Wed, 23 Sep 2026 11:27:56 -0500
Subject: [PATCH] [CIR] Lower __builtin_memcpy/mempcpy to cir.libc.memcpy

These previously were lowered to a call to undefined memcpy function
which caused link failures when compiled for AMDGPU since there it
is never resolved to a library function.
cir.libc.memcpy is later lowered to llvm.memcpy intrinsic call which
matches classic codegen.
This also adds alignment attributes to cir.libc.memcpy op so resulting
LLVM IR also has them just like LLVM IR produced by the classic codegen

Assisted by: claude
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  9 ++-
 clang/lib/CIR/CodeGen/CIRGenAtomic.cpp        |  2 +-
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         |  9 ++-
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       | 19 ++++-
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp |  3 +-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 ++++-
 clang/test/CIR/CodeGen/assign-operator.cpp    |  5 +-
 clang/test/CIR/CodeGen/atomic.c               |  4 +-
 clang/test/CIR/CodeGen/builtin-memcpy.c       | 74 +++++++++++++++++++
 clang/test/CIR/CodeGen/libc.c                 |  9 ++-
 .../CodeGen/union-copy-move-assignment.cpp    | 19 ++---
 .../CIR/CodeGenBuiltins/builtin-bit-cast.cpp  |  8 +-
 12 files changed, 146 insertions(+), 33 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/builtin-memcpy.c

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index f6b524176a6559..825a13e344a4ea 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5232,10 +5232,15 @@ def CIR_MemCpyOp : CIR_MemOp<"libc.memcpy"> {
     ```
   }];
 
-  let arguments = !con(commonArgs, (ins CIR_AnyFundamentalUIntType:$len));
+  let arguments = !con(commonArgs, (ins
+    CIR_AnyFundamentalUIntType:$len,
+    OptionalAttr<I64Attr>:$dst_alignment,
+    OptionalAttr<I64Attr>:$src_alignment
+  ));
 
   let assemblyFormat = [{
-    $len `bytes` `from` $src `to` $dst attr-dict
+    $len `bytes` `from` $src (`align` `(` $src_alignment^ `)`)?
+    `to` $dst (`align` `(` $dst_alignment^ `)`)? attr-dict
     `:` type($len) `,` qualified(type($src)) `->` qualified(type($dst))
   }];
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp 
b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index c4c3b455bf11cd..e89be4fc60975c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -216,7 +216,7 @@ Address AtomicInfo::convertToAtomicIntPointer(Address addr,
 
     tmp = tmp.withElementType(builder, cgf.cgm.voidTy);
     builder.createMemCpy(
-        loc, tmp.getPointer(), addr.getPointer(),
+        loc, tmp, addr,
         builder.getConstInt(loc, cgf.cgm.uInt64Ty,
                             std::min(atomicSizeInBits, sourceSizeInBits) / 8));
     addr = tmp;
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h 
b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 91e3b18a6b3155..01d74e1549fa53 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -195,9 +195,12 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     return op;
   }
 
-  cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst,
-                             mlir::Value src, mlir::Value len) {
-    return cir::MemCpyOp::create(*this, loc, dst, src, len);
+  cir::MemCpyOp createMemCpy(mlir::Location loc, Address dst, Address src,
+                             mlir::Value len) {
+    return cir::MemCpyOp::create(
+        *this, loc, dst.getPointer(), src.getPointer(), len,
+        getI64IntegerAttr(dst.getAlignment().getQuantity()),
+        getI64IntegerAttr(src.getAlignment().getQuantity()));
   }
 
   cir::MemMoveOp createMemMove(mlir::Location loc, mlir::Value dst,
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index f86385c7330443..4dc9783202305c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -2376,7 +2376,24 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
   case Builtin::BImemcpy:
   case Builtin::BI__builtin_memcpy:
   case Builtin::BImempcpy:
-  case Builtin::BI__builtin_mempcpy:
+  case Builtin::BI__builtin_mempcpy: {
+    mlir::Location loc = getLoc(e->getSourceRange());
+    Address dest = emitPointerWithAlignment(e->getArg(0));
+    Address src = emitPointerWithAlignment(e->getArg(1));
+    mlir::Value sizeVal = emitScalarExpr(e->getArg(2));
+    Address destCast = dest.withElementType(builder, cgm.voidTy);
+    Address srcCast = src.withElementType(builder, cgm.voidTy);
+    assert(!cir::MissingFeatures::sanitizers());
+    builder.createMemCpy(loc, destCast, srcCast, sizeVal);
+    if (builtinID == Builtin::BImempcpy ||
+        builtinID == Builtin::BI__builtin_mempcpy) {
+      mlir::Value destPtr = destCast.getPointer();
+      mlir::Value end =
+          builder.createPtrStride(loc, destPtr, sizeVal);
+      return RValue::get(end);
+    }
+    return RValue::get(dest.getPointer());
+  }
   case Builtin::BI__builtin_memcpy_inline:
   case Builtin::BI__builtin___memcpy_chk:
   case Builtin::BI__builtin_objc_memmove_collectable:
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index f9a4eb2b2033a2..e098090bd3bc72 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -208,8 +208,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
       mlir::Value sizeVal = cgf.getBuilder().getConstInt(
           loc, cgf.sizeTy,
           cgf.getContext().getTypeSizeInChars(e->getType()).getQuantity());
-      cgf.getBuilder().createMemCpy(loc, destAddress.getPointer(),
-                                    sourceAddress.getPointer(), sizeVal);
+      cgf.getBuilder().createMemCpy(loc, destAddress, sourceAddress, sizeVal);
 
       break;
     }
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 1b1423862ba7bb..576c0224babfc9 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -324,9 +324,25 @@ mlir::LogicalResult 
CIRToLLVMCopyOpLowering::matchAndRewrite(
 mlir::LogicalResult CIRToLLVMMemCpyOpLowering::matchAndRewrite(
     cir::MemCpyOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
+  mlir::ArrayAttr argAttrs;
+  if (op.getDstAlignment() || op.getSrcAlignment()) {
+    mlir::NamedAttribute dstAlignAttr = rewriter.getNamedAttr(
+        mlir::LLVM::LLVMDialect::getAlignAttrName(),
+        rewriter.getI64IntegerAttr(op.getDstAlignment().value_or(1)));
+    mlir::NamedAttribute srcAlignAttr = rewriter.getNamedAttr(
+        mlir::LLVM::LLVMDialect::getAlignAttrName(),
+        rewriter.getI64IntegerAttr(op.getSrcAlignment().value_or(1)));
+    argAttrs = rewriter.getArrayAttr({
+        /*dst_attrs=*/rewriter.getDictionaryAttr({dstAlignAttr}),
+        /*src_attrs=*/rewriter.getDictionaryAttr({srcAlignAttr}),
+    });
+  }
   rewriter.replaceOpWithNewOp<mlir::LLVM::MemcpyOp>(
       op, adaptor.getDst(), adaptor.getSrc(), adaptor.getLen(),
-      /*isVolatile=*/false);
+      /*isVolatile=*/false,
+      /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
+      /*noalias_scopes=*/nullptr, /*tbaa=*/nullptr, /*arg_attrs=*/argAttrs,
+      /*res_attrs=*/nullptr);
   return mlir::success();
 }
 
diff --git a/clang/test/CIR/CodeGen/assign-operator.cpp 
b/clang/test/CIR/CodeGen/assign-operator.cpp
index e01572198d6085..5a874746ccb73d 100644
--- a/clang/test/CIR/CodeGen/assign-operator.cpp
+++ b/clang/test/CIR/CodeGen/assign-operator.cpp
@@ -85,7 +85,7 @@ void copy_c(C &c1, C &c2) {
 // CIR:   %[[B_MEMBER_2:.*]] = cir.get_member %[[RET_LOAD]][1] {name = "b"}
 // CIR:   %[[B_VOID_PTR_2:.*]] = cir.cast bitcast %[[B_MEMBER_2]] : 
!cir.ptr<!cir.array<!rec_B x 16>> -> !cir.ptr<!void>
 // CIR:   %[[SIZE:.*]] = cir.const #cir.int<64> : !u64i
-// CIR:   %[[COUNT:.*]] = cir.call @memcpy(%[[B_VOID_PTR]], %[[B_VOID_PTR_2]], 
%[[SIZE]])
+// CIR:   cir.libc.memcpy %[[SIZE]] bytes from %[[B_VOID_PTR_2]] align(4) to 
%[[B_VOID_PTR]] align(4)
 // CIR:   cir.store %[[THIS]], %[[RET_ADDR]]
 // CIR:   %[[RET_VAL:.*]] = cir.load{{.*}} %[[RET_ADDR]]
 // CIR:   cir.return %[[RET_VAL]]
@@ -101,7 +101,7 @@ void copy_c(C &c1, C &c2) {
 // LLVM:   %[[B1:.*]] = getelementptr inbounds nuw %struct.C, ptr 
%[[THIS_LOAD]], i32 0, i32 1
 // LLVM:   %[[ARG_LOAD2:.*]] = load ptr, ptr %[[ARG_ADDR]]
 // LLVM:   %[[B2:.*]] = getelementptr inbounds nuw %struct.C, ptr 
%[[ARG_LOAD2]], i32 0, i32 1
-// LLVM:   %{{.*}} = call ptr @memcpy(ptr {{.*}} %[[B1]], ptr {{.*}} %[[B2]], 
i64 {{.*}} 64)
+// LLVM:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[B1]], ptr align 4 
%[[B2]], i64 64, i1 false)
 
 // OGCG: define {{.*}} ptr @_ZN1CaSERKS_(ptr {{.*}} %[[THIS:.*]], ptr {{.*}} 
%[[ARG:.*]])
 // OGCG:   %[[THIS_ADDR:.*]] = alloca ptr
@@ -144,7 +144,6 @@ void copy_ref_to_ref(E &e1, E &e2) {
 // CIR:   cir.return
 
 // CIR: cir.func private @_ZN1AaSERKS_(!cir.ptr<!rec_A> {{.*}}, 
!cir.ptr<!rec_A> {{.*}}) -> (!cir.ptr<!rec_A>{{.*}})
-// CIR: cir.func private @memcpy(!cir.ptr<!void> {{.*}}, !cir.ptr<!void> 
{{.*}}, !u64i {{.*}}) -> !cir.ptr<!void>
 
 // LLVM: define{{.*}} void @_Z15copy_ref_to_refR1ES0_(ptr{{.*}} %[[ARG0:.*]], 
ptr{{.*}} %[[ARG1:.*]]){{.*}} {
 // LLVM:   %[[E1_ADDR:.*]] = alloca ptr
diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
index f3913ea28072eb..28fe01e83ed657 100644
--- a/clang/test/CIR/CodeGen/atomic.c
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -3991,7 +3991,7 @@ void store_atomic_different_size(S a) {
  // CIR: cir.libc.memset %[[MEMSET_SIZE]] bytes at %[[A_VOID_PTR]] {{.*}} to 
%[[CONST_0]] : !cir.ptr<!void>, !u8i, !u64i
  // CIR: %[[ATOMIC_TMP:.*]] = cir.cast bitcast %[[ATOMIC_TMP_ADDR]] : 
!cir.ptr<!rec_anon_struct1> -> !cir.ptr<!void>
  // CIR: %[[MEMCPY_SIZE:.*]] = cir.const #cir.int<3> : !u64i
- // CIR: cir.libc.memcpy %[[MEMCPY_SIZE]] bytes from %[[A_VOID_PTR]] to 
%[[ATOMIC_TMP]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+ // CIR: cir.libc.memcpy %[[MEMCPY_SIZE]] bytes from %[[A_VOID_PTR]] align(1) 
to %[[ATOMIC_TMP]] align(4) : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
  // CIR: %[[ATOMIC_TMP_U32:.*]] = cir.cast bitcast %[[ATOMIC_TMP]] : 
!cir.ptr<!void> -> !cir.ptr<!u32i>
  // CIR: %[[DATA:.*]] = cir.load {{.*}} %[[ATOMIC_TMP_U32]] : !cir.ptr<!u32i>, 
!u32i
  // CIR: cir.store {{.*}} syncscope(system) atomic(seq_cst) %[[DATA]], 
%[[B_VOID_PTR]] : !u32i, !cir.ptr<!u32i>
@@ -4006,7 +4006,7 @@ void store_atomic_different_size(S a) {
  // LLVM: store %struct.S %[[A]], ptr %[[A_ADDR]], align 1
  // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[A_ATOMIC_TMP_ADDR]], 
ptr align 1 %[[A_ADDR]], i64 3, i1 false)
  // LLVM: call void @llvm.memset.p0.i64(ptr align 1 %[[A_ATOMIC_TMP_ADDR]], i8 
0, i64 4, i1 false)
- // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[ATOMIC_TMP_ADDR]], ptr 
%[[A_ATOMIC_TMP_ADDR]], i64 3, i1 false)
+ // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ATOMIC_TMP_ADDR]], 
ptr align 1 %[[A_ATOMIC_TMP_ADDR]], i64 3, i1 false)
  // LLVM: %[[ATOMIC_TMP:.*]] = load i32, ptr %[[ATOMIC_TMP_ADDR]], align 4
  // LLVM: store atomic i32 %[[ATOMIC_TMP]], ptr %[[B_ADDR]] seq_cst, align 4
 
diff --git a/clang/test/CIR/CodeGen/builtin-memcpy.c 
b/clang/test/CIR/CodeGen/builtin-memcpy.c
new file mode 100644
index 00000000000000..4e3853a8f711a9
--- /dev/null
+++ b/clang/test/CIR/CodeGen/builtin-memcpy.c
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -o - 
%s | FileCheck %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -o - 
%s | FileCheck %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | 
FileCheck %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fclangir -emit-cir -o - %s | 
FileCheck %s --check-prefix=CIR
+// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fclangir -emit-llvm -o - %s | 
FileCheck %s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm -o - %s | FileCheck %s 
--check-prefix=LLVM
+
+typedef unsigned long size_t;
+
+void test_memcpy(void *dst, const void *src, size_t n) {
+  __builtin_memcpy(dst, src, n);
+}
+
+// CIR-LABEL: cir.func no_inline dso_local @test_memcpy
+// CIR:         %[[DST:.*]] = cir.load align(8) %{{.*}} : 
!cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR-NEXT:    %[[SRC:.*]] = cir.load align(8) %{{.*}} : 
!cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR-NEXT:    %[[N:.*]] = cir.load align(8) %{{.*}} : !cir.ptr<!u64i>, !u64i
+// CIR-NEXT:    cir.libc.memcpy %[[N]] bytes from %[[SRC]] align(1) to 
%[[DST]] align(1) : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+
+// LLVM-LABEL: define dso_local void @test_memcpy
+// LLVM:         call void @llvm.memcpy.p0.p0.i64(ptr align 1 %{{.*}}, ptr 
align 1 %{{.*}}, i64 %{{.*}}, i1 false)
+
+void *test_memcpy_ret(void *dst, const void *src, size_t n) {
+  return __builtin_memcpy(dst, src, n);
+}
+
+// CIR-LABEL: cir.func no_inline dso_local @test_memcpy_ret
+// CIR:         %[[DST:.*]] = cir.load align(8) %{{.*}} : 
!cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR-NEXT:    %[[SRC:.*]] = cir.load align(8) %{{.*}} : 
!cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR-NEXT:    %[[N:.*]] = cir.load align(8) %{{.*}} : !cir.ptr<!u64i>, !u64i
+// CIR-NEXT:    cir.libc.memcpy %[[N]] bytes from %[[SRC]] align(1) to 
%[[DST]] align(1) : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+// CIR:         cir.return %{{.*}} : !cir.ptr<!void>
+
+// LLVM-LABEL: define dso_local ptr @test_memcpy_ret
+// LLVM:         call void @llvm.memcpy.p0.p0.i64(ptr align 1 %{{.*}}, ptr 
align 1 %{{.*}}, i64 %{{.*}}, i1 false)
+// LLVM:         ret ptr %{{.*}}
+
+void test_memcpy_int(int *dst, const int *src, size_t n) {
+  __builtin_memcpy(dst, src, n);
+}
+
+// CIR-LABEL: cir.func no_inline dso_local @test_memcpy_int
+// CIR:         %[[DST_I:.*]] = cir.load align(8) %{{.*}} : 
!cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR-NEXT:    %[[DST:.*]] = cir.cast bitcast %[[DST_I]] : !cir.ptr<!s32i> -> 
!cir.ptr<!void>
+// CIR-NEXT:    %[[SRC_I:.*]] = cir.load align(8) %{{.*}} : 
!cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+// CIR-NEXT:    %[[SRC:.*]] = cir.cast bitcast %[[SRC_I]] : !cir.ptr<!s32i> -> 
!cir.ptr<!void>
+// CIR-NEXT:    %[[N:.*]] = cir.load align(8) %{{.*}} : !cir.ptr<!u64i>, !u64i
+// CIR-NEXT:    cir.libc.memcpy %[[N]] bytes from %[[SRC]] align(4) to 
%[[DST]] align(4) : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+
+// LLVM-LABEL: define dso_local void @test_memcpy_int
+// LLVM:         %[[DST:.*]] = load ptr, ptr %{{.*}}, align 8
+// LLVM-NEXT:    %[[SRC:.*]] = load ptr, ptr %{{.*}}, align 8
+// LLVM-NEXT:    %[[N:.*]] = load i64, ptr %{{.*}}, align 8
+// LLVM-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[DST]], ptr 
align 4 %[[SRC]], i64 %[[N]], i1 false)
+
+void *test_mempcpy(void *dst, const void *src, size_t n) {
+  return __builtin_mempcpy(dst, src, n);
+}
+
+// CIR-LABEL: cir.func no_inline dso_local @test_mempcpy
+// CIR:         %[[DST:.*]] = cir.load align(8) %{{.*}} : 
!cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR-NEXT:    %[[SRC:.*]] = cir.load align(8) %{{.*}} : 
!cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR-NEXT:    %[[N:.*]] = cir.load align(8) %{{.*}} : !cir.ptr<!u64i>, !u64i
+// CIR-NEXT:    cir.libc.memcpy %[[N]] bytes from %[[SRC]] align(1) to 
%[[DST]] align(1) : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+// CIR-NEXT:    %[[END:.*]] = cir.ptr_stride %[[DST]], %[[N]] : 
(!cir.ptr<!void>, !u64i) -> !cir.ptr<!void>
+// CIR:         cir.return %{{.*}} : !cir.ptr<!void>
+
+// LLVM-LABEL: define dso_local ptr @test_mempcpy
+// LLVM:         %[[DST:.*]] = load ptr, ptr %{{.*}}, align 8
+// LLVM-NEXT:    %[[SRC:.*]] = load ptr, ptr %{{.*}}, align 8
+// LLVM-NEXT:    %[[N:.*]] = load i64, ptr %{{.*}}, align 8
+// LLVM-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[DST]], ptr 
align 1 %[[SRC]], i64 %[[N]], i1 false)
+// LLVM-NEXT:    getelementptr{{.*}} i8, ptr %[[DST]], i64 %[[N]]
+// Note: OG emits getelementptr inbounds; CIR omits inbounds (missing feature 
in cir.ptr_stride lowering).
diff --git a/clang/test/CIR/CodeGen/libc.c b/clang/test/CIR/CodeGen/libc.c
index e20cdc3dfbbf5d..1ea383b1559d2a 100644
--- a/clang/test/CIR/CodeGen/libc.c
+++ b/clang/test/CIR/CodeGen/libc.c
@@ -20,7 +20,14 @@
 void *memcpy(void *, const void *, unsigned long);
 void testMemcpy(void *dst, const void *src, unsigned long size) {
   memcpy(dst, src, size);
-  // CHECK: cir.call @memcpy
+  // CHECK: cir.libc.memcpy
+}
+
+void *mempcpy(void *, const void *, unsigned long);
+void *testMempcpy(void *dst, const void *src, unsigned long size) {
+  return mempcpy(dst, src, size);
+  // CHECK: cir.libc.memcpy
+  // CHECK: cir.ptr_stride
 }
 
 void *memmove(void *, const void *, unsigned long);
diff --git a/clang/test/CIR/CodeGen/union-copy-move-assignment.cpp 
b/clang/test/CIR/CodeGen/union-copy-move-assignment.cpp
index aeb3461990e5c3..cd68e2cacba8c9 100644
--- a/clang/test/CIR/CodeGen/union-copy-move-assignment.cpp
+++ b/clang/test/CIR/CodeGen/union-copy-move-assignment.cpp
@@ -1,9 +1,9 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
 // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
-// RUN: FileCheck --check-prefixes=LLVM,LLVMCIR --input-file=%t-cir.ll %s
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
-// RUN: FileCheck --check-prefixes=LLVM,OGCG --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
 
 union U {
   int a;
@@ -16,18 +16,11 @@ auto get_copy = static_cast<U &(U::*)(const U 
&)>(&U::operator=);
 auto get_move = static_cast<U &(U::*)(U &&)>(&U::operator=);
 
 // CIR: cir.func{{.*}}@_ZN1UaSERKS_{{.*}}cxx_assign<!rec_U, copy, trivial true>
-// CIR:   cir.call @memcpy(
+// CIR:   cir.libc.memcpy {{.*}} align(4) to {{.*}} align(4)
 // CIR: cir.func{{.*}}@_ZN1UaSEOS_{{.*}}cxx_assign<!rec_U, move, trivial true>
-// CIR:   cir.call @memcpy(
-
-// The CIR backend calls the memcpy libcall where the classic backend emits the
-// llvm.memcpy intrinsic.
+// CIR:   cir.libc.memcpy {{.*}} align(4) to {{.*}} align(4)
 
 // LLVM: define linkonce_odr noundef nonnull align 4 dereferenceable(4) ptr 
@_ZN1UaSERKS_(ptr noundef nonnull align 4 dereferenceable(4) %{{.+}}, ptr 
noundef nonnull align 4 dereferenceable(4) %{{.+}})
-// LLVMCIR:     call ptr @memcpy(ptr noundef %{{.+}}, ptr noundef %{{.+}}, i64 
noundef 4)
-// LLVMCIR-NOT: call ptr @memcpy
-// OGCG:        call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr 
align 4 %{{.+}}, i64 4, i1 false)
-// OGCG-NOT:    call void @llvm.memcpy
+// LLVM:        call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr 
align 4 %{{.+}}, i64 4, i1 false)
 // LLVM: define linkonce_odr noundef nonnull align 4 dereferenceable(4) ptr 
@_ZN1UaSEOS_(ptr noundef nonnull align 4 dereferenceable(4) %{{.+}}, ptr 
noundef nonnull align 4 dereferenceable(4) %{{.+}})
-// LLVMCIR:     call ptr @memcpy(ptr noundef %{{.+}}, ptr noundef %{{.+}}, i64 
noundef 4)
-// OGCG:        call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr 
align 4 %{{.+}}, i64 4, i1 false)
+// LLVM:        call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.+}}, ptr 
align 4 %{{.+}}, i64 4, i1 false)
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-bit-cast.cpp 
b/clang/test/CIR/CodeGenBuiltins/builtin-bit-cast.cpp
index 24eb7211551bf9..26ad0deb9c373e 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-bit-cast.cpp
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-bit-cast.cpp
@@ -58,7 +58,7 @@ two_floats test_aggregate_record(two_ints& ti) {
 //  CIR-NEXT:   %[[#SRC_VOID_PTR:]] = cir.cast bitcast %[[#SRC_PTR]] : 
!cir.ptr<!rec_two_ints> -> !cir.ptr<!void>
 //  CIR-NEXT:   %[[#DST_VOID_PTR:]] = cir.cast bitcast %{{.+}} : 
!cir.ptr<!rec_two_floats> -> !cir.ptr<!void>
 //  CIR-NEXT:   %[[#SIZE:]] = cir.const #cir.int<8> : !u64i
-//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] to 
%[[#DST_VOID_PTR]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] 
align(4) to %[[#DST_VOID_PTR]] align(4) : !u64i, !cir.ptr<!void> -> 
!cir.ptr<!void>
 
 // LLVM-LABEL: define dso_local{{.*}} %struct.two_floats 
@_Z21test_aggregate_recordR8two_ints
 //       LLVM:   %[[DST_SLOT:.*]] = alloca %struct.two_floats{{.*}}, align 4
@@ -75,7 +75,7 @@ two_floats test_aggregate_array(int (&ary)[2]) {
 //  CIR-NEXT:   %[[#SRC_VOID_PTR:]] = cir.cast bitcast %[[#SRC_PTR]] : 
!cir.ptr<!cir.array<!s32i x 2>> -> !cir.ptr<!void>
 //  CIR-NEXT:   %[[#DST_VOID_PTR:]] = cir.cast bitcast %{{.+}} : 
!cir.ptr<!rec_two_floats> -> !cir.ptr<!void>
 //  CIR-NEXT:   %[[#SIZE:]] = cir.const #cir.int<8> : !u64i
-//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] to 
%[[#DST_VOID_PTR]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] 
align(4) to %[[#DST_VOID_PTR]] align(4) : !u64i, !cir.ptr<!void> -> 
!cir.ptr<!void>
 
 // LLVM-LABEL: define dso_local{{.*}} %struct.two_floats 
@_Z20test_aggregate_arrayRA2_i
 //       LLVM:   %[[DST_SLOT:.*]] = alloca %struct.two_floats{{.*}}, align 4
@@ -91,7 +91,7 @@ two_ints test_scalar_to_aggregate(unsigned long ul) {
 //       CIR:   %[[#SRC_VOID_PTR:]] = cir.cast bitcast %{{.+}} : 
!cir.ptr<!u64i> -> !cir.ptr<!void>
 //  CIR-NEXT:   %[[#DST_VOID_PTR:]] = cir.cast bitcast %{{.+}} : 
!cir.ptr<!rec_two_ints> -> !cir.ptr<!void>
 //  CIR-NEXT:   %[[#SIZE:]] = cir.const #cir.int<8> : !u64i
-//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] to 
%[[#DST_VOID_PTR]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] 
align(8) to %[[#DST_VOID_PTR]] align(4) : !u64i, !cir.ptr<!void> -> 
!cir.ptr<!void>
 
 // LLVM-DIRECT-LABEL: define dso_local i64 @_Z24test_scalar_to_aggregatem
 // LLVM-VIA-CIR-LABEL: define dso_local %struct.two_ints 
@_Z24test_scalar_to_aggregatem
@@ -124,7 +124,7 @@ two_ints test_rvalue_aggregate() {
 //  CIR-NEXT:   %[[#SRC_VOID_PTR:]] = cir.cast bitcast %[[#TMP_SLOT]] : 
!cir.ptr<!u64i> -> !cir.ptr<!void>
 //  CIR-NEXT:   %[[#DST_VOID_PTR:]] = cir.cast bitcast %0 : 
!cir.ptr<!rec_two_ints> -> !cir.ptr<!void>
 //  CIR-NEXT:   %[[#SIZE:]] = cir.const #cir.int<8> : !u64i
-//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] to 
%[[#DST_VOID_PTR]] : !u64i, !cir.ptr<!void> -> !cir.ptr<!void>
+//  CIR-NEXT:   cir.libc.memcpy %[[#SIZE]] bytes from %[[#SRC_VOID_PTR]] 
align(8) to %[[#DST_VOID_PTR]] align(4) : !u64i, !cir.ptr<!void> -> 
!cir.ptr<!void>
 
 /// FIXME: The function signature below should be identical for both lowering
 /// paths, but CIR is still missing calling convention lowering. Update this

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to