[llvm] [SelectionDAG] Scalarize legal operands of scalarized vector binops (PR #226616)
Demetrios Chiuratto Agourakis via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 25 18:05:24 PDT 2026
https://github.com/agourakis82 created https://github.com/llvm/llvm-project/pull/226616
Fixes #219695.
`ScalarizeVecRes_BinOp` assumed both operands of a scalarized `<1 x ty>` result also needed scalarizing, and looked each up in the scalarized-vector map. Under AVX-512 `<1 x i1>` is a legal type, so the exponent of `llvm.ldexp.v1f32.v1i1` was never scalarized. The lookup then asserted in `DAGTypeLegalizer::getSDValue` with `TableId should be non-zero` during X86 instruction selection.
Extract a legal operand element instead of requiring it to have been scalarized, matching the per-operand handling already used by `ScalarizeVecRes_StrictFPOp`.
The exponent is then promoted by the existing `PromoteIntOp_ExpOp` path. Because the promoted `i1` is narrower than `sizeof(int)`, it is lowered to the `ldexp`/`ldexpf` libcall rather than `vscalef`; the `i32` exponent case is unchanged and still selects `vscalefss`.
```llvm
define <1 x float> @test(<1 x float> %x, <1 x i1> %e) {
%r = call <1 x float> @llvm.ldexp.v1f32.v1i1(<1 x float> %x, <1 x i1> %e)
ret <1 x float> %r
}
```
`llc -mtriple=x86_64 -mattr=+avx512f` aborts before this change and compiles after it.
>From ec19a60e890505696b3a3312693b19aaaabd9c2c Mon Sep 17 00:00:00 2001
From: Demetrios Chiuratto Agourakis <demetrios at agourakis.med.br>
Date: Sat, 26 Sep 2026 01:05:01 +0000
Subject: [PATCH] [SelectionDAG] Scalarize legal operands of scalarized vector
binops
ScalarizeVecRes_BinOp assumed both operands needed scalarizing. Under AVX-512 a <1 x i1> FLDEXP exponent is a legal type, so looking it up in the scalarized-vector map asserted with "TableId should be non-zero". Extract a legal operand element instead, matching ScalarizeVecRes_StrictFPOp.
Fixes #219695.
Co-Authored-By: Claude <noreply at anthropic.com>
---
.../SelectionDAG/LegalizeVectorTypes.cpp | 21 ++++++++---
llvm/test/CodeGen/X86/ldexp-v1i1.ll | 36 +++++++++++++++++++
2 files changed, 53 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/ldexp-v1i1.ll
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index 913aa4536bc81..b3404bcb25170 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -281,10 +281,23 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_BinOp(SDNode *N) {
- SDValue LHS = GetScalarizedVector(N->getOperand(0));
- SDValue RHS = GetScalarizedVector(N->getOperand(1));
- return DAG.getNode(N->getOpcode(), SDLoc(N),
- LHS.getValueType(), LHS, RHS, N->getFlags());
+ SDLoc DL(N);
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+ // The result needs scalarizing, but it is not a given that both operands
+ // do. For instance, AVX-512 has a legal <1 x i1> exponent for FLDEXP.
+ if (getTypeAction(LHS.getValueType()) == TargetLowering::TypeScalarizeVector)
+ LHS = GetScalarizedVector(LHS);
+ else
+ LHS = DAG.getExtractVectorElt(DL, LHS.getValueType().getVectorElementType(),
+ LHS, 0);
+ if (getTypeAction(RHS.getValueType()) == TargetLowering::TypeScalarizeVector)
+ RHS = GetScalarizedVector(RHS);
+ else
+ RHS = DAG.getExtractVectorElt(DL, RHS.getValueType().getVectorElementType(),
+ RHS, 0);
+ return DAG.getNode(N->getOpcode(), DL, LHS.getValueType(), LHS, RHS,
+ N->getFlags());
}
SDValue DAGTypeLegalizer::ScalarizeVecRes_MaskedBinOp(SDNode *N) {
diff --git a/llvm/test/CodeGen/X86/ldexp-v1i1.ll b/llvm/test/CodeGen/X86/ldexp-v1i1.ll
new file mode 100644
index 0000000000000..b6cb4c27a8305
--- /dev/null
+++ b/llvm/test/CodeGen/X86/ldexp-v1i1.ll
@@ -0,0 +1,36 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+avx512f | FileCheck %s
+
+; <1 x i1> is a legal type under AVX-512, while <1 x float> and <1 x double>
+; are scalarized. The exponent operand must be extracted rather than looked up
+; as a scalarized vector, which previously crashed type legalization with
+; "TableId should be non-zero".
+
+define <1 x float> @test_v1f32(<1 x float> %x, <1 x i1> %e) nounwind {
+; CHECK-LABEL: test_v1f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pushq %rax
+; CHECK-NEXT: andl $1, %edi
+; CHECK-NEXT: negl %edi
+; CHECK-NEXT: callq ldexpf at PLT
+; CHECK-NEXT: popq %rax
+; CHECK-NEXT: retq
+ %r = call <1 x float> @llvm.ldexp.v1f32.v1i1(<1 x float> %x, <1 x i1> %e)
+ ret <1 x float> %r
+}
+
+define <1 x double> @test_v1f64(<1 x double> %x, <1 x i1> %e) nounwind {
+; CHECK-LABEL: test_v1f64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pushq %rax
+; CHECK-NEXT: andl $1, %edi
+; CHECK-NEXT: negl %edi
+; CHECK-NEXT: callq ldexp at PLT
+; CHECK-NEXT: popq %rax
+; CHECK-NEXT: retq
+ %r = call <1 x double> @llvm.ldexp.v1f64.v1i1(<1 x double> %x, <1 x i1> %e)
+ ret <1 x double> %r
+}
+
+declare <1 x float> @llvm.ldexp.v1f32.v1i1(<1 x float>, <1 x i1>) memory(none)
+declare <1 x double> @llvm.ldexp.v1f64.v1i1(<1 x double>, <1 x i1>) memory(none)
More information about the llvm-commits
mailing list