https://github.com/bai-tim updated 
https://github.com/llvm/llvm-project/pull/225091

>From b91e715ff2bb6397b2be4ada4a7d82fb542e4291 Mon Sep 17 00:00:00 2001
From: Timur Baidusenov <[email protected]>
Date: Mon, 21 Sep 2026 13:58:45 +0300
Subject: [PATCH 1/2] [SelectionDAG][GlobalISel] Diagnose va_arg with an
 aggregate type

The code generator does not support va_arg with an aggregate type on any
target, as LangRef notes, but instead of saying so it crashed. SelectionDAG
asked for the value type of the aggregate and hit "Unknown type!" in
MVT::getVT(), and the IRTranslator asked for the single vreg to define and hit
"attempt to get single VReg for aggregate or void". Report the construct as
unsupported in SelectionDAG, and have the IRTranslator give up on it so that
the fallback to SelectionDAG reports it too.

Fixes #162900.
---
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  |  5 ++++
 .../SelectionDAG/SelectionDAGBuilder.cpp      | 11 +++++++++
 .../GlobalISel/vaarg-aggregate-fallback.ll    | 14 +++++++++++
 llvm/test/CodeGen/X86/vaarg-aggregate.ll      | 24 +++++++++++++++++++
 4 files changed, 54 insertions(+)
 create mode 100644 
llvm/test/CodeGen/AArch64/GlobalISel/vaarg-aggregate-fallback.ll
 create mode 100644 llvm/test/CodeGen/X86/vaarg-aggregate.ll

diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp 
b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index d9e88f22ac2ca..a00f5aeaede2e 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -4086,6 +4086,11 @@ bool IRTranslatorImpl::translateAlloca(const User &U,
 
 bool IRTranslatorImpl::translateVAArg(const User &U,
                                       MachineIRBuilder &MIRBuilder) {
+  // The code generator does not support va_arg with an aggregate type, and an
+  // aggregate has no single vreg to define here.
+  if (U.getType()->isAggregateType())
+    return false;
+
   // FIXME: We may need more info about the type. Because of how LLT works,
   // we're completely discarding the i64/double distinction here (amongst
   // others). Fortunately the ABIs I know of where that matters don't use 
va_arg
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp 
b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 065347d903033..8f03010256755 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -10905,6 +10905,17 @@ void SelectionDAGBuilder::visitVAStart(const CallInst 
&I) {
 }
 
 void SelectionDAGBuilder::visitVAArg(const VAArgInst &I) {
+  // The code generator does not support va_arg with an aggregate type on any
+  // target, and such a type has no value type to lower it to.
+  if (I.getType()->isAggregateType()) {
+    SDLoc sdl = getCurSDLoc();
+    DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
+        *I.getFunction(), "va_arg with an aggregate type is not supported",
+        sdl.getDebugLoc()));
+    setValueToPoison(&I, sdl);
+    return;
+  }
+
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
   const DataLayout &DL = DAG.getDataLayout();
   SDValue V = DAG.getVAArg(
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/vaarg-aggregate-fallback.ll 
b/llvm/test/CodeGen/AArch64/GlobalISel/vaarg-aggregate-fallback.ll
new file mode 100644
index 0000000000000..b9f753881fd45
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/vaarg-aggregate-fallback.ll
@@ -0,0 +1,14 @@
+; RUN: not llc %s -mtriple=aarch64-- -O0 -global-isel -global-isel-abort=2 \
+; RUN:   -pass-remarks-missed='gisel*' -filetype=null 2>&1 | FileCheck %s
+
+; The code generator does not support va_arg with an aggregate type. The
+; IRTranslator gives up on it, so that the fallback to SelectionDAG reports it
+; instead of crashing (see issue #162900).
+
+; CHECK: remark: {{.*}}unable to translate instruction: va_arg:{{.*}}(in 
function: struct)
+; CHECK: warning: Instruction selection used fallback path for struct
+; CHECK: error: {{.*}}in function struct {{.*}}: va_arg with an aggregate type 
is not supported
+define { i32, i64 } @struct(ptr %ap) {
+  %v = va_arg ptr %ap, { i32, i64 }
+  ret { i32, i64 } %v
+}
diff --git a/llvm/test/CodeGen/X86/vaarg-aggregate.ll 
b/llvm/test/CodeGen/X86/vaarg-aggregate.ll
new file mode 100644
index 0000000000000..083d65e242cdf
--- /dev/null
+++ b/llvm/test/CodeGen/X86/vaarg-aggregate.ll
@@ -0,0 +1,24 @@
+; RUN: not llc %s -mtriple=x86_64-- -filetype=null 2>&1 | FileCheck %s
+; RUN: not llc %s -mtriple=x86_64-- -O0 -filetype=null 2>&1 | FileCheck %s
+; RUN: not llc %s -mtriple=i686-- -filetype=null 2>&1 | FileCheck %s
+
+; The code generator does not support va_arg with an aggregate type on any
+; target. Emit a clean diagnostic instead of crashing (see issue #162900).
+
+; CHECK: error: {{.*}}in function packed_struct {{.*}}: va_arg with an 
aggregate type is not supported
+define <{ i32 }> @packed_struct(ptr %ap) {
+  %v = va_arg ptr %ap, <{ i32 }>
+  ret <{ i32 }> %v
+}
+
+; CHECK: error: {{.*}}in function struct {{.*}}: va_arg with an aggregate type 
is not supported
+define { i32, i64 } @struct(ptr %ap) {
+  %v = va_arg ptr %ap, { i32, i64 }
+  ret { i32, i64 } %v
+}
+
+; CHECK: error: {{.*}}in function array {{.*}}: va_arg with an aggregate type 
is not supported
+define [2 x i32] @array(ptr %ap) {
+  %v = va_arg ptr %ap, [2 x i32]
+  ret [2 x i32] %v
+}

>From 2f7b9f75bfdce5358d98790530165e900d6fb04e Mon Sep 17 00:00:00 2001
From: Timur Baidusenov <[email protected]>
Date: Mon, 21 Sep 2026 21:51:24 +0300
Subject: [PATCH 2/2] [IR] Reject va_arg with an aggregate type in the verifier

No target can lower va_arg with an aggregate type, and the reference clang
codegen never emits one: it expands va_arg of an aggregate into accesses to
its members in the frontend. Make such a va_arg invalid IR rather than a crash
in the code generator, and drop the diagnostics added to SelectionDAG and the
IRTranslator, which can no longer see it.

ClangIR still emits it while it lacks calling convention lowering, so drop the
CIR-to-LLVM checks of the two affected tests until it lowers these the way the
reference codegen does.

Assisted-by: Claude (Anthropic)
---
 clang/test/CIR/CodeGen/complex-va-arg.cpp     | 54 ++++++++++++++++++
 clang/test/CIR/CodeGen/complex.cpp            | 56 -------------------
 clang/test/CIR/CodeGen/var-arg-aggregate.c    | 11 +---
 llvm/docs/LangRef.md                          | 10 ++--
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  |  5 --
 .../SelectionDAG/SelectionDAGBuilder.cpp      | 11 ----
 llvm/lib/IR/Verifier.cpp                      |  9 ++-
 .../GlobalISel/vaarg-aggregate-fallback.ll    | 14 -----
 llvm/test/CodeGen/X86/vaarg-aggregate.ll      | 24 --------
 llvm/test/Verifier/va_arg-aggregate.ll        | 18 ++++++
 10 files changed, 88 insertions(+), 124 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/complex-va-arg.cpp
 delete mode 100644 
llvm/test/CodeGen/AArch64/GlobalISel/vaarg-aggregate-fallback.ll
 delete mode 100644 llvm/test/CodeGen/X86/vaarg-aggregate.ll
 create mode 100644 llvm/test/Verifier/va_arg-aggregate.ll

diff --git a/clang/test/CIR/CodeGen/complex-va-arg.cpp 
b/clang/test/CIR/CodeGen/complex-va-arg.cpp
new file mode 100644
index 0000000000000..6a89d04c69af3
--- /dev/null
+++ b/clang/test/CIR/CodeGen/complex-va-arg.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -std=c++20 -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=c++20 -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
+
+// TODO(CIR): Without calling convention lowering, CIR lowers this va_arg to an
+// LLVM va_arg of { float, float }, which the verifier rejects. Add the
+// CIR-to-LLVM checks back once it is lowered the way OGCG does below.
+
+void foo33(__builtin_va_list a) {
+  float _Complex b = __builtin_va_arg(a, float _Complex);
+}
+
+// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} init : 
!cir.ptr<!cir.ptr<!rec___va_list_tag>>
+// CIR: %[[B_ADDR:.*]] = cir.alloca "b" {{.*}} init : 
!cir.ptr<!cir.complex<!cir.float>>
+// CIR: cir.store %[[ARG_0:.*]], %[[A_ADDR]] : !cir.ptr<!rec___va_list_tag>, 
!cir.ptr<!cir.ptr<!rec___va_list_tag>>
+// CIR: %[[VA_TAG:.*]] = cir.load{{.*}} %[[A_ADDR]] : 
!cir.ptr<!cir.ptr<!rec___va_list_tag>>, !cir.ptr<!rec___va_list_tag>
+// CIR: %[[COMPLEX:.*]] = cir.va_arg %[[VA_TAG]] : 
(!cir.ptr<!rec___va_list_tag>) -> !cir.complex<!cir.float>
+// CIR: cir.store{{.*}} %[[COMPLEX]], %[[B_ADDR]] : !cir.complex<!cir.float>, 
!cir.ptr<!cir.complex<!cir.float>>
+
+// OGCG: %[[A_ADDR:.*]] = alloca ptr, align 8
+// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
+// OGCG: store ptr %[[ARG_0:.*]], ptr %[[A_ADDR]], align 8
+// OGCG: %[[TMP_A:.*]] = load ptr, ptr %[[A_ADDR]], align 8
+// OGCG: %[[GP_OFFSET_PTR:.*]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 1
+// OGCG: %[[GP_OFFSET:.*]] = load i32, ptr %[[GP_OFFSET_PTR]], align 4
+// OGCG: %[[COND:.*]] = icmp ule i32 %[[GP_OFFSET]], 160
+// OGCG: br i1 %[[COND]], label %[[VA_ARG_IN_REG:.*]], label 
%[[VA_ARG_IN_MEM:.*]]
+//
+// OGCG: [[VA_ARG_IN_REG]]:
+// OGCG:  %[[REG_SAVE_PTR:.*]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 3
+// OGCG:  %[[REG_SAVE:.*]] = load ptr, ptr %[[REG_SAVE_PTR]], align 8
+// OGCG:  %[[VA_ADDR:..*]] = getelementptr i8, ptr %[[REG_SAVE]], i32 
%[[GP_OFFSET]]
+// OGCG:  %[[GP_OFFSET_NEXT:.*]] = add i32 %[[GP_OFFSET]], 16
+// OGCG:  store i32 %[[GP_OFFSET_NEXT]], ptr %[[GP_OFFSET_PTR]], align 4
+// OGCG:  br label %[[VA_ARG_END:.*]]
+//
+// OGCG: [[VA_ARG_IN_MEM]]:
+// OGCG:  %[[OVERFLOW_PTR:.*]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 2
+// OGCG:  %[[OVERFLOW:.*]] = load ptr, ptr %[[OVERFLOW_PTR]], align 8
+// OGCG:  %[[OVERFLOW_NEXT:.*]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8
+// OGCG:  store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]], align 8
+// OGCG:  br label %[[VA_ARG_END]]
+//
+// OGCG: [[VA_ARG_END]]:
+// OGCG:  %[[RESULT:.*]] = phi ptr [ %[[VA_ADDR]], %[[VA_ARG_IN_REG]] ], [ 
%[[OVERFLOW]], %[[VA_ARG_IN_MEM]] ]
+// OGCG:  %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float 
}, ptr %[[RESULT]], i32 0, i32 0
+// OGCG:  %[[RESULT_REAL:.*]] = load float, ptr %[[RESULT_REAL_PTR]], align 4
+// OGCG:  %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float 
}, ptr %[[RESULT]], i32 0, i32 1
+// OGCG:  %[[RESULT_IMAG:.*]] = load float, ptr %[[RESULT_IMAG_PTR]], align 4
+// OGCG:  %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, 
ptr %[[B_ADDR]], i32 0, i32 0
+// OGCG:  %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, 
ptr %[[B_ADDR]], i32 0, i32 1
+// OGCG:  store float %[[RESULT_REAL]], ptr %[[B_REAL_PTR]], align 4
+// OGCG:  store float %[[RESULT_IMAG]], ptr %[[B_IMAG_PTR]], align 4
diff --git a/clang/test/CIR/CodeGen/complex.cpp 
b/clang/test/CIR/CodeGen/complex.cpp
index abf70f89fa7e7..f37e5b1416bd6 100644
--- a/clang/test/CIR/CodeGen/complex.cpp
+++ b/clang/test/CIR/CodeGen/complex.cpp
@@ -932,62 +932,6 @@ void foo32() {
 // OGCG: %[[REAL:.*]] = load i32, ptr @_ZN9Container1cE, align 4
 // OGCG: store i32 %[[REAL]], ptr %[[REAL_ADDR]], align 4
 
-void foo33(__builtin_va_list a) {
-  float _Complex b = __builtin_va_arg(a, float _Complex);
-}
-
-// CIR: %[[A_ADDR:.*]] = cir.alloca "a" {{.*}} init : 
!cir.ptr<!cir.ptr<!rec___va_list_tag>>
-// CIR: %[[B_ADDR:.*]] = cir.alloca "b" {{.*}} init : 
!cir.ptr<!cir.complex<!cir.float>>
-// CIR: cir.store %[[ARG_0:.*]], %[[A_ADDR]] : !cir.ptr<!rec___va_list_tag>, 
!cir.ptr<!cir.ptr<!rec___va_list_tag>>
-// CIR: %[[VA_TAG:.*]] = cir.load{{.*}} %[[A_ADDR]] : 
!cir.ptr<!cir.ptr<!rec___va_list_tag>>, !cir.ptr<!rec___va_list_tag>
-// CIR: %[[COMPLEX:.*]] = cir.va_arg %[[VA_TAG]] : 
(!cir.ptr<!rec___va_list_tag>) -> !cir.complex<!cir.float>
-// CIR: cir.store{{.*}} %[[COMPLEX]], %[[B_ADDR]] : !cir.complex<!cir.float>, 
!cir.ptr<!cir.complex<!cir.float>>
-
-// LLVM: %[[A_ADDR:.*]] = alloca ptr, align 8
-// LLVM: %[[B_ADDR:.*]] = alloca { float, float }, align 4
-// LLVM: store ptr %[[ARG_0:.*]], ptr %[[A_ADDR]], align 8
-// LLVM: %[[TMP_A:.*]] = load ptr, ptr %[[A_ADDR]], align 8
-// LLVM: %[[COMPLEX:.*]] = va_arg ptr %[[TMP_A]], { float, float }
-// LLVM: store { float, float } %[[COMPLEX]], ptr %[[B_ADDR]], align 4
-
-// TODO(CIR): the difference between the CIR LLVM and OGCG is because the lack 
of calling convention lowering,
-// Test will be updated when that is implemented
-
-// OGCG: %[[A_ADDR:.*]] = alloca ptr, align 8
-// OGCG: %[[B_ADDR:.*]] = alloca { float, float }, align 4
-// OGCG: store ptr %[[ARG_0:.*]], ptr %[[A_ADDR]], align 8
-// OGCG: %[[TMP_A:.*]] = load ptr, ptr %[[A_ADDR]], align 8
-// OGCG: %[[GP_OFFSET_PTR:.*]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 1
-// OGCG: %[[GP_OFFSET:.*]] = load i32, ptr %[[GP_OFFSET_PTR]], align 4
-// OGCG: %[[COND:.*]] = icmp ule i32 %[[GP_OFFSET]], 160
-// OGCG: br i1 %[[COND]], label %[[VA_ARG_IN_REG:.*]], label 
%[[VA_ARG_IN_MEM:.*]]
-//
-// OGCG: [[VA_ARG_IN_REG]]:
-// OGCG:  %[[REG_SAVE_PTR:.*]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 3
-// OGCG:  %[[REG_SAVE:.*]] = load ptr, ptr %[[REG_SAVE_PTR]], align 8
-// OGCG:  %[[VA_ADDR:..*]] = getelementptr i8, ptr %[[REG_SAVE]], i32 
%[[GP_OFFSET]]
-// OGCG:  %[[GP_OFFSET_NEXT:.*]] = add i32 %[[GP_OFFSET]], 16
-// OGCG:  store i32 %[[GP_OFFSET_NEXT]], ptr %[[GP_OFFSET_PTR]], align 4
-// OGCG:  br label %[[VA_ARG_END:.*]]
-//
-// OGCG: [[VA_ARG_IN_MEM]]:
-// OGCG:  %[[OVERFLOW_PTR:.*]] = getelementptr inbounds nuw 
%struct.__va_list_tag, ptr %[[TMP_A]], i32 0, i32 2
-// OGCG:  %[[OVERFLOW:.*]] = load ptr, ptr %[[OVERFLOW_PTR]], align 8
-// OGCG:  %[[OVERFLOW_NEXT:.*]] = getelementptr i8, ptr %[[OVERFLOW]], i32 8
-// OGCG:  store ptr %[[OVERFLOW_NEXT]], ptr %[[OVERFLOW_PTR]], align 8
-// OGCG:  br label %[[VA_ARG_END]]
-//
-// OGCG: [[VA_ARG_END]]:
-// OGCG:  %[[RESULT:.*]] = phi ptr [ %[[VA_ADDR]], %[[VA_ARG_IN_REG]] ], [ 
%[[OVERFLOW]], %[[VA_ARG_IN_MEM]] ]
-// OGCG:  %[[RESULT_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float 
}, ptr %[[RESULT]], i32 0, i32 0
-// OGCG:  %[[RESULT_REAL:.*]] = load float, ptr %[[RESULT_REAL_PTR]], align 4
-// OGCG:  %[[RESULT_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float 
}, ptr %[[RESULT]], i32 0, i32 1
-// OGCG:  %[[RESULT_IMAG:.*]] = load float, ptr %[[RESULT_IMAG_PTR]], align 4
-// OGCG:  %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, 
ptr %[[B_ADDR]], i32 0, i32 0
-// OGCG:  %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, 
ptr %[[B_ADDR]], i32 0, i32 1
-// OGCG:  store float %[[RESULT_REAL]], ptr %[[B_REAL_PTR]], align 4
-// OGCG:  store float %[[RESULT_IMAG]], ptr %[[B_IMAG_PTR]], align 4
-
 void foo34() {
   _Atomic(float _Complex) a;
   __c11_atomic_init(&a, {1.0f, 2.0f});
diff --git a/clang/test/CIR/CodeGen/var-arg-aggregate.c 
b/clang/test/CIR/CodeGen/var-arg-aggregate.c
index 94da8e2b80ad9..3d96f88d26f22 100644
--- a/clang/test/CIR/CodeGen/var-arg-aggregate.c
+++ b/clang/test/CIR/CodeGen/var-arg-aggregate.c
@@ -1,7 +1,5 @@
 // RUN: %clang_cc1 -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
 
@@ -40,12 +38,9 @@ struct Bar varargs_aggregate(int count, ...) {
 // CIR:   %[[COERCED:.+]] = cir.load %[[COERCE]] : !cir.ptr<!rec_anon_struct>, 
!rec_anon_struct
 // CIR:   cir.return %[[COERCED]] : !rec_anon_struct
 
-// LLVM-LABEL: define dso_local { <2 x float>, i32 } @varargs_aggregate(i32 
noundef %{{.*}}, ...)
-// LLVM:   call void @llvm.va_start.p0(ptr %{{.*}})
-// LLVM:   %[[VA_PTR1:.+]] = getelementptr %struct.__va_list_tag, ptr %{{.*}}, 
i32 0
-// LLVM:   %[[VA_ARG:.+]] = va_arg ptr %[[VA_PTR1]], %struct.Bar
-// LLVM:   store %struct.Bar %[[VA_ARG]], ptr %{{.*}}
-// LLVM:   call void @llvm.memcpy.p0.p0.i64(ptr align 4 %{{.*}}, ptr align 4 
%{{.*}}, i64 12, i1 false)
+// TODO(CIR): Without calling convention lowering, CIR lowers this va_arg to an
+// LLVM va_arg of %struct.Bar, which the verifier rejects. Add the CIR-to-LLVM
+// checks back once it is lowered the way OGCG does below.
 
 // OGCG-LABEL: define dso_local { <2 x float>, i32 } @varargs_aggregate
 // OGCG:   call void @llvm.va_start.p0(ptr %{{.*}})
diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index a4816d337e02b..9e2e1f4becbba 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -14051,9 +14051,10 @@ the `va_arg` macro in C.
 ##### Arguments:
 
 This instruction takes a `va_list*` value and the type of the
-argument. It returns a value of the specified argument type and
-increments the `va_list` to point to the next argument. The actual
-type of `va_list` is target specific.
+argument, which must not be an {ref}`aggregate <t_aggregate>` type. It
+returns a value of the specified argument type and increments the
+`va_list` to point to the next argument. The actual type of `va_list` is
+target specific.
 
 ##### Semantics:
 
@@ -14073,8 +14074,7 @@ function.
 See the {ref}`variable argument processing <int_varargs>` section.
 
 Note that the code generator does not yet fully support `va_arg` on many
-targets. Also, it does not currently support `va_arg` with aggregate
-types on any target.
+targets.
 
 (i_landingpad)=
 
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp 
b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index a00f5aeaede2e..d9e88f22ac2ca 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -4086,11 +4086,6 @@ bool IRTranslatorImpl::translateAlloca(const User &U,
 
 bool IRTranslatorImpl::translateVAArg(const User &U,
                                       MachineIRBuilder &MIRBuilder) {
-  // The code generator does not support va_arg with an aggregate type, and an
-  // aggregate has no single vreg to define here.
-  if (U.getType()->isAggregateType())
-    return false;
-
   // FIXME: We may need more info about the type. Because of how LLT works,
   // we're completely discarding the i64/double distinction here (amongst
   // others). Fortunately the ABIs I know of where that matters don't use 
va_arg
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp 
b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 8f03010256755..065347d903033 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -10905,17 +10905,6 @@ void SelectionDAGBuilder::visitVAStart(const CallInst 
&I) {
 }
 
 void SelectionDAGBuilder::visitVAArg(const VAArgInst &I) {
-  // The code generator does not support va_arg with an aggregate type on any
-  // target, and such a type has no value type to lower it to.
-  if (I.getType()->isAggregateType()) {
-    SDLoc sdl = getCurSDLoc();
-    DAG.getContext()->diagnose(DiagnosticInfoUnsupported(
-        *I.getFunction(), "va_arg with an aggregate type is not supported",
-        sdl.getDebugLoc()));
-    setValueToPoison(&I, sdl);
-    return;
-  }
-
   const TargetLowering &TLI = DAG.getTargetLoweringInfo();
   const DataLayout &DL = DAG.getDataLayout();
   SDValue V = DAG.getVAArg(
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 1440b95896474..0e157e1490ff4 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -428,7 +428,7 @@ class Verifier : public InstVisitor<Verifier>, 
VerifierSupport {
   void visitExtractElementInst(ExtractElementInst &EI);
   void visitInsertElementInst(InsertElementInst &EI);
   void visitShuffleVectorInst(ShuffleVectorInst &EI);
-  void visitVAArgInst(VAArgInst &VAA) { visitInstruction(VAA); }
+  void visitVAArgInst(VAArgInst &VAA);
   void visitCallInst(CallInst &CI);
   void visitInvokeInst(InvokeInst &II);
   void visitGetElementPtrInst(GetElementPtrInst &GEP);
@@ -4582,6 +4582,13 @@ void Verifier::visitShuffleVectorInst(ShuffleVectorInst 
&SV) {
   visitInstruction(SV);
 }
 
+void Verifier::visitVAArgInst(VAArgInst &VAA) {
+  // No target can lower va_arg of an aggregate, so frontends expand it.
+  Check(!VAA.getType()->isAggregateType(),
+        "va_arg with an aggregate type is not supported", &VAA);
+  visitInstruction(VAA);
+}
+
 void Verifier::visitGetElementPtrInst(GetElementPtrInst &GEP) {
   if (auto *MD = mdconst::extract_or_null<ConstantInt>(
           GEP.getModule()->getModuleFlag("require-logical-pointer")))
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/vaarg-aggregate-fallback.ll 
b/llvm/test/CodeGen/AArch64/GlobalISel/vaarg-aggregate-fallback.ll
deleted file mode 100644
index b9f753881fd45..0000000000000
--- a/llvm/test/CodeGen/AArch64/GlobalISel/vaarg-aggregate-fallback.ll
+++ /dev/null
@@ -1,14 +0,0 @@
-; RUN: not llc %s -mtriple=aarch64-- -O0 -global-isel -global-isel-abort=2 \
-; RUN:   -pass-remarks-missed='gisel*' -filetype=null 2>&1 | FileCheck %s
-
-; The code generator does not support va_arg with an aggregate type. The
-; IRTranslator gives up on it, so that the fallback to SelectionDAG reports it
-; instead of crashing (see issue #162900).
-
-; CHECK: remark: {{.*}}unable to translate instruction: va_arg:{{.*}}(in 
function: struct)
-; CHECK: warning: Instruction selection used fallback path for struct
-; CHECK: error: {{.*}}in function struct {{.*}}: va_arg with an aggregate type 
is not supported
-define { i32, i64 } @struct(ptr %ap) {
-  %v = va_arg ptr %ap, { i32, i64 }
-  ret { i32, i64 } %v
-}
diff --git a/llvm/test/CodeGen/X86/vaarg-aggregate.ll 
b/llvm/test/CodeGen/X86/vaarg-aggregate.ll
deleted file mode 100644
index 083d65e242cdf..0000000000000
--- a/llvm/test/CodeGen/X86/vaarg-aggregate.ll
+++ /dev/null
@@ -1,24 +0,0 @@
-; RUN: not llc %s -mtriple=x86_64-- -filetype=null 2>&1 | FileCheck %s
-; RUN: not llc %s -mtriple=x86_64-- -O0 -filetype=null 2>&1 | FileCheck %s
-; RUN: not llc %s -mtriple=i686-- -filetype=null 2>&1 | FileCheck %s
-
-; The code generator does not support va_arg with an aggregate type on any
-; target. Emit a clean diagnostic instead of crashing (see issue #162900).
-
-; CHECK: error: {{.*}}in function packed_struct {{.*}}: va_arg with an 
aggregate type is not supported
-define <{ i32 }> @packed_struct(ptr %ap) {
-  %v = va_arg ptr %ap, <{ i32 }>
-  ret <{ i32 }> %v
-}
-
-; CHECK: error: {{.*}}in function struct {{.*}}: va_arg with an aggregate type 
is not supported
-define { i32, i64 } @struct(ptr %ap) {
-  %v = va_arg ptr %ap, { i32, i64 }
-  ret { i32, i64 } %v
-}
-
-; CHECK: error: {{.*}}in function array {{.*}}: va_arg with an aggregate type 
is not supported
-define [2 x i32] @array(ptr %ap) {
-  %v = va_arg ptr %ap, [2 x i32]
-  ret [2 x i32] %v
-}
diff --git a/llvm/test/Verifier/va_arg-aggregate.ll 
b/llvm/test/Verifier/va_arg-aggregate.ll
new file mode 100644
index 0000000000000..f709103d47195
--- /dev/null
+++ b/llvm/test/Verifier/va_arg-aggregate.ll
@@ -0,0 +1,18 @@
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+; No target can lower va_arg with an aggregate type, so frontends expand it
+; into accesses to its members instead (see issue #162900).
+
+; CHECK: va_arg with an aggregate type is not supported
+; CHECK-NEXT: %s = va_arg ptr %ap, { i32, i64 }
+define { i32, i64 } @struct(ptr %ap) {
+  %s = va_arg ptr %ap, { i32, i64 }
+  ret { i32, i64 } %s
+}
+
+; CHECK: va_arg with an aggregate type is not supported
+; CHECK-NEXT: %a = va_arg ptr %ap, [2 x i32]
+define [2 x i32] @array(ptr %ap) {
+  %a = va_arg ptr %ap, [2 x i32]
+  ret [2 x i32] %a
+}

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

Reply via email to