[llvm] [X86] Lower bf16 round-to-integer on AVX10.2 via vrndscalebf16 (PR #213276)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 06:00:02 PDT 2026


================
@@ -0,0 +1,1145 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -verify-machineinstrs -mtriple=x86_64-unknown-unknown -mattr=+avx10.2 | FileCheck %s --check-prefixes=AVX10_2
+; RUN: llc < %s -verify-machineinstrs -mtriple=x86_64-unknown-unknown -mattr=+avx512bf16,+avx512vl | FileCheck %s --check-prefixes=AVX512BF16
+
+; AVX10.2 has packed bf16 round-to-integer instructions. The integral result of
+; floor/ceil/trunc/rint/nearbyint/roundeven is always representable in bf16, so
+; vrndscalebf16 gives the same answer as the AVX512BF16 sequence below (promote
+; each element to f32, round, convert back), but without scalarizing.
+
+define <8 x bfloat> @floor_v8bf16(<8 x bfloat> %a) {
+; AVX10_2-LABEL: floor_v8bf16:
+; AVX10_2:       # %bb.0:
+; AVX10_2-NEXT:    vrndscalebf16 $9, %xmm0, %xmm0
+; AVX10_2-NEXT:    retq
+;
+; AVX512BF16-LABEL: floor_v8bf16:
+; AVX512BF16:       # %bb.0:
+; AVX512BF16-NEXT:    vpextrw $7, %xmm0, %eax
+; AVX512BF16-NEXT:    shll $16, %eax
+; AVX512BF16-NEXT:    vmovd %eax, %xmm1
+; AVX512BF16-NEXT:    vroundss $9, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %eax
+; AVX512BF16-NEXT:    vpextrw $6, %xmm0, %ecx
+; AVX512BF16-NEXT:    shll $16, %ecx
+; AVX512BF16-NEXT:    vmovd %ecx, %xmm1
+; AVX512BF16-NEXT:    vroundss $9, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %ecx
+; AVX512BF16-NEXT:    vpextrw $5, %xmm0, %edx
+; AVX512BF16-NEXT:    shll $16, %edx
+; AVX512BF16-NEXT:    vmovd %edx, %xmm1
+; AVX512BF16-NEXT:    vroundss $9, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %edx
+; AVX512BF16-NEXT:    vpextrw $4, %xmm0, %esi
+; AVX512BF16-NEXT:    shll $16, %esi
+; AVX512BF16-NEXT:    vmovd %esi, %xmm1
+; AVX512BF16-NEXT:    vroundss $9, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %esi
+; AVX512BF16-NEXT:    vpextrw $3, %xmm0, %edi
+; AVX512BF16-NEXT:    shll $16, %edi
+; AVX512BF16-NEXT:    vmovd %edi, %xmm1
+; AVX512BF16-NEXT:    vroundss $9, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %edi
+; AVX512BF16-NEXT:    vpextrw $2, %xmm0, %r8d
+; AVX512BF16-NEXT:    shll $16, %r8d
+; AVX512BF16-NEXT:    vmovd %r8d, %xmm1
+; AVX512BF16-NEXT:    vroundss $9, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %r8d
+; AVX512BF16-NEXT:    vpextrw $1, %xmm0, %r9d
+; AVX512BF16-NEXT:    shll $16, %r9d
+; AVX512BF16-NEXT:    vmovd %r9d, %xmm1
+; AVX512BF16-NEXT:    vroundss $9, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm0, %r9d
+; AVX512BF16-NEXT:    shll $16, %r9d
+; AVX512BF16-NEXT:    vmovd %r9d, %xmm0
+; AVX512BF16-NEXT:    vroundss $9, %xmm0, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpunpcklwd {{.*#+}} xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
+; AVX512BF16-NEXT:    vpinsrw $2, %r8d, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $3, %edi, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $4, %esi, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $5, %edx, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $6, %ecx, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $7, %eax, %xmm0, %xmm0
+; AVX512BF16-NEXT:    retq
+  %r = call <8 x bfloat> @llvm.floor.v8bf16(<8 x bfloat> %a)
+  ret <8 x bfloat> %r
+}
+
+define bfloat @floor_bf16(bfloat %a) {
+; AVX10_2-LABEL: floor_bf16:
+; AVX10_2:       # %bb.0:
+; AVX10_2-NEXT:    vrndscalebf16 $9, %xmm0, %xmm0
+; AVX10_2-NEXT:    retq
+;
+; AVX512BF16-LABEL: floor_bf16:
+; AVX512BF16:       # %bb.0:
+; AVX512BF16-NEXT:    vpextrw $0, %xmm0, %eax
+; AVX512BF16-NEXT:    shll $16, %eax
+; AVX512BF16-NEXT:    vmovd %eax, %xmm0
+; AVX512BF16-NEXT:    vroundss $9, %xmm0, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm0, %xmm0
+; AVX512BF16-NEXT:    retq
+  %r = call bfloat @llvm.floor.bf16(bfloat %a)
+  ret bfloat %r
+}
+
+define <8 x bfloat> @ceil_v8bf16(<8 x bfloat> %a) {
+; AVX10_2-LABEL: ceil_v8bf16:
+; AVX10_2:       # %bb.0:
+; AVX10_2-NEXT:    vrndscalebf16 $10, %xmm0, %xmm0
+; AVX10_2-NEXT:    retq
+;
+; AVX512BF16-LABEL: ceil_v8bf16:
+; AVX512BF16:       # %bb.0:
+; AVX512BF16-NEXT:    vpextrw $7, %xmm0, %eax
+; AVX512BF16-NEXT:    shll $16, %eax
+; AVX512BF16-NEXT:    vmovd %eax, %xmm1
+; AVX512BF16-NEXT:    vroundss $10, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %eax
+; AVX512BF16-NEXT:    vpextrw $6, %xmm0, %ecx
+; AVX512BF16-NEXT:    shll $16, %ecx
+; AVX512BF16-NEXT:    vmovd %ecx, %xmm1
+; AVX512BF16-NEXT:    vroundss $10, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %ecx
+; AVX512BF16-NEXT:    vpextrw $5, %xmm0, %edx
+; AVX512BF16-NEXT:    shll $16, %edx
+; AVX512BF16-NEXT:    vmovd %edx, %xmm1
+; AVX512BF16-NEXT:    vroundss $10, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %edx
+; AVX512BF16-NEXT:    vpextrw $4, %xmm0, %esi
+; AVX512BF16-NEXT:    shll $16, %esi
+; AVX512BF16-NEXT:    vmovd %esi, %xmm1
+; AVX512BF16-NEXT:    vroundss $10, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %esi
+; AVX512BF16-NEXT:    vpextrw $3, %xmm0, %edi
+; AVX512BF16-NEXT:    shll $16, %edi
+; AVX512BF16-NEXT:    vmovd %edi, %xmm1
+; AVX512BF16-NEXT:    vroundss $10, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %edi
+; AVX512BF16-NEXT:    vpextrw $2, %xmm0, %r8d
+; AVX512BF16-NEXT:    shll $16, %r8d
+; AVX512BF16-NEXT:    vmovd %r8d, %xmm1
+; AVX512BF16-NEXT:    vroundss $10, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm1, %r8d
+; AVX512BF16-NEXT:    vpextrw $1, %xmm0, %r9d
+; AVX512BF16-NEXT:    shll $16, %r9d
+; AVX512BF16-NEXT:    vmovd %r9d, %xmm1
+; AVX512BF16-NEXT:    vroundss $10, %xmm1, %xmm1, %xmm1
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm1, %xmm1
+; AVX512BF16-NEXT:    vmovd %xmm0, %r9d
+; AVX512BF16-NEXT:    shll $16, %r9d
+; AVX512BF16-NEXT:    vmovd %r9d, %xmm0
+; AVX512BF16-NEXT:    vroundss $10, %xmm0, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vcvtneps2bf16 %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpunpcklwd {{.*#+}} xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
+; AVX512BF16-NEXT:    vpinsrw $2, %r8d, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $3, %edi, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $4, %esi, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $5, %edx, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $6, %ecx, %xmm0, %xmm0
+; AVX512BF16-NEXT:    vpinsrw $7, %eax, %xmm0, %xmm0
+; AVX512BF16-NEXT:    retq
+  %r = call <8 x bfloat> @llvm.ceil.v8bf16(<8 x bfloat> %a)
+  ret <8 x bfloat> %r
+}
+
+define bfloat @ceil_bf16(bfloat %a) {
+; AVX10_2-LABEL: ceil_bf16:
+; AVX10_2:       # %bb.0:
+; AVX10_2-NEXT:    vrndscalebf16 $10, %xmm0, %xmm0
+; AVX10_2-NEXT:    retq
+;
+; AVX512BF16-LABEL: ceil_bf16:
+; AVX512BF16:       # %bb.0:
+; AVX512BF16-NEXT:    vpextrw $0, %xmm0, %eax
+; AVX512BF16-NEXT:    shll $16, %eax
+; AVX512BF16-NEXT:    vmovd %eax, %xmm0
----------------
tfzee wrote:

Regenerated tests after merging and while the original case is resolved. We still seem to some what fail here.
; AVX512BF16-NEXT:    vpextrw $5, %xmm0, %edx
; AVX512BF16-NEXT:    shll $16, %edx
; AVX512BF16-NEXT:    vmovd %edx, %xmm1


; AVX512BF16-NEXT:    vpextrw $5, %xmm0, %edx
; AVX512BF16-NEXT:    vmovd %edx, %xmm1
; AVX512BF16-NEXT:    vpslld $16, %xmm1, %xmm1

https://github.com/llvm/llvm-project/pull/213276


More information about the llvm-commits mailing list