Index: HashProgramOutput.sh
===================================================================
--- HashProgramOutput.sh
+++ HashProgramOutput.sh
@@ -1,7 +1,7 @@
 #!/bin/sh
 
-if [ $# != 1 ]; then
-  echo "$0 <output path>"
+if [ $# -lt 1 -o $# -gt 2 ]; then
+  echo "$0 <output path> [<copy of original output>]"
   exit 1
 fi
 
@@ -22,4 +22,9 @@
 else
     $md5cmd < $1.bak | cut -d' ' -f 1 > $1
 fi
-rm -f $1.bak
+
+if [ x"$2" != x ]; then
+    mv -f $1.bak $2
+else
+    rm -f $1.bak
+fi
Index: MultiSource/Applications/oggenc/CMakeLists.txt
===================================================================
--- MultiSource/Applications/oggenc/CMakeLists.txt
+++ MultiSource/Applications/oggenc/CMakeLists.txt
@@ -3,4 +3,5 @@
 list(APPEND LDFLAGS -lm)
 set(STDIN_FILENAME ${CMAKE_CURRENT_SOURCE_DIR}/tune)
 set(RUN_OPTIONS "-Q -s 901820 -")
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_multisource()
Index: MultiSource/Benchmarks/VersaBench/beamformer/CMakeLists.txt
===================================================================
--- MultiSource/Benchmarks/VersaBench/beamformer/CMakeLists.txt
+++ MultiSource/Benchmarks/VersaBench/beamformer/CMakeLists.txt
@@ -10,4 +10,5 @@
   endif()
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_multisource()
Index: SingleSource/Benchmarks/Polybench/datamining/correlation/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/datamining/correlation/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/datamining/correlation/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/datamining/covariance/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/datamining/covariance/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/datamining/covariance/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/2mm/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/2mm/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/2mm/CMakeLists.txt
@@ -15,4 +15,5 @@
   set(RUNTIMELIMIT 1000)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/3mm/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/3mm/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/3mm/CMakeLists.txt
@@ -15,4 +15,5 @@
   set(RUNTIMELIMIT 1000)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/atax/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/atax/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/atax/CMakeLists.txt
@@ -5,4 +5,5 @@
 if(ARCH STREQUAL "XCore")
   set(XCORE_TARGET_NEEDS_MEMORY 128)
 endif()
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/bicg/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/bicg/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/bicg/CMakeLists.txt
@@ -2,6 +2,8 @@
 set(PROG bicg)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+# FIXME: Checking the exact output of this benchmark takes an unreasonable amount of time and space.
+#set(FP_ABSTOLERANCE 1.0e-5)
 if(ARCH STREQUAL "XCore")
   set(XCORE_TARGET_NEEDS_MEMORY 128)
 endif()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/cholesky/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/cholesky/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/cholesky/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/doitgen/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/doitgen/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/doitgen/CMakeLists.txt
@@ -9,4 +9,5 @@
   endif()
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gemm/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gemm/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gemm/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gemver/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gemver/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gemver/CMakeLists.txt
@@ -2,6 +2,7 @@
 set(PROG gemver)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 if(ARCH STREQUAL "XCore")
   set(XCORE_TARGET_NEEDS_MEMORY 128)
 endif()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gesummv/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gesummv/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/gesummv/CMakeLists.txt
@@ -9,4 +9,5 @@
   endif()
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/mvt/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/mvt/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/mvt/CMakeLists.txt
@@ -2,6 +2,8 @@
 set(PROG mvt)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+# FIXME: Checking the exact output of this benchmark takes an unreasonable amount of time and space.
+#set(FP_ABSTOLERANCE 1.0e-5)
 if(ARCH STREQUAL "XCore")
   set(XCORE_TARGET_NEEDS_MEMORY 128)
 endif()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/symm/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/symm/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/symm/CMakeLists.txt
@@ -8,4 +8,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/syr2k/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/syr2k/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/syr2k/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/syrk/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/syrk/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/syrk/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/trisolv/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/trisolv/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/trisolv/CMakeLists.txt
@@ -2,6 +2,7 @@
 set(PROG trisolv)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 if(ARCH STREQUAL "XCore")
   set(XCORE_TARGET_NEEDS_MEMORY 128)
 endif()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/kernels/trmm/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/kernels/trmm/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/kernels/trmm/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/solvers/durbin/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/solvers/durbin/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/solvers/durbin/CMakeLists.txt
@@ -2,6 +2,7 @@
 set(PROG durbin)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 if(ARCH STREQUAL "XCore")
   set(XCORE_TARGET_NEEDS_MEMORY 256)
 endif()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/solvers/dynprog/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/solvers/dynprog/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/solvers/dynprog/CMakeLists.txt
@@ -2,4 +2,5 @@
 set(PROG dynprog)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/solvers/gramschmidt/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/solvers/gramschmidt/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/solvers/gramschmidt/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/solvers/lu/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/solvers/lu/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/solvers/lu/CMakeLists.txt
@@ -2,4 +2,5 @@
 set(PROG lu)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/linear-algebra/solvers/ludcmp/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/linear-algebra/solvers/ludcmp/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/linear-algebra/solvers/ludcmp/CMakeLists.txt
@@ -2,4 +2,5 @@
 set(PROG ludcmp)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/medley/floyd-warshall/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/medley/floyd-warshall/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/medley/floyd-warshall/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/stencils/adi/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/stencils/adi/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/stencils/adi/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/stencils/fdtd-2d/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/stencils/fdtd-2d/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/stencils/fdtd-2d/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/stencils/fdtd-apml/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/stencils/fdtd-apml/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/stencils/fdtd-apml/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/stencils/jacobi-1d-imper/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/stencils/jacobi-1d-imper/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/stencils/jacobi-1d-imper/CMakeLists.txt
@@ -2,4 +2,5 @@
 set(PROG jacobi-1d-imper)
 list(APPEND CFLAGS -I ${CMAKE_SOURCE_DIR}/${POLYBENCH_UTILS} -DPOLYBENCH_DUMP_ARRAYS)
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/stencils/jacobi-2d-imper/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/stencils/jacobi-2d-imper/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/stencils/jacobi-2d-imper/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: SingleSource/Benchmarks/Polybench/stencils/seidel-2d/CMakeLists.txt
===================================================================
--- SingleSource/Benchmarks/Polybench/stencils/seidel-2d/CMakeLists.txt
+++ SingleSource/Benchmarks/Polybench/stencils/seidel-2d/CMakeLists.txt
@@ -5,4 +5,5 @@
   list(APPEND CFLAGS -DSMALL_DATASET)
 endif()
 set(HASH_PROGRAM_OUTPUT 1)
+set(FP_ABSTOLERANCE 1.0e-5)
 llvm_singlesource()
Index: cmake/modules/SingleMultiSource.cmake
===================================================================
--- cmake/modules/SingleMultiSource.cmake
+++ cmake/modules/SingleMultiSource.cmake
@@ -87,7 +87,13 @@
 
   # Hash if we've been asked to.
   if(HASH_PROGRAM_OUTPUT)
-    llvm_test_verify("${CMAKE_SOURCE_DIR}/HashProgramOutput.sh %o")
+    if(DEFINED OUTPUT_FP_CONTRACT_OFF)
+      llvm_test_verify("${CMAKE_SOURCE_DIR}/HashProgramOutput.sh %o ${OUTPUT_FP_CONTRACT_OFF}")
+    else()
+      llvm_test_verify("${CMAKE_SOURCE_DIR}/HashProgramOutput.sh %o")
+    endif()
+  elseif(DEFINED OUTPUT_FP_CONTRACT_OFF AND DEFINED FP_FIRST_STEP)
+    llvm_test_verify("cp -p %o ${OUTPUT_FP_CONTRACT_OFF}")
   endif()
 
   if(NOT DEFINED PROGRAM_IS_NONDETERMINISTIC)
@@ -101,7 +107,9 @@
     endif()
 
     # Pick the best reference output based on "programname.reference_output".
-    if(NOT DEFINED NO_REFERENCE_OUTPUT)
+    if(DEFINED OUTPUT_FP_CONTRACT_OFF AND NOT DEFINED FP_FIRST_STEP)
+      set(REFERENCE_OUTPUT ${OUTPUT_FP_CONTRACT_OFF})
+    elseif(NOT DEFINED NO_REFERENCE_OUTPUT)
       if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.reference_output.${ENDIAN}-endian.${KEY})
         set(REFERENCE_OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${name}.reference_output.${ENDIAN}-endian.${KEY})
       elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.reference_output.${KEY})
@@ -116,10 +124,10 @@
     endif()
 
     set(DIFFPROG ${CMAKE_BINARY_DIR}/tools/fpcmp)
-    if(DEFINED FP_TOLERANCE)
+    if(DEFINED FP_TOLERANCE AND NOT DEFINED HASH_PROGRAM_OUTPUT)
       set(DIFFPROG "${DIFFPROG} -r ${FP_TOLERANCE}")
     endif()
-    if(DEFINED FP_ABSTOLERANCE)
+    if(DEFINED FP_ABSTOLERANCE AND NOT DEFINED HASH_PROGRAM_OUTPUT)
       set(DIFFPROG "${DIFFPROG} -a ${FP_ABSTOLERANCE}")
     endif()
     if(REFERENCE_OUTPUT)
@@ -136,6 +144,34 @@
   add_dependencies(${executable} timeit-host fpcmp-host)
 endmacro()
 
+macro(llvm_test_executable_end executable name)
+  if (_LTARG_TARGET_VAR)
+    set(${_LTARG_TARGET_VAR} ${executable})
+  endif()
+  append_compile_flags(${executable} ${CFLAGS})
+  append_compile_flags(${executable} ${CPPFLAGS})
+  append_compile_flags(${executable} ${CXXFLAGS})
+  # Note that we cannot use target_link_libraries() here because that one
+  # only interprets inputs starting with '-' as flags.
+  append_link_flags(${executable} ${LDFLAGS})
+  set(executable_path ${CMAKE_CURRENT_BINARY_DIR}/${executable})
+  if (TEST_SUITE_PROFILE_USE)
+    append_compile_flags(${executable} -fprofile-instr-use=${executable_path}.profdata)
+    append_link_flags(${executable} -fprofile-instr-use=${executable_path}.profdata)
+  endif()
+
+  set_property(GLOBAL APPEND PROPERTY TEST_SUITE_TARGETS ${executable})
+
+  # Fall back to old style involving RUN_OPTIONS and STDIN_FILENAME if
+  # llvm_test_run() was not called yet.
+  if(NOT TESTSCRIPT)
+    llvm_test_traditional(${executable_path}.test ${executable_path} ${name})
+  else()
+    llvm_add_test(${executable_path}.test ${executable_path})
+  endif()
+  test_suite_add_build_dependencies(${executable})
+endmacro()
+
 macro(llvm_test_executable name)
   cmake_parse_arguments(_LTARG "" "PREFIX;TARGET_VAR" "" ${ARGN})
   if (_LTARG_PREFIX)
@@ -148,32 +184,36 @@
   list(FIND PROGRAMS_TO_SKIP ${name} name_idx)
   # Should we skip this?
   if(${name_idx} EQUAL -1 AND ${exe_idx} EQUAL -1)
-    add_executable(${executable} ${_LTARG_UNPARSED_ARGUMENTS})
-    if (_LTARG_TARGET_VAR)
-      set(${_LTARG_TARGET_VAR} ${executable})
-    endif()
-    append_compile_flags(${executable} ${CFLAGS})
-    append_compile_flags(${executable} ${CPPFLAGS})
-    append_compile_flags(${executable} ${CXXFLAGS})
-    # Note that we cannot use target_link_libraries() here because that one
-    # only interprets inputs starting with '-' as flags.
-    append_link_flags(${executable} ${LDFLAGS})
-    set(executable_path ${CMAKE_CURRENT_BINARY_DIR}/${executable})
-    if (TEST_SUITE_PROFILE_USE)
-      append_compile_flags(${executable} -fprofile-instr-use=${executable_path}.profdata)
-      append_link_flags(${executable} -fprofile-instr-use=${executable_path}.profdata)
-    endif()
+    # FP tests need two steps: the first run records the output of the program
+    # compiled with -ffp-contract=off, and compares the hash of the output
+    # against a reference hashed value.  The second run tests the default
+    # behavior of the compiler, and compares the output with tolerance against
+    # the output of the first step.
+    if (DEFINED FP_ABSTOLERANCE OR DEFINED FP_TOLERANCE)
+      set(executable_fpcoff "${executable}-fp-contract-off")
+      add_executable(${executable_fpcoff} ${_LTARG_UNPARSED_ARGUMENTS})
+      # The first step must compile without -ffast-math and -ffp-contract.
+      append_compile_flags(${executable_fpcoff} "-ffp-contract=off" "-fno-fast-math")
+      set(OUTPUT_FP_CONTRACT_OFF ${CMAKE_CURRENT_BINARY_DIR}/Output/${executable_fpcoff}.out)
 
-    set_property(GLOBAL APPEND PROPERTY TEST_SUITE_TARGETS ${executable})
+      # The first run cannot do an exact comparison: there are some tests that are failing.
+      #set(ORIG_FP_TOLERANCE ${FP_TOLERANCE})
+      #set(ORIG_FP_ABSTOLERANCE ${FP_ABSTOLERANCE})
+      #unset(FP_TOLERANCE)
+      #unset(FP_ABSTOLERANCE)
+      set(FP_FIRST_STEP 1)
+      llvm_test_executable_end(${executable_fpcoff} ${name})
+      unset(FP_FIRST_STEP)
 
-    # Fall back to old style involving RUN_OPTIONS and STDIN_FILENAME if
-    # llvm_test_run() was not called yet.
-    if(NOT TESTSCRIPT)
-      llvm_test_traditional(${executable_path}.test ${executable_path} ${name})
-    else()
-      llvm_add_test(${executable_path}.test ${executable_path})
-    endif()
-    test_suite_add_build_dependencies(${executable})
+      # Next run should be a comparison against the golden file recorded in the
+      # first step.
+      unset(HASH_PROGRAM_OUTPUT)
+      #set(FP_TOLERANCE ${ORIG_FP_TOLERANCE})
+      #set(FP_ABSTOLERANCE ${ORIG_FP_ABSTOLERANCE})
+    endif ()
+
+    add_executable(${executable} ${_LTARG_UNPARSED_ARGUMENTS})
+    llvm_test_executable_end(${executable} ${name})
   endif()
 endmacro()