[llvm] [AArch64] Lower BF16 FPTRUNC (PR #193941)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 24 04:11:52 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: David Green (davemgreen)
<details>
<summary>Changes</summary>
When the architecture +bf16 features is available this is simple as we lower to a standard instruction. When not available we need to expand to a series of instructions that performs the necessary rounding. The code to do that is a port of TargetLowering::expandFP_ROUND to GISel, minus the float64 odd rounding via expandRoundInexactToOdd. f64 will follow in a followup patch.
uitofp and sitofp are currently disabled, so that we can take this one step at a time and check each part in turn. The LLT fp types attempt to return true for ieee types without UseExtended for types of the correct size, always returning false for non-standard types.
---
Patch is 24.22 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/193941.diff
7 Files Affected:
- (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h (+1)
- (modified) llvm/include/llvm/CodeGenTypes/LowLevelType.h (+32-3)
- (modified) llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (+46-6)
- (modified) llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp (+7-7)
- (modified) llvm/test/CodeGen/AArch64/bf16-instructions.ll (+77-39)
- (modified) llvm/test/CodeGen/AArch64/bf16-v4-instructions.ll (+31-15)
- (modified) llvm/test/CodeGen/AArch64/bf16-v8-instructions.ll (+50-22)
``````````diff
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
index 37936af6d853c..3dfca7ea250f6 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
@@ -524,6 +524,7 @@ class LegalizerHelper {
LLVM_ABI LegalizeResult lowerFPTOINT_SAT(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerFPTRUNC_F64_TO_F16(MachineInstr &MI);
+ LLVM_ABI LegalizeResult lowerFPTRUNC_F32_TO_BF16(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerFPTRUNC(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerFPOWI(MachineInstr &MI);
LLVM_ABI LegalizeResult lowerFMODF(MachineInstr &MI);
diff --git a/llvm/include/llvm/CodeGenTypes/LowLevelType.h b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
index 920bd9ad9bf51..6bcd06201e305 100644
--- a/llvm/include/llvm/CodeGenTypes/LowLevelType.h
+++ b/llvm/include/llvm/CodeGenTypes/LowLevelType.h
@@ -305,11 +305,40 @@ class LLT {
isFloat(APFloatBase::S_IEEEdouble) ||
isFloat(APFloatBase::S_IEEEquad);
}
- constexpr bool isBFloat16() const { return isFloat(FpSemantics::S_BFloat); }
- constexpr bool isX86FP80() const {
+
+ bool isFloat16() const {
+ if (!getUseExtended())
+ return isAnyScalar() && getSizeInBits() == 16;
+ return isFloat(APFloatBase::S_IEEEhalf);
+ }
+ bool isFloat32() const {
+ if (!getUseExtended())
+ return isAnyScalar() && getSizeInBits() == 32;
+ return isFloat(APFloatBase::S_IEEEsingle);
+ }
+ bool isFloat64() const {
+ if (!getUseExtended())
+ return isAnyScalar() && getSizeInBits() == 64;
+ return isFloat(APFloatBase::S_IEEEdouble);
+ }
+ bool isFloat128() const {
+ if (!getUseExtended())
+ return isAnyScalar() && getSizeInBits() == 128;
+ return isFloat(APFloatBase::S_IEEEquad);
+ }
+ bool isBFloat16() const {
+ if (!getUseExtended())
+ return false;
+ return isFloat(FpSemantics::S_BFloat);
+ }
+ bool isX86FP80() const {
+ if (!getUseExtended())
+ return false;
return isFloat(FpSemantics::S_x87DoubleExtended);
}
- constexpr bool isPPCF128() const {
+ bool isPPCF128() const {
+ if (!getUseExtended())
+ return false;
return isFloat(FpSemantics::S_PPCDoubleDouble);
}
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index a33f4bcd0535b..eebcbab3da672 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -8634,8 +8634,8 @@ LegalizerHelper::lowerFPTRUNC_F64_TO_F16(MachineInstr &MI) {
const LLT S32 = LLT::scalar(32);
auto [Dst, Src] = MI.getFirst2Regs();
- assert(MRI.getType(Dst).getScalarType() == LLT::scalar(16) &&
- MRI.getType(Src).getScalarType() == LLT::scalar(64));
+ assert(MRI.getType(Dst).getScalarType() == LLT::float16() &&
+ MRI.getType(Src).getScalarType() == LLT::float64());
if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
return UnableToLegalize;
@@ -8743,15 +8743,55 @@ LegalizerHelper::lowerFPTRUNC_F64_TO_F16(MachineInstr &MI) {
return Legalized;
}
+// f32 -> bf16 conversion using round-to-nearest-even rounding mode.
+LegalizerHelper::LegalizeResult
+LegalizerHelper::lowerFPTRUNC_F32_TO_BF16(MachineInstr &MI) {
+ auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
+ assert(DstTy.getScalarType() == LLT::bfloat16() &&
+ SrcTy.getScalarType() == LLT::float32());
+
+ LLT I1Ty = SrcTy.changeElementType(LLT::integer(1));
+ LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
+ LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
+
+ auto IsNaN = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, I1Ty, SrcReg, SrcReg);
+ auto SrcI = MIRBuilder.buildBitcast(I32Ty, SrcReg);
+
+ // Conversions should set NaN's quiet bit. This also prevents NaNs from
+ // turning into infinities.
+ auto NaN = MIRBuilder.buildOr(I32Ty, SrcI,
+ MIRBuilder.buildConstant(I32Ty, 0x400000));
+
+ // Factor in the contribution of the low 16 bits.
+ auto Lsb =
+ MIRBuilder.buildLShr(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
+ Lsb = MIRBuilder.buildAnd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 1));
+ auto RoundingBias =
+ MIRBuilder.buildAdd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 0x7fff));
+ auto Add = MIRBuilder.buildAdd(I32Ty, SrcI, RoundingBias);
+
+ // Don't round if we had a NaN, we don't want to turn 0x7fffffff into
+ // 0x80000000.
+ auto Sel = MIRBuilder.buildSelect(I32Ty, IsNaN, NaN, Add);
+
+ // Now that we have rounded, shift the bits into position.
+ auto Srl =
+ MIRBuilder.buildLShr(I32Ty, Sel, MIRBuilder.buildConstant(I32Ty, 16));
+ auto Trunc = MIRBuilder.buildTrunc(I16Ty, Srl);
+ MIRBuilder.buildBitcast(DstReg, Trunc);
+ MI.eraseFromParent();
+ return Legalized;
+}
+
LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFPTRUNC(MachineInstr &MI) {
auto [DstTy, SrcTy] = MI.getFirst2LLTs();
- const LLT S64 = LLT::scalar(64);
- const LLT S16 = LLT::scalar(16);
-
- if (DstTy.getScalarType() == S16 && SrcTy.getScalarType() == S64)
+ if (DstTy.getScalarType().isFloat16() && SrcTy.getScalarType().isFloat64())
return lowerFPTRUNC_F64_TO_F16(MI);
+ if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat32())
+ return lowerFPTRUNC_F32_TO_BF16(MI);
+
return UnableToLegalize;
}
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index c62d760e9c77f..f47f651f3c581 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -862,15 +862,17 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
getActionDefinitionsBuilder(G_FPTRUNC)
.legalFor(
{{f16, f32}, {f16, f64}, {f32, f64}, {v4f16, v4f32}, {v2f32, v2f64}})
+ .legalFor(ST.hasBF16(), {{bf16, f32}, {v4bf16, v4f32}})
.libcallFor({{f16, f128}, {f32, f128}, {f64, f128}})
.moreElementsToNextPow2(1)
.customIf([](const LegalityQuery &Q) {
LLT DstTy = Q.Types[0];
LLT SrcTy = Q.Types[1];
return SrcTy.isFixedVector() && DstTy.isFixedVector() &&
- SrcTy.getScalarSizeInBits() == 64 &&
- DstTy.getScalarSizeInBits() == 16;
+ SrcTy.getScalarType().isFloat64() &&
+ DstTy.getScalarType().isFloat16();
})
+ .lowerFor({{bf16, f32}, {v4bf16, v4f32}})
// Clamp based on input
.clampNumElements(1, v4s32, v4s32)
.clampNumElements(1, v2s64, v2s64)
@@ -998,6 +1000,9 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
{v2f64, v2i64}})
.legalFor(HasFP16,
{{f16, i32}, {f16, i64}, {v4f16, v4i16}, {v8f16, v8i16}})
+ .unsupportedIf([&](const LegalityQuery &Query) {
+ return Query.Types[0].getScalarType().isBFloat16();
+ })
.scalarizeIf(scalarOrEltWiderThan(1, 64), 1)
.scalarizeIf(scalarOrEltWiderThan(0, 64), 0)
.moreElementsToNextPow2(1)
@@ -1008,11 +1013,6 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
Query.Types[1].getScalarSizeInBits() == 64 &&
Query.Types[0].getScalarSizeInBits() == 16;
})
- .widenScalarIf(
- [=](const LegalityQuery &Query) {
- return Query.Types[0].getScalarType() == bf16;
- },
- changeElementTo(0, f32))
.widenScalarOrEltToNextPow2OrMinSize(0, /*MinSize=*/HasFP16 ? 16 : 32)
.scalarizeIf(
// v2i64->v2f32 needs to scalarize to avoid double-rounding issues.
diff --git a/llvm/test/CodeGen/AArch64/bf16-instructions.ll b/llvm/test/CodeGen/AArch64/bf16-instructions.ll
index ddb869abba971..d603a9b5d68de 100644
--- a/llvm/test/CodeGen/AArch64/bf16-instructions.ll
+++ b/llvm/test/CodeGen/AArch64/bf16-instructions.ll
@@ -38,7 +38,6 @@
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_sitofp_i64
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_uitofp_i32_fadd
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_sitofp_i32_fadd
-; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_fptrunc_float
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_fptrunc_double
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_fpext_double
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_sqrt
@@ -63,7 +62,6 @@
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_fabs
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_minnum
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_maxnum
-; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_copysign_f32
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_copysign_f64
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_floor
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for test_ceil
@@ -108,7 +106,6 @@
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_sitofp_i64
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_uitofp_i32_fadd
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_sitofp_i32_fadd
-; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_fptrunc_float
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_fptrunc_double
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_fpext_double
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_sqrt
@@ -133,7 +130,6 @@
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_fabs
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_minnum
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_maxnum
-; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_copysign_f32
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_copysign_f64
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_floor
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for test_ceil
@@ -1082,25 +1078,40 @@ define bfloat @test_sitofp_i32_fadd(i32 %a, bfloat %b) #0 {
}
define bfloat @test_fptrunc_float(float %a) #0 {
-; CHECK-CVT-LABEL: test_fptrunc_float:
-; CHECK-CVT: // %bb.0:
-; CHECK-CVT-NEXT: fmov w9, s0
-; CHECK-CVT-NEXT: mov w8, #32767 // =0x7fff
-; CHECK-CVT-NEXT: fcmp s0, s0
-; CHECK-CVT-NEXT: ubfx w10, w9, #16, #1
-; CHECK-CVT-NEXT: add w8, w9, w8
-; CHECK-CVT-NEXT: orr w9, w9, #0x400000
-; CHECK-CVT-NEXT: add w8, w10, w8
-; CHECK-CVT-NEXT: csel w8, w9, w8, vs
-; CHECK-CVT-NEXT: lsr w8, w8, #16
-; CHECK-CVT-NEXT: fmov s0, w8
-; CHECK-CVT-NEXT: // kill: def $h0 killed $h0 killed $s0
-; CHECK-CVT-NEXT: ret
+; CHECK-CVT-SD-LABEL: test_fptrunc_float:
+; CHECK-CVT-SD: // %bb.0:
+; CHECK-CVT-SD-NEXT: fmov w9, s0
+; CHECK-CVT-SD-NEXT: mov w8, #32767 // =0x7fff
+; CHECK-CVT-SD-NEXT: fcmp s0, s0
+; CHECK-CVT-SD-NEXT: ubfx w10, w9, #16, #1
+; CHECK-CVT-SD-NEXT: add w8, w9, w8
+; CHECK-CVT-SD-NEXT: orr w9, w9, #0x400000
+; CHECK-CVT-SD-NEXT: add w8, w10, w8
+; CHECK-CVT-SD-NEXT: csel w8, w9, w8, vs
+; CHECK-CVT-SD-NEXT: lsr w8, w8, #16
+; CHECK-CVT-SD-NEXT: fmov s0, w8
+; CHECK-CVT-SD-NEXT: // kill: def $h0 killed $h0 killed $s0
+; CHECK-CVT-SD-NEXT: ret
;
; CHECK-BF16-LABEL: test_fptrunc_float:
; CHECK-BF16: // %bb.0:
; CHECK-BF16-NEXT: bfcvt h0, s0
; CHECK-BF16-NEXT: ret
+;
+; CHECK-CVT-GI-LABEL: test_fptrunc_float:
+; CHECK-CVT-GI: // %bb.0:
+; CHECK-CVT-GI-NEXT: fmov w9, s0
+; CHECK-CVT-GI-NEXT: mov w8, #32767 // =0x7fff
+; CHECK-CVT-GI-NEXT: fcmp s0, s0
+; CHECK-CVT-GI-NEXT: ubfx w10, w9, #16, #1
+; CHECK-CVT-GI-NEXT: add w8, w9, w8
+; CHECK-CVT-GI-NEXT: orr w9, w9, #0x400000
+; CHECK-CVT-GI-NEXT: add w8, w8, w10
+; CHECK-CVT-GI-NEXT: csel w8, w9, w8, vs
+; CHECK-CVT-GI-NEXT: lsr w8, w8, #16
+; CHECK-CVT-GI-NEXT: fmov s0, w8
+; CHECK-CVT-GI-NEXT: // kill: def $h0 killed $h0 killed $s0
+; CHECK-CVT-GI-NEXT: ret
%r = fptrunc float %a to bfloat
ret bfloat %r
}
@@ -1928,28 +1939,55 @@ define bfloat @test_copysign(bfloat %a, bfloat %b) #0 {
}
define bfloat @test_copysign_f32(bfloat %a, float %b) #0 {
-; CHECK-CVT-LABEL: test_copysign_f32:
-; CHECK-CVT: // %bb.0:
-; CHECK-CVT-NEXT: // kill: def $h0 killed $h0 def $d0
-; CHECK-CVT-NEXT: mvni v2.4s, #128, lsl #24
-; CHECK-CVT-NEXT: // kill: def $s1 killed $s1 def $q1
-; CHECK-CVT-NEXT: shll v0.4s, v0.4h, #16
-; CHECK-CVT-NEXT: bif v0.16b, v1.16b, v2.16b
-; CHECK-CVT-NEXT: fmov w8, s0
-; CHECK-CVT-NEXT: lsr w8, w8, #16
-; CHECK-CVT-NEXT: fmov s0, w8
-; CHECK-CVT-NEXT: // kill: def $h0 killed $h0 killed $s0
-; CHECK-CVT-NEXT: ret
+; CHECK-CVT-SD-LABEL: test_copysign_f32:
+; CHECK-CVT-SD: // %bb.0:
+; CHECK-CVT-SD-NEXT: // kill: def $h0 killed $h0 def $d0
+; CHECK-CVT-SD-NEXT: mvni v2.4s, #128, lsl #24
+; CHECK-CVT-SD-NEXT: // kill: def $s1 killed $s1 def $q1
+; CHECK-CVT-SD-NEXT: shll v0.4s, v0.4h, #16
+; CHECK-CVT-SD-NEXT: bif v0.16b, v1.16b, v2.16b
+; CHECK-CVT-SD-NEXT: fmov w8, s0
+; CHECK-CVT-SD-NEXT: lsr w8, w8, #16
+; CHECK-CVT-SD-NEXT: fmov s0, w8
+; CHECK-CVT-SD-NEXT: // kill: def $h0 killed $h0 killed $s0
+; CHECK-CVT-SD-NEXT: ret
;
-; CHECK-BF16-LABEL: test_copysign_f32:
-; CHECK-BF16: // %bb.0:
-; CHECK-BF16-NEXT: // kill: def $h0 killed $h0 def $d0
-; CHECK-BF16-NEXT: mvni v2.4s, #128, lsl #24
-; CHECK-BF16-NEXT: // kill: def $s1 killed $s1 def $q1
-; CHECK-BF16-NEXT: shll v0.4s, v0.4h, #16
-; CHECK-BF16-NEXT: bif v0.16b, v1.16b, v2.16b
-; CHECK-BF16-NEXT: bfcvt h0, s0
-; CHECK-BF16-NEXT: ret
+; CHECK-BF16-SD-LABEL: test_copysign_f32:
+; CHECK-BF16-SD: // %bb.0:
+; CHECK-BF16-SD-NEXT: // kill: def $h0 killed $h0 def $d0
+; CHECK-BF16-SD-NEXT: mvni v2.4s, #128, lsl #24
+; CHECK-BF16-SD-NEXT: // kill: def $s1 killed $s1 def $q1
+; CHECK-BF16-SD-NEXT: shll v0.4s, v0.4h, #16
+; CHECK-BF16-SD-NEXT: bif v0.16b, v1.16b, v2.16b
+; CHECK-BF16-SD-NEXT: bfcvt h0, s0
+; CHECK-BF16-SD-NEXT: ret
+;
+; CHECK-CVT-GI-LABEL: test_copysign_f32:
+; CHECK-CVT-GI: // %bb.0:
+; CHECK-CVT-GI-NEXT: fmov w9, s1
+; CHECK-CVT-GI-NEXT: mov w8, #32767 // =0x7fff
+; CHECK-CVT-GI-NEXT: fcmp s1, s1
+; CHECK-CVT-GI-NEXT: mvni v1.4h, #128, lsl #8
+; CHECK-CVT-GI-NEXT: // kill: def $h0 killed $h0 def $d0
+; CHECK-CVT-GI-NEXT: ubfx w10, w9, #16, #1
+; CHECK-CVT-GI-NEXT: add w8, w9, w8
+; CHECK-CVT-GI-NEXT: orr w9, w9, #0x400000
+; CHECK-CVT-GI-NEXT: add w8, w8, w10
+; CHECK-CVT-GI-NEXT: csel w8, w9, w8, vs
+; CHECK-CVT-GI-NEXT: lsr w8, w8, #16
+; CHECK-CVT-GI-NEXT: fmov s2, w8
+; CHECK-CVT-GI-NEXT: bif v0.8b, v2.8b, v1.8b
+; CHECK-CVT-GI-NEXT: // kill: def $h0 killed $h0 killed $d0
+; CHECK-CVT-GI-NEXT: ret
+;
+; CHECK-BF16-GI-LABEL: test_copysign_f32:
+; CHECK-BF16-GI: // %bb.0:
+; CHECK-BF16-GI-NEXT: bfcvt h1, s1
+; CHECK-BF16-GI-NEXT: mvni v2.4h, #128, lsl #8
+; CHECK-BF16-GI-NEXT: // kill: def $h0 killed $h0 def $d0
+; CHECK-BF16-GI-NEXT: bif v0.8b, v1.8b, v2.8b
+; CHECK-BF16-GI-NEXT: // kill: def $h0 killed $h0 killed $d0
+; CHECK-BF16-GI-NEXT: ret
%tb = fptrunc float %b to bfloat
%r = call bfloat @llvm.copysign.bf16(bfloat %a, bfloat %tb)
ret bfloat %r
diff --git a/llvm/test/CodeGen/AArch64/bf16-v4-instructions.ll b/llvm/test/CodeGen/AArch64/bf16-v4-instructions.ll
index 3fcda00c8ecf9..c2e71486c5cd3 100644
--- a/llvm/test/CodeGen/AArch64/bf16-v4-instructions.ll
+++ b/llvm/test/CodeGen/AArch64/bf16-v4-instructions.ll
@@ -8,7 +8,6 @@
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for sub_h
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for mul_h
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for div_h
-; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for s_to_h
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for d_to_h
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for sitofp_i8
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for sitofp_i16
@@ -41,7 +40,6 @@
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for sub_h
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for mul_h
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for div_h
-; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for s_to_h
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for d_to_h
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for sitofp_i8
; CHECK-BF16-GI-NEXT: warning: Instruction selection used fallback path for sitofp_i16
@@ -223,24 +221,42 @@ entry:
}
define <4 x bfloat> @s_to_h(<4 x float> %a) {
-; CHECK-CVT-LABEL: s_to_h:
-; CHECK-CVT: // %bb.0:
-; CHECK-CVT-NEXT: movi v1.4s, #1
-; CHECK-CVT-NEXT: movi v2.4s, #127, msl #8
-; CHECK-CVT-NEXT: ushr v3.4s, v0.4s, #16
-; CHECK-CVT-NEXT: and v1.16b, v3.16b, v1.16b
-; CHECK-CVT-NEXT: add v2.4s, v0.4s, v2.4s
-; CHECK-CVT-NEXT: fcmeq v3.4s, v0.4s, v0.4s
-; CHECK-CVT-NEXT: orr v0.4s, #64, lsl #16
-; CHECK-CVT-NEXT: add v1.4s, v1.4s, v2.4s
-; CHECK-CVT-NEXT: bit v0.16b, v1.16b, v3.16b
-; CHECK-CVT-NEXT: shrn v0.4h, v0.4s, #16
-; CHECK-CVT-NEXT: ret
+; CHECK-CVT-SD-LABEL: s_to_h:
+; CHECK-CVT-SD: // %bb.0:
+; CHECK-CVT-SD-NEXT: movi v1.4s, #1
+; CHECK-CVT-SD-NEXT: movi v2.4s, #127, msl #8
+; CHECK-CVT-SD-NEXT: ushr v3.4s, v0.4s, #16
+; CHECK-CVT-SD-NEXT: and v1.16b, v3.16b, v1.16b
+; CHECK-CVT-SD-NEXT: add v2.4s, v0.4s, v2.4s
+; CHECK-CVT-SD-NEXT: fcmeq v3.4s, v0.4s, v0.4s
+; CHECK-CVT-SD-NEXT: orr v0.4s, #64, lsl #16
+; CHECK-CVT-SD-NEXT: add v1.4s, v1.4s, v2.4s
+; CHECK-CVT-SD-NEXT: bit v0.16b, v1.16b, v3.16b
+; CHECK-CVT-SD-NEXT: shrn v0.4h, v0.4s, #16
+; CHECK-CVT-SD-NEXT: ret
;
; CHECK-BF16-LABEL: s_to_h:
; CHECK-BF16: // %bb.0:
; CHECK-BF16-NEXT: bfcvtn v0.4h, v0.4s
; CHECK-BF16-NEXT: ret
+;
+; CHECK-CVT-GI-LABEL: s_to_h:
+; CHECK-CVT-GI: // %bb.0:
+; CHECK-CVT-GI-NEXT: movi v1.4s, #1
+; CHECK-CVT-GI-NEXT: fcmge v2.4s, v0.4s, v0.4s
+; CHECK-CVT-GI-NEXT: fcmgt v3.4s, v0.4s, v0.4s
+; CHECK-CVT-GI-NEXT: movi v4.4s, #127, msl #8
+; CHECK-CVT-GI-NEXT: ushr v5.4s, v0.4s, #16
+; CHECK-CVT-GI-NEXT: movi v6.4s, #64, lsl #16
+; CHECK-CVT-GI-NEXT: orr v2.16b, v3.16b, v2.16b
+; CHECK-CVT-GI-NEXT: and v1.16b, v5.16b, v1.16b
+; CHECK-CVT-GI-NEXT: add v3.4s, v0.4s, v4.4s
+; CHECK-CVT-GI-NEXT: orr v0.16b, v0.16b, v6.16b
+; CHECK-CVT-GI-NEXT: mvn v2.16b, v2.16b
+; CHECK-CVT-GI-NEXT: add v1.4s, v3.4s, v1.4s
+; CHECK-CVT-GI-NEXT: bif v0.16b, v1.16b, v2.16b
+; CHECK-CVT-GI-NEXT: shrn v0.4h, v0.4s, #16
+; CHECK-CVT-GI-NEXT: ret
%1 = fptrunc <4 x float> %a to <4 x bfloat>
ret <4 x bfloat> %1
}
diff --git a/llvm/test/CodeGen/AArch64/bf16-v8-instructions.ll b/llvm/test/CodeGen/AArch64/bf16-v8-instructions.ll
index e6018f9096c03..e2eca853de693 100644
--- a/llvm/test/CodeGen/AArch64/bf16-v8-instructions.ll
+++ b/llvm/test/CodeGen/AArch64/bf16-v8-instructions.ll
@@ -9,7 +9,6 @@
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for sub_h
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for mul_h
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for div_h
-; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for s_to_h
; CHECK-CVT-GI-NEXT: warning: Instruction selection used fallback path for d_to_h
;...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/193941
More information about the llvm-commits
mailing list