Index: llvm/include/llvm/CodeGen/GlobalISel/Utils.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/Utils.h +++ llvm/include/llvm/CodeGen/GlobalISel/Utils.h @@ -204,6 +204,9 @@ Optional ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI); +Optional ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, + const Register Op2, + const MachineRegisterInfo &MRI); Optional ConstantFoldExtOp(unsigned Opcode, const Register Op1, uint64_t Imm, const MachineRegisterInfo &MRI); Index: llvm/lib/CodeGen/GlobalISel/Utils.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -490,6 +490,60 @@ return None; } +Optional llvm::ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, + const Register Op2, + const MachineRegisterInfo &MRI) { + const ConstantFP *Op2Cst = getConstantFPVRegVal(Op2, MRI); + if (!Op2Cst) + return None; + + const ConstantFP *Op1Cst = getConstantFPVRegVal(Op1, MRI); + if (!Op1Cst) + return None; + + APFloat C1 = Op1Cst->getValueAPF(); + const APFloat &C2 = Op2Cst->getValueAPF(); + switch (Opcode) { + case TargetOpcode::G_FADD: + C1.add(C2, APFloat::rmNearestTiesToEven); + return C1; + case TargetOpcode::G_FSUB: + C1.subtract(C2, APFloat::rmNearestTiesToEven); + return C1; + case TargetOpcode::G_FMUL: + C1.multiply(C2, APFloat::rmNearestTiesToEven); + return C1; + case TargetOpcode::G_FDIV: + C1.divide(C2, APFloat::rmNearestTiesToEven); + return C1; + case TargetOpcode::G_FREM: + C1.mod(C2); + return C1; + case TargetOpcode::G_FCOPYSIGN: + C1.copySign(C2); + return C1; + case TargetOpcode::G_FMINNUM: + return minnum(C1, C2); + case TargetOpcode::G_FMAXNUM: + return maxnum(C1, C2); + case TargetOpcode::G_FMINIMUM: + return minimum(C1, C2); + case TargetOpcode::G_FMAXIMUM: + return maximum(C1, C2); + case TargetOpcode::G_FMINNUM_IEEE: + case TargetOpcode::G_FMAXNUM_IEEE: + // FIXME: These operations were unfortunately named. fminnum/fmaxnum do not + // follow the IEEE behavior for signaling nans and follow libm's fmin/fmax, + // and currently there isn't a nice wrapper in APFloat for the version with + // correct snan handling. + break; + default: + break; + } + + return None; +} + bool llvm::isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI, bool SNaN) { const MachineInstr *DefMI = MRI.getVRegDef(Val);