[llvm] SelectionDAG] Expand CLMUL of zero-extended all-ones operand via parallel prefix XOR (PR #207339)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 3 00:55:46 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-selectiondag
Author: Jan Schultke (eisenwave)
<details>
<summary>Changes</summary>
Fixes #<!-- -->204870
---
Full diff: https://github.com/llvm/llvm-project/pull/207339.diff
3 Files Affected:
- (modified) llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp (+24-10)
- (modified) llvm/test/CodeGen/X86/clmul-vector.ll (+131)
- (modified) llvm/test/CodeGen/X86/clmul.ll (+43)
``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 00153ef66cf2c..20494c6cc9550 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -8909,16 +8909,30 @@ SDValue TargetLowering::expandCLMUL(SDNode *Node, SelectionDAG &DAG) const {
}
}
- // Special case: clmul(X, ~0) is equivalent to a "parallel prefix XOR" or
- // "bitwise parity" operation.
- if (isAllOnesOrAllOnesSplat(Y)) {
- SDValue R = X;
- for (unsigned I = 1; I < BW; I <<= 1) {
- SDValue ShAmt = DAG.getShiftAmountConstant(I, VT, DL);
- SDValue Shifted = DAG.getNode(ISD::SHL, DL, VT, R, ShAmt);
- R = DAG.getNode(ISD::XOR, DL, VT, R, Shifted);
- }
- return R;
+ // Special case: clmul(X, Y) where Y is a known constant (splat) that forms
+ // a contiguous block of trailing ones (e.g. i8 0xFF, i8 0x0F, ...). In this
+ // special case, clmul(X, Y) is equivalent to a "parallel prefix XOR" or
+ // "bitwise parity" operation on X, optionally surrounded by truncation
+ // and zero-extension.
+ if (auto *C = isConstOrConstSplat(Y, /*AllowUndefs=*/true)) {
+ APInt YVal = C->getAPIntValue();
+ unsigned N = YVal.countr_one();
+ if (N > 0 && YVal.countl_zero() + N == BW) {
+ EVT LoopVT = VT;
+ SDValue R = X;
+ if (N < BW) {
+ LoopVT = VT.changeElementType(Ctx, EVT::getIntegerVT(Ctx, N));
+ R = DAG.getNode(ISD::TRUNCATE, DL, LoopVT, R);
+ }
+ for (unsigned I = 1; I < N; I <<= 1) {
+ SDValue ShAmt = DAG.getShiftAmountConstant(I, LoopVT, DL);
+ SDValue Shifted = DAG.getNode(ISD::SHL, DL, LoopVT, R, ShAmt);
+ R = DAG.getNode(ISD::XOR, DL, LoopVT, R, Shifted);
+ }
+ if (N < BW)
+ R = DAG.getNode(ISD::ZERO_EXTEND, DL, VT, R);
+ return R;
+ }
}
// NOTE: If you change this expansion, please update the cost model
diff --git a/llvm/test/CodeGen/X86/clmul-vector.ll b/llvm/test/CodeGen/X86/clmul-vector.ll
index c56bd11d8e658..32f6cd83c1532 100644
--- a/llvm/test/CodeGen/X86/clmul-vector.ll
+++ b/llvm/test/CodeGen/X86/clmul-vector.ll
@@ -6673,6 +6673,137 @@ define <4 x i32> @clmul_v4i32_allones(<4 x i32> %x) nounwind {
ret <4 x i32> %r
}
+define <4 x i32> @clmul_v4i32_zext_allones(<4 x i16> %x) nounwind {
+; SSE2-NOPCLMUL-LABEL: clmul_v4i32_zext_allones:
+; SSE2-NOPCLMUL: # %bb.0:
+; SSE2-NOPCLMUL-NEXT: movdqa %xmm0, %xmm1
+; SSE2-NOPCLMUL-NEXT: paddw %xmm1, %xmm1
+; SSE2-NOPCLMUL-NEXT: pxor %xmm1, %xmm0
+; SSE2-NOPCLMUL-NEXT: movdqa %xmm0, %xmm1
+; SSE2-NOPCLMUL-NEXT: psllw $2, %xmm1
+; SSE2-NOPCLMUL-NEXT: pxor %xmm1, %xmm0
+; SSE2-NOPCLMUL-NEXT: movdqa %xmm0, %xmm1
+; SSE2-NOPCLMUL-NEXT: psllw $4, %xmm1
+; SSE2-NOPCLMUL-NEXT: pxor %xmm1, %xmm0
+; SSE2-NOPCLMUL-NEXT: movdqa %xmm0, %xmm1
+; SSE2-NOPCLMUL-NEXT: psllw $8, %xmm1
+; SSE2-NOPCLMUL-NEXT: pxor %xmm1, %xmm0
+; SSE2-NOPCLMUL-NEXT: pxor %xmm1, %xmm1
+; SSE2-NOPCLMUL-NEXT: punpcklwd {{.*#+}} xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
+; SSE2-NOPCLMUL-NEXT: retq
+;
+; SSE42-NOPCLMUL-LABEL: clmul_v4i32_zext_allones:
+; SSE42-NOPCLMUL: # %bb.0:
+; SSE42-NOPCLMUL-NEXT: pshufd {{.*#+}} xmm0 = xmm0[0,1,0,1]
+; SSE42-NOPCLMUL-NEXT: movdqa %xmm0, %xmm1
+; SSE42-NOPCLMUL-NEXT: paddw %xmm1, %xmm1
+; SSE42-NOPCLMUL-NEXT: pxor %xmm0, %xmm1
+; SSE42-NOPCLMUL-NEXT: movdqa %xmm1, %xmm0
+; SSE42-NOPCLMUL-NEXT: psllw $2, %xmm0
+; SSE42-NOPCLMUL-NEXT: pxor %xmm1, %xmm0
+; SSE42-NOPCLMUL-NEXT: movdqa %xmm0, %xmm1
+; SSE42-NOPCLMUL-NEXT: psllw $4, %xmm1
+; SSE42-NOPCLMUL-NEXT: pxor %xmm0, %xmm1
+; SSE42-NOPCLMUL-NEXT: movdqa %xmm1, %xmm0
+; SSE42-NOPCLMUL-NEXT: psllw $8, %xmm0
+; SSE42-NOPCLMUL-NEXT: pxor %xmm1, %xmm0
+; SSE42-NOPCLMUL-NEXT: pmovzxwd {{.*#+}} xmm0 = xmm0[0],zero,xmm0[1],zero,xmm0[2],zero,xmm0[3],zero
+; SSE42-NOPCLMUL-NEXT: retq
+;
+; SSE2-PCLMUL-LABEL: clmul_v4i32_zext_allones:
+; SSE2-PCLMUL: # %bb.0:
+; SSE2-PCLMUL-NEXT: pxor %xmm1, %xmm1
+; SSE2-PCLMUL-NEXT: movl $65535, %eax # imm = 0xFFFF
+; SSE2-PCLMUL-NEXT: movq %rax, %xmm2
+; SSE2-PCLMUL-NEXT: pextrw $3, %xmm0, %eax
+; SSE2-PCLMUL-NEXT: movd %eax, %xmm3
+; SSE2-PCLMUL-NEXT: pextrw $1, %xmm0, %eax
+; SSE2-PCLMUL-NEXT: punpcklwd {{.*#+}} xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
+; SSE2-PCLMUL-NEXT: movdqa %xmm0, %xmm1
+; SSE2-PCLMUL-NEXT: pclmulqdq $1, %xmm2, %xmm1
+; SSE2-PCLMUL-NEXT: pclmulqdq $0, %xmm2, %xmm3
+; SSE2-PCLMUL-NEXT: punpckldq {{.*#+}} xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
+; SSE2-PCLMUL-NEXT: pclmulqdq $0, %xmm2, %xmm0
+; SSE2-PCLMUL-NEXT: movd %eax, %xmm3
+; SSE2-PCLMUL-NEXT: pclmulqdq $0, %xmm2, %xmm3
+; SSE2-PCLMUL-NEXT: punpckldq {{.*#+}} xmm0 = xmm0[0],xmm3[0],xmm0[1],xmm3[1]
+; SSE2-PCLMUL-NEXT: punpcklqdq {{.*#+}} xmm0 = xmm0[0],xmm1[0]
+; SSE2-PCLMUL-NEXT: retq
+;
+; SSE42-PCLMUL-LABEL: clmul_v4i32_zext_allones:
+; SSE42-PCLMUL: # %bb.0:
+; SSE42-PCLMUL-NEXT: movl $65535, %eax # imm = 0xFFFF
+; SSE42-PCLMUL-NEXT: movq %rax, %xmm2
+; SSE42-PCLMUL-NEXT: pextrw $1, %xmm0, %eax
+; SSE42-PCLMUL-NEXT: movd %eax, %xmm3
+; SSE42-PCLMUL-NEXT: pclmulqdq $0, %xmm2, %xmm3
+; SSE42-PCLMUL-NEXT: pextrw $0, %xmm0, %eax
+; SSE42-PCLMUL-NEXT: movd %eax, %xmm1
+; SSE42-PCLMUL-NEXT: pclmulqdq $0, %xmm2, %xmm1
+; SSE42-PCLMUL-NEXT: punpckldq {{.*#+}} xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
+; SSE42-PCLMUL-NEXT: pextrw $2, %xmm0, %eax
+; SSE42-PCLMUL-NEXT: movd %eax, %xmm3
+; SSE42-PCLMUL-NEXT: pclmulqdq $0, %xmm2, %xmm3
+; SSE42-PCLMUL-NEXT: movq %xmm3, %rax
+; SSE42-PCLMUL-NEXT: pinsrd $2, %eax, %xmm1
+; SSE42-PCLMUL-NEXT: pextrw $3, %xmm0, %eax
+; SSE42-PCLMUL-NEXT: movd %eax, %xmm0
+; SSE42-PCLMUL-NEXT: pclmulqdq $0, %xmm2, %xmm0
+; SSE42-PCLMUL-NEXT: movq %xmm0, %rax
+; SSE42-PCLMUL-NEXT: pinsrd $3, %eax, %xmm1
+; SSE42-PCLMUL-NEXT: movdqa %xmm1, %xmm0
+; SSE42-PCLMUL-NEXT: retq
+;
+; AVX2-LABEL: clmul_v4i32_zext_allones:
+; AVX2: # %bb.0:
+; AVX2-NEXT: movl $65535, %eax # imm = 0xFFFF
+; AVX2-NEXT: vmovq %rax, %xmm1
+; AVX2-NEXT: vpextrw $1, %xmm0, %eax
+; AVX2-NEXT: vmovd %eax, %xmm2
+; AVX2-NEXT: vpclmulqdq $0, %xmm1, %xmm2, %xmm2
+; AVX2-NEXT: vpextrw $0, %xmm0, %eax
+; AVX2-NEXT: vmovd %eax, %xmm3
+; AVX2-NEXT: vpclmulqdq $0, %xmm1, %xmm3, %xmm3
+; AVX2-NEXT: vpunpckldq {{.*#+}} xmm2 = xmm3[0],xmm2[0],xmm3[1],xmm2[1]
+; AVX2-NEXT: vpextrw $2, %xmm0, %eax
+; AVX2-NEXT: vmovd %eax, %xmm3
+; AVX2-NEXT: vpclmulqdq $0, %xmm1, %xmm3, %xmm3
+; AVX2-NEXT: vmovq %xmm3, %rax
+; AVX2-NEXT: vpinsrd $2, %eax, %xmm2, %xmm2
+; AVX2-NEXT: vpextrw $3, %xmm0, %eax
+; AVX2-NEXT: vmovd %eax, %xmm0
+; AVX2-NEXT: vpclmulqdq $0, %xmm1, %xmm0, %xmm0
+; AVX2-NEXT: vmovq %xmm0, %rax
+; AVX2-NEXT: vpinsrd $3, %eax, %xmm2, %xmm0
+; AVX2-NEXT: retq
+;
+; AVX512-LABEL: clmul_v4i32_zext_allones:
+; AVX512: # %bb.0:
+; AVX512-NEXT: movl $65535, %eax # imm = 0xFFFF
+; AVX512-NEXT: vmovq %rax, %xmm1
+; AVX512-NEXT: vpextrw $1, %xmm0, %eax
+; AVX512-NEXT: vmovd %eax, %xmm2
+; AVX512-NEXT: vpclmulqdq $0, %xmm1, %xmm2, %xmm2
+; AVX512-NEXT: vpextrw $0, %xmm0, %eax
+; AVX512-NEXT: vmovd %eax, %xmm3
+; AVX512-NEXT: vpclmulqdq $0, %xmm1, %xmm3, %xmm3
+; AVX512-NEXT: vpunpckldq {{.*#+}} xmm2 = xmm3[0],xmm2[0],xmm3[1],xmm2[1]
+; AVX512-NEXT: vpextrw $2, %xmm0, %eax
+; AVX512-NEXT: vmovd %eax, %xmm3
+; AVX512-NEXT: vpclmulqdq $0, %xmm1, %xmm3, %xmm3
+; AVX512-NEXT: vmovq %xmm3, %rax
+; AVX512-NEXT: vpinsrd $2, %eax, %xmm2, %xmm2
+; AVX512-NEXT: vpextrw $3, %xmm0, %eax
+; AVX512-NEXT: vmovd %eax, %xmm0
+; AVX512-NEXT: vpclmulqdq $0, %xmm1, %xmm0, %xmm0
+; AVX512-NEXT: vmovq %xmm0, %rax
+; AVX512-NEXT: vpinsrd $3, %eax, %xmm2, %xmm0
+; AVX512-NEXT: retq
+ %x32 = zext <4 x i16> %x to <4 x i32>
+ %r = call <4 x i32> @llvm.clmul.v4i32(<4 x i32> %x32, <4 x i32> <i32 65535, i32 65535, i32 65535, i32 65535>)
+ ret <4 x i32> %r
+}
+
define <2 x i64> @clmul_v2i64_allones(<2 x i64> %x) nounwind {
; SSE-NOPCLMUL-LABEL: clmul_v2i64_allones:
; SSE-NOPCLMUL: # %bb.0:
diff --git a/llvm/test/CodeGen/X86/clmul.ll b/llvm/test/CodeGen/X86/clmul.ll
index 3394d7081a677..0a87c876297fb 100644
--- a/llvm/test/CodeGen/X86/clmul.ll
+++ b/llvm/test/CodeGen/X86/clmul.ll
@@ -2022,6 +2022,49 @@ define i32 @clmul_i32_allones(i32 %x) nounwind {
ret i32 %r
}
+define i32 @clmul_i32_zext_allones(i16 %x) nounwind {
+; SCALAR-LABEL: clmul_i32_zext_allones:
+; SCALAR: # %bb.0:
+; SCALAR-NEXT: # kill: def $edi killed $edi def $rdi
+; SCALAR-NEXT: leal (%rdi,%rdi), %eax
+; SCALAR-NEXT: xorl %edi, %eax
+; SCALAR-NEXT: leal (,%rax,4), %ecx
+; SCALAR-NEXT: xorl %eax, %ecx
+; SCALAR-NEXT: movl %ecx, %eax
+; SCALAR-NEXT: shll $4, %eax
+; SCALAR-NEXT: xorl %ecx, %eax
+; SCALAR-NEXT: movl %eax, %ecx
+; SCALAR-NEXT: shll $8, %ecx
+; SCALAR-NEXT: xorl %eax, %ecx
+; SCALAR-NEXT: movzwl %cx, %eax
+; SCALAR-NEXT: retq
+;
+; SSE-PCLMUL-LABEL: clmul_i32_zext_allones:
+; SSE-PCLMUL: # %bb.0:
+; SSE-PCLMUL-NEXT: movzwl %di, %eax
+; SSE-PCLMUL-NEXT: movl $65535, %ecx # imm = 0xFFFF
+; SSE-PCLMUL-NEXT: movq %rcx, %xmm0
+; SSE-PCLMUL-NEXT: movd %eax, %xmm1
+; SSE-PCLMUL-NEXT: pclmulqdq $0, %xmm0, %xmm1
+; SSE-PCLMUL-NEXT: movq %xmm1, %rax
+; SSE-PCLMUL-NEXT: # kill: def $eax killed $eax killed $rax
+; SSE-PCLMUL-NEXT: retq
+;
+; AVX-LABEL: clmul_i32_zext_allones:
+; AVX: # %bb.0:
+; AVX-NEXT: movzwl %di, %eax
+; AVX-NEXT: movl $65535, %ecx # imm = 0xFFFF
+; AVX-NEXT: vmovq %rcx, %xmm0
+; AVX-NEXT: vmovd %eax, %xmm1
+; AVX-NEXT: vpclmulqdq $0, %xmm0, %xmm1, %xmm0
+; AVX-NEXT: vmovq %xmm0, %rax
+; AVX-NEXT: # kill: def $eax killed $eax killed $rax
+; AVX-NEXT: retq
+ %x32 = zext i16 %x to i32
+ %r = call i32 @llvm.clmul.i32(i32 %x32, i32 65535)
+ ret i32 %r
+}
+
define i64 @clmul_i64_allones(i64 %x) nounwind {
; SCALAR-LABEL: clmul_i64_allones:
; SCALAR: # %bb.0:
``````````
</details>
https://github.com/llvm/llvm-project/pull/207339
More information about the llvm-commits
mailing list