/// Perform folds that are common to any floating-point operation. This implies
/// transforms based on undef/NaN because the operation itself makes no
/// difference to the result.
-static Constant *simplifyFPOp(ArrayRef<Value *> Ops) {
+static Constant *simplifyFPOp(ArrayRef<Value *> Ops,
+ FastMathFlags FMF = FastMathFlags()) {
for (Value *V : Ops) {
- if (match(V, m_Undef()) || match(V, m_NaN()))
+ bool IsNan = match(V, m_NaN());
+ bool IsInf = match(V, m_Inf());
+ bool IsUndef = match(V, m_Undef());
+
+ // If this operation has 'nnan' or 'ninf' and at least 1 disallowed operand
+ // (TODO: an undef operand can be chosen to be Nan/Inf), then the result of
+ // this operation is poison. That result can be relaxed to undef.
+ if (FMF.noNaNs() && IsNan)
+ return UndefValue::get(V->getType());
+ if (FMF.noInfs() && IsInf)
+ return UndefValue::get(V->getType());
+
+ if (IsUndef || IsNan)
return propagateNaN(cast<Constant>(V));
}
return nullptr;
if (Constant *C = foldOrCommuteConstant(Instruction::FAdd, Op0, Op1, Q))
return C;
- if (Constant *C = simplifyFPOp({Op0, Op1}))
+ if (Constant *C = simplifyFPOp({Op0, Op1}, FMF))
return C;
// fadd X, -0 ==> X
if (Constant *C = foldOrCommuteConstant(Instruction::FSub, Op0, Op1, Q))
return C;
- if (Constant *C = simplifyFPOp({Op0, Op1}))
+ if (Constant *C = simplifyFPOp({Op0, Op1}, FMF))
return C;
// fsub X, +0 ==> X
static Value *SimplifyFMAFMul(Value *Op0, Value *Op1, FastMathFlags FMF,
const SimplifyQuery &Q, unsigned MaxRecurse) {
- if (Constant *C = simplifyFPOp({Op0, Op1}))
+ if (Constant *C = simplifyFPOp({Op0, Op1}, FMF))
return C;
// fmul X, 1.0 ==> X
if (Constant *C = foldOrCommuteConstant(Instruction::FDiv, Op0, Op1, Q))
return C;
- if (Constant *C = simplifyFPOp({Op0, Op1}))
+ if (Constant *C = simplifyFPOp({Op0, Op1}, FMF))
return C;
// X / 1.0 -> X
if (Constant *C = foldOrCommuteConstant(Instruction::FRem, Op0, Op1, Q))
return C;
- if (Constant *C = simplifyFPOp({Op0, Op1}))
+ if (Constant *C = simplifyFPOp({Op0, Op1}, FMF))
return C;
// Unlike fdiv, the result of frem always matches the sign of the dividend.
define float @fadd_nan_op0_nnan(float %x) {
; CHECK-LABEL: @fadd_nan_op0_nnan(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = fadd nnan float 0x7FF8000000000000, %x
ret float %r
define float @fadd_nan_op1_fast(float %x) {
; CHECK-LABEL: @fadd_nan_op1_fast(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = fadd fast float %x, 0x7FF8000000000000
ret float %r
define float @fsub_nan_op0_fast(float %x) {
; CHECK-LABEL: @fsub_nan_op0_fast(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = fsub fast float 0x7FF8000000000000, %x
ret float %r
define float @fsub_nan_op1_nnan(float %x) {
; CHECK-LABEL: @fsub_nan_op1_nnan(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = fsub nnan float %x, 0x7FF8000000000000
ret float %r
define float @fmul_nan_op0_nnan(float %x) {
; CHECK-LABEL: @fmul_nan_op0_nnan(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = fmul nnan float 0x7FF8000000000000, %x
ret float %r
define float @fmul_nan_op1_fast(float %x) {
; CHECK-LABEL: @fmul_nan_op1_fast(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = fmul fast float %x, 0x7FF8000000000000
ret float %r
define float @fdiv_nan_op0_fast(float %x) {
; CHECK-LABEL: @fdiv_nan_op0_fast(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = fdiv fast float 0x7FF8000000000000, %x
ret float %r
define float @fdiv_nan_op1_nnan(float %x) {
; CHECK-LABEL: @fdiv_nan_op1_nnan(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = fdiv nnan float %x, 0x7FF8000000000000
ret float %r
define float @frem_nan_op0_nnan(float %x) {
; CHECK-LABEL: @frem_nan_op0_nnan(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = frem nnan float 0x7FF8000000000000, %x
ret float %r
define float @frem_nan_op1_fast(float %x) {
; CHECK-LABEL: @frem_nan_op1_fast(
-; CHECK-NEXT: ret float 0x7FF8000000000000
+; CHECK-NEXT: ret float undef
;
%r = frem fast float %x, 0x7FF8000000000000
ret float %r
ret double %r
}
-; TODO: Should simplify to undef.
-
define double @fdiv_ninf_inf_op0(double %x) {
; CHECK-LABEL: @fdiv_ninf_inf_op0(
-; CHECK-NEXT: [[R:%.*]] = fdiv ninf double 0x7FF0000000000000, [[X:%.*]]
-; CHECK-NEXT: ret double [[R]]
+; CHECK-NEXT: ret double undef
;
%r = fdiv ninf double 0x7ff0000000000000, %x
ret double %r
}
-; TODO: Should simplify to undef.
-
define double @fadd_ninf_inf_op1(double %x) {
; CHECK-LABEL: @fadd_ninf_inf_op1(
-; CHECK-NEXT: [[R:%.*]] = fadd ninf double [[X:%.*]], 0xFFF0000000000000
-; CHECK-NEXT: ret double [[R]]
+; CHECK-NEXT: ret double undef
;
%r = fadd ninf double %x, 0xfff0000000000000
ret double %r