[llvm] [X86] Fold XOR of VGF2P8AFFINEQB and its source (PR #198448)
Simon Pilgrim via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 1 05:32:39 PDT 2026
https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/198448
>From 68a6ab0c4be85ea1c391299810577dcfbc8051ef Mon Sep 17 00:00:00 2001
From: Walter <walter.kruger at hotmail.com>
Date: Mon, 18 May 2026 16:36:22 +1000
Subject: [PATCH 1/5] [NFC] Baseline tests without fold
Regression check line tests without the fold, demonstrating the current code gen.
---
llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll | 57 ++++++++++
llvm/test/CodeGen/X86/gfni-xor-fold.ll | 105 ++++++++++++++++++
2 files changed, 162 insertions(+)
diff --git a/llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll b/llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll
index 414a9a849b4cc..212e026b3c7c4 100644
--- a/llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll
+++ b/llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll
@@ -62,6 +62,63 @@ define <64 x i8> @test_affine_xor_no_fold_512_variable(<64 x i8> %src1, <64 x i8
ret <64 x i8> %xor
}
+define <64 x i8> @test_affine_src_xor_fold_512(<64 x i8> %src) nounwind {
+; CHECK-LABEL: test_affine_src_xor_fold_512:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %zmm0, %zmm1 # [53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53]
+; CHECK-NEXT: vpxorq %zmm0, %zmm1, %zmm0
+; CHECK-NEXT: retq
+ %gfni = call <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8> %src, <64 x i8> splat(i8 53), i8 0)
+ %xor = xor <64 x i8> %gfni, %src
+ ret <64 x i8> %xor
+}
+
+define <64 x i8> @test_affine_src_xor_fold_alternative_matrix(<64 x i8> %src) nounwind {
+; CHECK-LABEL: test_affine_src_xor_fold_alternative_matrix:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %zmm0, %zmm1 # [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63]
+; CHECK-NEXT: vpxorq %zmm0, %zmm1, %zmm0
+; CHECK-NEXT: retq
+ %gfni = call <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8> %src, <64 x i8> <i8 0, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16, i8 17, i8 18, i8 19, i8 20, i8 21, i8 22, i8 23, i8 24, i8 25, i8 26, i8 27, i8 28, i8 29, i8 30, i8 31, i8 32, i8 33, i8 34, i8 35, i8 36, i8 37, i8 38, i8 39, i8 40, i8 41, i8 42, i8 43, i8 44, i8 45, i8 46, i8 47, i8 48, i8 49, i8 50, i8 51, i8 52, i8 53, i8 54, i8 55, i8 56, i8 57, i8 58, i8 59, i8 60, i8 61, i8 62, i8 63>, i8 0)
+ %xor = xor <64 x i8> %gfni, %src
+ ret <64 x i8> %xor
+}
+
+define <64 x i8> @test_affine_src_xor_nonzero_imm(<64 x i8> %src) nounwind {
+; CHECK-LABEL: test_affine_src_xor_nonzero_imm:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %zmm0, %zmm1 # [53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53]
+; CHECK-NEXT: vpxorq %zmm0, %zmm1, %zmm0
+; CHECK-NEXT: retq
+ %gfni = call <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8> %src, <64 x i8> splat(i8 53), i8 107)
+ %xor = xor <64 x i8> %gfni, %src
+ ret <64 x i8> %xor
+}
+
+define <64 x i8> @test_affine_src_xor_no_fold_multi_use(<64 x i8> %src, ptr %sink) nounwind {
+; CHECK-LABEL: test_affine_src_xor_no_fold_multi_use:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %zmm0, %zmm1 # [53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53]
+; CHECK-NEXT: vmovdqa64 %zmm1, (%rdi)
+; CHECK-NEXT: vpxorq %zmm0, %zmm1, %zmm0
+; CHECK-NEXT: retq
+ %gfni = call <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8> %src, <64 x i8> splat(i8 53), i8 0)
+ store <64 x i8> %gfni, ptr %sink
+ %xor = xor <64 x i8> %gfni, %src
+ ret <64 x i8> %xor
+}
+
+define <64 x i8> @test_affine_src_xor_no_fold_var_matrix(<64 x i8> %src, <64 x i8> %matrix) nounwind {
+; CHECK-LABEL: test_affine_src_xor_no_fold_var_matrix:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vgf2p8affineqb $0, %zmm1, %zmm0, %zmm1
+; CHECK-NEXT: vpxorq %zmm0, %zmm1, %zmm0
+; CHECK-NEXT: retq
+ %gfni = call <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8> %src, <64 x i8> %matrix, i8 0)
+ %xor = xor <64 x i8> %gfni, %src
+ ret <64 x i8> %xor
+}
+
;; Test folding XOR of two vgf2p8affineqb with same input - 512-bit
define <64 x i8> @test_affine_affine_xor_fold_512(<64 x i8> %src, <64 x i8> %m1, <64 x i8> %m2) nounwind {
;
diff --git a/llvm/test/CodeGen/X86/gfni-xor-fold.ll b/llvm/test/CodeGen/X86/gfni-xor-fold.ll
index e907410ae7bab..7fd54b14a073a 100644
--- a/llvm/test/CodeGen/X86/gfni-xor-fold.ll
+++ b/llvm/test/CodeGen/X86/gfni-xor-fold.ll
@@ -143,6 +143,111 @@ define <16 x i8> @test_affine_xor_no_fold_variable(<16 x i8> %src1, <16 x i8> %s
ret <16 x i8> %xor
}
+define <16 x i8> @test_affine_src_xor_fold_128(<16 x i8> %src) nounwind {
+; AVX-LABEL: test_affine_src_xor_fold_128:
+; AVX: # %bb.0:
+; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
+; AVX-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX-NEXT: retq
+;
+; AVX512-LABEL: test_affine_src_xor_fold_128:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
+; AVX512-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: retq
+ %gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %src, <16 x i8> <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16>, i8 0)
+ %xor = xor <16 x i8> %gfni, %src
+ ret <16 x i8> %xor
+}
+
+define <32 x i8> @test_affine_src_xor_fold_256(<32 x i8> %src) nounwind {
+; AVX-LABEL: test_affine_src_xor_fold_256:
+; AVX: # %bb.0:
+; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]
+; AVX-NEXT: vxorps %ymm0, %ymm1, %ymm0
+; AVX-NEXT: retq
+;
+; AVX512-LABEL: test_affine_src_xor_fold_256:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]
+; AVX512-NEXT: vpxor %ymm0, %ymm1, %ymm0
+; AVX512-NEXT: retq
+ %gfni = call <32 x i8> @llvm.x86.vgf2p8affineqb.256(<32 x i8> %src, <32 x i8> <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16, i8 17, i8 18, i8 19, i8 20, i8 21, i8 22, i8 23, i8 24, i8 25, i8 26, i8 27, i8 28, i8 29, i8 30, i8 31, i8 32>, i8 0)
+ %xor = xor <32 x i8> %gfni, %src
+ ret <32 x i8> %xor
+}
+
+define <16 x i8> @test_affine_src_xor_fold_alternative_matrix(<16 x i8> %src) nounwind {
+; AVX-LABEL: test_affine_src_xor_fold_alternative_matrix:
+; AVX: # %bb.0:
+; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
+; AVX-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX-NEXT: retq
+;
+; AVX512-LABEL: test_affine_src_xor_fold_alternative_matrix:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to2}, %xmm0, %xmm1 # [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
+; AVX512-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: retq
+ %gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %src, <16 x i8> splat(i8 1), i8 0)
+ %xor = xor <16 x i8> %gfni, %src
+ ret <16 x i8> %xor
+}
+
+define <16 x i8> @test_affine_src_xor_nonzero_imm(<16 x i8> %src) nounwind {
+; AVX-LABEL: test_affine_src_xor_nonzero_imm:
+; AVX: # %bb.0:
+; AVX-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
+; AVX-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX-NEXT: retq
+;
+; AVX512-LABEL: test_affine_src_xor_nonzero_imm:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
+; AVX512-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: retq
+ %gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %src, <16 x i8> <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16>, i8 107)
+ %xor = xor <16 x i8> %gfni, %src
+ ret <16 x i8> %xor
+}
+
+define <16 x i8> @test_affine_src_xor_no_fold_multi_use(<16 x i8> %src, ptr %sink) nounwind {
+; AVX-LABEL: test_affine_src_xor_no_fold_multi_use:
+; AVX: # %bb.0:
+; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
+; AVX-NEXT: vmovdqa %xmm1, (%rdi)
+; AVX-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX-NEXT: retq
+;
+; AVX512-LABEL: test_affine_src_xor_no_fold_multi_use:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
+; AVX512-NEXT: vmovdqa %xmm1, (%rdi)
+; AVX512-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: retq
+ %gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %src, <16 x i8> <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16>, i8 0)
+ store <16 x i8> %gfni, ptr %sink
+ %xor = xor <16 x i8> %gfni, %src
+ ret <16 x i8> %xor
+}
+
+define <16 x i8> @test_affine_src_xor_no_fold_var_matrix(<16 x i8> %src, <16 x i8> %matrix) nounwind {
+; AVX-LABEL: test_affine_src_xor_no_fold_var_matrix:
+; AVX: # %bb.0:
+; AVX-NEXT: vgf2p8affineqb $0, %xmm1, %xmm0, %xmm1
+; AVX-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX-NEXT: retq
+;
+; AVX512-LABEL: test_affine_src_xor_no_fold_var_matrix:
+; AVX512: # %bb.0:
+; AVX512-NEXT: vgf2p8affineqb $0, %xmm1, %xmm0, %xmm1
+; AVX512-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: retq
+ %gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %src, <16 x i8> %matrix, i8 0)
+ %xor = xor <16 x i8> %gfni, %src
+ ret <16 x i8> %xor
+}
+
;; Test folding XOR of two vgf2p8affineqb with same input - 128-bit
define <16 x i8> @test_affine_affine_xor_fold_128(<16 x i8> %src, <16 x i8> %m1, <16 x i8> %m2) nounwind {
;
>From 19f89827a930e51d0cfeab322c4fb468b0dc1770 Mon Sep 17 00:00:00 2001
From: Walter <walter.kruger at hotmail.com>
Date: Tue, 19 May 2026 15:31:36 +1000
Subject: [PATCH 2/5] GFNI XOR fold + update tests
- Added fold when XORing VGF2P8AFFINEQB and its source when the matrix is a constant.
- Updated tests to reflect improved code gen.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 35 +++++++++++++++----
llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll | 9 ++---
llvm/test/CodeGen/X86/gfni-xor-fold.ll | 24 +++++--------
3 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index b6aee44b4de2e..0e7c6d6327059 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -56435,21 +56435,44 @@ static SDValue combineXorWithGF2P8AFFINEQB(SDNode *N, const SDLoc &DL,
SelectionDAG &DAG, EVT VT) {
using namespace SDPatternMatch;
- SDValue X, Y, SplatOp;
- APInt Imm;
- // Use sd_match for structure matching - m_Xor handles commutation
+ unsigned NumElts = VT.getVectorNumElements();
+
+ SDValue X, Y, XorOp;
+ APInt Imm, ConstUndef;
+
if (!sd_match(N, m_Xor(m_OneUse(m_TernaryOp(X86ISD::GF2P8AFFINEQB, m_Value(X),
m_Value(Y), m_ConstInt(Imm))),
- m_Value(SplatOp))))
+ m_Value(XorOp))))
return SDValue();
// GF2P8AFFINEQB only operates on i8 vector types
assert((VT == MVT::v16i8 || VT == MVT::v32i8 || VT == MVT::v64i8) &&
"Unsupported GFNI type");
- // Use X86::isConstantSplat for robust splat constant extraction
+ // Fold: GF2P8AFFINEQB(x, M) ^ x
+ // => GF2P8AFFINEQB(x, M ^ IDENTITY)
+ // The "identity" is a noop. It adds a XOR by the unmodified input.
+ SmallVector<APInt> YEltBits;
+ if (X == XorOp && getTargetConstantBitsFromNode(Y, 8, ConstUndef, YEltBits,
+ /*AllowWholeUndefs=*/false)) {
+ static const uint8_t IdentityMatrtix[] = {128, 64, 32, 16, 8, 4, 2, 1};
+
+ SmallVector<SDValue> BuildMatrix;
+ for (unsigned I = 0; I != NumElts; ++I) {
+ APInt MatrixRow = YEltBits[I] ^ IdentityMatrtix[I % 8];
+ BuildMatrix.push_back(DAG.getConstant(MatrixRow, DL, MVT::i8));
+ }
+
+ SDValue NewMatrix = DAG.getBuildVector(VT, DL, BuildMatrix);
+
+ return DAG.getNode(X86ISD::GF2P8AFFINEQB, DL, VT, X, NewMatrix,
+ DAG.getTargetConstant(Imm, DL, MVT::i8));
+ }
+
+ // Fold: GF2P8AFFINEQB(x, m, Imm) ^ Splat(C)
+ // => GF2P8AFFINEQB(x, m, Imm ^ C)
APInt SplatVal;
- if (!X86::isConstantSplat(SplatOp, SplatVal, /*AllowPartialUndefs=*/false))
+ if (!X86::isConstantSplat(XorOp, SplatVal, /*AllowPartialUndefs=*/false))
return SDValue();
uint64_t NewImm = Imm.getZExtValue() ^ SplatVal.getZExtValue();
diff --git a/llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll b/llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll
index 212e026b3c7c4..4107f07741991 100644
--- a/llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll
+++ b/llvm/test/CodeGen/X86/gfni-xor-fold-avx512.ll
@@ -65,8 +65,7 @@ define <64 x i8> @test_affine_xor_no_fold_512_variable(<64 x i8> %src1, <64 x i8
define <64 x i8> @test_affine_src_xor_fold_512(<64 x i8> %src) nounwind {
; CHECK-LABEL: test_affine_src_xor_fold_512:
; CHECK: # %bb.0:
-; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %zmm0, %zmm1 # [53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53]
-; CHECK-NEXT: vpxorq %zmm0, %zmm1, %zmm0
+; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %zmm0, %zmm0 # [181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52]
; CHECK-NEXT: retq
%gfni = call <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8> %src, <64 x i8> splat(i8 53), i8 0)
%xor = xor <64 x i8> %gfni, %src
@@ -76,8 +75,7 @@ define <64 x i8> @test_affine_src_xor_fold_512(<64 x i8> %src) nounwind {
define <64 x i8> @test_affine_src_xor_fold_alternative_matrix(<64 x i8> %src) nounwind {
; CHECK-LABEL: test_affine_src_xor_fold_alternative_matrix:
; CHECK: # %bb.0:
-; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %zmm0, %zmm1 # [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63]
-; CHECK-NEXT: vpxorq %zmm0, %zmm1, %zmm0
+; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %zmm0, %zmm0 # [128,65,34,19,12,1,4,6,136,73,42,27,4,9,12,14,144,81,50,3,28,17,20,22,152,89,58,11,20,25,28,30,160,97,2,51,44,33,36,38,168,105,10,59,36,41,44,46,176,113,18,35,60,49,52,54,184,121,26,43,52,57,60,62]
; CHECK-NEXT: retq
%gfni = call <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8> %src, <64 x i8> <i8 0, i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16, i8 17, i8 18, i8 19, i8 20, i8 21, i8 22, i8 23, i8 24, i8 25, i8 26, i8 27, i8 28, i8 29, i8 30, i8 31, i8 32, i8 33, i8 34, i8 35, i8 36, i8 37, i8 38, i8 39, i8 40, i8 41, i8 42, i8 43, i8 44, i8 45, i8 46, i8 47, i8 48, i8 49, i8 50, i8 51, i8 52, i8 53, i8 54, i8 55, i8 56, i8 57, i8 58, i8 59, i8 60, i8 61, i8 62, i8 63>, i8 0)
%xor = xor <64 x i8> %gfni, %src
@@ -87,8 +85,7 @@ define <64 x i8> @test_affine_src_xor_fold_alternative_matrix(<64 x i8> %src) no
define <64 x i8> @test_affine_src_xor_nonzero_imm(<64 x i8> %src) nounwind {
; CHECK-LABEL: test_affine_src_xor_nonzero_imm:
; CHECK: # %bb.0:
-; CHECK-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %zmm0, %zmm1 # [53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53]
-; CHECK-NEXT: vpxorq %zmm0, %zmm1, %zmm0
+; CHECK-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to8}, %zmm0, %zmm0 # [181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52,181,117,21,37,61,49,55,52]
; CHECK-NEXT: retq
%gfni = call <64 x i8> @llvm.x86.vgf2p8affineqb.512(<64 x i8> %src, <64 x i8> splat(i8 53), i8 107)
%xor = xor <64 x i8> %gfni, %src
diff --git a/llvm/test/CodeGen/X86/gfni-xor-fold.ll b/llvm/test/CodeGen/X86/gfni-xor-fold.ll
index 7fd54b14a073a..d7bd66377bc3d 100644
--- a/llvm/test/CodeGen/X86/gfni-xor-fold.ll
+++ b/llvm/test/CodeGen/X86/gfni-xor-fold.ll
@@ -146,14 +146,12 @@ define <16 x i8> @test_affine_xor_no_fold_variable(<16 x i8> %src1, <16 x i8> %s
define <16 x i8> @test_affine_src_xor_fold_128(<16 x i8> %src) nounwind {
; AVX-LABEL: test_affine_src_xor_fold_128:
; AVX: # %bb.0:
-; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
-; AVX-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 # [129,66,35,20,13,2,5,9,137,74,43,28,5,10,13,17]
; AVX-NEXT: retq
;
; AVX512-LABEL: test_affine_src_xor_fold_128:
; AVX512: # %bb.0:
-; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
-; AVX512-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 # [129,66,35,20,13,2,5,9,137,74,43,28,5,10,13,17]
; AVX512-NEXT: retq
%gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %src, <16 x i8> <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16>, i8 0)
%xor = xor <16 x i8> %gfni, %src
@@ -163,14 +161,12 @@ define <16 x i8> @test_affine_src_xor_fold_128(<16 x i8> %src) nounwind {
define <32 x i8> @test_affine_src_xor_fold_256(<32 x i8> %src) nounwind {
; AVX-LABEL: test_affine_src_xor_fold_256:
; AVX: # %bb.0:
-; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]
-; AVX-NEXT: vxorps %ymm0, %ymm1, %ymm0
+; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm0 # [129,66,35,20,13,2,5,9,137,74,43,28,5,10,13,17,145,82,51,4,29,18,21,25,153,90,59,12,21,26,29,33]
; AVX-NEXT: retq
;
; AVX512-LABEL: test_affine_src_xor_fold_256:
; AVX512: # %bb.0:
-; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]
-; AVX512-NEXT: vpxor %ymm0, %ymm1, %ymm0
+; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %ymm0, %ymm0 # [129,66,35,20,13,2,5,9,137,74,43,28,5,10,13,17,145,82,51,4,29,18,21,25,153,90,59,12,21,26,29,33]
; AVX512-NEXT: retq
%gfni = call <32 x i8> @llvm.x86.vgf2p8affineqb.256(<32 x i8> %src, <32 x i8> <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16, i8 17, i8 18, i8 19, i8 20, i8 21, i8 22, i8 23, i8 24, i8 25, i8 26, i8 27, i8 28, i8 29, i8 30, i8 31, i8 32>, i8 0)
%xor = xor <32 x i8> %gfni, %src
@@ -180,14 +176,12 @@ define <32 x i8> @test_affine_src_xor_fold_256(<32 x i8> %src) nounwind {
define <16 x i8> @test_affine_src_xor_fold_alternative_matrix(<16 x i8> %src) nounwind {
; AVX-LABEL: test_affine_src_xor_fold_alternative_matrix:
; AVX: # %bb.0:
-; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
-; AVX-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 # [129,65,33,17,9,5,3,0,129,65,33,17,9,5,3,0]
; AVX-NEXT: retq
;
; AVX512-LABEL: test_affine_src_xor_fold_alternative_matrix:
; AVX512: # %bb.0:
-; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to2}, %xmm0, %xmm1 # [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
-; AVX512-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to2}, %xmm0, %xmm0 # [129,65,33,17,9,5,3,0,129,65,33,17,9,5,3,0]
; AVX512-NEXT: retq
%gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %src, <16 x i8> splat(i8 1), i8 0)
%xor = xor <16 x i8> %gfni, %src
@@ -197,14 +191,12 @@ define <16 x i8> @test_affine_src_xor_fold_alternative_matrix(<16 x i8> %src) no
define <16 x i8> @test_affine_src_xor_nonzero_imm(<16 x i8> %src) nounwind {
; AVX-LABEL: test_affine_src_xor_nonzero_imm:
; AVX: # %bb.0:
-; AVX-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
-; AVX-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 # [129,66,35,20,13,2,5,9,137,74,43,28,5,10,13,17]
; AVX-NEXT: retq
;
; AVX512-LABEL: test_affine_src_xor_nonzero_imm:
; AVX512: # %bb.0:
-; AVX512-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
-; AVX512-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; AVX512-NEXT: vgf2p8affineqb $107, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0 # [129,66,35,20,13,2,5,9,137,74,43,28,5,10,13,17]
; AVX512-NEXT: retq
%gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %src, <16 x i8> <i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8, i8 9, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15, i8 16>, i8 107)
%xor = xor <16 x i8> %gfni, %src
>From 647594981c6fda5735fc1c3294e03ffecebf8f47 Mon Sep 17 00:00:00 2001
From: Walter <walter.kruger at hotmail.com>
Date: Sat, 30 May 2026 10:04:28 +1000
Subject: [PATCH 3/5] Typo + Drop static
- Fixed the typo in `IdentityMatrtix` => `IdentityMatrix`
- Removed the static keyword from it as well.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 0e7c6d6327059..a1fafd536b237 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -56455,11 +56455,11 @@ static SDValue combineXorWithGF2P8AFFINEQB(SDNode *N, const SDLoc &DL,
SmallVector<APInt> YEltBits;
if (X == XorOp && getTargetConstantBitsFromNode(Y, 8, ConstUndef, YEltBits,
/*AllowWholeUndefs=*/false)) {
- static const uint8_t IdentityMatrtix[] = {128, 64, 32, 16, 8, 4, 2, 1};
+ const uint8_t IdentityMatrix[] = {128, 64, 32, 16, 8, 4, 2, 1};
SmallVector<SDValue> BuildMatrix;
for (unsigned I = 0; I != NumElts; ++I) {
- APInt MatrixRow = YEltBits[I] ^ IdentityMatrtix[I % 8];
+ APInt MatrixRow = YEltBits[I] ^ IdentityMatrix[I % 8];
BuildMatrix.push_back(DAG.getConstant(MatrixRow, DL, MVT::i8));
}
>From d9fcf3151c88324312092d0b9e8a88cabc772b0d Mon Sep 17 00:00:00 2001
From: Walter <walter.kruger at hotmail.com>
Date: Sat, 30 May 2026 12:56:34 +1000
Subject: [PATCH 4/5] Move `getNumElts` to after match guard
Moved `getVectorNumElements` to after `if sd_match` guard as the parent function is meant for generic XOR folds so it can assert when used with scalar types.
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index a1fafd536b237..85f74d4f26445 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -56435,8 +56435,6 @@ static SDValue combineXorWithGF2P8AFFINEQB(SDNode *N, const SDLoc &DL,
SelectionDAG &DAG, EVT VT) {
using namespace SDPatternMatch;
- unsigned NumElts = VT.getVectorNumElements();
-
SDValue X, Y, XorOp;
APInt Imm, ConstUndef;
@@ -56449,6 +56447,8 @@ static SDValue combineXorWithGF2P8AFFINEQB(SDNode *N, const SDLoc &DL,
assert((VT == MVT::v16i8 || VT == MVT::v32i8 || VT == MVT::v64i8) &&
"Unsupported GFNI type");
+ unsigned NumElts = VT.getVectorNumElements();
+
// Fold: GF2P8AFFINEQB(x, M) ^ x
// => GF2P8AFFINEQB(x, M ^ IDENTITY)
// The "identity" is a noop. It adds a XOR by the unmodified input.
>From 04891e51868b3537c3e5962bcd7e7dfd117e8683 Mon Sep 17 00:00:00 2001
From: Walter <walter.kruger at hotmail.com>
Date: Sat, 30 May 2026 14:38:54 +1000
Subject: [PATCH 5/5] Safer multi-use in `gfni-operand-and-fold.ll`
A (previously) upstream test used an XOR between the input to test multi-use. This was optimized away by this pull. I changed it to instead use a store, which also better matches the other existing, safer, multi-use test.
---
llvm/test/CodeGen/X86/gfni-operand-and-fold.ll | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/test/CodeGen/X86/gfni-operand-and-fold.ll b/llvm/test/CodeGen/X86/gfni-operand-and-fold.ll
index a16771baaff7c..666b0015fd448 100644
--- a/llvm/test/CodeGen/X86/gfni-operand-and-fold.ll
+++ b/llvm/test/CodeGen/X86/gfni-operand-and-fold.ll
@@ -103,21 +103,21 @@ define <16 x i8> @test_const_splat_on_const_matrix_multi_use(<16 x i8> %src, ptr
}
;; Negative test: multi use would generate an additional AND
-define <16 x i8> @test_var_splat_on_const_matrix_multi_use(<16 x i8> %src, i8 %scalar) nounwind {
+define <16 x i8> @test_var_splat_on_const_matrix_multi_use(<16 x i8> %src, i8 %scalar, ptr %sink) nounwind {
; CHECK-LABEL: test_var_splat_on_const_matrix_multi_use:
; CHECK: # %bb.0:
; CHECK-NEXT: vmovd %edi, %xmm1
; CHECK-NEXT: vpbroadcastb %xmm1, %xmm1
-; CHECK-NEXT: vpand %xmm1, %xmm0, %xmm0
-; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm1 # [64,32,16,8,4,2,1,128,64,32,16,8,4,2,1,128]
-; CHECK-NEXT: vpxor %xmm0, %xmm1, %xmm0
+; CHECK-NEXT: vpand %xmm1, %xmm0, %xmm1
+; CHECK-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1, %xmm0 # [64,32,16,8,4,2,1,128,64,32,16,8,4,2,1,128]
+; CHECK-NEXT: vmovdqa %xmm1, (%rsi)
; CHECK-NEXT: retq
%inlo = insertelement <16 x i8> poison, i8 %scalar, i64 0
%varsplat = shufflevector <16 x i8> %inlo, <16 x i8> poison, <16 x i32> zeroinitializer
%and = and <16 x i8> %src, %varsplat
%gfni = call <16 x i8> @llvm.x86.vgf2p8affineqb.128(<16 x i8> %and, <16 x i8> <i8 64, i8 32, i8 16, i8 8, i8 4, i8 2, i8 1, i8 128, i8 64, i8 32, i8 16, i8 8, i8 4, i8 2, i8 1, i8 128>, i8 0)
- %xor = xor <16 x i8> %gfni, %and
- ret <16 x i8> %xor
+ store <16 x i8> %and, ptr %sink
+ ret <16 x i8> %gfni
}
;; Negative test: don't fold as it may increase dependency chain
More information about the llvm-commits
mailing list