From b8f7da6c5a244c4015da1e739f7f40b21f4c40c8 Mon Sep 17 00:00:00 2001 From: Guoqi Chen Date: Thu, 6 Mar 2025 19:41:06 +0800 Subject: [PATCH] cpu: add support for detecting cpu features on loong64 Except for lasx, all other features have been implemented in the Go mainline. Change-Id: I61a09396ed23d17991b641a1265e952585cb5636 Reviewed-on: https://go-review.googlesource.com/c/sys/+/655355 Reviewed-by: David Chase Reviewed-by: sophie zhao LUCI-TryBot-Result: Go LUCI Reviewed-by: Junyang Shao Reviewed-by: Meidan Li --- cpu/cpu.go | 12 ++++++++++++ cpu/cpu_linux_loong64.go | 22 ++++++++++++++++++++++ cpu/cpu_linux_noinit.go | 2 +- cpu/cpu_loong64.go | 38 ++++++++++++++++++++++++++++++++++++++ cpu/cpu_loong64.s | 12 ++++++++++++ cpu/cpu_test.go | 8 ++++++++ 6 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 cpu/cpu_linux_loong64.go create mode 100644 cpu/cpu_loong64.s diff --git a/cpu/cpu.go b/cpu/cpu.go index 9c105f23..2e73ee19 100644 --- a/cpu/cpu.go +++ b/cpu/cpu.go @@ -149,6 +149,18 @@ var ARM struct { _ CacheLinePad } +// The booleans in Loong64 contain the correspondingly named cpu feature bit. +// The struct is padded to avoid false sharing. +var Loong64 struct { + _ CacheLinePad + HasLSX bool // support 128-bit vector extension + HasLASX bool // support 256-bit vector extension + HasCRC32 bool // support CRC instruction + HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction + HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} instruction + _ CacheLinePad +} + // MIPS64X contains the supported CPU features of the current mips64/mips64le // platforms. If the current platform is not mips64/mips64le or the current // operating system is not Linux then all feature flags are false. diff --git a/cpu/cpu_linux_loong64.go b/cpu/cpu_linux_loong64.go new file mode 100644 index 00000000..4f341143 --- /dev/null +++ b/cpu/cpu_linux_loong64.go @@ -0,0 +1,22 @@ +// Copyright 2025 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. + +package cpu + +// HWCAP bits. These are exposed by the Linux kernel. +const ( + hwcap_LOONGARCH_LSX = 1 << 4 + hwcap_LOONGARCH_LASX = 1 << 5 +) + +func doinit() { + // TODO: Features that require kernel support like LSX and LASX can + // be detected here once needed in std library or by the compiler. + Loong64.HasLSX = hwcIsSet(hwCap, hwcap_LOONGARCH_LSX) + Loong64.HasLASX = hwcIsSet(hwCap, hwcap_LOONGARCH_LASX) +} + +func hwcIsSet(hwc uint, val uint) bool { + return hwc&val != 0 +} diff --git a/cpu/cpu_linux_noinit.go b/cpu/cpu_linux_noinit.go index 7d902b68..a428dec9 100644 --- a/cpu/cpu_linux_noinit.go +++ b/cpu/cpu_linux_noinit.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64 +//go:build linux && !arm && !arm64 && !loong64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64 package cpu diff --git a/cpu/cpu_loong64.go b/cpu/cpu_loong64.go index 55863585..45ecb29a 100644 --- a/cpu/cpu_loong64.go +++ b/cpu/cpu_loong64.go @@ -8,5 +8,43 @@ package cpu const cacheLineSize = 64 +// Bit fields for CPUCFG registers, Related reference documents: +// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_cpucfg +const ( + // CPUCFG1 bits + cpucfg1_CRC32 = 1 << 25 + + // CPUCFG2 bits + cpucfg2_LAM_BH = 1 << 27 + cpucfg2_LAMCAS = 1 << 28 +) + func initOptions() { + options = []option{ + {Name: "lsx", Feature: &Loong64.HasLSX}, + {Name: "lasx", Feature: &Loong64.HasLASX}, + {Name: "crc32", Feature: &Loong64.HasCRC32}, + {Name: "lam_bh", Feature: &Loong64.HasLAM_BH}, + {Name: "lamcas", Feature: &Loong64.HasLAMCAS}, + } + + // The CPUCFG data on Loong64 only reflects the hardware capabilities, + // not the kernel support status, so features such as LSX and LASX that + // require kernel support cannot be obtained from the CPUCFG data. + // + // These features only require hardware capability support and do not + // require kernel specific support, so they can be obtained directly + // through CPUCFG + cfg1 := get_cpucfg(1) + cfg2 := get_cpucfg(2) + + Loong64.HasCRC32 = cfgIsSet(cfg1, cpucfg1_CRC32) + Loong64.HasLAMCAS = cfgIsSet(cfg2, cpucfg2_LAMCAS) + Loong64.HasLAM_BH = cfgIsSet(cfg2, cpucfg2_LAM_BH) +} + +func get_cpucfg(reg uint32) uint32 + +func cfgIsSet(cfg uint32, val uint32) bool { + return cfg&val != 0 } diff --git a/cpu/cpu_loong64.s b/cpu/cpu_loong64.s new file mode 100644 index 00000000..30b4c0d1 --- /dev/null +++ b/cpu/cpu_loong64.s @@ -0,0 +1,12 @@ +// Copyright 2025 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. + +#include "textflag.h" + +// func get_cpucfg(reg uint32) uint32 +TEXT ·get_cpucfg(SB), NOSPLIT|NOFRAME, $0 + MOVW reg+0(FP), R5 + CPUCFG R5, R4 + MOVW R4, ret+8(FP) + RET diff --git a/cpu/cpu_test.go b/cpu/cpu_test.go index dd493ece..69067864 100644 --- a/cpu/cpu_test.go +++ b/cpu/cpu_test.go @@ -87,6 +87,14 @@ func TestARM64minimalFeatures(t *testing.T) { } } +func TestLOONG64Initialized(t *testing.T) { + if runtime.GOARCH == "loong64" { + if !cpu.Initialized { + t.Fatal("Initialized expected true, got false") + } + } +} + func TestMIPS64Initialized(t *testing.T) { if runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" { if !cpu.Initialized {