[llvm] [X86] Use round-to-odd for f64->f16 with F16C (PR #230079)
Aochang Liu via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 11 22:28:24 PDT 2026
================
@@ -62,6 +112,164 @@ entry:
ret i16 %0
}
+define half @fptrunc_afn(double %d) #0 {
+; F16C-LABEL: fptrunc_afn:
+; F16C: # %bb.0:
+; F16C-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm0
+; F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0
+; F16C-NEXT: retq
+;
+; AVX-LABEL: fptrunc_afn:
+; AVX: # %bb.0:
+; AVX-NEXT: pushq %rax
+; AVX-NEXT: callq __truncdfhf2 at PLT
+; AVX-NEXT: popq %rax
+; AVX-NEXT: retq
+ %r = fptrunc afn double %d to half
+ ret half %r
+}
+
+define half @fptrunc_afn_twostep(double %d) #0 {
+; F16C-LABEL: fptrunc_afn_twostep:
+; F16C: # %bb.0:
+; F16C-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm0
+; F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0
+; F16C-NEXT: retq
+;
+; AVX-LABEL: fptrunc_afn_twostep:
+; AVX: # %bb.0:
+; AVX-NEXT: pushq %rax
+; AVX-NEXT: callq __truncdfhf2 at PLT
+; AVX-NEXT: popq %rax
+; AVX-NEXT: retq
+ %f = fptrunc contract afn double %d to float
+ %r = fptrunc contract afn float %f to half
+ ret half %r
+}
+
+define <4 x half> @fptrunc_afn_v4f64(<4 x double> %d) #0 {
+; F16C-LABEL: fptrunc_afn_v4f64:
+; F16C: # %bb.0:
+; F16C-NEXT: vextractf128 $1, %ymm0, %xmm1
+; F16C-NEXT: vcvtsd2ss %xmm1, %xmm1, %xmm2
+; F16C-NEXT: vcvtps2ph $4, %xmm2, %xmm2
+; F16C-NEXT: vshufpd {{.*#+}} xmm1 = xmm1[1,0]
+; F16C-NEXT: vcvtsd2ss %xmm1, %xmm1, %xmm1
+; F16C-NEXT: vcvtps2ph $4, %xmm1, %xmm1
+; F16C-NEXT: vpunpcklwd {{.*#+}} xmm1 = xmm2[0],xmm1[0],xmm2[1],xmm1[1],xmm2[2],xmm1[2],xmm2[3],xmm1[3]
+; F16C-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm2
+; F16C-NEXT: vcvtps2ph $4, %xmm2, %xmm2
+; F16C-NEXT: vshufpd {{.*#+}} xmm0 = xmm0[1,0]
+; F16C-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm0
+; F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0
+; F16C-NEXT: vpunpcklwd {{.*#+}} xmm0 = xmm2[0],xmm0[0],xmm2[1],xmm0[1],xmm2[2],xmm0[2],xmm2[3],xmm0[3]
+; F16C-NEXT: vinsertps {{.*#+}} xmm0 = xmm0[0],xmm1[0],zero,zero
+; F16C-NEXT: vzeroupper
+; F16C-NEXT: retq
+;
+; AVX-LABEL: fptrunc_afn_v4f64:
+; AVX: # %bb.0:
+; AVX-NEXT: subq $88, %rsp
+; AVX-NEXT: vmovupd %ymm0, (%rsp) # 32-byte Spill
+; AVX-NEXT: vshufpd {{.*#+}} xmm0 = xmm0[1,0]
+; AVX-NEXT: vzeroupper
+; AVX-NEXT: callq __truncdfhf2 at PLT
+; AVX-NEXT: vmovapd %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
+; AVX-NEXT: vmovups (%rsp), %ymm0 # 32-byte Reload
+; AVX-NEXT: # kill: def $xmm0 killed $xmm0 killed $ymm0
+; AVX-NEXT: vzeroupper
+; AVX-NEXT: callq __truncdfhf2 at PLT
+; AVX-NEXT: vmovaps %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
+; AVX-NEXT: vmovups (%rsp), %ymm0 # 32-byte Reload
+; AVX-NEXT: vextractf128 $1, %ymm0, %xmm0
+; AVX-NEXT: vmovapd %xmm0, (%rsp) # 16-byte Spill
+; AVX-NEXT: vshufpd {{.*#+}} xmm0 = xmm0[1,0]
+; AVX-NEXT: vzeroupper
+; AVX-NEXT: callq __truncdfhf2 at PLT
+; AVX-NEXT: vmovapd %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 16-byte Spill
+; AVX-NEXT: vmovdqa (%rsp), %xmm0 # 16-byte Reload
+; AVX-NEXT: callq __truncdfhf2 at PLT
+; AVX-NEXT: vpunpcklwd {{[-0-9]+}}(%r{{[sb]}}p), %xmm0, %xmm0 # 16-byte Folded Reload
+; AVX-NEXT: # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1],xmm0[2],mem[2],xmm0[3],mem[3]
+; AVX-NEXT: vmovdqa {{[-0-9]+}}(%r{{[sb]}}p), %xmm1 # 16-byte Reload
+; AVX-NEXT: vpunpcklwd {{[-0-9]+}}(%r{{[sb]}}p), %xmm1, %xmm1 # 16-byte Folded Reload
+; AVX-NEXT: # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1],xmm1[2],mem[2],xmm1[3],mem[3]
+; AVX-NEXT: vinsertps {{.*#+}} xmm0 = xmm1[0],xmm0[0],zero,zero
+; AVX-NEXT: addq $88, %rsp
+; AVX-NEXT: retq
+ %r = fptrunc afn <4 x double> %d to <4 x half>
+ ret <4 x half> %r
+}
+
+define half @fptrunc_contract(double %d) #0 {
+; F16C-LABEL: fptrunc_contract:
+; F16C: # %bb.0:
+; F16C-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm1
+; F16C-NEXT: vmovd %xmm1, %eax
+; F16C-NEXT: leal 1(%rax), %ecx
+; F16C-NEXT: leal -1(%rax), %edx
+; F16C-NEXT: vmovddup {{.*#+}} xmm2 = [NaN,NaN]
+; F16C-NEXT: # xmm2 = mem[0,0]
+; F16C-NEXT: vandps %xmm2, %xmm0, %xmm3
+; F16C-NEXT: vcvtss2sd %xmm1, %xmm1, %xmm1
+; F16C-NEXT: vandps %xmm2, %xmm1, %xmm2
+; F16C-NEXT: vucomisd %xmm2, %xmm3
+; F16C-NEXT: cmoval %ecx, %edx
+; F16C-NEXT: vucomisd %xmm1, %xmm0
+; F16C-NEXT: sete %cl
+; F16C-NEXT: testb $1, %al
+; F16C-NEXT: setne %sil
+; F16C-NEXT: orb %cl, %sil
+; F16C-NEXT: cmovnel %eax, %edx
+; F16C-NEXT: vmovd %edx, %xmm0
+; F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0
+; F16C-NEXT: retq
+;
+; AVX-LABEL: fptrunc_contract:
+; AVX: # %bb.0:
+; AVX-NEXT: pushq %rax
+; AVX-NEXT: callq __truncdfhf2 at PLT
+; AVX-NEXT: popq %rax
+; AVX-NEXT: retq
+ %r = fptrunc contract double %d to half
+ ret half %r
+}
+
+define half @fptrunc_contract_twostep(double %d) #0 {
+; F16C-LABEL: fptrunc_contract_twostep:
+; F16C: # %bb.0:
+; F16C-NEXT: vcvtsd2ss %xmm0, %xmm0, %xmm1
+; F16C-NEXT: vmovd %xmm1, %eax
+; F16C-NEXT: leal 1(%rax), %ecx
+; F16C-NEXT: leal -1(%rax), %edx
+; F16C-NEXT: vmovddup {{.*#+}} xmm2 = [NaN,NaN]
+; F16C-NEXT: # xmm2 = mem[0,0]
+; F16C-NEXT: vandps %xmm2, %xmm0, %xmm3
+; F16C-NEXT: vcvtss2sd %xmm1, %xmm1, %xmm1
+; F16C-NEXT: vandps %xmm2, %xmm1, %xmm2
+; F16C-NEXT: vucomisd %xmm2, %xmm3
+; F16C-NEXT: cmoval %ecx, %edx
+; F16C-NEXT: vucomisd %xmm1, %xmm0
+; F16C-NEXT: sete %cl
+; F16C-NEXT: testb $1, %al
+; F16C-NEXT: setne %sil
+; F16C-NEXT: orb %cl, %sil
+; F16C-NEXT: cmovnel %eax, %edx
+; F16C-NEXT: vmovd %edx, %xmm0
+; F16C-NEXT: vcvtps2ph $4, %xmm0, %xmm0
+; F16C-NEXT: retq
----------------
HelloWorldU wrote:
Yes, it's kind of like putting the cart before the horse. Since this change affects every scalar f64->f16, let me measure it against the libcall first.
https://github.com/llvm/llvm-project/pull/230079
More information about the llvm-commits
mailing list