Add support for non-NEON ARM FFT

This adds non-NEON support for float FFTs and two new functions for
the forward and inverse real float FFTs.  The two new functions will
automatically choose whether to use the NEON or non-NEON versions.

Tests updated to include separate test programs for the non-NEON code.

BUG=
R=andrew@webrtc.org, xingnan.wang@chromium.org

Review URL: https://webrtc-codereview.appspot.com/2065004

git-svn-id: http://webrtc.googlecode.com/svn/deps/third_party/openmax@5124 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/dl/dl.gyp b/dl/dl.gyp
index 29e27b1..61a05b0 100644
--- a/dl/dl.gyp
+++ b/dl/dl.gyp
@@ -38,29 +38,39 @@
             # runtime detection.
             '-mfpu=neon',
           ],
+          'dependencies': [
+            '<(android_ndk_root)/android_tools_ndk.gyp:cpu_features',
+            'openmax_dl_armv7',
+          ],
+          'link_settings' : {
+            'libraries': [
+              # To get the __android_log_print routine
+              '-llog',
+            ],
+          },
           'sources': [
+            # Common files that are used by both the NEON and non-NEON code.
             'api/armCOMM_s.h',
             'api/armOMX.h',
             'api/omxtypes_s.h',
             'sp/api/armSP.h',
-            # Common C code for NEON and non-NEON implementations.
             'sp/src/arm/armSP_FFT_S32TwiddleTable.c',
-            'sp/src/arm/omxSP_FFTGetBufSize_C_SC32.c',
-            'sp/src/arm/omxSP_FFTInit_C_SC32.c',
-            'sp/src/arm/omxSP_FFTGetBufSize_R_S32.c',
-            'sp/src/arm/omxSP_FFTInit_R_S32.c',
-            'sp/src/arm/omxSP_FFTInit_C_SC16.c',
-            'sp/src/arm/omxSP_FFTGetBufSize_C_SC16.c',
-            'sp/src/arm/omxSP_FFTGetBufSize_R_S16.c',
-            'sp/src/arm/omxSP_FFTInit_R_S16.c',
-            'sp/src/arm/omxSP_FFTGetBufSize_R_S16S32.c',
-            'sp/src/arm/omxSP_FFTInit_R_S16S32.c',
+            'sp/src/arm/detect.c',
             'sp/src/arm/omxSP_FFTGetBufSize_C_FC32.c',
-            'sp/src/arm/omxSP_FFTInit_C_FC32.c',
+            'sp/src/arm/omxSP_FFTGetBufSize_C_SC16.c',
+            'sp/src/arm/omxSP_FFTGetBufSize_C_SC32.c',
             'sp/src/arm/omxSP_FFTGetBufSize_R_F32.c',
+            'sp/src/arm/omxSP_FFTGetBufSize_R_S16.c',
+            'sp/src/arm/omxSP_FFTGetBufSize_R_S16S32.c',
+            'sp/src/arm/omxSP_FFTGetBufSize_R_S32.c',
+            'sp/src/arm/omxSP_FFTInit_C_FC32.c',
+            'sp/src/arm/omxSP_FFTInit_C_SC16.c',
+            'sp/src/arm/omxSP_FFTInit_C_SC32.c',
             'sp/src/arm/omxSP_FFTInit_R_F32.c',
+            'sp/src/arm/omxSP_FFTInit_R_S16.c',
+            'sp/src/arm/omxSP_FFTInit_R_S16S32.c',
+            'sp/src/arm/omxSP_FFTInit_R_S32.c',
 
-            # NEON-specific implementation
             # Complex 32-bit fixed-point FFT.
             'sp/src/arm/neon/armSP_FFT_CToC_SC32_Radix2_fs_unsafe_s.S',
             'sp/src/arm/neon/armSP_FFT_CToC_SC32_Radix2_ls_unsafe_s.S',
@@ -147,5 +157,38 @@
           ],
         }],
       ],
-  }]
+    },
+  ],
+  'conditions': [
+    ['target_arch=="arm"', {
+      'targets': [
+        {
+          # Non-NEON implementation of FFT. This library is NOT
+          # standalone. Applications must link with openmax_dl.
+          'target_name': 'openmax_dl_armv7',
+          'type': 'static_library',
+          'include_dirs': [
+            '../',
+          ],
+          'cflags!': [
+            '-mfpu=neon',
+          ],
+          'sources': [
+            # Complex floating-point FFT
+            'sp/src/arm/armv7/armSP_FFT_CToC_FC32_Radix2_fs_unsafe_s.S',
+            'sp/src/arm/armv7/armSP_FFT_CToC_FC32_Radix2_fs_unsafe_s.S',
+            'sp/src/arm/armv7/armSP_FFT_CToC_FC32_Radix4_fs_unsafe_s.S',
+            'sp/src/arm/armv7/armSP_FFT_CToC_FC32_Radix4_unsafe_s.S',
+            'sp/src/arm/armv7/armSP_FFT_CToC_FC32_Radix8_fs_unsafe_s.S',
+            'sp/src/arm/armv7/omxSP_FFTInv_CToC_FC32_Sfs_s.S',
+            'sp/src/arm/armv7/omxSP_FFTFwd_CToC_FC32_Sfs_s.S',
+            # Real floating-point FFT
+            'sp/src/arm/armv7/armSP_FFTInv_CCSToR_F32_preTwiddleRadix2_unsafe_s.S',
+            'sp/src/arm/armv7/omxSP_FFTFwd_RToCCS_F32_Sfs_s.S',
+            'sp/src/arm/armv7/omxSP_FFTInv_CCSToR_F32_Sfs_s.S',
+          ],
+        },
+      ],
+    }],
+  ],
 }
diff --git a/dl/sp/api/omxSP.h b/dl/sp/api/omxSP.h
index 8f70236..b0030c6 100644
--- a/dl/sp/api/omxSP.h
+++ b/dl/sp/api/omxSP.h
@@ -2253,7 +2253,27 @@
     const OMXFFTSpec_R_F32* pFFTSpec
 );
 
+#ifdef __arm__
+/*
+ * Non-NEON version of omxSP_FFTFwd_RToCCS_F32_Sfs
+ */    
+OMXResult omxSP_FFTFwd_RToCCS_F32_Sfs_vfp(
+    const OMX_F32* pSrc,
+    OMX_F32* pDst,
+    const OMXFFTSpec_R_F32* pFFTSpec
+);
 
+/*
+ * Just like omxSP_FFTFwd_RToCCS_F32_Sfs, but automatically detects
+ * whether NEON is available or not and chooses the appropriate
+ * routine.
+ */    
+extern OMXResult (*omxSP_FFTFwd_RToCCS_F32)(
+    const OMX_F32* pSrc,
+    OMX_F32* pDst,
+    const OMXFFTSpec_R_F32* pFFTSpec
+);
+#endif
 
 /**
  * Function:  omxSP_FFTInv_CCSToR_S32S16_Sfs   (2.2.4.4.4)
@@ -2445,7 +2465,26 @@
     const OMXFFTSpec_R_F32* pFFTSpec
 );
 
+#ifdef __arm__
+/*
+ * Non-NEON version of omxSP_FFTInv_CCSToR_F32_Sfs
+ */    
+OMXResult omxSP_FFTInv_CCSToR_F32_Sfs_vfp(
+    const OMX_F32* pSrc,
+    OMX_F32* pDst,
+    const OMXFFTSpec_R_F32* pFFTSpec
+);
 
+/*
+ * Just like omxSP_FFTInv_CCSToR_F32_Sfs, but automatically detects
+ * whether NEON is available or not and chooses the appropriate
+ * routine.
+ */    
+extern OMXResult (*omxSP_FFTInv_CCSToR_F32)(
+    const OMX_F32* pSrc,
+    OMX_F32* pDst,
+    const OMXFFTSpec_R_F32* pFFTSpec);
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/dl/sp/src/arm/detect.c b/dl/sp/src/arm/detect.c
new file mode 100644
index 0000000..b74220a
--- /dev/null
+++ b/dl/sp/src/arm/detect.c
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#include <cpu-features.h>
+
+#include "android/log.h"
+#include "dl/sp/api/omxSP.h"
+
+int HasArmNeon() {
+  return (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
+}
+
+static void SetFFTRoutines() {
+  /*
+   * Choose the correct (NEON or non-NEON) routines for both the
+   * forward and inverse FFTs
+   */
+  if (HasArmNeon()) {
+    __android_log_print(ANDROID_LOG_INFO, "OpenMAX DL FFT",
+                        "Using NEON FFT");
+    omxSP_FFTFwd_RToCCS_F32 = omxSP_FFTFwd_RToCCS_F32_Sfs;
+    omxSP_FFTInv_CCSToR_F32 = omxSP_FFTInv_CCSToR_F32_Sfs;
+  } else {
+    __android_log_print(ANDROID_LOG_INFO, "OpenMAX DL FFT",
+                        "Using non-NEON FFT");
+    omxSP_FFTFwd_RToCCS_F32 = omxSP_FFTFwd_RToCCS_F32_Sfs_vfp;
+    omxSP_FFTInv_CCSToR_F32 = omxSP_FFTInv_CCSToR_F32_Sfs_vfp;
+  }
+}
+
+/*
+ * FIXME: It would be beneficial to use the GCC ifunc attribute to
+ * select the appropriate function at load time. This is apparently
+ * not supported on Android at this time. (Compiler warning that the
+ * ifunc attribute is ignored.)
+ */
+
+/*
+ * Forward FFT.  Detect if NEON is supported and update function
+ * pointers to the correct routines for both the forward and inverse
+ * FFTs.  Then run the forward FFT routine.
+ */
+static OMXResult DetectForwardRealFFT(
+    const OMX_F32* pSrc,
+    OMX_F32* pDst,
+    const OMXFFTSpec_R_F32* pFFTSpec) {
+  SetFFTRoutines();
+  return omxSP_FFTFwd_RToCCS_F32(pSrc, pDst, pFFTSpec);
+}
+
+/*
+ * Inverse FFT.  Detect if NEON is supported and update function
+ * pointers to the correct routines for both the forward and inverse
+ * FFTs.  Then run the inverse FFT routine.
+ */
+static OMXResult DetectInverseRealFFT(
+    const OMX_F32* pSrc,
+    OMX_F32* pDst,
+    const OMXFFTSpec_R_F32* pFFTSpec) {
+  SetFFTRoutines();
+  return omxSP_FFTInv_CCSToR_F32(pSrc, pDst, pFFTSpec);
+}
+
+/*
+ * Implementation of the forward and inverse real float FFT.
+ * Initialize to detection routine which will update the pointer to
+ * the correct routine and then call the correct one.
+ */
+OMXResult (*omxSP_FFTFwd_RToCCS_F32)(
+    const OMX_F32* pSrc,
+    OMX_F32* pDst,
+    const OMXFFTSpec_R_F32* pFFTSpec) = DetectForwardRealFFT;
+
+OMXResult (*omxSP_FFTInv_CCSToR_F32)(
+    const OMX_F32* pSrc,
+    OMX_F32* pDst,
+    const OMXFFTSpec_R_F32* pFFTSpec) = DetectInverseRealFFT;
diff --git a/dl/sp/src/test/support/float_fft_armv7.c b/dl/sp/src/test/support/float_fft_armv7.c
new file mode 100644
index 0000000..7daed1b
--- /dev/null
+++ b/dl/sp/src/test/support/float_fft_armv7.c
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "dl/sp/api/armSP.h"
+#include "dl/sp/api/omxSP.h"
+#include "dl/sp/src/test/test_util.h"
+
+static const char* message =
+    "Test forward and inverse floating-point FFT (Non-NEON)\n";
+
+const char* UsageMessage() {
+  return message;
+}
+
+void FinishedMessage() {
+  printf("Non-NEON tests finished.\n");
+}
+
+void SetThresholds(struct TestInfo* info) {
+#ifdef BIG_FFT_TABLE
+  info->forward_threshold_ = 138.84;
+  info->inverse_threshold_ = 137.99;
+#else
+  info->forward_threshold_ = 139.52;
+  info->inverse_threshold_ = 139.21;
+#endif
+}
+
+OMXResult ForwardFFT(OMX_FC32* x,
+                     OMX_FC32* y,
+                     OMXFFTSpec_C_FC32 *fft_fwd_spec) {
+  return omxSP_FFTFwd_CToC_FC32_Sfs_vfp(x, y, fft_fwd_spec);
+}
+
+OMXResult InverseFFT(OMX_FC32* y,
+                     OMX_FC32* z,
+                     OMXFFTSpec_C_FC32 *fft_inv_spec) {
+  return omxSP_FFTInv_CToC_FC32_Sfs_vfp(y, z, fft_inv_spec);
+}
diff --git a/dl/sp/src/test/support/float_fft_neon.c b/dl/sp/src/test/support/float_fft_neon.c
new file mode 100644
index 0000000..3f0cf16
--- /dev/null
+++ b/dl/sp/src/test/support/float_fft_neon.c
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "dl/sp/api/armSP.h"
+#include "dl/sp/api/omxSP.h"
+#include "dl/sp/src/test/test_util.h"
+
+static const char* message =
+    "Test forward and inverse floating-point FFT (NEON)\n";
+
+const char* UsageMessage() {
+  return message;
+}
+
+void FinishedMessage() {
+  printf("NEON tests finished.\n");
+}
+
+void SetThresholds(struct TestInfo* info) {
+#ifdef BIG_FFT_TABLE
+  info->forward_threshold_ = 138.81;
+  info->inverse_threshold_ = 137.81;
+#else
+  info->forward_threshold_ = 138.81;
+  info->inverse_threshold_ = 138.81;
+#endif
+}
+
+OMXResult ForwardFFT(OMX_FC32* x,
+                     OMX_FC32* y,
+                     OMXFFTSpec_C_FC32 *fft_fwd_spec) {
+  return omxSP_FFTFwd_CToC_FC32_Sfs(x, y, fft_fwd_spec);
+}
+
+OMXResult InverseFFT(OMX_FC32* y,
+                     OMX_FC32* z,
+                     OMXFFTSpec_C_FC32 *fft_inv_spec) {
+  return omxSP_FFTInv_CToC_FC32_Sfs(y, z, fft_inv_spec);
+}
diff --git a/dl/sp/src/test/support/float_rfft_armv7.c b/dl/sp/src/test/support/float_rfft_armv7.c
new file mode 100644
index 0000000..35646d9
--- /dev/null
+++ b/dl/sp/src/test/support/float_rfft_armv7.c
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "dl/sp/api/armSP.h"
+#include "dl/sp/api/omxSP.h"
+#include "dl/sp/src/test/test_util.h"
+#include "dl/sp/src/test/support/float_rfft_thresholds.h"
+
+static const char* message =
+    "Test forward and inverse real floating-point FFT (Non-NEON)\n";
+
+const char* UsageMessage() {
+  return message;
+}
+
+void FinishedMessage() {
+  printf("Non-NEON tests finished.\n");
+}
+
+void SetThresholds(struct TestInfo* info) {
+  info->forward_threshold_ = FLOAT_RFFT_FORWARD_THRESHOLD_ARMV7;
+  info->inverse_threshold_ = FLOAT_RFFT_INVERSE_THRESHOLD_ARMV7;
+}
+
+OMXResult ForwardRFFT(OMX_F32* x,
+                      OMX_F32* y,
+                      OMXFFTSpec_R_F32 *fft_fwd_spec) {
+  return omxSP_FFTFwd_RToCCS_F32_Sfs_vfp(x, y, fft_fwd_spec);
+}
+
+OMXResult InverseRFFT(OMX_F32* y,
+                      OMX_F32* z,
+                      OMXFFTSpec_R_F32 *fft_inv_spec) {
+  return omxSP_FFTInv_CCSToR_F32_Sfs_vfp(y, z, fft_inv_spec);
+}
diff --git a/dl/sp/src/test/support/float_rfft_detect.c b/dl/sp/src/test/support/float_rfft_detect.c
new file mode 100644
index 0000000..cf81e8d
--- /dev/null
+++ b/dl/sp/src/test/support/float_rfft_detect.c
@@ -0,0 +1,50 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "dl/sp/api/armSP.h"
+#include "dl/sp/api/omxSP.h"
+#include "dl/sp/src/test/test_util.h"
+#include "dl/sp/src/test/support/float_rfft_thresholds.h"
+
+static const char* message =
+    "Test forward and inverse real floating-point FFT (Autodetect NEON)\n";
+
+const char* UsageMessage() {
+  return message;
+}
+
+void FinishedMessage() {
+  printf("Tests finished. (Detected %s).\n",
+         HasArmNeon() ? "NEON" : "Non-NEON");
+}
+
+void SetThresholds(struct TestInfo* info) {
+  extern int HasArmNeon();
+
+  if (HasArmNeon()) {
+    info->forward_threshold_ = FLOAT_RFFT_FORWARD_THRESHOLD_NEON;
+    info->inverse_threshold_ = FLOAT_RFFT_INVERSE_THRESHOLD_NEON;
+  } else {
+    info->forward_threshold_ = FLOAT_RFFT_FORWARD_THRESHOLD_ARMV7;
+    info->inverse_threshold_ = FLOAT_RFFT_INVERSE_THRESHOLD_ARMV7;
+  }    
+}
+
+OMXResult ForwardRFFT(OMX_F32* x,
+                      OMX_F32* y,
+                      OMXFFTSpec_R_F32 *fft_fwd_spec) {
+  return omxSP_FFTFwd_RToCCS_F32(x, y, fft_fwd_spec);
+}
+
+OMXResult InverseRFFT(OMX_F32* y,
+                      OMX_F32* z,
+                      OMXFFTSpec_R_F32 *fft_inv_spec) {
+  return omxSP_FFTInv_CCSToR_F32(y, z, fft_inv_spec);
+}
diff --git a/dl/sp/src/test/support/float_rfft_neon.c b/dl/sp/src/test/support/float_rfft_neon.c
new file mode 100644
index 0000000..3ec0846
--- /dev/null
+++ b/dl/sp/src/test/support/float_rfft_neon.c
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "dl/sp/api/armSP.h"
+#include "dl/sp/api/omxSP.h"
+#include "dl/sp/src/test/test_util.h"
+#include "dl/sp/src/test/support/float_rfft_thresholds.h"
+
+static const char* message =
+    "Test forward and inverse real floating-point FFT (NEON)\n";
+
+const char* UsageMessage() {
+  return message;
+}
+
+void FinishedMessage() {
+  printf("NEON tests finished.\n");
+}
+
+void SetThresholds(struct TestInfo* info) {
+  info->forward_threshold_ = FLOAT_RFFT_FORWARD_THRESHOLD_NEON;
+  info->inverse_threshold_ = FLOAT_RFFT_INVERSE_THRESHOLD_NEON;
+}
+
+OMXResult ForwardRFFT(OMX_F32* x,
+                      OMX_F32* y,
+                      OMXFFTSpec_R_F32 *fft_fwd_spec) {
+  return omxSP_FFTFwd_RToCCS_F32_Sfs(x, y, fft_fwd_spec);
+}
+
+OMXResult InverseRFFT(OMX_F32* y,
+                      OMX_F32* z,
+                      OMXFFTSpec_R_F32 *fft_inv_spec) {
+  return omxSP_FFTInv_CCSToR_F32_Sfs(y, z, fft_inv_spec);
+}
diff --git a/dl/sp/src/test/support/float_rfft_thresholds.h b/dl/sp/src/test/support/float_rfft_thresholds.h
new file mode 100644
index 0000000..2d84eec
--- /dev/null
+++ b/dl/sp/src/test/support/float_rfft_thresholds.h
@@ -0,0 +1,36 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_ARM_FLOAT_RFFT_THRESHOLDS_H_
+#define WEBRTC_ARM_FLOAT_RFFT_THRESHOLDS_H_
+
+#if defined(__arm__)
+#ifdef BIG_FFT_TABLE
+#define FLOAT_RFFT_FORWARD_THRESHOLD_NEON (136.07)
+#define FLOAT_RFFT_INVERSE_THRESHOLD_NEON (140.76)
+#define FLOAT_RFFT_FORWARD_THRESHOLD_ARMV7 (134.95)
+#define FLOAT_RFFT_INVERSE_THRESHOLD_ARMV7 (140.69)
+#else
+#define FLOAT_RFFT_FORWARD_THRESHOLD_NEON (136.07)
+#define FLOAT_RFFT_INVERSE_THRESHOLD_NEON (142.41)
+#define FLOAT_RFFT_FORWARD_THRESHOLD_ARMV7 (134.95)
+#define FLOAT_RFFT_INVERSE_THRESHOLD_ARMV7 (142.25)
+#endif
+#else
+#ifdef BIG_FFT_TABLE
+#define FLOAT_RFFT_FORWARD_THRESHOLD_X86 (135.97)
+#define FLOAT_RFFT_INVERSE_THRESHOLD_X86 (140.76)
+#else
+#define FLOAT_RFFT_FORWARD_THRESHOLD_X86 (135.97)
+#define FLOAT_RFFT_INVERSE_THRESHOLD_X86 (142.69)
+#endif
+#endif
+
+#endif /* WEBRTC_ARM_FLOAT_RFFT_THRESHOLDS_H_ */
diff --git a/dl/sp/src/test/support/float_rfft_x86.c b/dl/sp/src/test/support/float_rfft_x86.c
new file mode 100644
index 0000000..0eb06cc
--- /dev/null
+++ b/dl/sp/src/test/support/float_rfft_x86.c
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "dl/sp/api/armSP.h"
+#include "dl/sp/api/omxSP.h"
+#include "dl/sp/src/test/test_util.h"
+#include "dl/sp/src/test/support/float_rfft_thresholds.h"
+
+static const char* message =
+    "Test forward and inverse real floating-point FFT (X86)\n";
+
+const char* UsageMessage() {
+  return message;
+}
+
+void FinishedMessage() {
+  printf("X86 tests finished.\n");
+}
+
+void SetThresholds(struct TestInfo* info) {
+  info->forward_threshold_ = FLOAT_RFFT_FORWARD_THRESHOLD_X86;
+  info->inverse_threshold_ = FLOAT_RFFT_INVERSE_THRESHOLD_X86;
+}
+
+OMXResult ForwardRFFT(OMX_F32* x,
+                      OMX_F32* y,
+                      OMXFFTSpec_R_F32 *fft_fwd_spec) {
+  return omxSP_FFTFwd_RToCCS_F32_Sfs(x, y, fft_fwd_spec);
+}
+
+OMXResult InverseRFFT(OMX_F32* y,
+                      OMX_F32* z,
+                      OMXFFTSpec_R_F32 *fft_inv_spec) {
+  return omxSP_FFTInv_CCSToR_F32_Sfs(y, z, fft_inv_spec);
+}
diff --git a/dl/sp/src/test/test_fft.gyp b/dl/sp/src/test/test_fft.gyp
index c3faca4..99280b5 100644
--- a/dl/sp/src/test/test_fft.gyp
+++ b/dl/sp/src/test/test_fft.gyp
@@ -17,7 +17,7 @@
     ],
     'dependencies' : [
       '../../../dl.gyp:openmax_dl',
-      'test_utilities'
+      'test_utilities',
     ],
     'conditions': [
       ['big_float_fft == 1', {
@@ -77,13 +77,52 @@
           'type': 'executable',
           'sources': [
             'test_float_fft.c',
+            'support/float_fft_neon.c',
+          ],
+        },
+        # Non-NEON test programs
+        {
+          # Test complex floating-point FFT, non-NEON
+          'target_name': 'test_float_fft_armv7',
+          'type': 'executable',
+          'defines': [
+            'ARM_VFP_TEST'
+          ],
+          'sources': [
+            'test_float_fft.c',
+            'support/float_fft_armv7.c',
           ],
         },
         {
-          # Simple timing test of FFTs
-          'target_name': 'test_fft_time',
+          # Test real floating-point FFT, non-NEON
+          'target_name': 'test_float_rfft_armv7',
           'type': 'executable',
           'sources': [
+            'test_float_rfft.c',
+            'support/float_rfft_armv7.c',
+            'support/float_rfft_thresholds.h',
+          ],
+        },
+        {
+          # Test real floating-point FFT, detecting NEON support
+          'target_name': 'test_float_rfft_detect',
+          'type': 'executable',
+          'sources': [
+            'test_float_rfft.c',
+            'support/float_rfft_detect.c',
+            'support/float_rfft_thresholds.h',
+          ],
+        },
+        {
+          # Simple timing test of FFTs, non-NEON
+          'target_name': 'test_fft_time_armv7',
+          'type': 'executable',
+          'defines': [
+            # Timing test for non-NEON is only supported for float FFTs.
+            'ARM_VFP_TEST',
+            'FLOAT_ONLY',
+          ],
+          'sources': [
             'test_fft_time.c',
           ],
         },
@@ -112,6 +151,35 @@
       'type': 'executable',
       'sources': [
         'test_float_rfft.c',
+        'support/float_rfft_thresholds.h',
+      ],
+      'conditions': [
+        ['target_arch == "arm"', {
+          'sources': [
+            'support/float_rfft_neon.c',
+          ],
+        }],
+        ['target_arch == "ia32"', {
+          'sources': [
+            'support/float_rfft_x86.c',
+          ],
+        }],
+      ],
+    },
+    {
+      # Simple timing test of FFTs
+      'target_name': 'test_fft_time',
+      'type': 'executable',
+      'sources': [
+        'test_fft_time.c',
+      ],
+      'conditions': [
+        ['target_arch == "ia32"', {
+          'defines': [
+            # Timing test only for float FFTs on x86
+            'FLOAT_ONLY',
+          ],
+        }],
       ],
     },
     {
@@ -129,13 +197,19 @@
             'test_rfft16_s32',
             'test_rfft16_s16',
             'test_rfft32',
-            'test_fft_time',
+            # Non-Neon tests
+            'test_fft_time_armv7',
+            'test_float_fft_armv7',
+            'test_float_rfft_armv7',
+            # Tests with detection
+            'test_float_rfft_detect',
           ],
         }],
       ],
       'dependencies' : [
         # All architectures must support at least the float rfft test
         'test_float_rfft',
+        'test_fft_time',
       ],
     },
   ],
diff --git a/dl/sp/src/test/test_fft_time.c b/dl/sp/src/test/test_fft_time.c
index 1a68cf4..04228d9 100644
--- a/dl/sp/src/test/test_fft_time.c
+++ b/dl/sp/src/test/test_fft_time.c
@@ -23,29 +23,57 @@
 #define MAX_FFT_ORDER TWIDDLE_TABLE_ORDER
 #define MAX_FFT_ORDER_FIXED_POINT 12
 
+#define ENABLE_FIXED_POINT_FFT_TESTS
+
+#if defined(FLOAT_ONLY) || defined(ARM_VFP_TEST)
+/*
+ * Fixed-point FFTs are disabled if we only want float tests or if
+ * we're building for non-NEON tests.
+ */
+#undef ENABLE_FIXED_POINT_FFT_TESTS
+#endif
+
+#if defined(ARM_VFP_TEST)
+#define FORWARD_FLOAT_FFT   omxSP_FFTFwd_CToC_FC32_Sfs_vfp
+#define INVERSE_FLOAT_FFT   omxSP_FFTInv_CToC_FC32_Sfs_vfp
+#define FORWARD_FLOAT_RFFT  omxSP_FFTFwd_RToCCS_F32_Sfs_vfp
+#define INVERSE_FLOAT_RFFT  omxSP_FFTInv_CCSToR_F32_Sfs_vfp
+#else
+#define FORWARD_FLOAT_FFT   omxSP_FFTFwd_CToC_FC32_Sfs
+#define INVERSE_FLOAT_FFT   omxSP_FFTInv_CToC_FC32_Sfs
+#define FORWARD_FLOAT_RFFT  omxSP_FFTFwd_RToCCS_F32_Sfs
+#define INVERSE_FLOAT_RFFT  omxSP_FFTInv_CCSToR_F32_Sfs
+#endif
+
 typedef enum {
   S16,
   S32,
 } s16_s32;
 
+#if defined(__arm__)
 void TimeOneFloatFFT(int count, int fft_log_size, float signal_value,
                      int signal_type);
 void TimeFloatFFT(int count, float signal_value, int signal_type);
+#endif
+
 void TimeOneFloatRFFT(int count, int fft_log_size, float signal_value,
                       int signal_type);
 void TimeFloatRFFT(int count, float signal_value, int signal_type);
-void TimeOneSC32FFT(int count, int fft_log_size, float signal_value,
-                    int signal_type);
-void TimeSC32FFT(int count, float signal_value, int signal_type);
+
+#ifdef ENABLE_FIXED_POINT_FFT_TESTS
 void TimeOneSC16FFT(int count, int fft_log_size, float signal_value,
                     int signal_type);
 void TimeSC16FFT(int count, float signal_value, int signal_type);
 void TimeOneRFFT16(int count, int fft_log_size, float signal_value,
                    int signal_type, s16_s32 s16s32);
 void TimeRFFT16(int count, float signal_value, int signal_type);
+void TimeOneSC32FFT(int count, int fft_log_size, float signal_value,
+                    int signal_type);
+void TimeSC32FFT(int count, float signal_value, int signal_type);
 void TimeOneRFFT32(int count, int fft_log_size, float signal_value,
                    int signal_type);
 void TimeRFFT32(int count, float signal_value, int signal_type);
+#endif
 
 static int verbose = 1;
 static int include_conversion = 0;
@@ -62,7 +90,11 @@
       "    [-m minFFTsize] [-M maxFFTsize]\n",
           ProgramName(prog));
   fprintf(stderr, 
-      "Simple FFT timing tests\n"
+#ifndef ARM_VFP_TEST
+      "Simple FFT timing tests (NEON)\n"
+#else
+      "Simple FFT timing tests (non-NEON)\n"
+#endif
       "  -h          This help\n"
       "  -v level    Verbose output level (default = 1)\n"
       "  -F          Skip forward FFT tests\n"
@@ -79,11 +111,16 @@
       "  -T          Run just one FFT timing test\n"
       "  -f          FFT type:\n"
       "              0 - Complex Float\n"
+#if defined(__arm__)
       "              1 - Real Float\n"
+#endif
+#ifdef ENABLE_FIXED_POINT_FFT_TESTS
       "              2 - Complex 16-bit\n"
       "              3 - Real 16-bit\n"
       "              4 - Complex 32-bit\n"
       "              5 - Real 32-bit\n"
+#else
+#endif
       "  -n logsize  Log2 of FFT size\n"
       "  -s scale    Scale factor for forward FFT (default = 0)\n"
       "  -S signal   Base value for the test signal (default = 1024)\n"
@@ -179,20 +216,27 @@
     printf("Warning:  -f ignored when -T not specified\n");
 
   if (test_mode) {
+#if defined(__arm__)
     TimeFloatFFT(count, signal_value, signal_type);
+#endif
     TimeFloatRFFT(count, signal_value, signal_type);
+#ifdef ENABLE_FIXED_POINT_FFT_TESTS
     TimeSC16FFT(count, signal_value, signal_type);
     TimeRFFT16(count, signal_value, signal_type);
     TimeSC32FFT(count, signal_value, signal_type);
     TimeRFFT32(count, signal_value, signal_type);
+#endif
   } else {
     switch (fft_type) {
+#if defined(__arm__)
       case 0:
         TimeOneFloatFFT(count, fft_log_size, signal_value, signal_type);
         break;
+#endif
       case 1:
         TimeOneFloatRFFT(count, fft_log_size, signal_value, signal_type);
         break;
+#ifdef ENABLE_FIXED_POINT_FFT_TESTS
       case 2:
         TimeOneSC16FFT(count, fft_log_size, signal_value, signal_type);
         break;
@@ -206,6 +250,7 @@
       case 5:
         TimeOneRFFT32(count, fft_log_size, signal_value, signal_type);
         break;
+#endif
       default:
         fprintf(stderr, "Unknown FFT type: %d\n", fft_type);
         break;
@@ -229,6 +274,17 @@
   return end_time - start_time;
 }
 
+void PrintShortHeader(const char* message) {
+  if (do_forward_test && do_inverse_test) {
+    /* Do nothing if both forward and inverse tests are being run. */
+  } else if (do_forward_test) {
+    printf("Forward ");
+  } else {
+    printf("Inverse ");
+  }
+  printf("%s\n", message);
+}
+
 void PrintResult(const char* prefix, int fft_log_size, double elapsed_time,
                  int count) {
   if (verbose == 0) {
@@ -263,7 +319,8 @@
 
   return count;
 }
-
+
+#if defined(__arm__)
 void TimeOneFloatFFT(int count, int fft_log_size, float signal_value,
                      int signal_type) {
   struct AlignedPtr* x_aligned;
@@ -308,7 +365,7 @@
   if (do_forward_test) {
     GetUserTime(&start_time);
     for (n = 0; n < count; ++n) {
-      omxSP_FFTFwd_CToC_FC32_Sfs(x, y, fft_fwd_spec);
+      FORWARD_FLOAT_FFT(x, y, fft_fwd_spec);
     }
     GetUserTime(&end_time);
 
@@ -320,7 +377,7 @@
   if (do_inverse_test) {
     GetUserTime(&start_time);
     for (n = 0; n < count; ++n) {
-      omxSP_FFTInv_CToC_FC32_Sfs(y, z, fft_inv_spec);
+      INVERSE_FLOAT_FFT(y, z, fft_inv_spec);
     }
     GetUserTime(&end_time);
 
@@ -341,13 +398,14 @@
   int k;
 
   if (verbose == 0)
-    printf("Float FFT\n");
+    PrintShortHeader("Float FFT");
 
   for (k = min_fft_order; k <= max_fft_order; ++k) {
     int testCount = ComputeCount(count, k);
     TimeOneFloatFFT(testCount, k, signal_value, signal_type);
   }
 }
+#endif
 
 void GenerateRealFloatSignal(OMX_F32* x, OMX_FC32* fft, int size,
                              int signal_type, float signal_value)
@@ -427,7 +485,7 @@
   if (do_forward_test) {
     GetUserTime(&start_time);
     for (n = 0; n < count; ++n) {
-      omxSP_FFTFwd_RToCCS_F32_Sfs(x, y, fft_fwd_spec);
+      FORWARD_FLOAT_RFFT(x, y, fft_fwd_spec);
     }
     GetUserTime(&end_time);
 
@@ -439,7 +497,7 @@
   if (do_inverse_test) {
     GetUserTime(&start_time);
     for (n = 0; n < count; ++n) {
-      omxSP_FFTInv_CCSToR_F32_Sfs(y, z, fft_inv_spec);
+      INVERSE_FLOAT_RFFT(y, z, fft_inv_spec);
     }
     GetUserTime(&end_time);
 
@@ -459,14 +517,15 @@
   int k;
 
   if (verbose == 0)
-    printf("Float RFFT\n");
-
+    PrintShortHeader("Float RFFT");
+  
   for (k = min_fft_order; k <= max_fft_order; ++k) {
     int testCount = ComputeCount(count, k);
     TimeOneFloatRFFT(testCount, k, signal_value, signal_type);
   }
 }
 
+#ifdef ENABLE_FIXED_POINT_FFT_TESTS
 void generateSC32Signal(OMX_SC32* x, OMX_SC32* fft, int size, int signal_type,
                         float signal_value) {
   int k;
@@ -641,7 +700,7 @@
       ? MAX_FFT_ORDER_FIXED_POINT : max_fft_order;
 
   if (verbose == 0)
-    printf("SC32 FFT\n");
+    PrintShortHeader("SC32 FFT");
 
   for (k = min_fft_order; k <= max_order; ++k) {
     int testCount = ComputeCount(count, k);
@@ -823,7 +882,7 @@
       ? MAX_FFT_ORDER_FIXED_POINT : max_fft_order;
 
   if (verbose == 0)
-    printf("SC16 FFT\n");
+    PrintShortHeader("SC16 FFT");
 
   for (k = min_fft_order; k <= max_order; ++k) {
     int testCount = ComputeCount(count, k);
@@ -998,10 +1057,12 @@
     elapsed_time = TimeDifference(&start_time, &end_time);
 
     if(s16s32 == S32) {
-      PrintResult("Forward RFFT16 (with S32)", fft_log_size, elapsed_time, count);
+      PrintResult("Forward RFFT16 (with S32)",
+		  fft_log_size, elapsed_time, count);
     }
     else {
-      PrintResult("Forward RFFT16 (with S16)", fft_log_size, elapsed_time, count);
+      PrintResult("Forward RFFT16 (with S16)",
+		  fft_log_size, elapsed_time, count);
     }
   }
 
@@ -1059,10 +1120,12 @@
     elapsed_time = TimeDifference(&start_time, &end_time);
 
     if(s16s32 == S32) {
-      PrintResult("Inverse RFFT16 (with S32)", fft_log_size, elapsed_time, count);
+      PrintResult("Inverse RFFT16 (with S32)",
+		  fft_log_size, elapsed_time, count);
     }
     else {
-      PrintResult("Inverse RFFT16 (with S16)", fft_log_size, elapsed_time, count);
+      PrintResult("Inverse RFFT16 (with S16)",
+		  fft_log_size, elapsed_time, count);
     }
   }
 
@@ -1082,14 +1145,16 @@
       ? MAX_FFT_ORDER_FIXED_POINT : max_fft_order;
 
   if (verbose == 0)
-    printf("RFFT16 (with S32)\n");
+    PrintShortHeader("RFFT16 (with S32)");
+
   for (k = min_fft_order; k <= max_order; ++k) {
     int testCount = ComputeCount(count, k);
     TimeOneRFFT16(testCount, k, signal_value, signal_type, 1);
   }
 
   if (verbose == 0)
-    printf("RFFT16 (with S16)\n");
+    PrintShortHeader("RFFT16 (with S16)");
+
   for (k = min_fft_order; k <= max_order; ++k) {
     int testCount = ComputeCount(count, k);
     TimeOneRFFT16(testCount, k, signal_value, signal_type, 0);
@@ -1309,10 +1374,11 @@
       ? MAX_FFT_ORDER_FIXED_POINT : max_fft_order;
 
   if (verbose == 0)
-    printf("RFFT32\n");
+    PrintShortHeader("RFFT32");
 
   for (k = min_fft_order; k <= max_order; ++k) {
     int testCount = ComputeCount(count, k);
     TimeOneRFFT32(testCount, k, signal_value, signal_type);
   }
 }
+#endif
diff --git a/dl/sp/src/test/test_float_fft.c b/dl/sp/src/test/test_float_fft.c
index 925aee3..289b197 100644
--- a/dl/sp/src/test/test_float_fft.c
+++ b/dl/sp/src/test/test_float_fft.c
@@ -25,20 +25,35 @@
 
 int verbose;
 
-void main(int argc, char* argv[]) {
+extern const char* UsageMessage();
+extern void FinishedMessage();
+extern void SetThresholds(struct TestInfo *info);
+extern OMXResult ForwardFFT(OMX_FC32* x,
+                            OMX_FC32* y,
+                            OMXFFTSpec_R_F32 *fft_fwd_spec);
+extern OMXResult InverseFFT(OMX_FC32* y,
+                            OMX_FC32* z,
+                            OMXFFTSpec_R_F32 *fft_inv_spec);
+
+void TestFloatFFT(int fft_log_size,
+                  int sigtype,
+                  float signal_value,
+                  const struct TestInfo* info);
+
+int main(int argc, char* argv[]) {
   struct Options options;
   struct TestInfo info;
+  int failed_count = 0;
 
   SetDefaultOptions(&options, 0, MAX_FFT_ORDER);
 
-  ProcessCommandLine(&options, argc, argv,
-                     "Test forward and inverse floating-point FFT\n");
+  ProcessCommandLine(&options,
+                     argc,
+                     argv,
+                     UsageMessage());
 
   verbose = options.verbose_;
 
-  if (verbose > 255)
-    DumpOptions(stderr, &options);
-
   info.real_only_ = options.real_only_;
   info.max_fft_order_ = options.max_fft_order_;
   info.min_fft_order_ = options.min_fft_order_;
@@ -47,11 +62,13 @@
   /* No known failures */
   info.known_failures_ = 0;
 
-  info.forward_threshold_ = 138.81;
-  info.inverse_threshold_ = 138.81;
+  SetThresholds(&info);
+
+  if (verbose > 255)
+    DumpOptions(stderr, &options);
 
   if (options.test_mode_) {
-    RunAllTests(&info);
+    failed_count = RunAllTests(&info);
   } else {
     TestOneFFT(options.fft_log_size_,
                options.signal_type_,
@@ -59,6 +76,9 @@
                &info,
                "Float FFT");
   }
+
+  FinishedMessage();
+  return failed_count > 0 ? 1 : 0;
 }
 
 void DumpFFTSpec(OMXFFTSpec_C_FC32* pSpec) {
@@ -118,6 +138,12 @@
 
   GenerateSignal(x, y_true, fft_size, signal_type, signal_value);
 
+  if (verbose > 255) {
+    printf("&x      = %p\n", (void*) x);
+    printf("&y      = %p\n", (void*) y);
+    printf("&buffer = %p\n", (void*) ((ARMsFFTSpec_R_FC32*)fft_fwd_spec)->pBuf);
+  }
+
   if (verbose > 63) {
     printf("Signal\n");
     DumpArrayComplexFloat("x", fft_size, x);
@@ -126,7 +152,8 @@
     DumpArrayComplexFloat("y", fft_size, y_true);
   }
 
-  status = omxSP_FFTFwd_CToC_FC32_Sfs(x, y, fft_fwd_spec);
+  status = ForwardFFT(x, y, fft_fwd_spec);
+
   if (status) {
     fprintf(stderr, "Forward FFT failed: status = %d\n", status);
     exit(1);
@@ -194,7 +221,8 @@
     DumpArrayComplexFloat("x", fft_size, x);
   }
 
-  status = omxSP_FFTInv_CToC_FC32_Sfs(y, z, fft_inv_spec);
+  status = InverseFFT(y, z, fft_inv_spec);
+
   if (status) {
     fprintf(stderr, "Inverse FFT failed: status = %d\n", status);
     exit(1);
diff --git a/dl/sp/src/test/test_float_rfft.c b/dl/sp/src/test/test_float_rfft.c
index 0cfa443..a976162 100644
--- a/dl/sp/src/test/test_float_rfft.c
+++ b/dl/sp/src/test/test_float_rfft.c
@@ -29,20 +29,31 @@
  */
 int verbose;
 
-void main(int argc, char* argv[]) {
+extern const char* UsageMessage();
+extern void FinishedMessage();
+extern void SetThresholds(struct TestInfo *info);
+extern OMXResult ForwardRFFT(OMX_F32* x,
+                             OMX_F32* y,
+                             OMXFFTSpec_R_F32 *fft_fwd_spec);
+extern OMXResult InverseRFFT(OMX_F32* y,
+                             OMX_F32* z,
+                             OMXFFTSpec_R_F32 *fft_inv_spec);
+void TestFloatFFT(int fft_log_size, int sigtype, float signal_value);
+
+int main(int argc, char* argv[]) {
   struct Options options;
   struct TestInfo info;
+  int failed_count = 0;
 
   SetDefaultOptions(&options, 1, MAX_FFT_ORDER);
 
-  ProcessCommandLine(&options, argc, argv,
-                     "Test forward and inverse real floating-point FFT\n");
+  ProcessCommandLine(&options,
+                     argc,
+                     argv,
+                     UsageMessage());
 
   verbose = options.verbose_;
 
-  if (verbose > 255)
-    DumpOptions(stderr, &options);
-
   info.real_only_ = options.real_only_;
   info.min_fft_order_ = options.min_fft_order_;
   info.max_fft_order_ = options.max_fft_order_;
@@ -50,26 +61,14 @@
   info.do_inverse_tests_ = options.do_inverse_tests_;
   /* No known failures */
   info.known_failures_ = 0;
-#ifdef BIG_FFT_TABLE
-#if defined(__arm__)
-  info.forward_threshold_ = 136.07;
-  info.inverse_threshold_ = 140.76;
-#else
-  info.forward_threshold_ = 135.97;
-  info.inverse_threshold_ = 140.76;
-#endif
-#else
-#if defined(__arm__)
-  info.forward_threshold_ = 136.07;
-  info.inverse_threshold_ = 142.41;
-#else
-  info.forward_threshold_ = 135.97;
-  info.inverse_threshold_ = 142.69;
-#endif
-#endif
+
+  SetThresholds(&info);
+
+  if (verbose > 255)
+    DumpOptions(stderr, &options);
 
   if (options.test_mode_) {
-    RunAllTests(&info);
+    failed_count = RunAllTests(&info);
   } else {
     TestOneFFT(options.fft_log_size_,
                options.signal_type_,
@@ -77,15 +76,21 @@
                &info,
                "Float Real FFT");
   }
+  FinishedMessage();
+
+  return failed_count > 0 ? 1 : 0;
 }
 
 /* Briefly print out the contents of the FFT spec */
 void DumpFFTSpec(OMXFFTSpec_R_F32* pSpec) {
   ARMsFFTSpec_R_FC32* p = (ARMsFFTSpec_R_FC32*) pSpec;
+  printf("FFTSpec %p:\n", (void*) pSpec);
   printf(" N = %d\n", p->N);
   printf(" pBitRev  = %p\n", p->pBitRev);
-  printf(" pTwiddle = %p\n", p->pTwiddle);
-  printf(" pBuf     = %p\n", p->pBuf);
+  /* See omxSP_FFTGetBufSize_R_S32 for the size of the twiddle table. */
+  printf(" pTwiddle = %p - %p\n", p->pTwiddle, p->pTwiddle + (5 * p->N / 8));
+  /* See omxSP_FFTGetBufSize_R_S32 for the size of pBuf. */
+  printf(" pBuf     = %p - %p\n", p->pBuf, p->pBuf + (p->N << 1));
 }
 
 /*
@@ -157,15 +162,21 @@
 
   GenerateSignal(x, y_true, fft_size, signal_type, signal_value);
 
+  if (verbose > 255) {
+    printf("input  = %p - %p\n", x, x + fft_size);
+    printf("output = %p - %p\n", y, y + fft_size / 2 + 1);
+    DumpFFTSpec(fft_fwd_spec);
+  }
+
   if (verbose > 63) {
     printf("Signal\n");
     DumpArrayFloat("x", fft_size, x);
 
     printf("Expected FFT output\n");
-    DumpArrayComplexFloat("y", fft_size / 2, y_true);
+    DumpArrayComplexFloat("y", 1 + fft_size / 2, y_true);
   }
 
-  status = omxSP_FFTFwd_RToCCS_F32_Sfs(x, (OMX_F32*) y, fft_fwd_spec);
+  status = ForwardRFFT(x, (OMX_F32*) y, fft_fwd_spec);
   if (status) {
     fprintf(stderr, "Forward FFT failed: status = %d\n", status);
     exit(1);
@@ -173,7 +184,7 @@
 
   if (verbose > 63) {
     printf("FFT Output\n");
-    DumpArrayComplexFloat("y", fft_size / 2, y);
+    DumpArrayComplexFloat("y", 1 + fft_size / 2, y);
   }
 
   CompareComplexFloat(snr, y, y_true, fft_size / 2 + 1);
@@ -231,15 +242,21 @@
 
   GenerateSignal(x, yTrue, fft_size, signal_type, signal_value);
 
+  if (verbose > 255) {
+    printf("input  = %p - %p\n", yTrue, yTrue + fft_size / 2 + 1);
+    printf("output = %p - %p\n", z, z + fft_size);
+    DumpFFTSpec(fft_inv_spec);
+  }
+
   if (verbose > 63) {
     printf("Inverse FFT Input Signal\n");
-    DumpArrayComplexFloat("y", fft_size / 2, yTrue);
+    DumpArrayComplexFloat("y", 1 + fft_size / 2, yTrue);
 
     printf("Expected Inverse FFT output\n");
     DumpArrayFloat("x", fft_size, x);
   }
 
-  status = omxSP_FFTInv_CCSToR_F32_Sfs((OMX_F32 *) yTrue, z, fft_inv_spec);
+  status = InverseRFFT((OMX_F32 *) yTrue, z, fft_inv_spec);
   if (status) {
     fprintf(stderr, "Inverse FFT failed: status = %d\n", status);
     exit(1);
diff --git a/dl/sp/src/test/test_util.c b/dl/sp/src/test/test_util.c
index 63e2a6b..e9ca0cf 100644
--- a/dl/sp/src/test/test_util.c
+++ b/dl/sp/src/test/test_util.c
@@ -332,6 +332,13 @@
   RunTests(result, RunOneForwardTest, "FwdFFT", 0, info, snr_threshold);
 }
 
+void initializeTestResult(struct TestResult *result) {
+  result->failed_count_ = 0;
+  result->test_count_ = 0;
+  result->expected_failure_count_ = 0;
+  result->min_snr_ = 1000;
+}
+
 /*
  * For all FFT orders and signal types, run the inverse FFT.
  * runOneInverseTest must be defined to compute the forward FFT and
@@ -349,7 +356,7 @@
  * Run all forward and inverse FFT tests, printing a summary of the
  * results.
  */
-void RunAllTests(const struct TestInfo* info) {
+int RunAllTests(const struct TestInfo* info) {
   int failed;
   int total;
   float min_forward_snr;
@@ -357,6 +364,9 @@
   struct TestResult forward_results;
   struct TestResult inverse_results;
 
+  initializeTestResult(&forward_results);
+  initializeTestResult(&inverse_results);
+
   if (info->do_forward_tests_)
     RunForwardTests(&forward_results, info, info->forward_threshold_);
   if (info->do_inverse_tests_)
@@ -392,6 +402,8 @@
   } else {
     printf("No tests run\n");
   }
+
+  return failed;
 }
 
 /*
diff --git a/dl/sp/src/test/test_util.h b/dl/sp/src/test/test_util.h
index 482f742..6293b9c 100644
--- a/dl/sp/src/test/test_util.h
+++ b/dl/sp/src/test/test_util.h
@@ -141,7 +141,7 @@
 /*
  * Run all FFT tests, as specified by |info|
  */
-void RunAllTests(const struct TestInfo* info);
+int RunAllTests(const struct TestInfo* info);
 
 /*
  * Returns the program name, for debugging.