Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -697,6 +697,10 @@ bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo); + /// \returns true if it is possible to simplify a select instruction \p MI + /// to a min/max instruction of some sort. + bool matchSimplifySelectToMinMax(MachineInstr &MI, BuildFnTy &MatchInfo); + private: /// Given a non-indexed load or store instruction \p MI, find an offset that /// can be usefully and legally folded into it as a post-indexing operation. @@ -742,6 +746,49 @@ /// a re-association of its operands would break an existing legal addressing /// mode that the address computation currently represents. bool reassociationCanBreakAddressingModePattern(MachineInstr &PtrAdd); + + /// Behavior when a floating point min/max is given one NaN and one + /// non-NaN as input. + enum SelectPatternNaNBehaviour { + NOT_APPLICABLE = 0, /// NaN behavior not applicable. + RETURNS_NAN, /// Given one NaN input, returns the NaN. + RETURNS_OTHER, /// Given one NaN input, returns the non-NaN. + RETURNS_ANY /// Given one NaN input, can return either (or both operands are + /// known non-NaN.) + }; + + /// \returns which of \p LHS and \p RHS would be the result of a non-equality + /// floating point comparison where one of \p LHS and \p RHS may be NaN. + /// + /// If both \p LHS and \p RHS may be NaN, returns + /// SelectPatternNaNBehaviour::NOT_APPLICABLE. + SelectPatternNaNBehaviour + computeRetValAgainstNaN(Register LHS, Register RHS, + bool IsOrderedComparison) const; + + /// Determines the floating point min/max opcode which should be used for + /// a G_SELECT fed by a G_FCMP with predicate \p Pred. + /// + /// \returns 0 if this G_SELECT should not be combined to a floating point + /// min or max. If it should be combined, returns one of + /// + /// * G_FMAXNUM + /// * G_FMAXIMUM + /// * G_FMINNUM + /// * G_FMINIMUM + /// + /// Helper function for matchFPSelectToMinMax. + unsigned getFPMinMaxOpcForSelect(unsigned Pred, LLT DstTy, + SelectPatternNaNBehaviour VsNaNRetVal) const; + + /// Handle floating point cases for matchSimplifySelectToMinMax. + /// + /// E.g. + /// + /// select (fcmp uge x, 1.0) x, 1.0 -> fmax x, 1.0 + /// select (fcmp uge x, 1.0) 1.0, x -> fminnm x, 1.0 + bool matchFPSelectToMinMax(Register Dst, Register Cond, Register TrueVal, + Register FalseVal, BuildFnTy &MatchInfo); }; } // namespace llvm Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -837,6 +837,12 @@ *${root}, ${info}); }]), (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; +def select_to_minmax: GICombineRule< + (defs root:$root, build_fn_matchinfo:$info), + (match (wip_match_opcode G_SELECT):$root, + [{ return Helper.matchSimplifySelectToMinMax(*${root}, ${info}); }]), + (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; + // FIXME: These should use the custom predicate feature once it lands. def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero, undef_to_negative_one, Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -27,6 +27,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/Target/TargetMachine.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/IR/DataLayout.h" @@ -5343,6 +5344,135 @@ return false; } +unsigned CombinerHelper::getFPMinMaxOpcForSelect( + unsigned Pred, LLT DstTy, SelectPatternNaNBehaviour VsNaNRetVal) const { + assert(VsNaNRetVal != NOT_APPLICABLE && "Expected a NaN behaviour?"); + // Choose an opcode based off of legality or the behaviour when one of the + // LHS/RHS may be NaN. + switch (Pred) { + default: + return 0; + case CmpInst::FCMP_UGT: + case CmpInst::FCMP_UGE: + case CmpInst::FCMP_OGT: + case CmpInst::FCMP_OGE: + if (VsNaNRetVal == RETURNS_OTHER) + return TargetOpcode::G_FMAXNUM; + if (VsNaNRetVal == RETURNS_NAN) + return TargetOpcode::G_FMAXIMUM; + if (isLegalOrBeforeLegalizer({TargetOpcode::G_FMAXNUM, {DstTy}})) + return TargetOpcode::G_FMAXNUM; + if (isLegalOrBeforeLegalizer({TargetOpcode::G_FMAXIMUM, {DstTy}})) + return TargetOpcode::G_FMAXIMUM; + return 0; + case CmpInst::FCMP_ULT: + case CmpInst::FCMP_ULE: + case CmpInst::FCMP_OLT: + case CmpInst::FCMP_OLE: + if (VsNaNRetVal == RETURNS_OTHER) + return TargetOpcode::G_FMINNUM; + if (VsNaNRetVal == RETURNS_NAN) + return TargetOpcode::G_FMINIMUM; + if (isLegalOrBeforeLegalizer({TargetOpcode::G_FMINNUM, {DstTy}})) + return TargetOpcode::G_FMINNUM; + else if (isLegalOrBeforeLegalizer({TargetOpcode::G_FMINIMUM, {DstTy}})) + return TargetOpcode::G_FMINIMUM; + return 0; + } +} + +CombinerHelper::SelectPatternNaNBehaviour +CombinerHelper::computeRetValAgainstNaN(Register LHS, Register RHS, + bool IsOrderedComparison) const { + bool LHSSafe = isKnownNeverNaN(LHS, MRI); + bool RHSSafe = isKnownNeverNaN(RHS, MRI); + // Completely unsafe. + if (!LHSSafe && !RHSSafe) + return NOT_APPLICABLE; + if (LHSSafe && RHSSafe) + return RETURNS_ANY; + // An ordered comparison will return false when given a NaN, so it + // returns the RHS. + if (IsOrderedComparison) + return LHSSafe ? RETURNS_NAN : RETURNS_OTHER; + // An unordered comparison will return true when given a NaN, so it + // returns the LHS. + return LHSSafe ? RETURNS_OTHER : RETURNS_NAN; +} + +bool CombinerHelper::matchFPSelectToMinMax(Register Dst, Register Cond, + Register TrueVal, Register FalseVal, + BuildFnTy &MatchInfo) { + // Match: select (fcmp cond x, y) x, y + // select (fcmp cond x, y) y, x + // And turn it into fminnum/fmaxnum or fmin/fmax based off of the condition. + LLT DstTy = MRI.getType(Dst); + // Bail out early on pointers, since we'll never want to fold to a min/max. + // TODO: Handle vectors. + if (DstTy.isPointer() || DstTy.isVector()) + return false; + // Match a floating point compare with a less-than/greater-than predicate. + // TODO: Allow multiple users of the compare if they are all selects. + CmpInst::Predicate Pred; + Register CmpLHS, CmpRHS; + if (!mi_match(Cond, MRI, + m_OneNonDBGUse( + m_GFCmp(m_Pred(Pred), m_Reg(CmpLHS), m_Reg(CmpRHS)))) || + CmpInst::isEquality(Pred)) + return false; + // Signed zero may return inconsistent results between implementations. + // (0.0 <= -0.0) ? 0.0 : -0.0 // Returns 0.0 + // minNum(0.0, -0.0) // May return -0.0 or 0.0 (IEEE 754-2008 5.3.1) + // Therefore, we behave conservatively and only proceed if at least one of the + // operands is known to not be zero or if we don't care about signed zero. + // + // TODO: Can probably use known bits here? + auto KnownNonZeroSide = getFConstantVRegValWithLookThrough(CmpLHS, MRI); + if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) { + KnownNonZeroSide = getFConstantVRegValWithLookThrough(CmpRHS, MRI); + if (!KnownNonZeroSide || !KnownNonZeroSide->Value.isNonZero()) + return false; + } + SelectPatternNaNBehaviour ResWithKnownNaNInfo = + computeRetValAgainstNaN(CmpLHS, CmpRHS, CmpInst::isOrdered(Pred)); + if (ResWithKnownNaNInfo == NOT_APPLICABLE) + return false; + if (TrueVal == CmpRHS && FalseVal == CmpLHS) { + std::swap(CmpLHS, CmpRHS); + Pred = CmpInst::getSwappedPredicate(Pred); + if (ResWithKnownNaNInfo == RETURNS_NAN) + ResWithKnownNaNInfo = RETURNS_OTHER; + else if (ResWithKnownNaNInfo == RETURNS_OTHER) + ResWithKnownNaNInfo = RETURNS_NAN; + } + if (TrueVal != CmpLHS || FalseVal != CmpRHS) + return false; + // Decide what type of max/min this should be based off of the predicate. + unsigned Opc = getFPMinMaxOpcForSelect(Pred, DstTy, ResWithKnownNaNInfo); + if (!Opc || !isLegalOrBeforeLegalizer({Opc, {DstTy}})) + return false; + MatchInfo = [=](MachineIRBuilder &B) { + B.buildInstr(Opc, {Dst}, {CmpLHS, CmpRHS}); + }; + errs() << "applied\n"; + return true; +} + +bool CombinerHelper::matchSimplifySelectToMinMax(MachineInstr &MI, + BuildFnTy &MatchInfo) { + // TODO: Handle integer cases. + assert(MI.getOpcode() == TargetOpcode::G_SELECT); + // Condition may be fed by a truncated compare. + Register Cond = MI.getOperand(1).getReg(); + Register MaybeTrunc; + if (mi_match(Cond, MRI, m_OneNonDBGUse(m_GTrunc(m_Reg(MaybeTrunc))))) + Cond = MaybeTrunc; + Register Dst = MI.getOperand(0).getReg(); + Register TrueVal = MI.getOperand(2).getReg(); + Register FalseVal = MI.getOperand(3).getReg(); + return matchFPSelectToMinMax(Dst, Cond, TrueVal, FalseVal, MatchInfo); +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { if (tryCombineCopy(MI)) return true; Index: llvm/lib/Target/AArch64/AArch64Combine.td =================================================================== --- llvm/lib/Target/AArch64/AArch64Combine.td +++ llvm/lib/Target/AArch64/AArch64Combine.td @@ -228,6 +228,7 @@ select_combines, fold_merge_to_zext, constant_fold, identity_combines, ptr_add_immed_chain, overlapping_and, - split_store_zero_128]> { + split_store_zero_128, + select_to_minmax]> { let DisableRuleOption = "aarch64postlegalizercombiner-disable-rule"; } Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-select-to-fminnum-fmaxnum.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-select-to-fminnum-fmaxnum.mir @@ -0,0 +1,1467 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple aarch64 -run-pass=aarch64-postlegalizer-combiner --aarch64postlegalizercombinerhelper-only-enable-rule="select_to_minmax" -verify-machineinstrs %s -o - | FileCheck %s + +################################################################################ +########################## G_FMAXNUM Positive Cases ############################ +################################################################################ + +#################### LHS and RHS both known to not be NaN. ##################### +... +--- +name: ugt_fmaxnum_lhs_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fmaxnum_lhs_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: uge_fmaxnum_lhs_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: uge_fmaxnum_lhs_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(uge), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: ogt_fmaxnum_lhs_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ogt_fmaxnum_lhs_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(ogt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: oge_fmaxnum_lhs_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: oge_fmaxnum_lhs_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(oge), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +#################### Unordered preds, LHS known non-NaN. ####################### +... +--- +name: ugt_fmaxnum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fmaxnum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: uge_fmaxnum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: uge_fmaxnum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(uge), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +##################### Ordered preds, RHS known non-NaN. ######################## +... +--- +name: ogt_fmaxnum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ogt_fmaxnum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(ogt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: oge_fmaxnum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: oge_fmaxnum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(oge), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +############################## Swapped operands ################################ +... +--- +name: ult_fmaxnum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ult_fmaxnum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ult), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: ule_fmaxnum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ule_fmaxnum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ule), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: ole_fmaxnum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ole_fmaxnum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(ole), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: olt_fmaxnum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: olt_fmaxnum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(olt), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +################################################################################ +########################## G_FMAXIMUM Positive Cases ############################ +################################################################################ + +##################### Ordered preds, LHS known non-NaN. ######################## +... +--- +name: ogt_fmaximum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ogt_fmaximum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %select:_(s32) = G_FMAXIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.0 + %rhs:_(s32) = COPY $s0 + %fcmp:_(s32) = G_FCMP floatpred(ogt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: oge_fmaximum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: oge_fmaximum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %select:_(s32) = G_FMAXIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.0 + %rhs:_(s32) = COPY $s0 + %fcmp:_(s32) = G_FCMP floatpred(oge), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +#################### Unordered preds, RHS known non-NaN. ####################### +... +--- +name: ugt_fmaximum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fmaximum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: uge_fmaximum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: uge_fmaximum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(uge), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +############################## Swapped operands ################################ +... +--- +name: ole_fmaximum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ole_fmaximum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMAXIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ole), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: olt_fmaximum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: olt_fmaximum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMAXIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(olt), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: ult_fmaximum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ult_fmaximum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(ult), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: ule_fmaximum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ule_fmaximum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(ule), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +################################################################################ +########################## G_FMINNUM Positive Cases ############################ +################################################################################ + +#################### LHS and RHS both known to not be NaN. ##################### +... +--- +name: ult_fminnum_lhs_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ult_fminnum_lhs_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(ult), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ule_fminnum_lhs_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ule_fminnum_lhs_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(ule), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: olt_fminnum_lhs_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: olt_fminnum_lhs_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(olt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ole_fminnum_lhs_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ole_fminnum_lhs_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp:_(s32) = G_FCMP floatpred(ole), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +#################### Unordered preds, LHS known non-NaN. ####################### +... +--- +name: ult_fminnum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ult_fminnum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ult), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ule_fminnum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ule_fminnum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ule), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +##################### Ordered preds, RHS known non-NaN. ######################## +... +--- +name: olt_fminnum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: olt_fminnum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 3.0 + %fcmp:_(s32) = G_FCMP floatpred(olt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ole_fminnum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ole_fminnum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 3.0 + %fcmp:_(s32) = G_FCMP floatpred(ole), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +############################## Swapped operands ################################ +... +--- +name: ugt_fminnum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fminnum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: uge_fminnum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: uge_fminnum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(uge), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: oge_fminnum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: oge_fminnum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(oge), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: ogt_fminnum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ogt_fminnum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(ogt), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + + +################################################################################ +########################## G_FMINIMUM Positive Cases ########################### +################################################################################ + +#################### Unordered preds, RHS known non-NaN. ####################### +... +--- +name: ult_fminimum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ult_fminimum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 3.0 + %fcmp:_(s32) = G_FCMP floatpred(ult), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ule_fminimum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ule_fminimum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 3.0 + %fcmp:_(s32) = G_FCMP floatpred(ule), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +##################### Ordered preds, LHS known non-NaN. ######################## +... +--- +name: olt_fminimum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: olt_fminimum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMINIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(olt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ole_fminimum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ole_fminimum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMINIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ole), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +############################## Swapped operands ################################ +... +--- +name: oge_fminimum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: oge_fminimum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMINIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(oge), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: ogt_fminimum_lhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ogt_fminimum_lhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %select:_(s32) = G_FMINIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ogt), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: ugt_fminimum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fminimum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: uge_fminimum_rhs_safe +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: uge_fminimum_rhs_safe + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMINIMUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s1 + %rhs:_(s32) = G_FCONSTANT float 1.000000e+00 + %fcmp:_(s32) = G_FCMP floatpred(uge), %rhs(s32), %lhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +################################################################################ +########################## Other Positive Cases ################################ +################################################################################ + +... +--- +name: ugt_fmaxnum_lhs_safe_rhs_pos_zero +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fmaxnum_lhs_safe_rhs_pos_zero + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 0.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ugt_fmaxnum_rhs_safe_lhs_pos_zero +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fmaxnum_rhs_safe_lhs_pos_zero + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 0.0 + %rhs:_(s32) = G_FCONSTANT float 3.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ugt_fmaxnum_lhs_safe_rhs_neg_zero +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fmaxnum_lhs_safe_rhs_neg_zero + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float -0.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float -0.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +... +--- +name: ugt_fmaxnum_rhs_safe_lhs_neg_zero +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: ugt_fmaxnum_rhs_safe_lhs_neg_zero + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float -0.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %select:_(s32) = G_FMAXNUM %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float -0.0 + %rhs:_(s32) = G_FCONSTANT float 3.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 + +################################################################################ +########################## Negative Testcases ################################## +################################################################################ + +... +--- +name: dont_combine_vector +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $d0, $d1 + ; CHECK-LABEL: name: dont_combine_vector + ; CHECK: liveins: $d0, $d1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(<2 x s32>) = COPY $d0 + ; CHECK-NEXT: %cst:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %rhs:_(<2 x s32>) = G_BUILD_VECTOR %cst(s32), %cst(s32) + ; CHECK-NEXT: %fcmp:_(<2 x s32>) = G_FCMP floatpred(ugt), %lhs(<2 x s32>), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(<2 x s1>) = G_TRUNC %fcmp(<2 x s32>) + ; CHECK-NEXT: %select:_(<2 x s32>) = G_SELECT %fcmp_trunc(<2 x s1>), %lhs, %rhs + ; CHECK-NEXT: $d0 = COPY %select(<2 x s32>) + ; CHECK-NEXT: RET_ReallyLR implicit $d0 + %lhs:_(<2 x s32>) = COPY $d0 + %cst:_(s32) = G_FCONSTANT float 1.0 + %rhs:_(<2 x s32>) = G_BUILD_VECTOR %cst, %cst + %fcmp:_(<2 x s32>) = G_FCMP floatpred(ugt), %lhs(<2 x s32>), %rhs + %fcmp_trunc:_(<2 x s1>) = G_TRUNC %fcmp(<2 x s32>) + %select:_(<2 x s32>) = G_SELECT %fcmp_trunc, %lhs, %rhs + $d0 = COPY %select + RET_ReallyLR implicit $d0 + +... +--- +name: dont_combine_pointer +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $x0, $x1 + ; CHECK-LABEL: name: dont_combine_pointer + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(p0) = COPY $x0 + ; CHECK-NEXT: %rhs:_(p0) = COPY $x1 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(p0), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(p0) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $d0 = COPY %select(p0) + ; CHECK-NEXT: RET_ReallyLR implicit $d0 + %lhs:_(p0) = COPY $x0 + %rhs:_(p0) = COPY $x1 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(p0), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(p0) = G_SELECT %fcmp_trunc, %lhs, %rhs + $d0 = COPY %select + RET_ReallyLR implicit $d0 + +... +--- +name: dont_combine_zero_rhs_lhs_unknown +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_zero_rhs_lhs_unknown + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s0 + %rhs:_(s32) = G_FCONSTANT float 0.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_zero_lhs_rhs_unknown +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_zero_lhs_rhs_unknown + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 0.0 + %rhs:_(s32) = COPY $s0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_negative_zero_rhs_lhs_unknown +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_negative_zero_rhs_lhs_unknown + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float -0.000000e+00 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s0 + %rhs:_(s32) = G_FCONSTANT float -0.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_negative_zero_lhs_rhs_unknown +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_negative_zero_lhs_rhs_unknown + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s0 + %rhs:_(s32) = G_FCONSTANT float 0.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_lhs_rhs_unknown +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_lhs_rhs_unknown + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = COPY $s0 + ; CHECK-NEXT: %rhs:_(s32) = COPY $s1 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = COPY $s0 + %rhs:_(s32) = COPY $s1 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_lhs_rhs_nan +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_lhs_rhs_nan + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 0x7FF1000000000000 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 0x7FF1000000000000 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 0x7FF1000000000000 + %rhs:_(s32) = G_FCONSTANT float 0x7FF1000000000000 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_different_lhs +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_different_lhs + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %select_lhs:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK-NEXT: %fcmp_lhs:_(s32) = G_FCONSTANT float 2.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ugt), %fcmp_lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %select_lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %select_lhs:_(s32) = G_FCONSTANT float 1.0 + %fcmp_lhs:_(s32) = G_FCONSTANT float 2.0 + %rhs:_(s32) = G_FCONSTANT float 3.0 + %fcmp:_(s32) = G_FCMP floatpred(ugt), %fcmp_lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %select_lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_oeq +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_oeq + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 2.000000e+00 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(oeq), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 2.0 + %fcmp:_(s32) = G_FCMP floatpred(oeq), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_ueq +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_ueq + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 2.000000e+00 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(ueq), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 2.0 + %fcmp:_(s32) = G_FCMP floatpred(ueq), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_one +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_one + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 2.000000e+00 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(one), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 2.0 + %fcmp:_(s32) = G_FCMP floatpred(one), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 +... +--- +name: dont_combine_une +alignment: 4 +legalized: true +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $s0, $s1 + ; CHECK-LABEL: name: dont_combine_une + ; CHECK: liveins: $s0, $s1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: %lhs:_(s32) = G_FCONSTANT float 3.000000e+00 + ; CHECK-NEXT: %rhs:_(s32) = G_FCONSTANT float 2.000000e+00 + ; CHECK-NEXT: %fcmp:_(s32) = G_FCMP floatpred(une), %lhs(s32), %rhs + ; CHECK-NEXT: %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + ; CHECK-NEXT: %select:_(s32) = G_SELECT %fcmp_trunc(s1), %lhs, %rhs + ; CHECK-NEXT: $s0 = COPY %select(s32) + ; CHECK-NEXT: RET_ReallyLR implicit $s0 + %lhs:_(s32) = G_FCONSTANT float 3.0 + %rhs:_(s32) = G_FCONSTANT float 2.0 + %fcmp:_(s32) = G_FCMP floatpred(une), %lhs(s32), %rhs + %fcmp_trunc:_(s1) = G_TRUNC %fcmp(s32) + %select:_(s32) = G_SELECT %fcmp_trunc, %lhs, %rhs + $s0 = COPY %select + RET_ReallyLR implicit $s0 Index: llvm/test/CodeGen/AArch64/known-never-nan.ll =================================================================== --- llvm/test/CodeGen/AArch64/known-never-nan.ll +++ llvm/test/CodeGen/AArch64/known-never-nan.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=aarch64 < %s | FileCheck %s +; RUN: llc -mtriple=aarch64 -global-isel < %s | FileCheck %s ; This should codegen to fmaxnm with no-signed-zeros. define float @fmaxnm(i32 %i1, i32 %i2) #0 {