cmd/dist: re-enable GOARM auto-detection

cmd/dist will re-exec itself to detect VFP support at run-time.

Fixes #9732, #12548.

Change-Id: I9ad0c5c7fa3e97bd79a32da372e1a962565bb3af
Reviewed-on: https://go-review.googlesource.com/3973
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
index f13210f..34cbf50 100644
--- a/src/cmd/dist/util.go
+++ b/src/cmd/dist/util.go
@@ -480,6 +480,14 @@
 		}
 	}
 
+	if len(os.Args) > 1 && os.Args[1] == "-check-goarm" {
+		useVFPv1() // might fail with SIGILL
+		println("VFPv1 OK.")
+		useVFPv3() // might fail with SIGILL
+		println("VFPv3 OK.")
+		os.Exit(0)
+	}
+
 	xinit()
 	xmain()
 	xexit(0)
@@ -515,40 +523,21 @@
 		// OpenBSD currently only supports softfloat.
 		return "5"
 	}
-	if goos != "linux" {
-		// All other arm platforms that we support
-		// require ARMv7.
+
+	// Try to exec ourselves in a mode to detect VFP support.
+	// Seeing how far it gets determines which instructions failed.
+	// The test is OS-agnostic.
+	out := run("", 0, os.Args[0], "-check-goarm")
+	v1ok := strings.Contains(out, "VFPv1 OK.")
+	v3ok := strings.Contains(out, "VFPv3 OK.")
+
+	if v1ok && v3ok {
 		return "7"
 	}
-	cpuinfo := readfile("/proc/cpuinfo")
-	goarm := "5"
-	for _, line := range splitlines(cpuinfo) {
-		line := strings.SplitN(line, ":", 2)
-		if len(line) < 2 {
-			continue
-		}
-		if strings.TrimSpace(line[0]) != "Features" {
-			continue
-		}
-		features := splitfields(line[1])
-		sort.Strings(features) // so vfpv3 sorts after vfp
-
-		// Infer GOARM value from the vfp features available
-		// on this host. Values of GOARM detected are:
-		// 5: no vfp support was found
-		// 6: vfp (v1) support was detected, but no higher
-		// 7: vfpv3 support was detected.
-		// This matches the assertions in runtime.checkarm.
-		for _, f := range features {
-			switch f {
-			case "vfp":
-				goarm = "6"
-			case "vfpv3":
-				goarm = "7"
-			}
-		}
+	if v1ok {
+		return "6"
 	}
-	return goarm
+	return "5"
 }
 
 func min(a, b int) int {
diff --git a/src/cmd/dist/util_gc.go b/src/cmd/dist/util_gc.go
index 9f6cfd0..81e52b6 100644
--- a/src/cmd/dist/util_gc.go
+++ b/src/cmd/dist/util_gc.go
@@ -17,3 +17,11 @@
 	cpuid(&info, 1)
 	return info[3]&(1<<26) != 0 // SSE2
 }
+
+// useVFPv1 tries to execute one VFPv1 instruction on ARM.
+// It will crash the current process if VFPv1 is missing.
+func useVFPv1()
+
+// useVFPv3 tries to execute one VFPv3 instruction on ARM.
+// It will crash the current process if VFPv3 is missing.
+func useVFPv3()
diff --git a/src/cmd/dist/util_gccgo.go b/src/cmd/dist/util_gccgo.go
index 14ac70b..18e328f 100644
--- a/src/cmd/dist/util_gccgo.go
+++ b/src/cmd/dist/util_gccgo.go
@@ -18,3 +18,7 @@
 import "C"
 
 func cansse2() bool { return C.supports_sse2() != 0 }
+
+func useVFPv1() {}
+
+func useVFPv3() {}
diff --git a/src/cmd/dist/vfp_arm.s b/src/cmd/dist/vfp_arm.s
new file mode 100644
index 0000000..647c439
--- /dev/null
+++ b/src/cmd/dist/vfp_arm.s
@@ -0,0 +1,17 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build gc,arm
+
+#include "textflag.h"
+
+// try to run "vmov.f64 d0, d0" instruction
+TEXT ·useVFPv1(SB),NOSPLIT,$0
+	WORD $0xeeb00b40	// vmov.f64 d0, d0
+	RET
+
+// try to run VFPv3-only "vmov.f64 d0, #112" instruction
+TEXT ·useVFPv3(SB),NOSPLIT,$0
+	WORD $0xeeb70b00	// vmov.f64 d0, #112
+	RET
diff --git a/src/cmd/dist/vfp_default.s b/src/cmd/dist/vfp_default.s
new file mode 100644
index 0000000..5cf9997
--- /dev/null
+++ b/src/cmd/dist/vfp_default.s
@@ -0,0 +1,13 @@
+// Copyright 2015 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !arm,gc
+
+#include "textflag.h"
+
+TEXT ·useVFPv1(SB),NOSPLIT,$0
+	RET
+
+TEXT ·useVFPv3(SB),NOSPLIT,$0
+	RET