Index: llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h =================================================================== --- llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -228,6 +228,10 @@ SmallVectorImpl &Results, SelectionDAG &DAG) const override; + SDValue combineFMinMaxLegacyImpl(const SDLoc &DL, EVT VT, SDValue LHS, + SDValue RHS, SDValue True, SDValue False, + SDValue CC, DAGCombinerInfo &DCI) const; + SDValue combineFMinMaxLegacy(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, SDValue True, SDValue False, SDValue CC, DAGCombinerInfo &DCI) const; Index: llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp =================================================================== --- llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -1387,15 +1387,16 @@ return DAG.getBuildVector(Op.getValueType(), SDLoc(Op), Args); } -/// Generate Min/Max node -SDValue AMDGPUTargetLowering::combineFMinMaxLegacy(const SDLoc &DL, EVT VT, - SDValue LHS, SDValue RHS, - SDValue True, SDValue False, - SDValue CC, - DAGCombinerInfo &DCI) const { - if (!(LHS == True && RHS == False) && !(LHS == False && RHS == True)) - return SDValue(); +// TODO: Handle fabs too +static SDValue peekFNeg(SDValue Val) { + if (Val.getOpcode() == ISD::FNEG) + return Val.getOperand(0); + return Val; +} +SDValue AMDGPUTargetLowering::combineFMinMaxLegacyImpl( + const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, SDValue True, + SDValue False, SDValue CC, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; ISD::CondCode CCOpcode = cast(CC)->get(); switch (CCOpcode) { @@ -1461,6 +1462,42 @@ return SDValue(); } +/// Generate Min/Max node +SDValue AMDGPUTargetLowering::combineFMinMaxLegacy(const SDLoc &DL, EVT VT, + SDValue LHS, SDValue RHS, + SDValue True, SDValue False, + SDValue CC, + DAGCombinerInfo &DCI) const { + if ((LHS == True && RHS == False) || (LHS == False && RHS == True)) + return combineFMinMaxLegacyImpl(DL, VT, LHS, RHS, True, False, CC, DCI); + + SelectionDAG &DAG = DCI.DAG; + + // If we can't directly match this, try to see if we can fold an fneg to + // match. + + ConstantFPSDNode *CLHS = dyn_cast(LHS); + ConstantFPSDNode *CRHS = dyn_cast(RHS); + + ConstantFPSDNode *CTrue = dyn_cast(True); + ConstantFPSDNode *CFalse = dyn_cast(False); + SDValue NegTrue = peekFNeg(True); + + // Undo the combine foldFreeOpFromSelect does if it helps us match the min/max + if (LHS == NegTrue && CFalse && CRHS) { + APFloat NegRHS = neg(CRHS->getValueAPF()); + if (NegRHS == CFalse->getValueAPF()) { + SDValue Combined = + combineFMinMaxLegacyImpl(DL, VT, LHS, RHS, NegTrue, False, CC, DCI); + if (Combined) + return DAG.getNode(ISD::FNEG, DL, VT, Combined); + return SDValue(); + } + } + + return SDValue(); +} + std::pair AMDGPUTargetLowering::split64BitValue(SDValue Op, SelectionDAG &DAG) const { SDLoc SL(Op); Index: llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp =================================================================== --- llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp +++ llvm/lib/Target/AMDGPU/AMDGPUPostLegalizerCombiner.cpp @@ -91,6 +91,8 @@ Info.True = MI.getOperand(2).getReg(); Info.False = MI.getOperand(3).getReg(); + // TODO: Handle case where the the selected value is an fneg and the compared + // constant is the negation of the selected value. if (!(Info.LHS == Info.True && Info.RHS == Info.False) && !(Info.LHS == Info.False && Info.RHS == Info.True)) return false;