From af537b8206a515f942e5ee0338113bd485b55eb7 Mon Sep 17 00:00:00 2001 From: Andrew Hsieh Date: Fri, 2 Nov 2012 21:54:11 -0700 Subject: Fix ARM hardfloat detection in linux See http://code.google.com/p/v8/issues/detail?id=2140 https://chromiumcodereview.appspot.com/10713009 The original code fails to detect at run-time when compiled with GCC 4.7, because the undefined behavior of casting void to double, and the r0/r1 clobbered in assembly code isn't reaching the use when compared to 1.0 in VFP reg. In summary, the old code is incorrect and overkill, and the new code fix it. Change-Id: I6b63a4f9789e08089368e431a5553f482400725a --- src/platform-linux.cc | 71 ++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/src/platform-linux.cc b/src/platform-linux.cc index 9781407e..6c4a549c 100644 --- a/src/platform-linux.cc +++ b/src/platform-linux.cc @@ -190,48 +190,43 @@ bool OS::ArmCpuHasFeature(CpuFeature feature) { } -// Simple helper function to detect whether the C code is compiled with -// option -mfloat-abi=hard. The register d0 is loaded with 1.0 and the register -// pair r0, r1 is loaded with 0.0. If -mfloat-abi=hard is pased to GCC then -// calling this will return 1.0 and otherwise 0.0. -static void ArmUsingHardFloatHelper() { - asm("mov r0, #0":::"r0"); -#if defined(__VFP_FP__) && !defined(__SOFTFP__) - // Load 0x3ff00000 into r1 using instructions available in both ARM - // and Thumb mode. - asm("mov r1, #3":::"r1"); - asm("mov r2, #255":::"r2"); - asm("lsl r1, r1, #8":::"r1"); - asm("orr r1, r1, r2":::"r1"); - asm("lsl r1, r1, #20":::"r1"); - // For vmov d0, r0, r1 use ARM mode. -#ifdef __thumb__ - asm volatile( - "@ Enter ARM Mode \n\t" - " adr r3, 1f \n\t" - " bx r3 \n\t" - " .ALIGN 4 \n\t" - " .ARM \n" - "1: vmov d0, r0, r1 \n\t" - "@ Enter THUMB Mode\n\t" - " adr r3, 2f+1 \n\t" - " bx r3 \n\t" - " .THUMB \n" - "2: \n\t":::"r3"); +bool OS::ArmUsingHardFloat() { + // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify + // the Floating Point ABI used (PCS stands for Procedure Call Standard). + // We use these as well as a couple of other defines to statically determine + // what FP ABI used. + // GCC versions 4.4 and below don't support hard-fp. + // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or + // __ARM_PCS_VFP. + +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#if GCC_VERSION >= 40600 +#if defined(__ARM_PCS_VFP) + return true; #else - asm("vmov d0, r0, r1"); -#endif // __thumb__ -#endif // defined(__VFP_FP__) && !defined(__SOFTFP__) - asm("mov r1, #0":::"r1"); -} + return false; +#endif +#elif GCC_VERSION < 40500 + return false; -bool OS::ArmUsingHardFloat() { - // Cast helper function from returning void to returning double. - typedef double (*F)(); - F f = FUNCTION_CAST(FUNCTION_ADDR(ArmUsingHardFloatHelper)); - return f() == 1.0; +#else +#if defined(__ARM_PCS_VFP) + return true; +#elif defined(__ARM_PCS) || defined(__SOFTFP) || !defined(__VFP_FP__) + return false; +#else +#error "Your version of GCC does not report the FP ABI compiled for." \ + "Please report it on this issue" \ + "http://code.google.com/p/v8/issues/detail?id=2140" + +#endif +#endif +#undef GCC_VERSION } + #endif // def __arm__ -- cgit v1.2.3