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
