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

From 905c12d4865978533b34ee2b20c77790d09e973e Mon Sep 17 00:00:00 2001
From: hhuebner <[email protected]>
Date: Mon, 24 Nov 2025 23:05:09 +0100
Subject: [PATCH 1/4] [CIR] Add VACopy builtin

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  26 +++++
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |   7 +-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  12 ++
 clang/test/CIR/CodeGen/var_arg.c              | 103 +++++++++++++++++-
 4 files changed, 146 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index a19c4f951fff9..8ad203c43a001 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4704,6 +4704,32 @@ def CIR_VAEndOp : CIR_Op<"va_end"> {
   }];
 }
 
+def CIR_VACopyOp : CIR_Op<"va.copy"> {
+  let summary = "Copied a variable argument list";
+  let description = [{
+    The `cir.copy` operation models the C/C++ va_copy macro.
+    The variable argument list passed as the `$src_list` is copied to an
+    unitialized `va_list` in the destination operand. The next argument that
+    can be extracted from the copied list is the same as the next argument in
+    the source list. The copied list must be destroyed with `va_end`.
+
+    Example:
+
+    ```mlir
+
+    ```
+  }];
+
+  let arguments = (ins
+    CIR_PointerType:$dst_list,
+    CIR_PointerType:$src_list
+  );
+
+  let assemblyFormat = [{
+    $src_list `to` $dst_list attr-dict `:` type(operands)
+  }];
+}
+
 def CIR_VAArgOp : CIR_Op<"va_arg"> {
   let summary = "Fetches next variadic element as a given type";
   let description = [{
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index d220fdf4dc8a7..95ddfdfc7358a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -266,7 +266,12 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl 
&gd, unsigned builtinID,
   case Builtin::BI__builtin_va_end:
     emitVAEnd(emitVAListRef(e->getArg(0)).getPointer());
     return {};
-
+  case Builtin::BI__builtin_va_copy: {
+    mlir::Value dstPtr = emitVAListRef(e->getArg(0)).getPointer();
+    mlir::Value srcPtr = emitVAListRef(e->getArg(1)).getPointer();
+    cir::VACopyOp::create(builder, dstPtr.getLoc(), dstPtr, srcPtr);
+    return {};
+  }
   case Builtin::BIcos:
   case Builtin::BIcosf:
   case Builtin::BIcosl:
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6136d48204e0c..f3c1b92fafcd3 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -4034,6 +4034,18 @@ mlir::LogicalResult 
CIRToLLVMVAEndOpLowering::matchAndRewrite(
   return mlir::success();
 }
 
+mlir::LogicalResult CIRToLLVMVACopyOpLowering::matchAndRewrite(
+    cir::VACopyOp op, OpAdaptor adaptor,
+    mlir::ConversionPatternRewriter &rewriter) const {
+  auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext());
+  auto dstList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), 
opaquePtr,
+                                               adaptor.getDstList());
+  auto srcList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), 
opaquePtr,
+                                               adaptor.getSrcList());
+  rewriter.replaceOpWithNewOp<mlir::LLVM::VaCopyOp>(op, dstList, srcList);
+  return mlir::success();
+}
+
 mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(
     cir::VAArgOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c
index f5b92c61e11ad..82de39a3db58a 100644
--- a/clang/test/CIR/CodeGen/var_arg.c
+++ b/clang/test/CIR/CodeGen/var_arg.c
@@ -141,7 +141,7 @@ int stdarg_start(int count, ...) {
 // OGCG:   %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
 // OGCG:   br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
 //
-// OGCG: vaarg.in_reg:                                   
+// OGCG: vaarg.in_reg:
 // OGCG:   %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 3
 // OGCG:   %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
 // OGCG:   %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 
%[[GPOFFSET]]
@@ -164,3 +164,104 @@ int stdarg_start(int count, ...) {
 // OGCG:   call void @llvm.va_end.p0(ptr %[[DECAY2]])
 // OGCG:   %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
 // OGCG:   ret i32 %[[VAL]]
+
+int stdarg_copy(int count, ...) {
+    __builtin_va_list args;
+    __builtin_stdarg_start(args, 12345);
+    __builtin_va_list dup;
+    __builtin_va_copy(args, dup);
+    int res = __builtin_va_arg(dup, int);
+    __builtin_va_end(args);
+    __builtin_va_end(dup);
+    return res;
+}
+
+// CIR-LABEL: cir.func dso_local @stdarg_copy(
+// CIR:   %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", 
init]
+// CIR:   %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
+// CIR:   %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
+// CIR:   %[[DUP_AREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["dup"]
+// CIR:   %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init]
+// CIR:   cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[VA_PTR0:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i
+// CIR:   cir.va_start %[[VA_PTR0]] %[[C12345]] : 
!cir.ptr<!rec___va_list_tag>, !s32i
+// CIR:   %[[VA_PTR_SRC:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[VA_PTR_DEST:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   cir.va.copy %[[VA_PTR_DEST]] to %[[VA_PTR_SRC]] : 
!cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[VA_PTR_COPY:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR_COPY]] : 
(!cir.ptr<!rec___va_list_tag>) -> !s32i
+// CIR:   cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[VA_PTR2:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[VA_PTR3:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:   cir.va_end %[[VA_PTR3]] : !cir.ptr<!rec___va_list_tag>
+// CIR:   %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, 
!s32i
+// CIR:   cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR:   %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, 
!s32i
+// CIR:   cir.return %[[RETVAL]] : !s32i
+
+// LLVM-LABEL: define dso_local i32 @stdarg_copy(
+// LLVM:   %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
+// LLVM:   %[[RET_ADDR:.+]] = alloca i32{{.*}}
+// LLVM:   %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM:   %[[DUP_AREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM:   %[[RES_ADDR:.+]] = alloca i32{{.*}}
+// LLVM:   %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[VAAREA]], i32 0
+// LLVM:   call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM:   %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[VAAREA]], i32 0
+// LLVM:   %[[VA_PTR_DUP:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[DUP_AREA]], i32 0
+// LLVM:   call void @llvm.va_copy.p0(ptr %[[VA_PTR1]], ptr %[[VA_PTR_DUP]])
+// LLVM:   %[[VA_PTR_DUP2:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[DUP_AREA]], i32 0
+// LLVM:   %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR_DUP2]], i32
+// LLVM:   store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
+// LLVM:   %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[VAAREA]], i32 0
+// LLVM:   call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
+// LLVM:   %[[VA_PTR3:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[DUP_AREA]], i32 0
+// LLVM:   call void @llvm.va_end.p0(ptr %[[VA_PTR3]])
+// LLVM:   %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
+// LLVM:   store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
+// LLVM:   %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
+// LLVM:   ret i32 %[[RETVAL]]
+
+// OGCG-LABEL: define dso_local i32 @stdarg_copy
+// OGCG:   %[[COUNT_ADDR:.+]] = alloca i32
+// OGCG:   %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// OGCG:   %[[DUP_AREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// OGCG:   %[[RES_ADDR:.+]] = alloca i32
+// OGCG:   %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], 
ptr %[[VAAREA]], i64 0, i64 0
+// OGCG:   call void @llvm.va_start.p0(ptr %[[DECAY]])
+// OGCG:   %[[DECAY1:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
+// OGCG:   %[[DECAY_DUP:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG:   call void @llvm.va_copy.p0(ptr %[[DECAY1]], ptr %[[DECAY_DUP]])
+// OGCG:   %[[DECAY_DUP2:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG:   %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 0
+// OGCG:   %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]]
+// OGCG:   %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
+// OGCG:   br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
+//
+// OGCG: vaarg.in_reg:
+// OGCG:   %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 3
+// OGCG:   %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
+// OGCG:   %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 
%[[GPOFFSET]]
+// OGCG:   %[[NEXT_GPOFFSET:.+]] = add i32 %[[GPOFFSET]], 8
+// OGCG:   store i32 %[[NEXT_GPOFFSET]], ptr %[[GPOFFSET_PTR]]
+// OGCG:   br label %vaarg.end
+//
+// OGCG: vaarg.in_mem:
+// OGCG:   %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 2
+// OGCG:   %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]]
+// OGCG:   %[[OVERFLOW_NEXT:.+]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8
+// OGCG:   store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]]
+// OGCG:   br label %vaarg.end
+//
+// OGCG: vaarg.end:
+// OGCG:   %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ 
%[[OVERFLOW]], %vaarg.in_mem ]
+// OGCG:   %[[LOADED:.+]] = load i32, ptr %[[PHI]]
+// OGCG:   store i32 %[[LOADED]], ptr %[[RES_ADDR]]
+// OGCG:   %[[DECAY2:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
+// OGCG:   call void @llvm.va_end.p0(ptr %[[DECAY2]])
+// OGCG:   %[[DECAY_DUP3:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
+// OGCG:   call void @llvm.va_end.p0(ptr %[[DECAY_DUP3]])
+// OGCG:   %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
+// OGCG:   ret i32 %[[VAL]]

From 6ddc17027ed4d51e8a62b281520421b0b4dcf7b2 Mon Sep 17 00:00:00 2001
From: hhuebner <[email protected]>
Date: Mon, 24 Nov 2025 23:07:36 +0100
Subject: [PATCH 2/4] example

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 8ad203c43a001..78143ab44fa7e 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4716,6 +4716,14 @@ def CIR_VACopyOp : CIR_Op<"va.copy"> {
     Example:
 
     ```mlir
+    ```mlir
+    // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
+    %p = cir.cast array_to_ptrdecay %args
+          : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
+          -> !cir.ptr<!rec___va_list_tag>
+    cir.va.copy %p to %dst
+          : (!cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>)
+    ```
 
     ```
   }];

From 1c5351ec69de26ece6835ec135ad41a542fb0ca4 Mon Sep 17 00:00:00 2001
From: hhuebner <[email protected]>
Date: Thu, 27 Nov 2025 02:06:30 +0100
Subject: [PATCH 3/4] test

---
 clang/test/CIR/CodeGen/var_arg.c | 111 +++++--------------------------
 1 file changed, 15 insertions(+), 96 deletions(-)

diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c
index 82de39a3db58a..6e59b9daba0f4 100644
--- a/clang/test/CIR/CodeGen/var_arg.c
+++ b/clang/test/CIR/CodeGen/var_arg.c
@@ -165,103 +165,22 @@ int stdarg_start(int count, ...) {
 // OGCG:   %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
 // OGCG:   ret i32 %[[VAL]]
 
-int stdarg_copy(int count, ...) {
-    __builtin_va_list args;
-    __builtin_stdarg_start(args, 12345);
-    __builtin_va_list dup;
-    __builtin_va_copy(args, dup);
-    int res = __builtin_va_arg(dup, int);
-    __builtin_va_end(args);
-    __builtin_va_end(dup);
-    return res;
+void stdarg_copy() {
+    __builtin_va_list src, dest;
+    __builtin_va_copy(src, dest);
 }
 
-// CIR-LABEL: cir.func dso_local @stdarg_copy(
-// CIR:   %[[COUNT_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["count", 
init]
-// CIR:   %[[RET_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
-// CIR:   %[[VAAREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["args"]
-// CIR:   %[[DUP_AREA:.+]] = cir.alloca !cir.array<!rec___va_list_tag x 1>, 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>>, ["dup"]
-// CIR:   %[[RES_ADDR:.+]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["res", init]
-// CIR:   cir.store %arg0, %[[COUNT_ADDR]] : !s32i, !cir.ptr<!s32i>
-// CIR:   %[[VA_PTR0:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
-// CIR:   %[[C12345:.+]] = cir.const #cir.int<12345> : !s32i
-// CIR:   cir.va_start %[[VA_PTR0]] %[[C12345]] : 
!cir.ptr<!rec___va_list_tag>, !s32i
-// CIR:   %[[VA_PTR_SRC:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
-// CIR:   %[[VA_PTR_DEST:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
-// CIR:   cir.va.copy %[[VA_PTR_DEST]] to %[[VA_PTR_SRC]] : 
!cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>
-// CIR:   %[[VA_PTR_COPY:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
-// CIR:   %[[VA_ARG:.+]] = cir.va_arg %[[VA_PTR_COPY]] : 
(!cir.ptr<!rec___va_list_tag>) -> !s32i
-// CIR:   cir.store{{.*}} %[[VA_ARG]], %[[RES_ADDR]] : !s32i, !cir.ptr<!s32i>
-// CIR:   %[[VA_PTR2:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
-// CIR:   cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
-// CIR:   %[[VA_PTR3:.+]] = cir.cast array_to_ptrdecay %[[DUP_AREA]] : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
-// CIR:   cir.va_end %[[VA_PTR3]] : !cir.ptr<!rec___va_list_tag>
-// CIR:   %[[RESULT:.+]] = cir.load{{.*}} %[[RES_ADDR]] : !cir.ptr<!s32i>, 
!s32i
-// CIR:   cir.store %[[RESULT]], %[[RET_ADDR]] : !s32i, !cir.ptr<!s32i>
-// CIR:   %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, 
!s32i
-// CIR:   cir.return %[[RETVAL]] : !s32i
+// CIR-LABEL: @stdarg_copy
+// CIR:    %{{.*}} = cir.cast array_to_ptrdecay %{{.*}} : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:    %{{.*}} = cir.cast array_to_ptrdecay %{{.*}} : 
!cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR:    cir.va.copy %{{.*}} to %{{.*}} : !cir.ptr<!rec___va_list_tag>, 
!cir.ptr<!rec___va_list_tag>
 
-// LLVM-LABEL: define dso_local i32 @stdarg_copy(
-// LLVM:   %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
-// LLVM:   %[[RET_ADDR:.+]] = alloca i32{{.*}}
-// LLVM:   %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
-// LLVM:   %[[DUP_AREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
-// LLVM:   %[[RES_ADDR:.+]] = alloca i32{{.*}}
-// LLVM:   %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[VAAREA]], i32 0
-// LLVM:   call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
-// LLVM:   %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[VAAREA]], i32 0
-// LLVM:   %[[VA_PTR_DUP:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[DUP_AREA]], i32 0
-// LLVM:   call void @llvm.va_copy.p0(ptr %[[VA_PTR1]], ptr %[[VA_PTR_DUP]])
-// LLVM:   %[[VA_PTR_DUP2:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[DUP_AREA]], i32 0
-// LLVM:   %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR_DUP2]], i32
-// LLVM:   store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
-// LLVM:   %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[VAAREA]], i32 0
-// LLVM:   call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
-// LLVM:   %[[VA_PTR3:.+]] = getelementptr %struct.__va_list_tag, ptr 
%[[DUP_AREA]], i32 0
-// LLVM:   call void @llvm.va_end.p0(ptr %[[VA_PTR3]])
-// LLVM:   %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
-// LLVM:   store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
-// LLVM:   %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
-// LLVM:   ret i32 %[[RETVAL]]
+// LLVM-LABEL: @stdarg_copy
+// LLVM:   %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
+// LLVM:   %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
+// LLVM:   call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}}
 
-// OGCG-LABEL: define dso_local i32 @stdarg_copy
-// OGCG:   %[[COUNT_ADDR:.+]] = alloca i32
-// OGCG:   %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
-// OGCG:   %[[DUP_AREA:.+]] = alloca [1 x %struct.__va_list_tag]
-// OGCG:   %[[RES_ADDR:.+]] = alloca i32
-// OGCG:   %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], 
ptr %[[VAAREA]], i64 0, i64 0
-// OGCG:   call void @llvm.va_start.p0(ptr %[[DECAY]])
-// OGCG:   %[[DECAY1:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
-// OGCG:   %[[DECAY_DUP:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
-// OGCG:   call void @llvm.va_copy.p0(ptr %[[DECAY1]], ptr %[[DECAY_DUP]])
-// OGCG:   %[[DECAY_DUP2:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
-// OGCG:   %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 0
-// OGCG:   %[[GPOFFSET:.+]] = load i32, ptr %[[GPOFFSET_PTR]]
-// OGCG:   %[[COND:.+]] = icmp ule i32 %[[GPOFFSET]], 40
-// OGCG:   br i1 %[[COND]], label %vaarg.in_reg, label %vaarg.in_mem
-//
-// OGCG: vaarg.in_reg:
-// OGCG:   %[[REGSAVE_PTR:.+]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 3
-// OGCG:   %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
-// OGCG:   %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 
%[[GPOFFSET]]
-// OGCG:   %[[NEXT_GPOFFSET:.+]] = add i32 %[[GPOFFSET]], 8
-// OGCG:   store i32 %[[NEXT_GPOFFSET]], ptr %[[GPOFFSET_PTR]]
-// OGCG:   br label %vaarg.end
-//
-// OGCG: vaarg.in_mem:
-// OGCG:   %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[DECAY_DUP2]], i32 0, i32 2
-// OGCG:   %[[OVERFLOW:.+]] = load ptr, ptr %[[OVERFLOW_PTR]]
-// OGCG:   %[[OVERFLOW_NEXT:.+]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8
-// OGCG:   store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]]
-// OGCG:   br label %vaarg.end
-//
-// OGCG: vaarg.end:
-// OGCG:   %[[PHI:.+]] = phi ptr [ %[[VAADDR1]], %vaarg.in_reg ], [ 
%[[OVERFLOW]], %vaarg.in_mem ]
-// OGCG:   %[[LOADED:.+]] = load i32, ptr %[[PHI]]
-// OGCG:   store i32 %[[LOADED]], ptr %[[RES_ADDR]]
-// OGCG:   %[[DECAY2:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[VAAREA]], i64 0, i64 0
-// OGCG:   call void @llvm.va_end.p0(ptr %[[DECAY2]])
-// OGCG:   %[[DECAY_DUP3:.+]] = getelementptr inbounds [1 x 
%struct.__va_list_tag], ptr %[[DUP_AREA]], i64 0, i64 0
-// OGCG:   call void @llvm.va_end.p0(ptr %[[DECAY_DUP3]])
-// OGCG:   %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
-// OGCG:   ret i32 %[[VAL]]
+// OGCG-LABEL: @stdarg_copy
+// OGCG:   %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr 
%{{.*}}
+// OGCG:   %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr 
%{{.*}}
+// OGCG:   call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}}

From 72bdfb076f5054ef405dd10b6dcee586a4b20005 Mon Sep 17 00:00:00 2001
From: hhuebner <[email protected]>
Date: Thu, 27 Nov 2025 22:12:52 +0100
Subject: [PATCH 4/4] formatting

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 78143ab44fa7e..0a9450f666c34 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4715,7 +4715,6 @@ def CIR_VACopyOp : CIR_Op<"va.copy"> {
 
     Example:
 
-    ```mlir
     ```mlir
     // %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
     %p = cir.cast array_to_ptrdecay %args
@@ -4724,8 +4723,6 @@ def CIR_VACopyOp : CIR_Op<"va.copy"> {
     cir.va.copy %p to %dst
           : (!cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>)
     ```
-
-    ```
   }];
 
   let arguments = (ins

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

Reply via email to