diff options
-rw-r--r-- | llvm/lib/Transforms/Scalar/GVN.cpp | 7 | ||||
-rw-r--r-- | llvm/test/Transforms/GVN/propagate-ir-flags.ll | 29 |
2 files changed, 35 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp index b6591531265..d5234c0f7e3 100644 --- a/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/llvm/lib/Transforms/Scalar/GVN.cpp @@ -1731,7 +1731,12 @@ static void patchReplacementInstruction(Instruction *I, Value *Repl) { // 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<LoadInst>(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 diff --git a/llvm/test/Transforms/GVN/propagate-ir-flags.ll b/llvm/test/Transforms/GVN/propagate-ir-flags.ll new file mode 100644 index 00000000000..07367a2ec51 --- /dev/null +++ b/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 +} + |