From 8390826c23ab5c7560c23956efe6cc65b8b32a51 Mon Sep 17 00:00:00 2001 From: AryanBhirud Date: Mon, 10 Aug 2026 00:45:48 +0530 Subject: [PATCH 1/3] [X86] use vdivph for i8 integer division on avx512fp16 --- llvm/lib/Target/X86/X86.td | 4 ++++ llvm/lib/Target/X86/X86ISelLowering.cpp | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td index f40b937efa74b..299950c061356 100644 --- a/llvm/lib/Target/X86/X86.td +++ b/llvm/lib/Target/X86/X86.td @@ -798,6 +798,10 @@ def TuningFastDPWSSD "Prefer vpdpwssd instruction over vpmaddwd+vpaddd instruction sequence", [], InlineIgnore>; +def TuningFastVectorFP16Div + : SubtargetFeature<"fast-vector-fp16-div", "HasFastFP16Div", "true", + "Vector FP16 division is fast", + [], InlineIgnore>; def TuningPreferNoGather : SubtargetFeature<"prefer-no-gather", "PreferGather", "false", "Prefer no gather instructions", diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index c74d342fed1cb..d12b14861bb56 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -50669,7 +50669,10 @@ static SDValue combineIntDivRem(SDNode *N, SelectionDAG &DAG, // f32 recovers the quotient exactly when both operands fit in 24 bits MVT FPSclVT = MVT::f64; - if (EltBits <= 16 || BothFitFP(APFloat::IEEEsingle())) + if (EltBits == 8 && Subtarget.hasFastFP16Div() && + BothFitFP(APFloat::IEEEhalf())) + FPSclVT = MVT::f16; + else if (EltBits <= 16 || BothFitFP(APFloat::IEEEsingle())) FPSclVT = MVT::f32; EVT FPVT = VT.changeVectorElementType(*DAG.getContext(), FPSclVT); @@ -50728,8 +50731,15 @@ static SDValue combineIntDivRem(SDNode *N, SelectionDAG &DAG, Q = IsSigned ? DAG.getSExtOrTrunc(Q, DL, VT) : DAG.getZExtOrTrunc(Q, DL, VT); } else { + SDValue FPQuot = DAG.getNode(ISD::FDIV, DL, FPVT, X, Y); unsigned FromFP = IsSigned ? ISD::FP_TO_SINT : ISD::FP_TO_UINT; - Q = DAG.getNode(FromFP, DL, VT, DAG.getNode(ISD::FDIV, DL, FPVT, X, Y)); + if (FPSclVT == MVT::f16 && EltBits == 8) { + EVT I16VT = VT.changeVectorElementType(*DAG.getContext(), MVT::i16); + SDValue Q16 = DAG.getNode(FromFP, DL, I16VT, FPQuot); + Q = DAG.getNode(ISD::TRUNCATE, DL, VT, Q16); + } else { + Q = DAG.getNode(FromFP, DL, VT, FPQuot); + } } if (!IsRem) return Q; From 0eed49f3751355c18432cda549157554d5308d69 Mon Sep 17 00:00:00 2001 From: AryanBhirud Date: Mon, 10 Aug 2026 18:36:02 +0530 Subject: [PATCH 2/3] [X86] Use vdivph for i8 integer division on targets with fast FP16 divide --- llvm/lib/Target/X86/X86ISelLowering.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index d12b14861bb56..1cff745fff4d7 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -50669,9 +50669,11 @@ static SDValue combineIntDivRem(SDNode *N, SelectionDAG &DAG, // f32 recovers the quotient exactly when both operands fit in 24 bits MVT FPSclVT = MVT::f64; - if (EltBits == 8 && Subtarget.hasFastFP16Div() && - BothFitFP(APFloat::IEEEhalf())) - FPSclVT = MVT::f16; + if ((EltBits == 8 || BothFitFP(APFloat::IEEEhalf())) && Subtarget.hasFastFP16Div()) { + EVT FP16VT = VT.changeVectorElementType(*DAG.getContext(), MVT::f16); + if (DAG.getTargetLoweringInfo().isTypeLegal(FP16VT)) + FPSclVT = MVT::f16; + } else if (EltBits <= 16 || BothFitFP(APFloat::IEEEsingle())) FPSclVT = MVT::f32; EVT FPVT = VT.changeVectorElementType(*DAG.getContext(), FPSclVT); @@ -50696,6 +50698,10 @@ static SDValue combineIntDivRem(SDNode *N, SelectionDAG &DAG, ? FPVT.getSizeInBits() <= 512 : DCI.isBeforeLegalize() || DAG.getTargetLoweringInfo().isTypeLegal(FPVT); + LLVM_DEBUG(dbgs() << "FPVT = " << FPVT << "\n"); + LLVM_DEBUG(dbgs() << "legal = " + << DAG.getTargetLoweringInfo().isTypeLegal(FPVT) + << "\n"); // Halve the divide while the integer halves stay legal. if (!FPVTUsable) { From c0b945655a3fe7371fd666a8cf65d66c5ceae3f8 Mon Sep 17 00:00:00 2001 From: AryanBhirud Date: Mon, 10 Aug 2026 18:37:02 +0530 Subject: [PATCH 3/3] [Tests][X86] Add tests for fast FP16 vector i8 division lowering --- llvm/test/CodeGen/X86/vector-idiv-sdiv-256.ll | 22 ++++++++++++++++++ llvm/test/CodeGen/X86/vector-idiv-udiv-256.ll | 23 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/llvm/test/CodeGen/X86/vector-idiv-sdiv-256.ll b/llvm/test/CodeGen/X86/vector-idiv-sdiv-256.ll index e42a3febbf041..1498f82f5699e 100644 --- a/llvm/test/CodeGen/X86/vector-idiv-sdiv-256.ll +++ b/llvm/test/CodeGen/X86/vector-idiv-sdiv-256.ll @@ -2,6 +2,8 @@ ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx | FileCheck %s --check-prefix=AVX1 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx2 | FileCheck %s --check-prefix=AVX2 --check-prefix=AVX2NOBW ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512bw | FileCheck %s --check-prefix=AVX2 --check-prefix=AVX512BW +; RUN: llc < %s -mtriple=x86_64 -mattr=+avx512fp16,+fast-vector-fp16-div | FileCheck %s --check-prefix=FAST-FP16 +; RUN: llc -mtriple=x86_64 -mattr=+avx512fp16 < %s | FileCheck %s --check-prefix=NO-FAST-FP16 ; ; sdiv by 7 @@ -856,3 +858,23 @@ define <8 x i32> @test_remv_8i32(<8 x i32> %a, <8 x i32> %b) nounwind { %res = srem <8 x i32> %a, %b ret <8 x i32> %res } + +define <32 x i8> @test_sdiv_32i8_fast_fp16(<32 x i8> %a, <32 x i8> %b) nounwind { +; FAST-FP16-LABEL: test_sdiv_32i8_fast_fp16: +; FAST-FP16: # %bb.0: +; FAST-FP16: vpmovsxbw +; FAST-FP16: vcvtw2ph +; FAST-FP16: vdivph +; FAST-FP16: vcvttph2w +; FAST-FP16: vpmovwb +; FAST-FP16-NOT: idiv +; FAST-FP16-NOT: div +; FAST-FP16-NEXT: retq + +; NO-FAST-FP16-LABEL: test_sdiv_32i8_fast_fp16: +; NO-FAST-FP16-NOT: vdivph +; NO-FAST-FP16: retq + +%res = sdiv <32 x i8> %a, %b +ret <32 x i8> %res +} diff --git a/llvm/test/CodeGen/X86/vector-idiv-udiv-256.ll b/llvm/test/CodeGen/X86/vector-idiv-udiv-256.ll index 7ca985872b875..3419bde72af70 100644 --- a/llvm/test/CodeGen/X86/vector-idiv-udiv-256.ll +++ b/llvm/test/CodeGen/X86/vector-idiv-udiv-256.ll @@ -2,6 +2,8 @@ ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx | FileCheck %s --check-prefix=AVX1 ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx2 | FileCheck %s --check-prefix=AVX2 --check-prefix=AVX2NOBW ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx512bw | FileCheck %s --check-prefix=AVX2 --check-prefix=AVX512BW +; RUN: llc < %s -mtriple=x86_64 -mattr=+avx512fp16,+fast-vector-fp16-div | FileCheck %s --check-prefix=FAST-FP16 +; RUN: llc -mtriple=x86_64 -mattr=+avx512fp16 < %s | FileCheck %s --check-prefix=NO-FAST-FP16 ; ; udiv by 7 @@ -961,3 +963,24 @@ define <8 x i32> @test_remv_8i32(<8 x i32> %a, <8 x i32> %b) nounwind { %res = urem <8 x i32> %a, %b ret <8 x i32> %res } + +define <32 x i8> @test_udiv_32i8_fast_fp16(<32 x i8> %a, <32 x i8> %b) nounwind { +; FAST-FP16-LABEL: test_udiv_32i8_fast_fp16: +; FAST-FP16: # %bb.0: +; FAST-FP16: vpmovzxbw +; FAST-FP16: vcvtw2ph +; FAST-FP16: vdivph +; FAST-FP16: vcvttph2uw +; FAST-FP16: vpmovwb +; FAST-FP16-NOT: idiv +; FAST-FP16-NOT: div +; FAST-FP16-NEXT: retq + +; NO-FAST-FP16-LABEL: test_udiv_32i8_fast_fp16: +; NO-FAST-FP16-NOT: vdivph +; NO-FAST-FP16: div +; NO-FAST-FP16: retq + +%res = udiv <32 x i8> %a, %b +ret <32 x i8> %res +}