[llvm] [AArch64][GlobalISel] Improve fixed-point int-to-fp selection (PR #224055)
Vimal Patel via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 04:14:18 PDT 2026
https://github.com/pvimal816a updated https://github.com/llvm/llvm-project/pull/224055
>From f524afef14b2fa1f641e593d86fa61c8f101c912 Mon Sep 17 00:00:00 2001
From: Vimal Patel <vimal.patel at arm.com>
Date: Wed, 16 Sep 2026 14:10:25 +0000
Subject: [PATCH] [AArch64][GlobalISel] Improve fixed-point int-to-fp selection
Select scalar fixed-point integer-to-float conversions directly in
GlobalISel when their integer operand is already in the FPR bank.
Teach the fixed-point immediate matcher about reciprocal constants.
Refine register-bank selection for scalar conversion intrinsics.
---
llvm/lib/Target/AArch64/AArch64InstrGISel.td | 33 ++
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 20 +-
.../GISel/AArch64InstructionSelector.cpp | 9 +
.../AArch64/GISel/AArch64RegisterBankInfo.cpp | 110 +++---
.../AArch64/GISel/AArch64RegisterBankInfo.h | 10 +
llvm/test/CodeGen/AArch64/fcvt-fixed.ll | 339 ++++++++----------
6 files changed, 289 insertions(+), 232 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrGISel.td b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
index 4be183641cb3eb..f607e6fa200a7c 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrGISel.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
@@ -386,6 +386,39 @@ def : Pat<(int_aarch64_stlxp GPR64:$lo, GPR64:$hi, GPR64:$addr),
def : Pat<(int_aarch64_stxp GPR64:$lo, GPR64:$hi, GPR64:$addr),
(STXPX GPR64:$lo, GPR64:$hi, GPR64:$addr)>;
+def : Pat<(int_aarch64_neon_vcvtfxu2fp FPR32:$Rn, vecshiftR32:$imm),
+ (UCVTFs FPR32:$Rn, vecshiftR32:$imm)>;
+def : Pat<(f64 (int_aarch64_neon_vcvtfxu2fp (i64 FPR64:$Rn),
+ vecshiftR64:$imm)),
+ (UCVTFd FPR64:$Rn, vecshiftR64:$imm)>;
+def : Pat<(f64 (int_aarch64_neon_vcvtfxs2fp (i64 FPR64:$Rn),
+ vecshiftR64:$imm)),
+ (SCVTFd FPR64:$Rn, vecshiftR64:$imm)>;
+def : Pat<(int_aarch64_neon_vcvtfxs2fp FPR32:$Rn, vecshiftR32:$imm),
+ (SCVTFs FPR32:$Rn, vecshiftR32:$imm)>;
+
+multiclass GIIntegerToFPScalarPats<SDPatternOperator OpNode, string INST> {
+ def : Pat<(f32 (fmul (f32 (OpNode (i32 FPR32:$Rn))),
+ fixedpoint_recip_f32_i32:$scale)),
+ (!cast<Instruction>(INST # "s") FPR32:$Rn,
+ (fixedpoint_recip_xform fixedpoint_recip_f32_i32:$scale))>;
+ def : Pat<(f64 (fmul (f64 (OpNode (i64 FPR64:$Rn))),
+ fixedpoint_recip_f64_i64:$scale)),
+ (!cast<Instruction>(INST # "d") FPR64:$Rn,
+ (fixedpoint_recip_xform fixedpoint_recip_f64_i64:$scale))>;
+ def : Pat<(f32 (fdiv (f32 (OpNode (i32 FPR32:$Rn))),
+ fixedpoint_f32_i32:$scale)),
+ (!cast<Instruction>(INST # "s") FPR32:$Rn,
+ (fixedpoint_xform fixedpoint_f32_i32:$scale))>;
+ def : Pat<(f64 (fdiv (f64 (OpNode (i64 FPR64:$Rn))),
+ fixedpoint_f64_i64:$scale)),
+ (!cast<Instruction>(INST # "d") FPR64:$Rn,
+ (fixedpoint_xform fixedpoint_f64_i64:$scale))>;
+}
+
+defm : GIIntegerToFPScalarPats<any_sint_to_fp, "SCVTF">;
+defm : GIIntegerToFPScalarPats<any_uint_to_fp, "UCVTF">;
+
let GIIgnoreCopies = 1 in
class PatIgnoreCopies<dag pattern, dag result> : Pat<pattern, result>, GISelFlags;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 0d8099b911894d..66071fbdeb0c45 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -7172,6 +7172,13 @@ def fixedpoint_xform : SDNodeXForm<timm, [{
}]>;
def gi_fixedpoint_xform : GICustomOperandRenderer<"renderFixedPointXForm">,
GISDNodeXFormEquiv<fixedpoint_xform>;
+def fixedpoint_recip_xform : SDNodeXForm<timm, [{
+ (void)N;
+ return V;
+}]>;
+def gi_fixedpoint_recip_xform
+ : GICustomOperandRenderer<"renderFixedPointRecipXForm">,
+ GISDNodeXFormEquiv<fixedpoint_recip_xform>;
def gi_fixedpoint_f16_i32 : GIComplexOperandMatcher<s32, "selectCVTFixedPoint<32>">,
GIComplexPatternEquiv<fixedpoint_f16_i32>;
@@ -7186,6 +7193,13 @@ def gi_fixedpoint_f64_i32 : GIComplexOperandMatcher<s64, "selectCVTFixedPoint<32
def gi_fixedpoint_f64_i64 : GIComplexOperandMatcher<s64, "selectCVTFixedPoint<64>">,
GIComplexPatternEquiv<fixedpoint_f64_i64>;
+def gi_fixedpoint_recip_f32_i32
+ : GIComplexOperandMatcher<s32, "selectCVTFixedPosRecipOperand<32>">,
+ GIComplexPatternEquiv<fixedpoint_recip_f32_i32>;
+def gi_fixedpoint_recip_f64_i64
+ : GIComplexOperandMatcher<s64, "selectCVTFixedPosRecipOperand<64>">,
+ GIComplexPatternEquiv<fixedpoint_recip_f64_i64>;
+
multiclass FPToIntegerFmulPats<SDPatternOperator round, string INST> {
let Predicates = [HasFullFP16] in {
def : Pat<(i32 (round (fmul f16:$Rn, fixedpoint_f16_i32:$scale))),
@@ -9718,12 +9732,10 @@ multiclass IntegerToFPScalarPats<SDPatternOperator OpNode, string INST> {
// Expect the integer operand to be in FPR register. The AdvSIMD scalar
// shifted conversion forms are same-width, so only i32->f32 and i64->f64
// can use them for generic integer-to-fp fixed-point conversions.
- let GISelShouldIgnore = 1 in {
def : Pat<(f32 (fmul (f32 (OpNode (i32 (bitconvert (f32 FPR32:$Rn))))), fixedpoint_recip_f32_i32:$scale)),
- (!cast<Instruction>(INST # "s") FPR32:$Rn, (fixedpoint_xform fixedpoint_recip_f32_i32:$scale))>;
+ (!cast<Instruction>(INST # "s") FPR32:$Rn, (fixedpoint_recip_xform fixedpoint_recip_f32_i32:$scale))>;
def : Pat<(f64 (fmul (f64 (OpNode (i64 (bitconvert (f64 FPR64:$Rn))))), fixedpoint_recip_f64_i64:$scale)),
- (!cast<Instruction>(INST # "d") FPR64:$Rn, (fixedpoint_xform fixedpoint_recip_f64_i64:$scale))>;
- }
+ (!cast<Instruction>(INST # "d") FPR64:$Rn, (fixedpoint_recip_xform fixedpoint_recip_f64_i64:$scale))>;
def : Pat<(f32 (fdiv (f32 (OpNode (i32 (bitconvert (f32 FPR32:$Rn))))), fixedpoint_f32_i32:$scale)),
(!cast<Instruction>(INST # "s") FPR32:$Rn, (fixedpoint_xform fixedpoint_f32_i32:$scale))>;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 0499d7771683eb..f91eeed81c8c47 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -487,6 +487,8 @@ class AArch64InstructionSelector : public InstructionSelector {
ComplexRendererFns selectExtractHigh(MachineOperand &Root) const;
template <unsigned Width>
ComplexRendererFns selectCVTFixedPoint(MachineOperand &Root) const;
+ template <unsigned Width>
+ ComplexRendererFns selectCVTFixedPosRecipOperand(MachineOperand &Root) const;
ComplexRendererFns selectCVTFixedPointBase(const MachineOperand &Root,
unsigned width,
bool isReciprocal = false) const;
@@ -8211,6 +8213,13 @@ AArch64InstructionSelector::selectCVTFixedPoint(MachineOperand &Root) const {
return selectCVTFixedPointBase(Root, Width, /*isReciprocal*/ false);
}
+template <unsigned Width>
+InstructionSelector::ComplexRendererFns
+AArch64InstructionSelector::selectCVTFixedPosRecipOperand(
+ MachineOperand &Root) const {
+ return selectCVTFixedPointBase(Root, Width, /*isReciprocal*/ true);
+}
+
InstructionSelector::ComplexRendererFns
AArch64InstructionSelector::selectCVTFixedPointVec(MachineOperand &Root) const {
return selectCVTFixedPointBase(Root, getFixedPointWidthFromOperand(Root),
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp
index 60463de1cff5be..196e09fd8a0489 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.cpp
@@ -816,6 +816,53 @@ bool AArch64RegisterBankInfo::prefersFPUse(const MachineInstr &MI,
return onlyDefinesFP(MI, MRI, TRI, Depth);
}
+bool AArch64RegisterBankInfo::shouldUseFPRForCvtOperand(
+ const MachineInstr &MI, CvtBankedOperand BankedOperand,
+ bool ForceFPRForBankedOp16, bool ForceFPRForOtherOp16, bool AllowFPRCVT,
+ bool CheckBankedOpUses) const {
+ const MachineFunction &MF = *MI.getMF();
+ const MachineRegisterInfo &MRI = MF.getRegInfo();
+ const AArch64Subtarget &STI = MF.getSubtarget<AArch64Subtarget>();
+ const AArch64RegisterInfo &TRI = *STI.getRegisterInfo();
+
+ unsigned BankedOpIdx;
+ unsigned OtherOpIdx;
+ switch (BankedOperand) {
+ case CvtBankedOperand::Def:
+ BankedOpIdx = 0;
+ OtherOpIdx = 2;
+ break;
+ case CvtBankedOperand::Src:
+ BankedOpIdx = 2;
+ OtherOpIdx = 0;
+ break;
+ }
+
+ Register BankedReg = MI.getOperand(BankedOpIdx).getReg();
+ if (MRI.getType(BankedReg).isVector())
+ return true;
+
+ TypeSize BankedSize = getSizeInBits(BankedReg, MRI, TRI);
+ TypeSize OtherSize =
+ getSizeInBits(MI.getOperand(OtherOpIdx).getReg(), MRI, TRI);
+ if ((ForceFPRForBankedOp16 && BankedSize == 16) ||
+ (ForceFPRForOtherOp16 && OtherSize == 16))
+ return true;
+
+ if (BankedSize != OtherSize && !AllowFPRCVT)
+ return false;
+
+ if (CheckBankedOpUses)
+ return all_of(
+ MRI.use_nodbg_instructions(BankedReg), [&](const MachineInstr &UseMI) {
+ return onlyUsesFP(UseMI, MRI, TRI) || prefersFPUse(UseMI, MRI, TRI);
+ });
+
+ const MachineInstr *DefMI = MRI.getVRegDef(BankedReg);
+ return DefMI &&
+ (onlyUsesFP(*DefMI, MRI, TRI) || prefersFPUse(*DefMI, MRI, TRI));
+}
+
bool AArch64RegisterBankInfo::isLoadFromFPType(const MachineInstr &MI) const {
// GMemOperation because we also want to match indexed loads.
auto *MemOp = cast<GMemOperation>(&MI);
@@ -1408,59 +1455,38 @@ AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case Intrinsic::aarch64_neon_fcvtps:
case Intrinsic::aarch64_neon_fcvtpu: {
OpRegBankIdx[2] = PMI_FirstFPR;
- if (MRI.getType(MI.getOperand(0).getReg()).isVector()) {
- OpRegBankIdx[0] = PMI_FirstFPR;
- break;
- }
- TypeSize DstSize = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
- TypeSize SrcSize = getSizeInBits(MI.getOperand(2).getReg(), MRI, TRI);
- // Fp conversions to i16 must be kept on fp register banks to ensure
- // proper saturation, as there are no 16-bit gprs.
- // In addition, conversion intrinsics have fpr output when the input
- // size matches the output size, or FPRCVT is present.
- if (DstSize == 16 ||
- ((DstSize == SrcSize || STI.hasFeature(AArch64::FeatureFPRCVT)) &&
- all_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
- [&](const MachineInstr &UseMI) {
- return onlyUsesFP(UseMI, MRI, TRI) ||
- prefersFPUse(UseMI, MRI, TRI);
- })))
+ if (shouldUseFPRForCvtOperand(
+ MI, CvtBankedOperand::Def,
+ /*ForceFPRForBankedOp16=*/true,
+ /*ForceFPRForOtherOp16=*/false,
+ /*AllowFPRCVT=*/STI.hasFeature(AArch64::FeatureFPRCVT),
+ /*CheckBankedOpUses=*/true))
OpRegBankIdx[0] = PMI_FirstFPR;
else
OpRegBankIdx[0] = PMI_FirstGPR;
break;
}
case Intrinsic::aarch64_neon_vcvtfxs2fp:
- case Intrinsic::aarch64_neon_vcvtfxu2fp:
- // Override these intrinsics, because they would have a partial
- // mapping. This is needed for 'half' types, which otherwise don't
- // get legalised correctly.
+ case Intrinsic::aarch64_neon_vcvtfxu2fp: {
OpRegBankIdx[0] = PMI_FirstFPR;
- OpRegBankIdx[2] = PMI_FirstFPR;
- // OpRegBankIdx[1] is the intrinsic ID.
- // OpRegBankIdx[3] is an integer immediate.
+ if (shouldUseFPRForCvtOperand(MI, CvtBankedOperand::Src,
+ /*ForceFPRForBankedOp16=*/false,
+ /*ForceFPRForOtherOp16=*/true,
+ /*AllowFPRCVT=*/false,
+ /*CheckBankedOpUses=*/false))
+ OpRegBankIdx[2] = PMI_FirstFPR;
+ else
+ OpRegBankIdx[2] = PMI_FirstGPR;
break;
+ }
case Intrinsic::aarch64_neon_vcvtfp2fxs:
case Intrinsic::aarch64_neon_vcvtfp2fxu: {
OpRegBankIdx[2] = PMI_FirstFPR;
- if (MRI.getType(MI.getOperand(0).getReg()).isVector()) {
- OpRegBankIdx[0] = PMI_FirstFPR;
- break;
- }
-
- TypeSize DstSize = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI);
- TypeSize SrcSize = getSizeInBits(MI.getOperand(2).getReg(), MRI, TRI);
-
- // Half-precision fixed-point FP-to-int scalar intrinsics are specified as
- // producing an H-register result. The LLVM intrinsic may still return an
- // i32/i64 type, so check the source size for 16 bits.
- if (SrcSize == 16 ||
- ((DstSize == SrcSize) &&
- all_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()),
- [&](const MachineInstr &UseMI) {
- return onlyUsesFP(UseMI, MRI, TRI) ||
- prefersFPUse(UseMI, MRI, TRI);
- })))
+ if (shouldUseFPRForCvtOperand(MI, CvtBankedOperand::Def,
+ /*ForceFPRForBankedOp16=*/false,
+ /*ForceFPRForOtherOp16=*/true,
+ /*AllowFPRCVT=*/false,
+ /*CheckBankedOpUses=*/true))
OpRegBankIdx[0] = PMI_FirstFPR;
else
OpRegBankIdx[0] = PMI_FirstGPR;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.h b/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.h
index b2de0317721089..aff56c16ea016d 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.h
+++ b/llvm/lib/Target/AArch64/GISel/AArch64RegisterBankInfo.h
@@ -145,6 +145,16 @@ class AArch64RegisterBankInfo final : public AArch64GenRegisterBankInfo {
bool prefersFPUse(const MachineInstr &MI, const MachineRegisterInfo &MRI,
const AArch64RegisterInfo &TRI, unsigned Depth = 0) const;
+ enum class CvtBankedOperand { Def, Src };
+
+ /// \returns true if a conversion operand should use FPRs based on operand
+ /// sizes and constraints from its defs or uses.
+ bool shouldUseFPRForCvtOperand(const MachineInstr &MI,
+ CvtBankedOperand BankedOperand,
+ bool ForceFPRForBankedOp16,
+ bool ForceFPRForOtherOp16, bool AllowFPRCVT,
+ bool CheckBankedOpUses) const;
+
/// \returns true if the load \p MI is likely loading from a floating-point
/// type.
bool isLoadFromFPType(const MachineInstr &MI) const;
diff --git a/llvm/test/CodeGen/AArch64/fcvt-fixed.ll b/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
index 48bd1c4ddfa54c..0fcfefeafa6fe1 100644
--- a/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
+++ b/llvm/test/CodeGen/AArch64/fcvt-fixed.ll
@@ -1304,21 +1304,12 @@ define float @neon_fcvtzu_f32_i32_32_bitcast(float %a) {
define float @scvtf_f32_i32_3_input_in_fpr(i32 %int) {
-; CHECK-SD-LABEL: scvtf_f32_i32_3_input_in_fpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: fmov s0, w0
-; CHECK-SD-NEXT: usqadd s0, s0
-; CHECK-SD-NEXT: scvtf s0, s0, #3
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: scvtf_f32_i32_3_input_in_fpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: fmov s0, w0
-; CHECK-GI-NEXT: fmov s1, #8.00000000
-; CHECK-GI-NEXT: usqadd s0, s0
-; CHECK-GI-NEXT: scvtf s0, s0
-; CHECK-GI-NEXT: fdiv s0, s0, s1
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: scvtf_f32_i32_3_input_in_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov s0, w0
+; CHECK-NEXT: usqadd s0, s0
+; CHECK-NEXT: scvtf s0, s0, #3
+; CHECK-NEXT: ret
%sum = call i32 @llvm.aarch64.neon.usqadd.i32(i32 %int, i32 %int)
%cvt = sitofp i32 %sum to float
%fix = fdiv float %cvt, 8.0
@@ -1326,21 +1317,12 @@ define float @scvtf_f32_i32_3_input_in_fpr(i32 %int) {
}
define float @scvtf_f32_i32_5_fmul_input_in_fpr(i32 %int) {
-; CHECK-SD-LABEL: scvtf_f32_i32_5_fmul_input_in_fpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: fmov s0, w0
-; CHECK-SD-NEXT: usqadd s0, s0
-; CHECK-SD-NEXT: scvtf s0, s0, #5
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: scvtf_f32_i32_5_fmul_input_in_fpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: fmov s1, w0
-; CHECK-GI-NEXT: movi v0.2s, #61, lsl #24
-; CHECK-GI-NEXT: usqadd s1, s1
-; CHECK-GI-NEXT: scvtf s1, s1
-; CHECK-GI-NEXT: fmul s0, s1, s0
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: scvtf_f32_i32_5_fmul_input_in_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov s0, w0
+; CHECK-NEXT: usqadd s0, s0
+; CHECK-NEXT: scvtf s0, s0, #5
+; CHECK-NEXT: ret
%sum = call i32 @llvm.aarch64.neon.usqadd.i32(i32 %int, i32 %int)
%cvt = sitofp i32 %sum to float
%fix = fmul float %cvt, 0x1.0p-5
@@ -1348,22 +1330,13 @@ define float @scvtf_f32_i32_5_fmul_input_in_fpr(i32 %int) {
}
define double @scvtf_f64_i64_6_input_in_fpr(i64 %long) {
-; CHECK-SD-LABEL: scvtf_f64_i64_6_input_in_fpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: fmov d0, x0
-; CHECK-SD-NEXT: usqadd d0, d0
-; CHECK-SD-NEXT: scvtf d0, d0, #6
-; CHECK-SD-NEXT: ret
-
-; CHECK-GI-LABEL: scvtf_f64_i64_6_input_in_fpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: fmov d0, x0
-; CHECK-GI-NEXT: mov x8, #4634204016564240384 // =0x4050000000000000
-; CHECK-GI-NEXT: fmov d1, x8
-; CHECK-GI-NEXT: usqadd d0, d0
-; CHECK-GI-NEXT: scvtf d0, d0
-; CHECK-GI-NEXT: fdiv d0, d0, d1
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: scvtf_f64_i64_6_input_in_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov d0, x0
+; CHECK-NEXT: usqadd d0, d0
+; CHECK-NEXT: scvtf d0, d0, #6
+; CHECK-NEXT: ret
+
%sum = call i64 @llvm.aarch64.neon.usqadd.i64(i64 %long, i64 %long)
%cvt = sitofp i64 %sum to double
%fix = fdiv double %cvt, 64.0
@@ -1371,22 +1344,12 @@ define double @scvtf_f64_i64_6_input_in_fpr(i64 %long) {
}
define double @scvtf_f64_i64_9_fmul_input_in_fpr(i64 %long) {
-; CHECK-SD-LABEL: scvtf_f64_i64_9_fmul_input_in_fpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: fmov d0, x0
-; CHECK-SD-NEXT: usqadd d0, d0
-; CHECK-SD-NEXT: scvtf d0, d0, #9
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: scvtf_f64_i64_9_fmul_input_in_fpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: fmov d0, x0
-; CHECK-GI-NEXT: mov x8, #4566650022153682944 // =0x3f60000000000000
-; CHECK-GI-NEXT: fmov d1, x8
-; CHECK-GI-NEXT: usqadd d0, d0
-; CHECK-GI-NEXT: scvtf d0, d0
-; CHECK-GI-NEXT: fmul d0, d0, d1
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: scvtf_f64_i64_9_fmul_input_in_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov d0, x0
+; CHECK-NEXT: usqadd d0, d0
+; CHECK-NEXT: scvtf d0, d0, #9
+; CHECK-NEXT: ret
%sum = call i64 @llvm.aarch64.neon.usqadd.i64(i64 %long, i64 %long)
%cvt = sitofp i64 %sum to double
%fix = fmul double %cvt, 0x1.0p-9
@@ -1394,22 +1357,12 @@ define double @scvtf_f64_i64_9_fmul_input_in_fpr(i64 %long) {
}
define float @ucvtf_f32_i32_3_input_in_fpr(i32 %int) {
-; CHECK-SD-LABEL: ucvtf_f32_i32_3_input_in_fpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: fmov s0, w0
-; CHECK-SD-NEXT: usqadd s0, s0
-; CHECK-SD-NEXT: ucvtf s0, s0, #3
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: ucvtf_f32_i32_3_input_in_fpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: fmov s0, w0
-; CHECK-GI-NEXT: fmov s1, #8.00000000
-; CHECK-GI-NEXT: usqadd s0, s0
-; CHECK-GI-NEXT: ucvtf s0, s0
-; CHECK-GI-NEXT: fdiv s0, s0, s1
-; CHECK-GI-NEXT: ret
-;
+; CHECK-LABEL: ucvtf_f32_i32_3_input_in_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov s0, w0
+; CHECK-NEXT: usqadd s0, s0
+; CHECK-NEXT: ucvtf s0, s0, #3
+; CHECK-NEXT: ret
%sum = call i32 @llvm.aarch64.neon.usqadd.i32(i32 %int, i32 %int)
%cvt = uitofp i32 %sum to float
%fix = fdiv float %cvt, 8.0
@@ -1417,22 +1370,12 @@ define float @ucvtf_f32_i32_3_input_in_fpr(i32 %int) {
}
define float @ucvtf_f32_i32_5_fmul_input_in_fpr(i32 %int) {
-; CHECK-SD-LABEL: ucvtf_f32_i32_5_fmul_input_in_fpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: fmov s0, w0
-; CHECK-SD-NEXT: usqadd s0, s0
-; CHECK-SD-NEXT: ucvtf s0, s0, #5
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: ucvtf_f32_i32_5_fmul_input_in_fpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: fmov s1, w0
-; CHECK-GI-NEXT: movi v0.2s, #61, lsl #24
-; CHECK-GI-NEXT: usqadd s1, s1
-; CHECK-GI-NEXT: ucvtf s1, s1
-; CHECK-GI-NEXT: fmul s0, s1, s0
-; CHECK-GI-NEXT: ret
-;
+; CHECK-LABEL: ucvtf_f32_i32_5_fmul_input_in_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov s0, w0
+; CHECK-NEXT: usqadd s0, s0
+; CHECK-NEXT: ucvtf s0, s0, #5
+; CHECK-NEXT: ret
%sum = call i32 @llvm.aarch64.neon.usqadd.i32(i32 %int, i32 %int)
%cvt = uitofp i32 %sum to float
%fix = fmul float %cvt, 0x1.0p-5
@@ -1440,23 +1383,12 @@ define float @ucvtf_f32_i32_5_fmul_input_in_fpr(i32 %int) {
}
define double @ucvtf_f64_i64_6_input_in_fpr(i64 %long) {
-; CHECK-SD-LABEL: ucvtf_f64_i64_6_input_in_fpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: fmov d0, x0
-; CHECK-SD-NEXT: usqadd d0, d0
-; CHECK-SD-NEXT: ucvtf d0, d0, #6
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: ucvtf_f64_i64_6_input_in_fpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: fmov d0, x0
-; CHECK-GI-NEXT: mov x8, #4634204016564240384 // =0x4050000000000000
-; CHECK-GI-NEXT: fmov d1, x8
-; CHECK-GI-NEXT: usqadd d0, d0
-; CHECK-GI-NEXT: ucvtf d0, d0
-; CHECK-GI-NEXT: fdiv d0, d0, d1
-; CHECK-GI-NEXT: ret
-;
+; CHECK-LABEL: ucvtf_f64_i64_6_input_in_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov d0, x0
+; CHECK-NEXT: usqadd d0, d0
+; CHECK-NEXT: ucvtf d0, d0, #6
+; CHECK-NEXT: ret
%sum = call i64 @llvm.aarch64.neon.usqadd.i64(i64 %long, i64 %long)
%cvt = uitofp i64 %sum to double
%fix = fdiv double %cvt, 64.0
@@ -1464,23 +1396,12 @@ define double @ucvtf_f64_i64_6_input_in_fpr(i64 %long) {
}
define double @ucvtf_f64_i64_9_fmul_input_in_fpr(i64 %long) {
-; CHECK-SD-LABEL: ucvtf_f64_i64_9_fmul_input_in_fpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: fmov d0, x0
-; CHECK-SD-NEXT: usqadd d0, d0
-; CHECK-SD-NEXT: ucvtf d0, d0, #9
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: ucvtf_f64_i64_9_fmul_input_in_fpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: fmov d0, x0
-; CHECK-GI-NEXT: mov x8, #4566650022153682944 // =0x3f60000000000000
-; CHECK-GI-NEXT: fmov d1, x8
-; CHECK-GI-NEXT: usqadd d0, d0
-; CHECK-GI-NEXT: ucvtf d0, d0
-; CHECK-GI-NEXT: fmul d0, d0, d1
-; CHECK-GI-NEXT: ret
-;
+; CHECK-LABEL: ucvtf_f64_i64_9_fmul_input_in_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov d0, x0
+; CHECK-NEXT: usqadd d0, d0
+; CHECK-NEXT: ucvtf d0, d0, #9
+; CHECK-NEXT: ret
%sum = call i64 @llvm.aarch64.neon.usqadd.i64(i64 %long, i64 %long)
%cvt = uitofp i64 %sum to double
%fix = fmul double %cvt, 0x1.0p-9
@@ -1500,20 +1421,11 @@ define float @scvtf_f32_i32_3_input_in_gpr(i32 %int) {
}
define float @scvtf_f32_i32_5_fmul_input_in_gpr(i32 %int) {
-; CHECK-SD-LABEL: scvtf_f32_i32_5_fmul_input_in_gpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: add w8, w0, w0
-; CHECK-SD-NEXT: scvtf s0, w8, #5
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: scvtf_f32_i32_5_fmul_input_in_gpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: add w8, w0, w0
-; CHECK-GI-NEXT: movi v0.2s, #61, lsl #24
-; CHECK-GI-NEXT: scvtf s1, w8
-; CHECK-GI-NEXT: fmul s0, s1, s0
-; CHECK-GI-NEXT: ret
-;
+; CHECK-LABEL: scvtf_f32_i32_5_fmul_input_in_gpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: add w8, w0, w0
+; CHECK-NEXT: scvtf s0, w8, #5
+; CHECK-NEXT: ret
%sum = add i32 %int, %int
%cvt = sitofp i32 %sum to float
%fix = fmul float %cvt, 0x1.0p-5
@@ -1533,21 +1445,11 @@ define double @scvtf_f64_i64_6_input_in_gpr(i64 %long) {
}
define double @scvtf_f64_i64_9_fmul_input_in_gpr(i64 %long) {
-; CHECK-SD-LABEL: scvtf_f64_i64_9_fmul_input_in_gpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: add x8, x0, x0
-; CHECK-SD-NEXT: scvtf d0, x8, #9
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: scvtf_f64_i64_9_fmul_input_in_gpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: add x8, x0, x0
-; CHECK-GI-NEXT: scvtf d0, x8
-; CHECK-GI-NEXT: mov x8, #4566650022153682944 // =0x3f60000000000000
-; CHECK-GI-NEXT: fmov d1, x8
-; CHECK-GI-NEXT: fmul d0, d0, d1
-; CHECK-GI-NEXT: ret
-;
+; CHECK-LABEL: scvtf_f64_i64_9_fmul_input_in_gpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: add x8, x0, x0
+; CHECK-NEXT: scvtf d0, x8, #9
+; CHECK-NEXT: ret
%sum = add i64 %long, %long
%cvt = sitofp i64 %sum to double
%fix = fmul double %cvt, 0x1.0p-9
@@ -1567,20 +1469,11 @@ define float @ucvtf_f32_i32_3_input_in_gpr(i32 %int) {
}
define float @ucvtf_f32_i32_5_fmul_input_in_gpr(i32 %int) {
-; CHECK-SD-LABEL: ucvtf_f32_i32_5_fmul_input_in_gpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: add w8, w0, w0
-; CHECK-SD-NEXT: ucvtf s0, w8, #5
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: ucvtf_f32_i32_5_fmul_input_in_gpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: add w8, w0, w0
-; CHECK-GI-NEXT: movi v0.2s, #61, lsl #24
-; CHECK-GI-NEXT: ucvtf s1, w8
-; CHECK-GI-NEXT: fmul s0, s1, s0
-; CHECK-GI-NEXT: ret
-;
+; CHECK-LABEL: ucvtf_f32_i32_5_fmul_input_in_gpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: add w8, w0, w0
+; CHECK-NEXT: ucvtf s0, w8, #5
+; CHECK-NEXT: ret
%sum = add i32 %int, %int
%cvt = uitofp i32 %sum to float
%fix = fmul float %cvt, 0x1.0p-5
@@ -1600,26 +1493,100 @@ define double @ucvtf_f64_i64_6_input_in_gpr(i64 %long) {
}
define double @ucvtf_f64_i64_9_fmul_input_in_gpr(i64 %long) {
-; CHECK-SD-LABEL: ucvtf_f64_i64_9_fmul_input_in_gpr:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: add x8, x0, x0
-; CHECK-SD-NEXT: ucvtf d0, x8, #9
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: ucvtf_f64_i64_9_fmul_input_in_gpr:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: add x8, x0, x0
-; CHECK-GI-NEXT: ucvtf d0, x8
-; CHECK-GI-NEXT: mov x8, #4566650022153682944 // =0x3f60000000000000
-; CHECK-GI-NEXT: fmov d1, x8
-; CHECK-GI-NEXT: fmul d0, d0, d1
-; CHECK-GI-NEXT: ret
-;
+; CHECK-LABEL: ucvtf_f64_i64_9_fmul_input_in_gpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: add x8, x0, x0
+; CHECK-NEXT: ucvtf d0, x8, #9
+; CHECK-NEXT: ret
%sum = add i64 %long, %long
%cvt = uitofp i64 %sum to double
%fix = fmul double %cvt, 0x1.0p-9
ret double %fix
}
+define float @neon_vcvtfxu2fp_i32_f32_gpr(i32 %a) {
+; CHECK-LABEL: neon_vcvtfxu2fp_i32_f32_gpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ucvtf s0, w0, #16
+; CHECK-NEXT: ret
+ %cvt = tail call float @llvm.aarch64.neon.vcvtfxu2fp.i32.f32(i32 %a, i32 16)
+ ret float %cvt
+}
+
+define float @neon_vcvtfxu2fp_i32_f32_fpr(i32 %a) {
+; CHECK-LABEL: neon_vcvtfxu2fp_i32_f32_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov s0, w0
+; CHECK-NEXT: usqadd s0, s0
+; CHECK-NEXT: ucvtf s0, s0, #16
+; CHECK-NEXT: ret
+ %sum = call i32 @llvm.aarch64.neon.usqadd.i32(i32 %a, i32 %a)
+ %cvt = tail call float @llvm.aarch64.neon.vcvtfxu2fp.i32.f32(i32 %sum, i32 16)
+ ret float %cvt
+}
+
+define float @neon_vcvtfxs2fp_i32_f32_gpr(i32 %a) {
+; CHECK-LABEL: neon_vcvtfxs2fp_i32_f32_gpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: scvtf s0, w0, #16
+; CHECK-NEXT: ret
+ %cvt = call float @llvm.aarch64.neon.vcvtfxs2fp.i32.f32(i32 %a, i32 16)
+ ret float %cvt
+}
+
+define double @neon_vcvtfxs2fp_i64_f64_gpr(i64 %a) {
+; CHECK-LABEL: neon_vcvtfxs2fp_i64_f64_gpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: scvtf d0, x0, #32
+; CHECK-NEXT: ret
+ %cvt = call double @llvm.aarch64.neon.vcvtfxs2fp.i64.f64(i64 %a, i32 32)
+ ret double %cvt
+}
+
+define double @neon_vcvtfxu2fp_i64_f64_gpr(i64 %a) {
+; CHECK-LABEL: neon_vcvtfxu2fp_i64_f64_gpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: ucvtf d0, x0, #32
+; CHECK-NEXT: ret
+ %cvt = call double @llvm.aarch64.neon.vcvtfxu2fp.i64.f64(i64 %a, i32 32)
+ ret double %cvt
+}
+
+define float @neon_vcvtfxs2fp_i32_f32_fpr(i32 %a) {
+; CHECK-LABEL: neon_vcvtfxs2fp_i32_f32_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov s0, w0
+; CHECK-NEXT: usqadd s0, s0
+; CHECK-NEXT: scvtf s0, s0, #16
+; CHECK-NEXT: ret
+ %sum = call i32 @llvm.aarch64.neon.usqadd.i32(i32 %a, i32 %a)
+ %cvt = call float @llvm.aarch64.neon.vcvtfxs2fp.i32.f32(i32 %sum, i32 16)
+ ret float %cvt
+}
+
+define double @neon_vcvtfxs2fp_i64_f64_fpr(i64 %a) {
+; CHECK-LABEL: neon_vcvtfxs2fp_i64_f64_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov d0, x0
+; CHECK-NEXT: usqadd d0, d0
+; CHECK-NEXT: scvtf d0, d0, #32
+; CHECK-NEXT: ret
+ %sum = call i64 @llvm.aarch64.neon.usqadd.i64(i64 %a, i64 %a)
+ %cvt = call double @llvm.aarch64.neon.vcvtfxs2fp.i64.f64(i64 %sum, i32 32)
+ ret double %cvt
+}
+
+define double @neon_vcvtfxu2fp_i64_f64_fpr(i64 %a) {
+; CHECK-LABEL: neon_vcvtfxu2fp_i64_f64_fpr:
+; CHECK: // %bb.0:
+; CHECK-NEXT: fmov d0, x0
+; CHECK-NEXT: usqadd d0, d0
+; CHECK-NEXT: ucvtf d0, d0, #32
+; CHECK-NEXT: ret
+ %sum = call i64 @llvm.aarch64.neon.usqadd.i64(i64 %a, i64 %a)
+ %cvt = call double @llvm.aarch64.neon.vcvtfxu2fp.i64.f64(i64 %sum, i32 32)
+ ret double %cvt
+}
+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-GI: {{.*}}
; CHECK-SD: {{.*}}
More information about the llvm-commits
mailing list