Skip to content

[GlobalISel][AArch64] Add G_FPTOSI_SAT/G_FPTOUI_SAT #96297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/docs/GlobalISel/GenericOpcode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,11 @@ G_FPTOSI, G_FPTOUI, G_SITOFP, G_UITOFP

Convert between integer and floating point.

G_FPTOSI_SAT, G_FPTOUI_SAT
^^^^^^^^^^^^^^^^^^^^^^^^^^

Saturating convert between integer and floating point.

G_FABS
^^^^^^

Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,8 @@ class GCastOp : public GenericMachineInstr {
case TargetOpcode::G_FPEXT:
case TargetOpcode::G_FPTOSI:
case TargetOpcode::G_FPTOUI:
case TargetOpcode::G_FPTOSI_SAT:
case TargetOpcode::G_FPTOUI_SAT:
case TargetOpcode::G_FPTRUNC:
case TargetOpcode::G_INTTOPTR:
case TargetOpcode::G_PTRTOINT:
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ class LegalizerHelper {
LegalizeResult lowerSITOFP(MachineInstr &MI);
LegalizeResult lowerFPTOUI(MachineInstr &MI);
LegalizeResult lowerFPTOSI(MachineInstr &MI);
LegalizeResult lowerFPTOINT_SAT(MachineInstr &MI);

LegalizeResult lowerFPTRUNC_F64_TO_F16(MachineInstr &MI);
LegalizeResult lowerFPTRUNC(MachineInstr &MI);
Expand Down
10 changes: 10 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2035,6 +2035,16 @@ class MachineIRBuilder {
return buildInstr(TargetOpcode::G_FPTOSI, {Dst}, {Src0});
}

/// Build and insert \p Res = G_FPTOUI_SAT \p Src0
MachineInstrBuilder buildFPTOUI_SAT(const DstOp &Dst, const SrcOp &Src0) {
return buildInstr(TargetOpcode::G_FPTOUI_SAT, {Dst}, {Src0});
}

/// Build and insert \p Res = G_FPTOSI_SAT \p Src0
MachineInstrBuilder buildFPTOSI_SAT(const DstOp &Dst, const SrcOp &Src0) {
return buildInstr(TargetOpcode::G_FPTOSI_SAT, {Dst}, {Src0});
}

/// Build and insert \p Dst = G_INTRINSIC_ROUNDEVEN \p Src0, \p Src1
MachineInstrBuilder
buildIntrinsicRoundeven(const DstOp &Dst, const SrcOp &Src0,
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Support/TargetOpcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,12 @@ HANDLE_TARGET_OPCODE(G_SITOFP)
/// Generic unsigned-int to float conversion
HANDLE_TARGET_OPCODE(G_UITOFP)

/// Generic saturating float to signed-int conversion
HANDLE_TARGET_OPCODE(G_FPTOSI_SAT)

/// Generic saturating float to unsigned-int conversion
HANDLE_TARGET_OPCODE(G_FPTOUI_SAT)

/// Generic FP absolute value.
HANDLE_TARGET_OPCODE(G_FABS)

Expand Down
12 changes: 12 additions & 0 deletions llvm/include/llvm/Target/GenericOpcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,18 @@ def G_UITOFP : GenericInstruction {
let hasSideEffects = false;
}

def G_FPTOSI_SAT : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type1:$src);
let hasSideEffects = false;
}

def G_FPTOUI_SAT : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type1:$src);
let hasSideEffects = false;
}

def G_FABS : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type0:$src);
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ def : GINodeEquiv<G_FPTOSI, fp_to_sint>;
def : GINodeEquiv<G_FPTOUI, fp_to_uint>;
def : GINodeEquiv<G_SITOFP, sint_to_fp>;
def : GINodeEquiv<G_UITOFP, uint_to_fp>;
def : GINodeEquiv<G_FPTOSI_SAT, fp_to_sint_sat_gi>;
def : GINodeEquiv<G_FPTOUI_SAT, fp_to_uint_sat_gi>;
def : GINodeEquiv<G_FADD, fadd>;
def : GINodeEquiv<G_FSUB, fsub>;
def : GINodeEquiv<G_FMA, fma>;
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Target/TargetSelectionDAG.td
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ def fp_to_sint : SDNode<"ISD::FP_TO_SINT" , SDTFPToIntOp>;
def fp_to_uint : SDNode<"ISD::FP_TO_UINT" , SDTFPToIntOp>;
def fp_to_sint_sat : SDNode<"ISD::FP_TO_SINT_SAT" , SDTFPToIntSatOp>;
def fp_to_uint_sat : SDNode<"ISD::FP_TO_UINT_SAT" , SDTFPToIntSatOp>;
def fp_to_sint_sat_gi : SDNode<"ISD::FP_TO_SINT_SAT" , SDTFPToIntOp>;
def fp_to_uint_sat_gi : SDNode<"ISD::FP_TO_UINT_SAT" , SDTFPToIntOp>;
def f16_to_fp : SDNode<"ISD::FP16_TO_FP" , SDTIntToFPOp>;
def fp_to_f16 : SDNode<"ISD::FP_TO_FP16" , SDTFPToIntOp>;
def bf16_to_fp : SDNode<"ISD::BF16_TO_FP" , SDTIntToFPOp>;
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2340,6 +2340,14 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
MachineInstr::copyFlagsFromInstruction(CI));
return true;
}
case Intrinsic::fptosi_sat:
MIRBuilder.buildFPTOSI_SAT(getOrCreateVReg(CI),
getOrCreateVReg(*CI.getArgOperand(0)));
return true;
case Intrinsic::fptoui_sat:
MIRBuilder.buildFPTOUI_SAT(getOrCreateVReg(CI),
getOrCreateVReg(*CI.getArgOperand(0)));
return true;
case Intrinsic::memcpy_inline:
return translateMemFunc(CI, MIRBuilder, TargetOpcode::G_MEMCPY_INLINE);
case Intrinsic::memcpy:
Expand Down
150 changes: 150 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1880,6 +1880,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
}
case TargetOpcode::G_FPTOUI:
case TargetOpcode::G_FPTOSI:
case TargetOpcode::G_FPTOUI_SAT:
case TargetOpcode::G_FPTOSI_SAT:
return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
case TargetOpcode::G_FPEXT:
if (TypeIdx != 0)
Expand Down Expand Up @@ -2872,6 +2874,47 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
else
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);

Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_FPTOSI_SAT:
case TargetOpcode::G_FPTOUI_SAT:
Observer.changingInstr(MI);

if (TypeIdx == 0) {
Register OldDst = MI.getOperand(0).getReg();
LLT Ty = MRI.getType(OldDst);
Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
Register NewDst;
MI.getOperand(0).setReg(ExtReg);
uint64_t ShortBits = Ty.getScalarSizeInBits();
uint64_t WideBits = WideTy.getScalarSizeInBits();
MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
// z = i16 fptosi_sat(a)
// ->
// x = i32 fptosi_sat(a)
// y = smin(x, 32767)
// z = smax(y, -32768)
auto MaxVal = MIRBuilder.buildConstant(
WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
auto MinVal = MIRBuilder.buildConstant(
WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
Register MidReg =
MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
} else {
// z = i16 fptoui_sat(a)
// ->
// x = i32 fptoui_sat(a)
// y = smin(x, 65535)
auto MaxVal = MIRBuilder.buildConstant(
WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
}
MIRBuilder.buildTrunc(OldDst, NewDst);
} else
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);

Observer.changedInstr(MI);
return Legalized;
case TargetOpcode::G_LOAD:
Expand Down Expand Up @@ -4170,6 +4213,9 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
return lowerFPTOUI(MI);
case G_FPTOSI:
return lowerFPTOSI(MI);
case G_FPTOUI_SAT:
case G_FPTOSI_SAT:
return lowerFPTOINT_SAT(MI);
case G_FPTRUNC:
return lowerFPTRUNC(MI);
case G_FPOWI:
Expand Down Expand Up @@ -4986,6 +5032,8 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
case G_UITOFP:
case G_FPTOSI:
case G_FPTOUI:
case G_FPTOSI_SAT:
case G_FPTOUI_SAT:
case G_INTTOPTR:
case G_PTRTOINT:
case G_ADDRSPACE_CAST:
Expand Down Expand Up @@ -5777,6 +5825,8 @@ LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx,
case TargetOpcode::G_FPEXT:
case TargetOpcode::G_FPTOSI:
case TargetOpcode::G_FPTOUI:
case TargetOpcode::G_FPTOSI_SAT:
case TargetOpcode::G_FPTOUI_SAT:
case TargetOpcode::G_SITOFP:
case TargetOpcode::G_UITOFP: {
Observer.changingInstr(MI);
Expand Down Expand Up @@ -7285,6 +7335,106 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPTOSI(MachineInstr &MI) {
return Legalized;
}

LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFPTOINT_SAT(MachineInstr &MI) {
auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();

bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
unsigned SatWidth = DstTy.getScalarSizeInBits();

// Determine minimum and maximum integer values and their corresponding
// floating-point values.
APInt MinInt, MaxInt;
if (IsSigned) {
MinInt = APInt::getSignedMinValue(SatWidth);
MaxInt = APInt::getSignedMaxValue(SatWidth);
} else {
MinInt = APInt::getMinValue(SatWidth);
MaxInt = APInt::getMaxValue(SatWidth);
}

const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
APFloat MinFloat(Semantics);
APFloat MaxFloat(Semantics);

APFloat::opStatus MinStatus =
MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);
APFloat::opStatus MaxStatus =
MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);
bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&
!(MaxStatus & APFloat::opStatus::opInexact);

// If the integer bounds are exactly representable as floats, emit a
// min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
// and selects.
if (AreExactFloatBounds) {
// Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);
auto MaxP = MIRBuilder.buildFCmp(CmpInst::FCMP_ULT,
SrcTy.changeElementSize(1), Src, MaxC);
auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);
// Clamp by MaxFloat from above. NaN cannot occur.
auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);
auto MinP =
MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, SrcTy.changeElementSize(1), Max,
MinC, MachineInstr::FmNoNans);
auto Min =
MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);
// Convert clamped value to integer. In the unsigned case we're done,
// because we mapped NaN to MinFloat, which will cast to zero.
if (!IsSigned) {
MIRBuilder.buildFPTOUI(Dst, Min);
MI.eraseFromParent();
return Legalized;
}

// Otherwise, select 0 if Src is NaN.
auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);
auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO,
DstTy.changeElementSize(1), Src, Src);
MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),
FpToInt);
MI.eraseFromParent();
return Legalized;
}

// Result of direct conversion. The assumption here is that the operation is
// non-trapping and it's fine to apply it to an out-of-range value if we
// select it away later.
auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)
: MIRBuilder.buildFPTOUI(DstTy, Src);

// If Src ULT MinFloat, select MinInt. In particular, this also selects
// MinInt if Src is NaN.
auto ULT =
MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, SrcTy.changeElementSize(1), Src,
MIRBuilder.buildFConstant(SrcTy, MinFloat));
auto Max = MIRBuilder.buildSelect(
DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);
// If Src OGT MaxFloat, select MaxInt.
auto OGT =
MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, SrcTy.changeElementSize(1), Src,
MIRBuilder.buildFConstant(SrcTy, MaxFloat));

// In the unsigned case we are done, because we mapped NaN to MinInt, which
// is already zero.
if (!IsSigned) {
MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),
Max);
MI.eraseFromParent();
return Legalized;
}

// Otherwise, select 0 if Src is NaN.
auto Min = MIRBuilder.buildSelect(
DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);
auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO,
DstTy.changeElementSize(1), Src, Src);
MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);
MI.eraseFromParent();
return Legalized;
}

// f64 -> f16 conversion using round-to-nearest-even rounding mode.
LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFPTRUNC_F64_TO_F16(MachineInstr &MI) {
Expand Down
54 changes: 48 additions & 6 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -4729,7 +4729,7 @@ defm FCVTZS : FPToIntegerScaled<0b11, 0b000, "fcvtzs", any_fp_to_sint>;
defm FCVTZU : FPToIntegerScaled<0b11, 0b001, "fcvtzu", any_fp_to_uint>;

// AArch64's FCVT instructions saturate when out of range.
multiclass FPToIntegerSatPats<SDNode to_int_sat, string INST> {
multiclass FPToIntegerSatPats<SDNode to_int_sat, SDNode to_int_sat_gi, string INST> {
let Predicates = [HasFullFP16] in {
def : Pat<(i32 (to_int_sat f16:$Rn, i32)),
(!cast<Instruction>(INST # UWHr) f16:$Rn)>;
Expand All @@ -4745,6 +4745,21 @@ multiclass FPToIntegerSatPats<SDNode to_int_sat, string INST> {
def : Pat<(i64 (to_int_sat f64:$Rn, i64)),
(!cast<Instruction>(INST # UXDr) f64:$Rn)>;

let Predicates = [HasFullFP16] in {
def : Pat<(i32 (to_int_sat_gi f16:$Rn)),
(!cast<Instruction>(INST # UWHr) f16:$Rn)>;
def : Pat<(i64 (to_int_sat_gi f16:$Rn)),
(!cast<Instruction>(INST # UXHr) f16:$Rn)>;
}
def : Pat<(i32 (to_int_sat_gi f32:$Rn)),
(!cast<Instruction>(INST # UWSr) f32:$Rn)>;
def : Pat<(i64 (to_int_sat_gi f32:$Rn)),
(!cast<Instruction>(INST # UXSr) f32:$Rn)>;
def : Pat<(i32 (to_int_sat_gi f64:$Rn)),
(!cast<Instruction>(INST # UWDr) f64:$Rn)>;
def : Pat<(i64 (to_int_sat_gi f64:$Rn)),
(!cast<Instruction>(INST # UXDr) f64:$Rn)>;

let Predicates = [HasFullFP16] in {
def : Pat<(i32 (to_int_sat (fmul f16:$Rn, fixedpoint_f16_i32:$scale), i32)),
(!cast<Instruction>(INST # SWHri) $Rn, $scale)>;
Expand All @@ -4759,10 +4774,25 @@ multiclass FPToIntegerSatPats<SDNode to_int_sat, string INST> {
(!cast<Instruction>(INST # SWDri) $Rn, $scale)>;
def : Pat<(i64 (to_int_sat (fmul f64:$Rn, fixedpoint_f64_i64:$scale), i64)),
(!cast<Instruction>(INST # SXDri) $Rn, $scale)>;

let Predicates = [HasFullFP16] in {
def : Pat<(i32 (to_int_sat_gi (fmul f16:$Rn, fixedpoint_f16_i32:$scale))),
(!cast<Instruction>(INST # SWHri) $Rn, $scale)>;
def : Pat<(i64 (to_int_sat_gi (fmul f16:$Rn, fixedpoint_f16_i64:$scale))),
(!cast<Instruction>(INST # SXHri) $Rn, $scale)>;
}
def : Pat<(i32 (to_int_sat_gi (fmul f32:$Rn, fixedpoint_f32_i32:$scale))),
(!cast<Instruction>(INST # SWSri) $Rn, $scale)>;
def : Pat<(i64 (to_int_sat_gi (fmul f32:$Rn, fixedpoint_f32_i64:$scale))),
(!cast<Instruction>(INST # SXSri) $Rn, $scale)>;
def : Pat<(i32 (to_int_sat_gi (fmul f64:$Rn, fixedpoint_f64_i32:$scale))),
(!cast<Instruction>(INST # SWDri) $Rn, $scale)>;
def : Pat<(i64 (to_int_sat_gi (fmul f64:$Rn, fixedpoint_f64_i64:$scale))),
(!cast<Instruction>(INST # SXDri) $Rn, $scale)>;
}

defm : FPToIntegerSatPats<fp_to_sint_sat, "FCVTZS">;
defm : FPToIntegerSatPats<fp_to_uint_sat, "FCVTZU">;
defm : FPToIntegerSatPats<fp_to_sint_sat, fp_to_sint_sat_gi, "FCVTZS">;
defm : FPToIntegerSatPats<fp_to_uint_sat, fp_to_uint_sat_gi, "FCVTZU">;

multiclass FPToIntegerIntPats<Intrinsic round, string INST> {
let Predicates = [HasFullFP16] in {
Expand Down Expand Up @@ -5308,22 +5338,34 @@ defm FCVTZS : SIMDTwoVectorFPToInt<0, 1, 0b11011, "fcvtzs", any_fp_to_sint>;
defm FCVTZU : SIMDTwoVectorFPToInt<1, 1, 0b11011, "fcvtzu", any_fp_to_uint>;

// AArch64's FCVT instructions saturate when out of range.
multiclass SIMDTwoVectorFPToIntSatPats<SDNode to_int_sat, string INST> {
multiclass SIMDTwoVectorFPToIntSatPats<SDNode to_int_sat, SDNode to_int_sat_gi, string INST> {
let Predicates = [HasFullFP16] in {
def : Pat<(v4i16 (to_int_sat v4f16:$Rn, i16)),
(!cast<Instruction>(INST # v4f16) v4f16:$Rn)>;
def : Pat<(v8i16 (to_int_sat v8f16:$Rn, i16)),
(!cast<Instruction>(INST # v8f16) v8f16:$Rn)>;

def : Pat<(v4i16 (to_int_sat_gi v4f16:$Rn)),
(!cast<Instruction>(INST # v4f16) v4f16:$Rn)>;
def : Pat<(v8i16 (to_int_sat_gi v8f16:$Rn)),
(!cast<Instruction>(INST # v8f16) v8f16:$Rn)>;
}
def : Pat<(v2i32 (to_int_sat v2f32:$Rn, i32)),
(!cast<Instruction>(INST # v2f32) v2f32:$Rn)>;
def : Pat<(v4i32 (to_int_sat v4f32:$Rn, i32)),
(!cast<Instruction>(INST # v4f32) v4f32:$Rn)>;
def : Pat<(v2i64 (to_int_sat v2f64:$Rn, i64)),
(!cast<Instruction>(INST # v2f64) v2f64:$Rn)>;

def : Pat<(v2i32 (to_int_sat_gi v2f32:$Rn)),
(!cast<Instruction>(INST # v2f32) v2f32:$Rn)>;
def : Pat<(v4i32 (to_int_sat_gi v4f32:$Rn)),
(!cast<Instruction>(INST # v4f32) v4f32:$Rn)>;
def : Pat<(v2i64 (to_int_sat_gi v2f64:$Rn)),
(!cast<Instruction>(INST # v2f64) v2f64:$Rn)>;
}
defm : SIMDTwoVectorFPToIntSatPats<fp_to_sint_sat, "FCVTZS">;
defm : SIMDTwoVectorFPToIntSatPats<fp_to_uint_sat, "FCVTZU">;
defm : SIMDTwoVectorFPToIntSatPats<fp_to_sint_sat, fp_to_sint_sat_gi, "FCVTZS">;
defm : SIMDTwoVectorFPToIntSatPats<fp_to_uint_sat, fp_to_uint_sat_gi, "FCVTZU">;

def : Pat<(v4i16 (int_aarch64_neon_fcvtzs v4f16:$Rn)), (FCVTZSv4f16 $Rn)>;
def : Pat<(v8i16 (int_aarch64_neon_fcvtzs v8f16:$Rn)), (FCVTZSv8f16 $Rn)>;
Expand Down
Loading
Loading