Index: lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1333,22 +1333,26 @@ return NV; } - // -A + B --> B - A - // -A + -B --> -(A + B) - if (Value *LHSV = dyn_castFNegVal(LHS)) { - Instruction *RI = BinaryOperator::CreateFSub(RHS, LHSV); - RI->copyFastMathFlags(&I); - return RI; - } - - // A + -B --> A - B - if (!isa(RHS)) - if (Value *V = dyn_castFNegVal(RHS)) { - Instruction *RI = BinaryOperator::CreateFSub(LHS, V); + // Skip this to break implicit infinite loop with "fsub" transformations of + // the form: (a + b) => (a - (-b)) => (a + b) => etc + if (I.hasNoExceptions() && I.hasNoRounding()) { + // -A + B --> B - A + // -A + -B --> -(A + B) + if (Value *LHSV = dyn_castFNegVal(LHS)) { + Instruction *RI = BinaryOperator::CreateFSub(RHS, LHSV); RI->copyFastMathFlags(&I); return RI; } + // A + -B --> A - B + if (!isa(RHS)) + if (Value *V = dyn_castFNegVal(RHS)) { + Instruction *RI = BinaryOperator::CreateFSub(LHS, V); + RI->copyFastMathFlags(&I); + return RI; + } + } + // Check for (fadd double (sitofp x), y), see if we can merge this into an // integer add followed by a promotion. if (SIToFPInst *LHSConv = dyn_cast(LHS)) { Index: test/Other/fpenv-constant-fold.ll =================================================================== --- test/Other/fpenv-constant-fold.ll +++ test/Other/fpenv-constant-fold.ll @@ -1,4 +1,5 @@ -; InstCombine is used just for its calls to constant folder. +; InstCombine is used just for its calls to constant folder, it is the cause of +; fsub -> fadd transformation. ; RUN: opt -S -instcombine -o - < %s | FileCheck %s ; Target independent constant folder should not fold floating-point operations @@ -7,7 +8,7 @@ define double @do-not-fold-fadd-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fadd-that-can-trap -; CHECK: fadd {{.*}} 1.000000e+308, {{.*}} 1.000000e+308 +; CHECK: fadd {{.*}} 1.000000e+308, 1.000000e+308 entry: %val = fadd nrnd double 1.000000e+308, 1.000000e+308 ret double %val @@ -15,7 +16,7 @@ define double @do-not-fold-fsub-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fsub-that-can-trap -; CHECK: fsub {{.*}} 1.000000e-308, {{.*}} 1.000000e+308 +; CHECK: fadd {{.*}} 1.000000e-308, -1.000000e+308 entry: %val = fsub nrnd double 1.000000e-308, 1.000000e+308 ret double %val @@ -23,7 +24,7 @@ define double @do-not-fold-fmul-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fmul-that-can-trap -; CHECK: fmul {{.*}} 1.000000e+300, {{.*}} 1.000000e+300 +; CHECK: fmul {{.*}} 1.000000e+300, 1.000000e+300 entry: %val = fmul nrnd double 1.000000e+300, 1.000000e+300 ret double %val @@ -31,7 +32,7 @@ define double @do-not-fold-fdiv-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fdiv-that-can-trap -; CHECK: fdiv {{.*}} 1.000000e+300, {{.*}} 1.000000e-300 +; CHECK: fdiv {{.*}} 1.000000e+300, 1.000000e-300 entry: %val = fdiv nrnd double 1.000000e+300, 1.000000e-300 ret double %val @@ -39,7 +40,7 @@ define double @do-not-fold-frem-that-can-trap() { ; CHECK-LABEL: @do-not-fold-frem-that-can-trap -; CHECK: frem {{.*}} 1.000000e+300, {{.*}} 1.000000e-300 +; CHECK: frem {{.*}} 1.000000e+300, 1.000000e-300 entry: %val = frem nrnd double 1.000000e+300, 1.000000e-300 ret double %val @@ -47,7 +48,7 @@ define double @do-not-fold-fadd-because-of-rounding() { ; CHECK-LABEL: @do-not-fold-fadd-because-of-rounding -; CHECK: fadd {{.*}} 1.010000e-01, {{.*}} 9.300000e-01 +; CHECK: fadd {{.*}} 1.010000e-01, 9.300000e-01 entry: %val = fadd nexc double 0.101, 0.93 ret double %val @@ -55,7 +56,7 @@ define double @do-not-fold-fsub-because-of-rounding() { ; CHECK-LABEL: @do-not-fold-fsub-because-of-rounding -; CHECK: fsub {{.*}} 1.010000e-01, {{.*}} 9.300000e-01 +; CHECK: fadd {{.*}} 1.010000e-01, -9.300000e-01 entry: %val = fsub nexc double 0.101, 0.93 ret double %val @@ -63,7 +64,7 @@ define double @do-not-fold-fmul-because-of-rounding() { ; CHECK-LABEL: @do-not-fold-fmul-because-of-rounding -; CHECK: fmul {{.*}} 1.010000e-01, {{.*}} 9.300000e-01 +; CHECK: fmul {{.*}} 1.010000e-01, 9.300000e-01 entry: %val = fmul nexc double 0.101, 0.93 ret double %val @@ -71,7 +72,7 @@ define double @do-not-fold-fdiv-because-of-rounding() { ; CHECK-LABEL: @do-not-fold-fdiv-because-of-rounding -; CHECK: fdiv {{.*}} 1.010000e-01, {{.*}} 9.300000e-01 +; CHECK: fdiv {{.*}} 1.010000e-01, 9.300000e-01 entry: %val = fdiv nexc double 0.101, 0.93 ret double %val @@ -122,7 +123,7 @@ define double @correcly-handle-nested-expressions() { ; CHECK-LABEL: @correcly-handle-nested-expressions -; CHECK: fmul {{.*}} 1.000000e+300, {{.*}} 1.000000e+300 +; CHECK: fmul {{.*}} 1.000000e+300, 1.000000e+300 entry: %val1 = fmul nrnd double 1.000000e+300, 1.000000e+300 %val2 = fdiv nrnd double %val1, 1.000000e+300 Index: test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/do-not-hand-on-fpops-with-fpenv-access.ll @@ -0,0 +1,42 @@ +; RUN: opt < %s -instcombine -S + +; InstCombine shouldn't hang in non-terminating sequence of conversions like: +; (a + b) => (a - (-b)) => (a + b) => etc. + +define double @test1() { +entry: + %add = fadd nrnd double 0x3FF921FB54442D18, 0x3870000000000000 + ret double %add +} + +define double @test2(double %x) { +entry: + %sub = fsub double -0.000000e+00, 1.000000e+00 + %div = fdiv double %sub, %x + ret double %div +} + +define double @test3() { +entry: + %sub = fsub double -0.000000e+00, 0x400921FB54442D18 + ret double %sub +} + +define double @test4(i32 %y) { +entry: + %tobool = icmp ne i32 %y, 0 + br i1 %tobool, label %cond.true, label %cond.false + +cond.true: + %sub = fsub double -0.000000e+00, 0x400921FB54442D18 + %div = fdiv double %sub, 2.000000e+00 + br label %cond.end + +cond.false: + %div1 = fdiv double 0x400921FB54442D18, 2.000000e+00 + br label %cond.end + +cond.end: + %cond = phi double [ %div, %cond.true ], [ %div1, %cond.false ] + ret double %cond +}