[llvm] [SelectionDAG][GlobalISel] Diagnose va_arg with an aggregate type (PR #225091)

Timur Baidusenov via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 07:01:07 PDT 2026


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

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.

>From b91e715ff2bb6397b2be4ada4a7d82fb542e4291 Mon Sep 17 00:00:00 2001
From: Timur Baidusenov <timurbaidusenov at gmail.com>
Date: Mon, 21 Sep 2026 13:58:45 +0300
Subject: [PATCH] [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
+}



More information about the llvm-commits mailing list