[clang] [CIR] Add support for lowering __builtin_c23_va_start in ClangIR (PR #208741)
Akshay K via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 16 09:36:33 PDT 2026
https://github.com/kumarak updated https://github.com/llvm/llvm-project/pull/208741
>From b97f5642ec7c8f970b04209022496390dc5af0d4 Mon Sep 17 00:00:00 2001
From: AkshayK <iit.akshay at gmail.com>
Date: Fri, 10 Jul 2026 10:30:16 -0400
Subject: [PATCH 1/4] [CIR] Handle __builtin_c23_va_start
C23 va_start expands to __builtin_c23_va_start, which was hitting the
unimplemented-builtin NYI path, so all variadic code failed to compile
with -fclangir in -std=c23 mode. Lower it exactly like
__builtin_va_start: the va_list is always arg 0.
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 1 +
clang/test/CIR/CodeGen/var_arg-c23.c | 41 +++++++++++++++++++++++++
2 files changed, 42 insertions(+)
create mode 100644 clang/test/CIR/CodeGen/var_arg-c23.c
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 3c48b8b67d9ee..84bb33663de05 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1059,6 +1059,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
// C stdarg builtins.
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
+ case Builtin::BI__builtin_c23_va_start:
case Builtin::BI__va_start: {
mlir::Value vaList = builtinID == Builtin::BI__va_start
? emitScalarExpr(e->getArg(0))
diff --git a/clang/test/CIR/CodeGen/var_arg-c23.c b/clang/test/CIR/CodeGen/var_arg-c23.c
new file mode 100644
index 0000000000000..1bb0b7099b5fe
--- /dev/null
+++ b/clang/test/CIR/CodeGen/var_arg-c23.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+void noargs(...) {
+ __builtin_va_list list;
+ __builtin_va_start(list, 0);
+ __builtin_c23_va_start(list);
+ __builtin_va_end(list);
+}
+
+// CIR-LABEL: cir.func {{.*}} @noargs(
+// CIR: %[[VAAREA:.+]] = cir.alloca "list" {{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
+// CIR: %[[VA_PTR0:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]]
+// CIR-NEXT: cir.va_start %[[VA_PTR0]] : !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_PTR1:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]]
+// CIR-NEXT: cir.va_start %[[VA_PTR1]] : !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va_end %{{.+}} : !cir.ptr<!rec___va_list_tag>
+
+// LLVM-LABEL: define {{.*}}void @noargs(...)
+// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM: call void @llvm.va_end.p0(ptr %{{.+}})
+
+void with_param(int count, ...) {
+ __builtin_va_list list;
+ __builtin_c23_va_start(list, count);
+ __builtin_va_end(list);
+}
+
+// CIR-LABEL: cir.func {{.*}} @with_param(
+// CIR: cir.va_start %{{.+}} : !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va_end %{{.+}} : !cir.ptr<!rec___va_list_tag>
+
+// LLVM-LABEL: define {{.*}}void @with_param(i32 noundef %{{.+}}, ...)
+// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM: call void @llvm.va_end.p0(ptr %{{.+}})
>From 14d47b5bf40354f2bd61e63abb164349a2ef8205 Mon Sep 17 00:00:00 2001
From: AkshayK <iit.akshay at gmail.com>
Date: Wed, 15 Jul 2026 13:29:29 -0400
Subject: [PATCH 2/4] [CIR] Merge C23 va_start test into var_arg.c
---
clang/test/CIR/CodeGen/var_arg-c23.c | 41 ---------------------
clang/test/CIR/CodeGen/var_arg.c | 54 ++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 41 deletions(-)
delete mode 100644 clang/test/CIR/CodeGen/var_arg-c23.c
diff --git a/clang/test/CIR/CodeGen/var_arg-c23.c b/clang/test/CIR/CodeGen/var_arg-c23.c
deleted file mode 100644
index 1bb0b7099b5fe..0000000000000
--- a/clang/test/CIR/CodeGen/var_arg-c23.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
-// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
-// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
-// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
-// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
-
-void noargs(...) {
- __builtin_va_list list;
- __builtin_va_start(list, 0);
- __builtin_c23_va_start(list);
- __builtin_va_end(list);
-}
-
-// CIR-LABEL: cir.func {{.*}} @noargs(
-// CIR: %[[VAAREA:.+]] = cir.alloca "list" {{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
-// CIR: %[[VA_PTR0:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]]
-// CIR-NEXT: cir.va_start %[[VA_PTR0]] : !cir.ptr<!rec___va_list_tag>
-// CIR: %[[VA_PTR1:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]]
-// CIR-NEXT: cir.va_start %[[VA_PTR1]] : !cir.ptr<!rec___va_list_tag>
-// CIR: cir.va_end %{{.+}} : !cir.ptr<!rec___va_list_tag>
-
-// LLVM-LABEL: define {{.*}}void @noargs(...)
-// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
-// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
-// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
-// LLVM: call void @llvm.va_end.p0(ptr %{{.+}})
-
-void with_param(int count, ...) {
- __builtin_va_list list;
- __builtin_c23_va_start(list, count);
- __builtin_va_end(list);
-}
-
-// CIR-LABEL: cir.func {{.*}} @with_param(
-// CIR: cir.va_start %{{.+}} : !cir.ptr<!rec___va_list_tag>
-// CIR: cir.va_end %{{.+}} : !cir.ptr<!rec___va_list_tag>
-
-// LLVM-LABEL: define {{.*}}void @with_param(i32 noundef %{{.+}}, ...)
-// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
-// LLVM: call void @llvm.va_end.p0(ptr %{{.+}})
diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c
index 7204cef68578b..40861667e5ba7 100644
--- a/clang/test/CIR/CodeGen/var_arg.c
+++ b/clang/test/CIR/CodeGen/var_arg.c
@@ -4,6 +4,17 @@
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+//
+// C23 is required for __builtin_c23_va_start and for variadic functions with
+// no named parameters; the *-C23 prefixes check the guarded functions at the
+// end of this file. The LLVM-C23 checks are shared between the ClangIR
+// pipeline and OG CodeGen.
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.c23.cir
+// RUN: FileCheck --input-file=%t.c23.cir %s -check-prefix=CIR-C23
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.c23.ll
+// RUN: FileCheck --input-file=%t-cir.c23.ll %s -check-prefix=LLVM-C23
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.c23.ll
+// RUN: FileCheck --input-file=%t.c23.ll %s -check-prefix=LLVM-C23
// CIR: !rec___va_list_tag = !cir.struct<"__va_list_tag" {!u32i, !u32i, !cir.ptr<!void>, !cir.ptr<!void>}
// LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr }
@@ -252,3 +263,46 @@ int varargs_new(char *fmt, ...) {
// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
// OGCG: ret i32 %[[VAL]]
+
+// C23 only: __builtin_c23_va_start and variadic functions with no named
+// parameters. Ensure that __builtin_va_start(list, 0) and
+// __builtin_c23_va_start(list) have the same codegen.
+#if __STDC_VERSION__ >= 202311L
+
+void noargs(...) {
+ __builtin_va_list list;
+ __builtin_va_start(list, 0);
+ __builtin_c23_va_start(list);
+ __builtin_va_end(list);
+}
+
+// CIR-C23-LABEL: cir.func {{.*}} @noargs(
+// CIR-C23: %[[VAAREA:.+]] = cir.alloca "list" {{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
+// CIR-C23: %[[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-C23-NEXT: cir.va_start %[[VA_PTR0]] : !cir.ptr<!rec___va_list_tag>
+// CIR-C23: %[[VA_PTR1:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR-C23-NEXT: cir.va_start %[[VA_PTR1]] : !cir.ptr<!rec___va_list_tag>
+// CIR-C23: %[[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-C23-NEXT: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
+
+// LLVM-C23-LABEL: define {{.*}}void @noargs(...)
+// LLVM-C23: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// LLVM-C23: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM-C23: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM-C23: call void @llvm.va_end.p0(ptr %{{.+}})
+
+void with_param(int count, ...) {
+ __builtin_va_list list;
+ __builtin_c23_va_start(list, count);
+ __builtin_va_end(list);
+}
+
+// CIR-C23-LABEL: cir.func {{.*}} @with_param(
+// CIR-C23: cir.va_start %{{.+}} : !cir.ptr<!rec___va_list_tag>
+// CIR-C23: cir.va_end %{{.+}} : !cir.ptr<!rec___va_list_tag>
+
+// LLVM-C23-LABEL: define {{.*}}void @with_param(i32 noundef %{{.+}}, ...)
+// LLVM-C23: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM-C23: call void @llvm.va_end.p0(ptr %{{.+}})
+
+#endif // __STDC_VERSION__ >= 202311L
>From 32829b13223a871ffd292b7c50dc951c96cc0720 Mon Sep 17 00:00:00 2001
From: AkshayK <iit.akshay at gmail.com>
Date: Wed, 15 Jul 2026 20:00:29 -0400
Subject: [PATCH 3/4] [CIR] Run var_arg.c under -std=c23 with a single RUN set
---
clang/test/CIR/CodeGen/var_arg.c | 174 ++++++++++++++-----------------
1 file changed, 81 insertions(+), 93 deletions(-)
diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c
index 40861667e5ba7..6a711ae4afa69 100644
--- a/clang/test/CIR/CodeGen/var_arg.c
+++ b/clang/test/CIR/CodeGen/var_arg.c
@@ -1,24 +1,17 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
-// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefixes=LLVM,LLVM-CIR
+// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=OGCG,LLVM
//
// C23 is required for __builtin_c23_va_start and for variadic functions with
-// no named parameters; the *-C23 prefixes check the guarded functions at the
-// end of this file. The LLVM-C23 checks are shared between the ClangIR
-// pipeline and OG CodeGen.
-// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.c23.cir
-// RUN: FileCheck --input-file=%t.c23.cir %s -check-prefix=CIR-C23
-// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.c23.ll
-// RUN: FileCheck --input-file=%t-cir.c23.ll %s -check-prefix=LLVM-C23
-// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.c23.ll
-// RUN: FileCheck --input-file=%t.c23.ll %s -check-prefix=LLVM-C23
+// no named parameters. LLVM checks lines where the ClangIR pipeline and OG
+// CodeGen emit identical LLVM IR; LLVM-CIR and OGCG check the lines where
+// the two pipelines differ.
// CIR: !rec___va_list_tag = !cir.struct<"__va_list_tag" {!u32i, !u32i, !cir.ptr<!void>, !cir.ptr<!void>}
// LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr }
-// OGCG: %struct.__va_list_tag = type { i32, i32, ptr, ptr }
int varargs(int count, ...) {
__builtin_va_list args;
@@ -44,22 +37,22 @@ int varargs(int count, ...) {
// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[RETVAL]] : !s32i
-// LLVM-LABEL: define dso_local i32 @varargs(
-// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
-// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}}
-// LLVM: %[[VAAREA:.+]] = 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_ARG:.+]] = va_arg ptr %[[VA_PTR1]], 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: %[[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-CIR-LABEL: define dso_local i32 @varargs(
+// LLVM-CIR: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
+// LLVM-CIR: %[[RET_ADDR:.+]] = alloca i32{{.*}}
+// LLVM-CIR: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM-CIR: %[[RES_ADDR:.+]] = alloca i32{{.*}}
+// LLVM-CIR: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM-CIR: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32
+// LLVM-CIR: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
+// LLVM-CIR: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
+// LLVM-CIR: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
+// LLVM-CIR: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
+// LLVM-CIR: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
+// LLVM-CIR: ret i32 %[[RETVAL]]
// OGCG-LABEL: define dso_local i32 @varargs
// OGCG: %[[COUNT_ADDR:.+]] = alloca i32
@@ -117,22 +110,22 @@ int stdarg_start(int count, ...) {
// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[RETVAL]] : !s32i
-// LLVM-LABEL: define dso_local i32 @stdarg_start(
-// LLVM: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
-// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}}
-// LLVM: %[[VAAREA:.+]] = 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_ARG:.+]] = va_arg ptr %[[VA_PTR1]], 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: %[[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-CIR-LABEL: define dso_local i32 @stdarg_start(
+// LLVM-CIR: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
+// LLVM-CIR: %[[RET_ADDR:.+]] = alloca i32{{.*}}
+// LLVM-CIR: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM-CIR: %[[RES_ADDR:.+]] = alloca i32{{.*}}
+// LLVM-CIR: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM-CIR: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32
+// LLVM-CIR: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
+// LLVM-CIR: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
+// LLVM-CIR: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
+// LLVM-CIR: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
+// LLVM-CIR: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
+// LLVM-CIR: ret i32 %[[RETVAL]]
// OGCG-LABEL: define dso_local i32 @stdarg_start
// OGCG: %[[COUNT_ADDR:.+]] = alloca i32
@@ -180,10 +173,10 @@ void 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.va_copy %{{.*}} to %{{.*}} : !cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>
-// 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 %{{.*}}
+// LLVM-CIR-LABEL: @stdarg_copy
+// LLVM-CIR: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
+// LLVM-CIR: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
+// LLVM-CIR: call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}}
// OGCG-LABEL: @stdarg_copy
// OGCG: %{{.*}} = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %{{.*}}
@@ -215,22 +208,22 @@ int varargs_new(char *fmt, ...) {
// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[RETVAL]] : !s32i
-// LLVM-LABEL: define dso_local i32 @varargs_new(
-// LLVM: %[[FMT_ADDR:.+]] = alloca ptr
-// LLVM: %[[RET_ADDR:.+]] = alloca i32{{.*}}
-// LLVM: %[[VAAREA:.+]] = 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_ARG:.+]] = va_arg ptr %[[VA_PTR1]], 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: %[[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-CIR-LABEL: define dso_local i32 @varargs_new(
+// LLVM-CIR: %[[FMT_ADDR:.+]] = alloca ptr
+// LLVM-CIR: %[[RET_ADDR:.+]] = alloca i32{{.*}}
+// LLVM-CIR: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
+// LLVM-CIR: %[[RES_ADDR:.+]] = alloca i32{{.*}}
+// LLVM-CIR: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM-CIR: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32
+// LLVM-CIR: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
+// LLVM-CIR: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
+// LLVM-CIR: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
+// LLVM-CIR: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
+// LLVM-CIR: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
+// LLVM-CIR: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
+// LLVM-CIR: ret i32 %[[RETVAL]]
// OGCG-LABEL: define dso_local i32 @varargs_new
// OGCG: %[[FMT_ADDR:.+]] = alloca ptr
@@ -264,11 +257,8 @@ int varargs_new(char *fmt, ...) {
// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
// OGCG: ret i32 %[[VAL]]
-// C23 only: __builtin_c23_va_start and variadic functions with no named
-// parameters. Ensure that __builtin_va_start(list, 0) and
-// __builtin_c23_va_start(list) have the same codegen.
-#if __STDC_VERSION__ >= 202311L
-
+// Ensure that __builtin_va_start(list, 0) and __builtin_c23_va_start(list)
+// have the same codegen.
void noargs(...) {
__builtin_va_list list;
__builtin_va_start(list, 0);
@@ -276,20 +266,20 @@ void noargs(...) {
__builtin_va_end(list);
}
-// CIR-C23-LABEL: cir.func {{.*}} @noargs(
-// CIR-C23: %[[VAAREA:.+]] = cir.alloca "list" {{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
-// CIR-C23: %[[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-C23-NEXT: cir.va_start %[[VA_PTR0]] : !cir.ptr<!rec___va_list_tag>
-// CIR-C23: %[[VA_PTR1:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
-// CIR-C23-NEXT: cir.va_start %[[VA_PTR1]] : !cir.ptr<!rec___va_list_tag>
-// CIR-C23: %[[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-C23-NEXT: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
+// CIR-LABEL: cir.func {{.*}} @noargs(
+// CIR: %[[VAAREA:.+]] = cir.alloca "list" {{.*}} : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
+// 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-NEXT: cir.va_start %[[VA_PTR0]] : !cir.ptr<!rec___va_list_tag>
+// CIR: %[[VA_PTR1:.+]] = cir.cast array_to_ptrdecay %[[VAAREA]] : !cir.ptr<!cir.array<!rec___va_list_tag x 1>> -> !cir.ptr<!rec___va_list_tag>
+// CIR-NEXT: cir.va_start %[[VA_PTR1]] : !cir.ptr<!rec___va_list_tag>
+// 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-NEXT: cir.va_end %[[VA_PTR2]] : !cir.ptr<!rec___va_list_tag>
-// LLVM-C23-LABEL: define {{.*}}void @noargs(...)
-// LLVM-C23: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
-// LLVM-C23: call void @llvm.va_start.p0(ptr %{{.+}})
-// LLVM-C23: call void @llvm.va_start.p0(ptr %{{.+}})
-// LLVM-C23: call void @llvm.va_end.p0(ptr %{{.+}})
+// LLVM-LABEL: define {{.*}}void @noargs(...)
+// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM: call void @llvm.va_end.p0(ptr %{{.+}})
void with_param(int count, ...) {
__builtin_va_list list;
@@ -297,12 +287,10 @@ void with_param(int count, ...) {
__builtin_va_end(list);
}
-// CIR-C23-LABEL: cir.func {{.*}} @with_param(
-// CIR-C23: cir.va_start %{{.+}} : !cir.ptr<!rec___va_list_tag>
-// CIR-C23: cir.va_end %{{.+}} : !cir.ptr<!rec___va_list_tag>
-
-// LLVM-C23-LABEL: define {{.*}}void @with_param(i32 noundef %{{.+}}, ...)
-// LLVM-C23: call void @llvm.va_start.p0(ptr %{{.+}})
-// LLVM-C23: call void @llvm.va_end.p0(ptr %{{.+}})
+// CIR-LABEL: cir.func {{.*}} @with_param(
+// CIR: cir.va_start %{{.+}} : !cir.ptr<!rec___va_list_tag>
+// CIR: cir.va_end %{{.+}} : !cir.ptr<!rec___va_list_tag>
-#endif // __STDC_VERSION__ >= 202311L
+// LLVM-LABEL: define {{.*}}void @with_param(i32 noundef %{{.+}}, ...)
+// LLVM: call void @llvm.va_start.p0(ptr %{{.+}})
+// LLVM: call void @llvm.va_end.p0(ptr %{{.+}})
>From 1c7be2f57f967b7cd3fdfe5d57dd750675e1b5f8 Mon Sep 17 00:00:00 2001
From: AkshayK <iit.akshay at gmail.com>
Date: Thu, 16 Jul 2026 12:35:25 -0400
Subject: [PATCH 4/4] [CIR] Address review: unify LLVM and OGCG checks into a
single shared prefix
---
clang/test/CIR/CodeGen/var_arg.c | 204 +++++++------------------------
1 file changed, 42 insertions(+), 162 deletions(-)
diff --git a/clang/test/CIR/CodeGen/var_arg.c b/clang/test/CIR/CodeGen/var_arg.c
index 6a711ae4afa69..c8a4e2ac1a732 100644
--- a/clang/test/CIR/CodeGen/var_arg.c
+++ b/clang/test/CIR/CodeGen/var_arg.c
@@ -1,14 +1,14 @@
// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
-// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefixes=LLVM,LLVM-CIR
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -std=c23 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
-// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=OGCG,LLVM
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
//
// C23 is required for __builtin_c23_va_start and for variadic functions with
-// no named parameters. LLVM checks lines where the ClangIR pipeline and OG
-// CodeGen emit identical LLVM IR; LLVM-CIR and OGCG check the lines where
-// the two pipelines differ.
+// no named parameters. The LLVM checks are shared between the ClangIR
+// pipeline and OG CodeGen, so they only check IR that is common to both
+// pipelines.
// CIR: !rec___va_list_tag = !cir.struct<"__va_list_tag" {!u32i, !u32i, !cir.ptr<!void>, !cir.ptr<!void>}
// LLVM: %struct.__va_list_tag = type { i32, i32, ptr, ptr }
@@ -37,54 +37,17 @@ int varargs(int count, ...) {
// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[RETVAL]] : !s32i
-// LLVM-CIR-LABEL: define dso_local i32 @varargs(
-// LLVM-CIR: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
-// LLVM-CIR: %[[RET_ADDR:.+]] = alloca i32{{.*}}
-// LLVM-CIR: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
-// LLVM-CIR: %[[RES_ADDR:.+]] = alloca i32{{.*}}
-// LLVM-CIR: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
-// LLVM-CIR: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32
-// LLVM-CIR: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
-// LLVM-CIR: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
-// LLVM-CIR: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
-// LLVM-CIR: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
-// LLVM-CIR: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
-// LLVM-CIR: ret i32 %[[RETVAL]]
-
-// OGCG-LABEL: define dso_local i32 @varargs
-// OGCG: %[[COUNT_ADDR:.+]] = alloca i32
-// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
-// OGCG: %[[RES_ADDR:.+]] = alloca i32
-// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]]
-// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]])
-// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]]
-// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], 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 %[[DECAY1]], i32 0, i32 3
-// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
-// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]]
-// OGCG: br label %vaarg.end
-//
-// OGCG: vaarg.in_mem:
-// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 2
-// OGCG: %[[OVERFLOW:.+]] = load ptr, 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]]
-// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
-// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
-// OGCG: ret i32 %[[VAL]]
+// LLVM-LABEL: define dso_local i32 @varargs(
+// LLVM: %[[COUNT_ADDR:.+]] = alloca i32
+// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// LLVM: %[[RES_ADDR:.+]] = alloca i32
+// LLVM: %[[VA_PTR0:.+]] = getelementptr {{.*}}%struct.__va_list_tag{{.?}}, ptr %[[VAAREA]]
+// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM: store i32 %{{.+}}, ptr %[[RES_ADDR]]
+// LLVM: %[[VA_PTR1:.+]] = getelementptr {{.*}}%struct.__va_list_tag{{.?}}, ptr %[[VAAREA]]
+// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR1]])
+// LLVM: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
+// LLVM: ret i32 %{{.+}}
int stdarg_start(int count, ...) {
__builtin_va_list args;
@@ -110,58 +73,17 @@ int stdarg_start(int count, ...) {
// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[RETVAL]] : !s32i
-// LLVM-CIR-LABEL: define dso_local i32 @stdarg_start(
-// LLVM-CIR: %[[COUNT_ADDR:.+]] = alloca i32{{.*}}
-// LLVM-CIR: %[[RET_ADDR:.+]] = alloca i32{{.*}}
-// LLVM-CIR: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
-// LLVM-CIR: %[[RES_ADDR:.+]] = alloca i32{{.*}}
-// LLVM-CIR: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
-// LLVM-CIR: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32
-// LLVM-CIR: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
-// LLVM-CIR: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
-// LLVM-CIR: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
-// LLVM-CIR: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
-// LLVM-CIR: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
-// LLVM-CIR: ret i32 %[[RETVAL]]
-
-// OGCG-LABEL: define dso_local i32 @stdarg_start
-// OGCG: %[[COUNT_ADDR:.+]] = alloca i32
-// OGCG: %[[VAAREA:.+]] = 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: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], 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 %[[DECAY1]], 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 %[[DECAY1]], 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: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
-// OGCG: ret i32 %[[VAL]]
+// LLVM-LABEL: define dso_local i32 @stdarg_start(
+// LLVM: %[[COUNT_ADDR:.+]] = alloca i32
+// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// LLVM: %[[RES_ADDR:.+]] = alloca i32
+// LLVM: %[[VA_PTR0:.+]] = getelementptr {{.*}}%struct.__va_list_tag{{.?}}, ptr %[[VAAREA]]
+// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM: store i32 %{{.+}}, ptr %[[RES_ADDR]]
+// LLVM: %[[VA_PTR1:.+]] = getelementptr {{.*}}%struct.__va_list_tag{{.?}}, ptr %[[VAAREA]]
+// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR1]])
+// LLVM: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
+// LLVM: ret i32 %{{.+}}
void stdarg_copy() {
__builtin_va_list src, dest;
@@ -173,15 +95,10 @@ void 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.va_copy %{{.*}} to %{{.*}} : !cir.ptr<!rec___va_list_tag>, !cir.ptr<!rec___va_list_tag>
-// LLVM-CIR-LABEL: @stdarg_copy
-// LLVM-CIR: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
-// LLVM-CIR: %{{.*}} = getelementptr %struct.__va_list_tag, ptr %{{.*}}
-// LLVM-CIR: call void @llvm.va_copy.p0(ptr %{{.*}}, ptr %{{.*}}
-
-// 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 %{{.*}}
+// 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 %{{.*}}
// Test handling where the first argument is not a count, as permitted by C23.
int varargs_new(char *fmt, ...) {
@@ -208,54 +125,17 @@ int varargs_new(char *fmt, ...) {
// CIR: %[[RETVAL:.+]] = cir.load{{.*}} %[[RET_ADDR]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.return %[[RETVAL]] : !s32i
-// LLVM-CIR-LABEL: define dso_local i32 @varargs_new(
-// LLVM-CIR: %[[FMT_ADDR:.+]] = alloca ptr
-// LLVM-CIR: %[[RET_ADDR:.+]] = alloca i32{{.*}}
-// LLVM-CIR: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]{{.*}}
-// LLVM-CIR: %[[RES_ADDR:.+]] = alloca i32{{.*}}
-// LLVM-CIR: %[[VA_PTR0:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
-// LLVM-CIR: %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], i32
-// LLVM-CIR: store i32 %[[VA_ARG]], ptr %[[RES_ADDR]], {{.*}}
-// LLVM-CIR: %[[VA_PTR2:.+]] = getelementptr %struct.__va_list_tag, ptr %[[VAAREA]], i32 0
-// LLVM-CIR: call void @llvm.va_end.p0(ptr %[[VA_PTR2]])
-// LLVM-CIR: %[[TMP_LOAD:.+]] = load i32, ptr %[[RES_ADDR]], {{.*}}
-// LLVM-CIR: store i32 %[[TMP_LOAD]], ptr %[[RET_ADDR]], {{.*}}
-// LLVM-CIR: %[[RETVAL:.+]] = load i32, ptr %[[RET_ADDR]], {{.*}}
-// LLVM-CIR: ret i32 %[[RETVAL]]
-
-// OGCG-LABEL: define dso_local i32 @varargs_new
-// OGCG: %[[FMT_ADDR:.+]] = alloca ptr
-// OGCG: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
-// OGCG: %[[RES_ADDR:.+]] = alloca i32
-// OGCG: %[[DECAY:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]]
-// OGCG: call void @llvm.va_start.p0(ptr %[[DECAY]])
-// OGCG: %[[DECAY1:.+]] = getelementptr inbounds [1 x %struct.__va_list_tag], ptr %[[VAAREA]]
-// OGCG: %[[GPOFFSET_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], 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 %[[DECAY1]], i32 0, i32 3
-// OGCG: %[[REGSAVE:.+]] = load ptr, ptr %[[REGSAVE_PTR]]
-// OGCG: %[[VAADDR1:.+]] = getelementptr i8, ptr %[[REGSAVE]], i32 %[[GPOFFSET]]
-// OGCG: br label %vaarg.end
-//
-// OGCG: vaarg.in_mem:
-// OGCG: %[[OVERFLOW_PTR:.+]] = getelementptr inbounds nuw %struct.__va_list_tag, ptr %[[DECAY1]], i32 0, i32 2
-// OGCG: %[[OVERFLOW:.+]] = load ptr, 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]]
-// OGCG: call void @llvm.va_end.p0(ptr %[[DECAY2]])
-// OGCG: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
-// OGCG: ret i32 %[[VAL]]
+// LLVM-LABEL: define dso_local i32 @varargs_new(
+// LLVM: %[[FMT_ADDR:.+]] = alloca ptr
+// LLVM: %[[VAAREA:.+]] = alloca [1 x %struct.__va_list_tag]
+// LLVM: %[[RES_ADDR:.+]] = alloca i32
+// LLVM: %[[VA_PTR0:.+]] = getelementptr {{.*}}%struct.__va_list_tag{{.?}}, ptr %[[VAAREA]]
+// LLVM: call void @llvm.va_start.p0(ptr %[[VA_PTR0]])
+// LLVM: store i32 %{{.+}}, ptr %[[RES_ADDR]]
+// LLVM: %[[VA_PTR1:.+]] = getelementptr {{.*}}%struct.__va_list_tag{{.?}}, ptr %[[VAAREA]]
+// LLVM: call void @llvm.va_end.p0(ptr %[[VA_PTR1]])
+// LLVM: %[[VAL:.+]] = load i32, ptr %[[RES_ADDR]]
+// LLVM: ret i32 %{{.+}}
// Ensure that __builtin_va_start(list, 0) and __builtin_c23_va_start(list)
// have the same codegen.
More information about the cfe-commits
mailing list