Index: llvm/lib/Transforms/Scalar/GVN.cpp =================================================================== --- llvm/lib/Transforms/Scalar/GVN.cpp +++ llvm/lib/Transforms/Scalar/GVN.cpp @@ -1731,7 +1731,12 @@ // Patch the replacement so that it is not more restrictive than the value // being replaced. - ReplInst->andIRFlags(I); + // Note that if 'I' is a load being replaced by some operation, + // for example, by an arithmetic operation, then andIRFlags() + // would just erase all math flags from the original arithmetic + // operation, which is clearly not wanted and not needed. + if (!isa(I)) + ReplInst->andIRFlags(I); // FIXME: If both the original and replacement value are part of the // same control-flow region (meaning that the execution of one Index: llvm/test/Transforms/GVN/propagate-ir-flags.ll =================================================================== --- llvm/test/Transforms/GVN/propagate-ir-flags.ll +++ llvm/test/Transforms/GVN/propagate-ir-flags.ll @@ -0,0 +1,29 @@ + +; RUN: opt < %s -gvn -S | FileCheck %s + +; CHECK-LABEL: func_fast +; CHECK: fadd fast double +; CHECK-NEXT: store +; CHECK-NEXT: ret +define double @func_fast(double %a, double %b) { +entry: + %a.addr = alloca double, align 8 + %add = fadd fast double %b, 3.000000e+00 + store double %add, double* %a.addr, align 8 + %load_add = load double, double* %a.addr, align 8 + ret double %load_add +} + +; CHECK-LABEL: func_no_fast +; CHECK: fadd double +; CHECK-NEXT: store +; CHECK-NEXT: ret +define double @func_no_fast(double %a, double %b) { +entry: + %a.addr = alloca double, align 8 + %add = fadd fast double %b, 3.000000e+00 + store double %add, double* %a.addr, align 8 + %duplicated_add = fadd double %b, 3.000000e+00 + ret double %duplicated_add +} +