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.hasKeepExceptions() && !I.hasKeepRounding()) { + // -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 @@ -15,7 +16,7 @@ define double @do-not-fold-fsub-that-can-trap() { ; CHECK-LABEL: @do-not-fold-fsub-that-can-trap -; CHECK: fsub +; CHECK: fadd entry: %val = fsub kexc double 1.000000e-308, 1.000000e+308 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 +; CHECK: fadd entry: %val = fsub kround double 0.101, 0.93 ret double %val @@ -92,7 +93,7 @@ ; CHECK-LABEL: @fold-fsub-that-cant-trap ; CHECK-NOT: fsub entry: - %val = fsub kexc kround double 1.0, 1.0 + %val = fadd kexc kround double 1.0, 1.0 ret double %val } 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 kexc double 0x3FF921FB54442D18, 0x3870000000000000 + ret double %add +} + +define double @test2(double %x) { +entry: + %sub = fsub kexc kround double -0.000000e+00, 1.000000e+00 + %div = fdiv kexc kround double %sub, %x + ret double %div +} + +define double @test3() { +entry: + %sub = fsub kexc kround 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 kexc kround double -0.000000e+00, 0x400921FB54442D18 + %div = fdiv kexc kround double %sub, 2.000000e+00 + br label %cond.end + +cond.false: + %div1 = fdiv kexc kround double 0x400921FB54442D18, 2.000000e+00 + br label %cond.end + +cond.end: + %cond = phi double [ %div, %cond.true ], [ %div1, %cond.false ] + ret double %cond +}