https://github.com/HendrikHuebner updated 
https://github.com/llvm/llvm-project/pull/168281

From 7b2d881dd8a510efd08c6218b14ce66cb62c27c0 Mon Sep 17 00:00:00 2001
From: hhuebner <[email protected]>
Date: Wed, 12 Nov 2025 21:20:30 +0100
Subject: [PATCH 1/8] [CIR] Replace trivial copy constructors with cir.copy

---
 .../Dialect/Transforms/LoweringPrepare.cpp    | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index f8f354c2d1072..24a164cb5af6d 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -74,6 +74,7 @@ struct LoweringPreparePass
   void lowerDynamicCastOp(cir::DynamicCastOp op);
   void lowerArrayDtor(cir::ArrayDtor op);
   void lowerArrayCtor(cir::ArrayCtor op);
+  void lowerTrivialConstructorCall(cir::CallOp op);
 
   /// Build the function that initializes the specified global
   cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
@@ -1085,6 +1086,29 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor 
op) {
                              true);
 }
 
+void LoweringPreparePass::lowerTrivialConstructorCall(cir::CallOp op) {
+  FuncOp funcOp = getCalledFunction(op);
+  if (!funcOp)
+    return;
+
+  mlir::Attribute cxxSpecialMember = funcOp.getCxxSpecialMemberAttr();
+  if (!cxxSpecialMember)
+    return;
+
+  if (auto cxxCtor = dyn_cast<cir::CXXCtorAttr>(cxxSpecialMember)) {
+    if (cxxCtor.getCtorKind() == cir::CtorKind::Copy) {
+      // Replace the trivial copy constructor call with a `CopyOp`
+      CIRBaseBuilderTy builder(getContext());
+      auto operands = op.getOperands();
+      mlir::Value dest = operands[0];
+      mlir::Value src = operands[1];
+      builder.setInsertionPoint(op);
+      builder.createCopy(dest, src);
+      op.erase();
+    }
+  }
+}
+
 void LoweringPreparePass::runOnOp(mlir::Operation *op) {
   if (auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
     lowerArrayCtor(arrayCtor);
@@ -1107,6 +1131,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
       globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
     else if (auto globalDtor = fnOp.getGlobalDtorPriority())
       globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
+  } else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
+    lowerTrivialConstructorCall(callOp);
   }
 }
 

From 4532ea4ef934307d1ddb8c40d7959ddb02a5292c Mon Sep 17 00:00:00 2001
From: hhuebner <[email protected]>
Date: Sun, 16 Nov 2025 13:47:45 +0100
Subject: [PATCH 2/8] Add cir parsing test

---
 .../Dialect/Transforms/LoweringPrepare.cpp    | 26 -------------------
 1 file changed, 26 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 24a164cb5af6d..f8f354c2d1072 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -74,7 +74,6 @@ struct LoweringPreparePass
   void lowerDynamicCastOp(cir::DynamicCastOp op);
   void lowerArrayDtor(cir::ArrayDtor op);
   void lowerArrayCtor(cir::ArrayCtor op);
-  void lowerTrivialConstructorCall(cir::CallOp op);
 
   /// Build the function that initializes the specified global
   cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
@@ -1086,29 +1085,6 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor 
op) {
                              true);
 }
 
-void LoweringPreparePass::lowerTrivialConstructorCall(cir::CallOp op) {
-  FuncOp funcOp = getCalledFunction(op);
-  if (!funcOp)
-    return;
-
-  mlir::Attribute cxxSpecialMember = funcOp.getCxxSpecialMemberAttr();
-  if (!cxxSpecialMember)
-    return;
-
-  if (auto cxxCtor = dyn_cast<cir::CXXCtorAttr>(cxxSpecialMember)) {
-    if (cxxCtor.getCtorKind() == cir::CtorKind::Copy) {
-      // Replace the trivial copy constructor call with a `CopyOp`
-      CIRBaseBuilderTy builder(getContext());
-      auto operands = op.getOperands();
-      mlir::Value dest = operands[0];
-      mlir::Value src = operands[1];
-      builder.setInsertionPoint(op);
-      builder.createCopy(dest, src);
-      op.erase();
-    }
-  }
-}
-
 void LoweringPreparePass::runOnOp(mlir::Operation *op) {
   if (auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
     lowerArrayCtor(arrayCtor);
@@ -1131,8 +1107,6 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
       globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
     else if (auto globalDtor = fnOp.getGlobalDtorPriority())
       globalDtorList.emplace_back(fnOp.getName(), globalDtor.value());
-  } else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
-    lowerTrivialConstructorCall(callOp);
   }
 }
 

From b46cf9634f9f9ae2e44ea83048f40f263ff822ea Mon Sep 17 00:00:00 2001
From: hhuebner <[email protected]>
Date: Sun, 16 Nov 2025 14:06:35 +0100
Subject: [PATCH 3/8] Lower trivial copy constructor to cir::CopyOp

---
 .../Dialect/Transforms/LoweringPrepare.cpp    | 25 ++++++++++++++++++-
 .../CIR/CodeGen/cxx-special-member-attr.cpp   |  9 ++++---
 clang/test/CIR/CodeGen/struct.cpp             |  2 +-
 .../combined-firstprivate-clause.cpp          |  4 +--
 .../compute-firstprivate-clause-templates.cpp |  2 +-
 .../compute-firstprivate-clause.cpp           |  6 ++---
 6 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index f8f354c2d1072..a465e6ba04945 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -74,6 +74,7 @@ struct LoweringPreparePass
   void lowerDynamicCastOp(cir::DynamicCastOp op);
   void lowerArrayDtor(cir::ArrayDtor op);
   void lowerArrayCtor(cir::ArrayCtor op);
+  void lowerTrivialCopyCall(cir::CallOp op);
 
   /// Build the function that initializes the specified global
   cir::FuncOp buildCXXGlobalVarDeclInitFunc(cir::GlobalOp op);
@@ -1085,6 +1086,26 @@ void LoweringPreparePass::lowerArrayCtor(cir::ArrayCtor 
op) {
                              true);
 }
 
+void LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
+  FuncOp funcOp = getCalledFunction(op);
+  if (!funcOp)
+    return;
+
+  std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind();
+  if (ctorKind && *ctorKind == cir::CtorKind::Copy &&
+      funcOp.isCxxTrivialMemberFunction()) {
+    llvm::outs() << "success \n";
+    // Replace the trivial copy constructor call with a `CopyOp`
+    CIRBaseBuilderTy builder(getContext());
+    auto operands = op.getOperands();
+    mlir::Value dest = operands[0];
+    mlir::Value src = operands[1];
+    builder.setInsertionPoint(op);
+    builder.createCopy(dest, src);
+    op.erase();
+  }
+}
+
 void LoweringPreparePass::runOnOp(mlir::Operation *op) {
   if (auto arrayCtor = dyn_cast<cir::ArrayCtor>(op)) {
     lowerArrayCtor(arrayCtor);
@@ -1102,6 +1123,8 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) {
     lowerDynamicCastOp(dynamicCast);
   } else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) {
     lowerUnaryOp(unary);
+  } else if (auto callOp = dyn_cast<cir::CallOp>(op)) {
+    lowerTrivialCopyCall(callOp);
   } else if (auto fnOp = dyn_cast<cir::FuncOp>(op)) {
     if (auto globalCtor = fnOp.getGlobalCtorPriority())
       globalCtorList.emplace_back(fnOp.getName(), globalCtor.value());
@@ -1120,7 +1143,7 @@ void LoweringPreparePass::runOnOperation() {
   op->walk([&](mlir::Operation *op) {
     if (mlir::isa<cir::ArrayCtor, cir::ArrayDtor, cir::CastOp,
                   cir::ComplexMulOp, cir::ComplexDivOp, cir::DynamicCastOp,
-                  cir::FuncOp, cir::GlobalOp, cir::UnaryOp>(op))
+                  cir::FuncOp, cir::CallOp, cir::GlobalOp, cir::UnaryOp>(op))
       opsToTransform.push_back(op);
   });
 
diff --git a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp 
b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
index 815ef2c2aaa25..cd1377ac04eac 100644
--- a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
+++ b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
@@ -3,8 +3,9 @@
 
 struct Flub {
   int a = 123;
-  // CIR: @_ZN4FlubC1ERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, copy, 
trivial true>>
-  // CIR: @_ZN4FlubC2EOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, move, 
trivial true>
+  // COM: Trivial copy constructors/assignments are replaced with cir.copy
+  // CIR: cir.copy {{.*}} : !cir.ptr<!rec_Flub>
+  // CIR: @_ZN4FlubC1EOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, move, 
trivial true>
   // CIR: @_ZN4FlubaSERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> 
special_member<#cir.cxx_assign<!rec_Flub, copy, trivial true>>
   // CIR: @_ZN4FlubaSEOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> 
special_member<#cir.cxx_assign<!rec_Flub, move, trivial true>>
 };
@@ -42,7 +43,7 @@ struct Foo {
   ~Foo();
 };
 
-void trivial() {
+void trivial_func() {
   Flub f1{};
   Flub f2 = f1;
   Flub f3 = static_cast<Flub&&>(f1);
@@ -50,7 +51,7 @@ void trivial() {
   f1 = static_cast<Flub&&>(f3);
 }
 
-void non_trivial() {
+void non_trivial_func() {
   Foo f1{};
   Foo f2 = f1;
   Foo f3 = static_cast<Foo&&>(f1);
diff --git a/clang/test/CIR/CodeGen/struct.cpp 
b/clang/test/CIR/CodeGen/struct.cpp
index c15e7e7c57b9f..969ab46339d62 100644
--- a/clang/test/CIR/CodeGen/struct.cpp
+++ b/clang/test/CIR/CodeGen/struct.cpp
@@ -109,7 +109,7 @@ void paren_expr() {
 // CIR:   %[[B_ADDR:.*]] = cir.alloca !rec_Point, !cir.ptr<!rec_Point>, ["b", 
init]
 // CIR:   %[[CONST:.*]] = cir.const #cir.zero : !rec_Point
 // CIR:   cir.store{{.*}} %[[CONST]], %[[A_ADDR]] : !rec_Point, 
!cir.ptr<!rec_Point>
-// CIR:   cir.call @_ZZ10paren_exprvEN5PointC1ERKS_(%[[B_ADDR]], %[[A_ADDR]]) 
nothrow : (!cir.ptr<!rec_Point>, !cir.ptr<!rec_Point>) -> ()
+// CIR:   cir.copy %[[A_ADDR]] to %[[B_ADDR]]) -> !cir.ptr<!rec_Point>
 
 // LLVM: define{{.*}} void @_Z10paren_exprv()
 // LLVM:   %[[A_ADDR:.*]] = alloca %struct.Point, i64 1, align 4
diff --git a/clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp 
b/clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp
index 94f3f1ace4350..3cd8209d05076 100644
--- a/clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp
@@ -43,7 +43,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_NoCopyConstruct> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_NoCopyConstruct> {{.*}}):
-// CHECK-NEXT: cir.call @_ZN15NoCopyConstructC1ERKS_(%[[ARG_TO]], 
%[[ARG_FROM]]) nothrow : (!cir.ptr<!rec_NoCopyConstruct>, 
!cir.ptr<!rec_NoCopyConstruct>) -> ()
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] TO %[[ARG_FROM]] -> 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: }
 //
@@ -176,7 +176,7 @@ struct HasDtor {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride %[[DECAY_FROM]], 
%[[ITR_LOAD]] : (!cir.ptr<!rec_NoCopyConstruct>, !u64i) -> 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: %[[DECAY_TO:.*]] = cir.cast array_to_ptrdecay %[[ARG_TO]] : 
!cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> -> !cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[DECAY_TO]], %[[ITR_LOAD]] 
: (!cir.ptr<!rec_NoCopyConstruct>, !u64i) -> !cir.ptr<!rec_NoCopyConstruct>
-// CHECK-NEXT: cir.call @_ZN15NoCopyConstructC1ERKS_(%[[STRIDE_TO]], 
%[[STRIDE_FROM]]) nothrow : (!cir.ptr<!rec_NoCopyConstruct>, 
!cir.ptr<!rec_NoCopyConstruct>) -> ()
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] -> 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR_LOAD]] = cir.load %[[ITR]] : !cir.ptr<!u64i>, !u64i
diff --git 
a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp 
b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp
index ed968e21630cc..fb424f65f28cd 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp
@@ -30,7 +30,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}):
-// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1ERKS_(%[[ARG_TO]], 
%[[ARG_FROM]]) nothrow : (!cir.ptr<!rec_NonDefaultCtor>, 
!cir.ptr<!rec_NonDefaultCtor>) -> ()
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]]) -> 
!cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: }
 //
diff --git a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp 
b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp
index a2c6c3834b1e2..ecc7a49cf8c62 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp
@@ -43,7 +43,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_NoCopyConstruct> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_NoCopyConstruct> {{.*}}):
-// CHECK-NEXT: cir.call @_ZN15NoCopyConstructC1ERKS_(%[[ARG_TO]], 
%[[ARG_FROM]]) nothrow : (!cir.ptr<!rec_NoCopyConstruct>, 
!cir.ptr<!rec_NoCopyConstruct>) -> ()
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]] : 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: }
 //
@@ -63,7 +63,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}):
-// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1ERKS_(%[[ARG_TO]], 
%[[ARG_FROM]]) nothrow : (!cir.ptr<!rec_NonDefaultCtor>, 
!cir.ptr<!rec_NonDefaultCtor>) -> ()
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]]) -> 
cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: }
 //
@@ -176,7 +176,7 @@ struct HasDtor {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride %[[DECAY_FROM]], 
%[[ITR_LOAD]] : (!cir.ptr<!rec_NoCopyConstruct>, !u64i) -> 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: %[[DECAY_TO:.*]] = cir.cast array_to_ptrdecay %[[ARG_TO]] : 
!cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> -> !cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[DECAY_TO]], %[[ITR_LOAD]] 
: (!cir.ptr<!rec_NoCopyConstruct>, !u64i) -> !cir.ptr<!rec_NoCopyConstruct>
-// CHECK-NEXT: cir.call @_ZN15NoCopyConstructC1ERKS_(%[[STRIDE_TO]], 
%[[STRIDE_FROM]]) nothrow : (!cir.ptr<!rec_NoCopyConstruct>, 
!cir.ptr<!rec_NoCopyConstruct>) -> ()
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]]) -> 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR_LOAD]] = cir.load %[[ITR]] : !cir.ptr<!u64i>, !u64i

From ab00cf9fe79442af288739ffe043fcd4d2e49b1b Mon Sep 17 00:00:00 2001
From: hhuebner <[email protected]>
Date: Sun, 23 Nov 2025 15:22:37 +0100
Subject: [PATCH 4/8] Fix tests

---
 clang/test/CIR/CodeGen/lambda.cpp              |  4 ++--
 clang/test/CIR/CodeGen/struct.cpp              | 18 ++++++++----------
 .../combined-firstprivate-clause.cpp           | 12 ++++++------
 .../compute-firstprivate-clause-templates.cpp  |  4 ++--
 .../compute-firstprivate-clause.cpp            | 13 +++++++------
 .../firstprivate-clause-recipes.cpp            |  6 +++---
 6 files changed, 28 insertions(+), 29 deletions(-)

diff --git a/clang/test/CIR/CodeGen/lambda.cpp 
b/clang/test/CIR/CodeGen/lambda.cpp
index 91380b9bea296..b766d7ba5daf6 100644
--- a/clang/test/CIR/CodeGen/lambda.cpp
+++ b/clang/test/CIR/CodeGen/lambda.cpp
@@ -334,7 +334,7 @@ struct A {
 // CIR:   cir.scope {
 // CIR:     %[[LAM_ADDR:.*]] = cir.alloca ![[REC_LAM_A]], 
!cir.ptr<![[REC_LAM_A]]>, ["ref.tmp0"]
 // CIR:     %[[STRUCT_A:.*]] = cir.get_member %[[LAM_ADDR]][0] {name = "this"} 
: !cir.ptr<![[REC_LAM_A]]> -> !cir.ptr<!rec_A>
-// CIR:     cir.call @_ZN1AC1ERKS_(%[[STRUCT_A]], %[[THIS]]){{.*}} : 
(!cir.ptr<!rec_A>, !cir.ptr<!rec_A>){{.*}} -> ()
+// CIR:     cir.copy %[[THIS]] to %[[STRUCT_A]] : !cir.ptr<!rec_A>
 // CIR:     %[[LAM_RET:.*]] = cir.call @_ZZN1A3fooEvENKUlvE_clEv(%[[LAM_ADDR]])
 // CIR:     cir.store{{.*}} %[[LAM_RET]], %[[RETVAL]]
 // CIR:   }
@@ -350,7 +350,7 @@ struct A {
 // LLVM:   br label %[[SCOPE_BB:.*]]
 // LLVM: [[SCOPE_BB]]:
 // LLVM:   %[[STRUCT_A:.*]] = getelementptr %[[REC_LAM_A]], ptr 
%[[LAM_ALLOCA]], i32 0, i32 0
-// LLVM:   call void @_ZN1AC1ERKS_(ptr %[[STRUCT_A]], ptr %[[THIS]])
+// LLVM:   call void @llvm.memcpy.p0.p0.i32(ptr %[[STRUCT_A]], ptr %[[THIS]], 
i32 4, i1 false)
 // LLVM:   %[[LAM_RET:.*]] = call i32 @_ZZN1A3fooEvENKUlvE_clEv(ptr 
%[[LAM_ALLOCA]])
 // LLVM:   store i32 %[[LAM_RET]], ptr %[[RETVAL]]
 // LLVM:   br label %[[RET_BB:.*]]
diff --git a/clang/test/CIR/CodeGen/struct.cpp 
b/clang/test/CIR/CodeGen/struct.cpp
index 969ab46339d62..dc3e24113d8d8 100644
--- a/clang/test/CIR/CodeGen/struct.cpp
+++ b/clang/test/CIR/CodeGen/struct.cpp
@@ -109,13 +109,13 @@ void paren_expr() {
 // CIR:   %[[B_ADDR:.*]] = cir.alloca !rec_Point, !cir.ptr<!rec_Point>, ["b", 
init]
 // CIR:   %[[CONST:.*]] = cir.const #cir.zero : !rec_Point
 // CIR:   cir.store{{.*}} %[[CONST]], %[[A_ADDR]] : !rec_Point, 
!cir.ptr<!rec_Point>
-// CIR:   cir.copy %[[A_ADDR]] to %[[B_ADDR]]) -> !cir.ptr<!rec_Point>
+// CIR:   cir.copy %[[A_ADDR]] to %[[B_ADDR]] : !cir.ptr<!rec_Point>
 
 // LLVM: define{{.*}} void @_Z10paren_exprv()
 // LLVM:   %[[A_ADDR:.*]] = alloca %struct.Point, i64 1, align 4
 // LLVM:   %[[B_ADDR:.*]] = alloca %struct.Point, i64 1, align 4
 // LLVM:   store %struct.Point zeroinitializer, ptr %[[A_ADDR]], align 4
-// LLVM:   call void @_ZZ10paren_exprvEN5PointC1ERKS_(ptr %[[B_ADDR]], ptr 
%[[A_ADDR]])
+// LLVM:   call void @llvm.memcpy.p0.p0.i32(ptr %[[B_ADDR]], ptr %[[A_ADDR]], 
i32 8, i1 false)
 
 // OGCG: define{{.*}} void @_Z10paren_exprv()
 // OGCG:   %[[A_ADDR:.*]] = alloca %struct.Point, align 4
@@ -133,14 +133,13 @@ void choose_expr() {
 // CIR:   %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, 
!cir.ptr<!rec_CompleteS>, ["a"]
 // CIR:   %[[B_ADDR:.*]] = cir.alloca !rec_CompleteS, 
!cir.ptr<!rec_CompleteS>, ["b"]
 // CIR:   %[[C_ADDR:.*]] = cir.alloca !rec_CompleteS, 
!cir.ptr<!rec_CompleteS>, ["c", init]
-// TODO(cir): Call to default copy constructor should be replaced by 
`cir.copy` op
-// CIR:   cir.call @_ZN9CompleteSC1ERKS_(%[[C_ADDR]], %[[A_ADDR]]) nothrow : 
(!cir.ptr<!rec_CompleteS>, !cir.ptr<!rec_CompleteS>) -> ()
+// CIR:   cir.copy %[[A_ADDR]] to %[[C_ADDR]] : !cir.ptr<!rec_CompleteS>
 
 // LLVM: define{{.*}} void @_Z11choose_exprv()
 // LLVM:   %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
 // LLVM:   %[[B_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
 // LLVM:   %[[C_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
-// LLVM:   call void @_ZN9CompleteSC1ERKS_(ptr %[[C_ADDR]], ptr %[[A_ADDR]])
+// LLVM:   call void @llvm.memcpy.p0.p0.i32(ptr %[[C_ADDR]], ptr %[[A_ADDR]], 
i32 8, i1 false)
 
 // OGCG: define{{.*}} void @_Z11choose_exprv()
 // OGCG:   %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
@@ -160,15 +159,14 @@ void generic_selection() {
 // CIR:   %[[B_ADDR:.*]] = cir.alloca !rec_CompleteS, 
!cir.ptr<!rec_CompleteS>, ["b"]
 // CIR:   %[[C_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["c"]
 // CIR:   %[[D_ADDR:.*]] = cir.alloca !rec_CompleteS, 
!cir.ptr<!rec_CompleteS>, ["d", init]
-// TODO(cir): Call to default copy constructor should be replaced by 
`cir.copy` op
-// CIR:   cir.call @_ZN9CompleteSC1ERKS_(%[[D_ADDR]], %[[A_ADDR]]) nothrow : 
(!cir.ptr<!rec_CompleteS>, !cir.ptr<!rec_CompleteS>) -> ()
+// CIR:   cir.copy %[[A_ADDR]] to %[[D_ADDR]] : !cir.ptr<!rec_CompleteS>
 
 // LLVM: define{{.*}} void @_Z17generic_selectionv()
 // LLVM:   %1 = alloca %struct.CompleteS, i64 1, align 4
 // LLVM:   %2 = alloca %struct.CompleteS, i64 1, align 4
 // LLVM:   %3 = alloca i32, i64 1, align 4
 // LLVM:   %4 = alloca %struct.CompleteS, i64 1, align 4
-// LLVM:   call void @_ZN9CompleteSC1ERKS_(ptr %4, ptr %1)
+// LLVM:   call void @llvm.memcpy.p0.p0.i32(ptr %4, ptr %1, i32 8, i1 false)
 
 // OGCG: define{{.*}} void @_Z17generic_selectionv()
 // OGCG:   %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4
@@ -188,7 +186,7 @@ void designated_init_update_expr() {
 // CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, 
["a"]
 // CIR: %[[B_ADDR:.*]] = cir.alloca !rec_Container, !cir.ptr<!rec_Container>, 
["b", init]
 // CIR: %[[C_ADDR:.*]] = cir.get_member %[[B_ADDR]][0] {name = "c"} : 
!cir.ptr<!rec_Container> -> !cir.ptr<!rec_CompleteS>
-// CIR: cir.call @_ZN9CompleteSC1ERKS_(%2, %[[A_ADDR]]) nothrow : 
(!cir.ptr<!rec_CompleteS>, !cir.ptr<!rec_CompleteS>) -> ()
+// CIR: cir.copy %[[A_ADDR]] to %[[C_ADDR]] : !cir.ptr<!rec_CompleteS>
 // CIR: %[[ELEM_0_PTR:.*]] = cir.get_member %[[C_ADDR]][0] {name = "a"} : 
!cir.ptr<!rec_CompleteS> -> !cir.ptr<!s32i>
 // CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i
 // CIR: cir.store{{.*}} %[[CONST_1]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i>
@@ -197,7 +195,7 @@ void designated_init_update_expr() {
 // LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4
 // LLVM: %[[B_ADDR:.*]] = alloca %struct.Container, i64 1, align 4
 // LLVM: %[[C_ADDR:.*]] = getelementptr %struct.Container, ptr %[[B_ADDR]], 
i32 0, i32 0
-// LLVM: call void @_ZN9CompleteSC1ERKS_(ptr %[[C_ADDR]], ptr %[[A_ADDR]])
+// LLVM: call void @llvm.memcpy.p0.p0.i32(ptr %[[C_ADDR]], ptr %[[A_ADDR]], 
i32 8, i1 false)
 // LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr 
%[[C_ADDR]], i32 0, i32 0
 // LLVM: store i32 1, ptr %[[ELEM_0_PTR]], align 4
 // LLVM: %[[ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr 
%[[C_ADDR]], i32 0, i32 1
diff --git a/clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp 
b/clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp
index 3cd8209d05076..b1fba89739109 100644
--- a/clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/combined-firstprivate-clause.cpp
@@ -43,7 +43,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_NoCopyConstruct> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_NoCopyConstruct> {{.*}}):
-// CHECK-NEXT: cir.copy %[[ARG_FROM]] TO %[[ARG_FROM]] -> 
!cir.ptr<!rec_NoCopyConstruct>
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]] : 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: }
 //
@@ -63,7 +63,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}):
-// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1ERKS_(%[[ARG_TO]], 
%[[ARG_FROM]]) nothrow : (!cir.ptr<!rec_NonDefaultCtor>, 
!cir.ptr<!rec_NonDefaultCtor>) -> ()
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]] : 
!cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: }
 //
@@ -73,7 +73,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}):
-// CHECK-NEXT: cir.call @_ZN7HasDtorC1ERKS_(%[[ARG_TO]], %[[ARG_FROM]]) 
nothrow : (!cir.ptr<!rec_HasDtor>, !cir.ptr<!rec_HasDtor>) -> ()
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]] : !cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } destroy {
 // CHECK-NEXT: ^bb0(%[[ORIG:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}, %[[ARG:.*]]: 
!cir.ptr<!rec_HasDtor> {{.*}}):
@@ -176,7 +176,7 @@ struct HasDtor {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride %[[DECAY_FROM]], 
%[[ITR_LOAD]] : (!cir.ptr<!rec_NoCopyConstruct>, !u64i) -> 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: %[[DECAY_TO:.*]] = cir.cast array_to_ptrdecay %[[ARG_TO]] : 
!cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> -> !cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[DECAY_TO]], %[[ITR_LOAD]] 
: (!cir.ptr<!rec_NoCopyConstruct>, !u64i) -> !cir.ptr<!rec_NoCopyConstruct>
-// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] -> 
!cir.ptr<!rec_NoCopyConstruct>
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] : 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR_LOAD]] = cir.load %[[ITR]] : !cir.ptr<!u64i>, !u64i
@@ -246,7 +246,7 @@ struct HasDtor {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride %[[DECAY_FROM]], 
%[[ITR_LOAD]] : (!cir.ptr<!rec_NonDefaultCtor>, !u64i) -> 
!cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: %[[DECAY_TO:.*]] = cir.cast array_to_ptrdecay %[[ARG_TO]] : 
!cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> -> !cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[DECAY_TO]], %[[ITR_LOAD]] 
: (!cir.ptr<!rec_NonDefaultCtor>, !u64i) -> !cir.ptr<!rec_NonDefaultCtor>
-// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1ERKS_(%[[STRIDE_TO]], 
%[[STRIDE_FROM]]) nothrow : (!cir.ptr<!rec_NonDefaultCtor>, 
!cir.ptr<!rec_NonDefaultCtor>) -> ()
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] : 
!cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR_LOAD]] = cir.load %[[ITR]] : !cir.ptr<!u64i>, !u64i
@@ -281,7 +281,7 @@ struct HasDtor {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride %[[DECAY_FROM]], 
%[[ITR_LOAD]] : (!cir.ptr<!rec_HasDtor>, !u64i) -> !cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: %[[DECAY_TO:.*]] = cir.cast array_to_ptrdecay %[[ARG_TO]] : 
!cir.ptr<!cir.array<!rec_HasDtor x 5>> -> !cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[DECAY_TO]], %[[ITR_LOAD]] 
: (!cir.ptr<!rec_HasDtor>, !u64i) -> !cir.ptr<!rec_HasDtor>
-// CHECK-NEXT: cir.call @_ZN7HasDtorC1ERKS_(%[[STRIDE_TO]], %[[STRIDE_FROM]]) 
nothrow : (!cir.ptr<!rec_HasDtor>, !cir.ptr<!rec_HasDtor>) -> ()
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] : 
!cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR_LOAD]] = cir.load %[[ITR]] : !cir.ptr<!u64i>, !u64i
diff --git 
a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp 
b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp
index fb424f65f28cd..30f1cc4d68123 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause-templates.cpp
@@ -30,7 +30,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}):
-// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]]) -> 
!cir.ptr<!rec_NonDefaultCtor>
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]] : 
!cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: }
 //
@@ -40,7 +40,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}):
-// CHECK-NEXT: cir.call @_ZN7HasDtorC1ERKS_(%[[ARG_TO]], %[[ARG_FROM]]) 
nothrow : (!cir.ptr<!rec_HasDtor>, !cir.ptr<!rec_HasDtor>) -> ()
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]] : !cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } destroy {
 // CHECK-NEXT: ^bb0(%[[ORIG:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}, %[[ARG:.*]]: 
!cir.ptr<!rec_HasDtor> {{.*}}):
diff --git a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp 
b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp
index ecc7a49cf8c62..aa69c08055da1 100644
--- a/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/compute-firstprivate-clause.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fopenacc -triple x86_64-linux-gnu 
-Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple 
x86_64-linux-pc %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fopenacc -triple x86_64-linux-gnu 
-Wno-openacc-self-if-potential-conflict -emit-cir -fclangir -triple 
x86_64-linux-pc %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s
 
 struct NoCopyConstruct {};
 
@@ -63,7 +64,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_NonDefaultCtor> {{.*}}):
-// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]]) -> 
cir.ptr<!rec_NonDefaultCtor>
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]] : 
!cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: }
 //
@@ -73,7 +74,7 @@ struct HasDtor {
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } copy {
 // CHECK-NEXT: ^bb0(%[[ARG_FROM:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}, 
%[[ARG_TO:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}):
-// CHECK-NEXT: cir.call @_ZN7HasDtorC1ERKS_(%[[ARG_TO]], %[[ARG_FROM]]) 
nothrow : (!cir.ptr<!rec_HasDtor>, !cir.ptr<!rec_HasDtor>) -> ()
+// CHECK-NEXT: cir.copy %[[ARG_FROM]] to %[[ARG_TO]] : !cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: acc.yield
 // CHECK-NEXT: } destroy {
 // CHECK-NEXT: ^bb0(%[[ORIG:.*]]: !cir.ptr<!rec_HasDtor> {{.*}}, %[[ARG:.*]]: 
!cir.ptr<!rec_HasDtor> {{.*}}):
@@ -176,7 +177,7 @@ struct HasDtor {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride %[[DECAY_FROM]], 
%[[ITR_LOAD]] : (!cir.ptr<!rec_NoCopyConstruct>, !u64i) -> 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: %[[DECAY_TO:.*]] = cir.cast array_to_ptrdecay %[[ARG_TO]] : 
!cir.ptr<!cir.array<!rec_NoCopyConstruct x 5>> -> !cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[DECAY_TO]], %[[ITR_LOAD]] 
: (!cir.ptr<!rec_NoCopyConstruct>, !u64i) -> !cir.ptr<!rec_NoCopyConstruct>
-// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]]) -> 
!cir.ptr<!rec_NoCopyConstruct>
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] : 
!cir.ptr<!rec_NoCopyConstruct>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR_LOAD]] = cir.load %[[ITR]] : !cir.ptr<!u64i>, !u64i
@@ -246,7 +247,7 @@ struct HasDtor {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride %[[DECAY_FROM]], 
%[[ITR_LOAD]] : (!cir.ptr<!rec_NonDefaultCtor>, !u64i) -> 
!cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: %[[DECAY_TO:.*]] = cir.cast array_to_ptrdecay %[[ARG_TO]] : 
!cir.ptr<!cir.array<!rec_NonDefaultCtor x 5>> -> !cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[DECAY_TO]], %[[ITR_LOAD]] 
: (!cir.ptr<!rec_NonDefaultCtor>, !u64i) -> !cir.ptr<!rec_NonDefaultCtor>
-// CHECK-NEXT: cir.call @_ZN14NonDefaultCtorC1ERKS_(%[[STRIDE_TO]], 
%[[STRIDE_FROM]]) nothrow : (!cir.ptr<!rec_NonDefaultCtor>, 
!cir.ptr<!rec_NonDefaultCtor>) -> ()
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] : 
!cir.ptr<!rec_NonDefaultCtor>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR_LOAD]] = cir.load %[[ITR]] : !cir.ptr<!u64i>, !u64i
@@ -281,7 +282,7 @@ struct HasDtor {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride %[[DECAY_FROM]], 
%[[ITR_LOAD]] : (!cir.ptr<!rec_HasDtor>, !u64i) -> !cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: %[[DECAY_TO:.*]] = cir.cast array_to_ptrdecay %[[ARG_TO]] : 
!cir.ptr<!cir.array<!rec_HasDtor x 5>> -> !cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[DECAY_TO]], %[[ITR_LOAD]] 
: (!cir.ptr<!rec_HasDtor>, !u64i) -> !cir.ptr<!rec_HasDtor>
-// CHECK-NEXT: cir.call @_ZN7HasDtorC1ERKS_(%[[STRIDE_TO]], %[[STRIDE_FROM]]) 
nothrow : (!cir.ptr<!rec_HasDtor>, !cir.ptr<!rec_HasDtor>) -> ()
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] : 
!cir.ptr<!rec_HasDtor>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR_LOAD]] = cir.load %[[ITR]] : !cir.ptr<!u64i>, !u64i
diff --git a/clang/test/CIR/CodeGenOpenACC/firstprivate-clause-recipes.cpp 
b/clang/test/CIR/CodeGenOpenACC/firstprivate-clause-recipes.cpp
index 95168812316ea..3a13a81b48828 100644
--- a/clang/test/CIR/CodeGenOpenACC/firstprivate-clause-recipes.cpp
+++ b/clang/test/CIR/CodeGenOpenACC/firstprivate-clause-recipes.cpp
@@ -75,7 +75,7 @@ void do_things(unsigned A, unsigned B) {
 // CHECK-NEXT: %[[BOUND1_STRIDE_FROM:.*]] = cir.ptr_stride 
%[[BOUND2_STRIDE_DECAY_FROM]], %[[ITR1_LOAD]] : (!cir.ptr<!rec_NoOps>, !u64i) 
-> !cir.ptr<!rec_NoOps>
 // CHECK-NEXT: %[[BOUND2_STRIDE_DECAY_TO:.*]] = cir.cast array_to_ptrdecay 
%[[BOUND2_STRIDE_TO]] : !cir.ptr<!cir.array<!rec_NoOps x 5>> -> 
!cir.ptr<!rec_NoOps>
 // CHECK-NEXT: %[[BOUND1_STRIDE_TO:.*]] = cir.ptr_stride 
%[[BOUND2_STRIDE_DECAY_TO]], %[[ITR1_LOAD]] : (!cir.ptr<!rec_NoOps>, !u64i) -> 
!cir.ptr<!rec_NoOps>
-// CHECK-NEXT: cir.call @_ZN5NoOpsC1ERKS_(%[[BOUND1_STRIDE_TO]], 
%[[BOUND1_STRIDE_FROM]]) nothrow : (!cir.ptr<!rec_NoOps>, !cir.ptr<!rec_NoOps>) 
-> ()
+// CHECK-NEXT: cir.copy %[[BOUND1_STRIDE_FROM]] to %[[BOUND1_STRIDE_TO]] : 
!cir.ptr<!rec_NoOps>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR1_LOAD]] = cir.load %[[ITR1]] : !cir.ptr<!u64i>, !u64i
@@ -342,7 +342,7 @@ void do_things(unsigned A, unsigned B) {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride 
%[[BOUND2_STRIDE_LOAD_FROM]], %[[ITR1_LOAD]] : (!cir.ptr<!rec_NoOps>, !u64i) -> 
!cir.ptr<!rec_NoOps>
 // CHECK-NEXT: %[[BOUND2_STRIDE_LOAD_TO:.*]] = cir.load %[[BOUND2_STRIDE_TO]] 
: !cir.ptr<!cir.ptr<!rec_NoOps>>, !cir.ptr<!rec_NoOps>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[BOUND2_STRIDE_LOAD_TO]], 
%[[ITR1_LOAD]] : (!cir.ptr<!rec_NoOps>, !u64i) -> !cir.ptr<!rec_NoOps>
-// CHECK-NEXT: cir.call @_ZN5NoOpsC1ERKS_(%[[BOUND1_STRIDE_TO]], 
%[[BOUND1_STRIDE_FROM]]) nothrow : (!cir.ptr<!rec_NoOps>, !cir.ptr<!rec_NoOps>) 
-> ()
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] : 
!cir.ptr<!rec_NoOps>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR1_LOAD]] = cir.load %[[ITR1]] : !cir.ptr<!u64i>, !u64i
@@ -580,7 +580,7 @@ void do_things(unsigned A, unsigned B) {
 // CHECK-NEXT: %[[STRIDE_FROM:.*]] = cir.ptr_stride 
%[[BOUND2_STRIDE_LOAD_FROM]], %[[ITR1_LOAD]] : (!cir.ptr<!rec_CtorDtor>, !u64i) 
-> !cir.ptr<!rec_CtorDtor>
 // CHECK-NEXT: %[[BOUND2_STRIDE_LOAD_TO:.*]] = cir.load %[[BOUND2_STRIDE_TO]] 
: !cir.ptr<!cir.ptr<!rec_CtorDtor>>, !cir.ptr<!rec_CtorDtor>
 // CHECK-NEXT: %[[STRIDE_TO:.*]] = cir.ptr_stride %[[BOUND2_STRIDE_LOAD_TO]], 
%[[ITR1_LOAD]] : (!cir.ptr<!rec_CtorDtor>, !u64i) -> !cir.ptr<!rec_CtorDtor>
-// CHECK-NEXT: cir.call @_ZN8CtorDtorC1ERKS_(%[[BOUND1_STRIDE_TO]], 
%[[BOUND1_STRIDE_FROM]]) nothrow : (!cir.ptr<!rec_CtorDtor>, 
!cir.ptr<!rec_CtorDtor>) -> ()
+// CHECK-NEXT: cir.copy %[[STRIDE_FROM]] to %[[STRIDE_TO]] : 
!cir.ptr<!rec_CtorDtor>
 // CHECK-NEXT: cir.yield
 // CHECK-NEXT: } step {
 // CHECK-NEXT: %[[ITR1_LOAD]] = cir.load %[[ITR1]] : !cir.ptr<!u64i>, !u64i

From 448adb521aae15d6f0b02d983c7158823f538c35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
 <[email protected]>
Date: Tue, 25 Nov 2025 16:14:17 +0100
Subject: [PATCH 5/8] Update clang/test/CIR/CodeGen/cxx-special-member-attr.cpp

Co-authored-by: Andy Kaylor <[email protected]>
---
 clang/test/CIR/CodeGen/cxx-special-member-attr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp 
b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
index cd1377ac04eac..397c72daeadef 100644
--- a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
+++ b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
@@ -3,7 +3,7 @@
 
 struct Flub {
   int a = 123;
-  // COM: Trivial copy constructors/assignments are replaced with cir.copy
+  // Trivial copy constructors/assignments are replaced with cir.copy
   // CIR: cir.copy {{.*}} : !cir.ptr<!rec_Flub>
   // CIR: @_ZN4FlubC1EOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, move, 
trivial true>
   // CIR: @_ZN4FlubaSERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> 
special_member<#cir.cxx_assign<!rec_Flub, copy, trivial true>>

From 35283410ccb8199065597dbb498909ee8cba0fe3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
 <[email protected]>
Date: Tue, 25 Nov 2025 16:14:36 +0100
Subject: [PATCH 6/8] Update
 clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp

Co-authored-by: Andy Kaylor <[email protected]>
---
 clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index a465e6ba04945..53a7cd81e61ec 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1097,7 +1097,7 @@ void 
LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
     llvm::outs() << "success \n";
     // Replace the trivial copy constructor call with a `CopyOp`
     CIRBaseBuilderTy builder(getContext());
-    auto operands = op.getOperands();
+    mlir::ValueRange operands = op.getOperands();
     mlir::Value dest = operands[0];
     mlir::Value src = operands[1];
     builder.setInsertionPoint(op);

From c2aa41ee1b1f39e2dad34f80ba2189b36f906429 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
 <[email protected]>
Date: Tue, 25 Nov 2025 16:18:43 +0100
Subject: [PATCH 7/8] Adjust test

---
 .../CIR/CodeGen/cxx-special-member-attr.cpp   | 32 +++++++++++--------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp 
b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
index 397c72daeadef..f2c2c1f683395 100644
--- a/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
+++ b/clang/test/CIR/CodeGen/cxx-special-member-attr.cpp
@@ -3,26 +3,15 @@
 
 struct Flub {
   int a = 123;
-  // Trivial copy constructors/assignments are replaced with cir.copy
-  // CIR: cir.copy {{.*}} : !cir.ptr<!rec_Flub>
-  // CIR: @_ZN4FlubC1EOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, move, 
trivial true>
-  // CIR: @_ZN4FlubaSERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> 
special_member<#cir.cxx_assign<!rec_Flub, copy, trivial true>>
-  // CIR: @_ZN4FlubaSEOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> 
special_member<#cir.cxx_assign<!rec_Flub, move, trivial true>>
 };
 
 struct Foo {
   int a;
 
-  // CIR: @_ZN3FooC2Ev(%arg0: !cir.ptr<!rec_Foo> loc({{.*}})) 
special_member<#cir.cxx_ctor<!rec_Foo, default>>
   Foo() : a(123) {}
-
-  // CIR: @_ZN3FooC2ERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, copy>>
   Foo(const Foo &other) : a(other.a) {}
-
-  // CIR: @_ZN3FooC2EOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, move>>
   Foo(Foo &&other) noexcept : a(other.a) { other.a = 0; }
 
-  // CIR: @_ZN3FooaSERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> 
special_member<#cir.cxx_assign<!rec_Foo, copy>>
   Foo &operator=(const Foo &other) {
     if (this != &other) {
       a = other.a;
@@ -30,7 +19,6 @@ struct Foo {
     return *this;
   }
 
-  // CIR: @_ZN3FooaSEOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> 
special_member<#cir.cxx_assign<!rec_Foo, move>>
   Foo &operator=(Foo &&other) noexcept {
     if (this != &other) {
       a = other.a;
@@ -39,22 +27,40 @@ struct Foo {
     return *this;
   }
 
-  // CIR: @_ZN3FooD1Ev(!cir.ptr<!rec_Foo>) 
special_member<#cir.cxx_dtor<!rec_Foo>>
   ~Foo();
 };
 
 void trivial_func() {
   Flub f1{};
+
   Flub f2 = f1;
+  // Trivial copy constructors/assignments are replaced with cir.copy
+  // CIR: cir.copy {{.*}} : !cir.ptr<!rec_Flub>
+
   Flub f3 = static_cast<Flub&&>(f1);
+  // CIR: @_ZN4FlubC1EOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Flub, move, 
trivial true>
+
   f2 = f1;
+  // CIR: @_ZN4FlubaSERKS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> 
special_member<#cir.cxx_assign<!rec_Flub, copy, trivial true>>
+
   f1 = static_cast<Flub&&>(f3);
+  // CIR: @_ZN4FlubaSEOS_(%arg0: !cir.ptr<!rec_Flub> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Flub> loc({{.*}})) -> !cir.ptr<!rec_Flub> 
special_member<#cir.cxx_assign<!rec_Flub, move, trivial true>>
 }
 
 void non_trivial_func() {
   Foo f1{};
+  // CIR: @_ZN3FooC2Ev(%arg0: !cir.ptr<!rec_Foo> loc({{.*}})) 
special_member<#cir.cxx_ctor<!rec_Foo, default>>
+
   Foo f2 = f1;
+  // CIR: @_ZN3FooC2ERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, copy>>
+
   Foo f3 = static_cast<Foo&&>(f1);
+  // CIR: @_ZN3FooC2EOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Foo> loc({{.*}})) special_member<#cir.cxx_ctor<!rec_Foo, move>>
+
   f2 = f1;
+  // CIR: @_ZN3FooaSERKS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> 
special_member<#cir.cxx_assign<!rec_Foo, copy>>
+
   f1 = static_cast<Foo&&>(f3);
+  // CIR: @_ZN3FooaSEOS_(%arg0: !cir.ptr<!rec_Foo> loc({{.*}}), %arg1: 
!cir.ptr<!rec_Foo> loc({{.*}})) -> !cir.ptr<!rec_Foo> 
special_member<#cir.cxx_assign<!rec_Foo, move>>
+  // CIR: @_ZN3FooD1Ev(!cir.ptr<!rec_Foo>) 
special_member<#cir.cxx_dtor<!rec_Foo>>
 }

From c9e5cbcbdd655b0acba4218c2d01b9493b0c0838 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hendrik=20H=C3=BCbner?=
 <[email protected]>
Date: Tue, 2 Dec 2025 18:34:20 +0100
Subject: [PATCH 8/8] Remove debug output for trivial copy constructor

Removed debug output for successful trivial copy constructor detection.
---
 clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 53a7cd81e61ec..79297babe2b1e 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -1094,7 +1094,6 @@ void 
LoweringPreparePass::lowerTrivialCopyCall(cir::CallOp op) {
   std::optional<cir::CtorKind> ctorKind = funcOp.getCxxConstructorKind();
   if (ctorKind && *ctorKind == cir::CtorKind::Copy &&
       funcOp.isCxxTrivialMemberFunction()) {
-    llvm::outs() << "success \n";
     // Replace the trivial copy constructor call with a `CopyOp`
     CIRBaseBuilderTy builder(getContext());
     mlir::ValueRange operands = op.getOperands();

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

Reply via email to