From e8b5bc63be22e2bebffabcfccaf54d4c19822fe6 Mon Sep 17 00:00:00 2001 From: Andrey Bokhanko Date: Tue, 30 Jan 2024 19:18:24 +0300 Subject: [PATCH] cmd/dist,internal: add GOARM64 environment variable Adds GOARM64 environment variable with accepted range of values "v8.{0-9}", "v9.{0-5}" and optional ",lse" and ",crypto" suffixes. Right now it doesn't affect anything, but can be used in the future to selectively target specific versions of different ARM64 hardware. For #60905 Change-Id: I6d530041b6931aa884e34f719f8ec41b1cb03ece Reviewed-on: https://go-review.googlesource.com/c/go/+/559555 LUCI-TryBot-Result: Go LUCI Reviewed-by: Mauri de Souza Meneguzzo Reviewed-by: Cherry Mui Reviewed-by: Shu-Chun Weng Reviewed-by: Fannie Zhang --- src/cmd/dist/build.go | 11 +++ src/cmd/dist/buildruntime.go | 1 + src/cmd/go/alldocs.go | 9 +++ src/cmd/go/internal/help/helpdoc.go | 9 +++ src/internal/buildcfg/cfg.go | 117 ++++++++++++++++++++++++++++ src/internal/buildcfg/cfg_test.go | 85 ++++++++++++++++++++ src/internal/cfg/cfg.go | 1 + 7 files changed, 233 insertions(+) diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index d4d1bd8f0b512c..64f8f530543d78 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -33,6 +33,7 @@ var ( gohostos string goos string goarm string + goarm64 string go386 string goamd64 string gomips string @@ -141,6 +142,12 @@ func xinit() { } goarm = b + b = os.Getenv("GOARM64") + if b == "" { + b = "v8.0" + } + goarm64 = b + b = os.Getenv("GO386") if b == "" { b = "sse2" @@ -230,6 +237,7 @@ func xinit() { os.Setenv("GOAMD64", goamd64) os.Setenv("GOARCH", goarch) os.Setenv("GOARM", goarm) + os.Setenv("GOARM64", goarm64) os.Setenv("GOHOSTARCH", gohostarch) os.Setenv("GOHOSTOS", gohostos) os.Setenv("GOOS", goos) @@ -1239,6 +1247,9 @@ func cmdenv() { if goarch == "arm" { xprintf(format, "GOARM", goarm) } + if goarch == "arm64" { + xprintf(format, "GOARM64", goarm64) + } if goarch == "386" { xprintf(format, "GO386", go386) } diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go index b041183bdf58d4..7095f437726284 100644 --- a/src/cmd/dist/buildruntime.go +++ b/src/cmd/dist/buildruntime.go @@ -54,6 +54,7 @@ func mkbuildcfg(file string) { fmt.Fprintf(&buf, "const defaultGO386 = `%s`\n", go386) fmt.Fprintf(&buf, "const defaultGOAMD64 = `%s`\n", goamd64) fmt.Fprintf(&buf, "const defaultGOARM = `%s`\n", goarm) + fmt.Fprintf(&buf, "const defaultGOARM64 = `%s`\n", goarm64) fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips) fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64) fmt.Fprintf(&buf, "const defaultGOPPC64 = `%s`\n", goppc64) diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 153128e715151b..dde47ac1b86bb3 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1990,6 +1990,8 @@ // correspond to the amd64.v1, amd64.v2, and amd64.v3 feature build tags. // - For GOARCH=arm, GOARM=5, 6, and 7 // correspond to the arm.5, arm.6, and arm.7 feature build tags. +// - For GOARCH=arm64, GOARM64=v8.{0-9} and v9.{0-5} +// correspond to the arm64.v8.{0-9} and arm64.v9.{0-5} feature build tags. // - For GOARCH=mips or mipsle, // GOMIPS=hardfloat and softfloat // correspond to the mips.hardfloat and mips.softfloat @@ -2289,6 +2291,13 @@ // Valid values are 5, 6, 7. // The value can be followed by an option specifying how to implement floating point instructions. // Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7). +// GOARM64 +// For GOARCH=arm64, the ARM64 architecture for which to compile. +// Valid values are v8.0 (default), v8.{1-9}, v9.{0-5}. +// The value can be followed by an option specifying extensions implemented by target hardware. +// Valid options are ,lse and ,crypto. +// Note that some extensions are enabled by default starting from a certain GOARM64 version; +// for example, lse is enabled by default starting from v8.1. // GO386 // For GOARCH=386, how to implement floating point instructions. // Valid values are sse2 (default), softfloat. diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index ddaca3807af7af..e1d719be4f1cf0 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -603,6 +603,13 @@ Architecture-specific environment variables: Valid values are 5, 6, 7. The value can be followed by an option specifying how to implement floating point instructions. Valid options are ,softfloat (default for 5) and ,hardfloat (default for 6 and 7). + GOARM64 + For GOARCH=arm64, the ARM64 architecture for which to compile. + Valid values are v8.0 (default), v8.{1-9}, v9.{0-5}. + The value can be followed by an option specifying extensions implemented by target hardware. + Valid options are ,lse and ,crypto. + Note that some extensions are enabled by default starting from a certain GOARM64 version; + for example, lse is enabled by default starting from v8.1. GO386 For GOARCH=386, how to implement floating point instructions. Valid values are sse2 (default), softfloat. @@ -893,6 +900,8 @@ The defined architecture feature build tags are: correspond to the amd64.v1, amd64.v2, and amd64.v3 feature build tags. - For GOARCH=arm, GOARM=5, 6, and 7 correspond to the arm.5, arm.6, and arm.7 feature build tags. + - For GOARCH=arm64, GOARM64=v8.{0-9} and v9.{0-5} + correspond to the arm64.v8.{0-9} and arm64.v9.{0-5} feature build tags. - For GOARCH=mips or mipsle, GOMIPS=hardfloat and softfloat correspond to the mips.hardfloat and mips.softfloat diff --git a/src/internal/buildcfg/cfg.go b/src/internal/buildcfg/cfg.go index 61810f1348258e..b074a36b941f7f 100644 --- a/src/internal/buildcfg/cfg.go +++ b/src/internal/buildcfg/cfg.go @@ -26,6 +26,7 @@ var ( GO386 = envOr("GO386", defaultGO386) GOAMD64 = goamd64() GOARM = goarm() + GOARM64 = goarm64() GOMIPS = gomips() GOMIPS64 = gomips64() GOPPC64 = goppc64() @@ -126,6 +127,106 @@ func goarm() (g goarmFeatures) { return } +type goarm64Features struct { + Version string + // Large Systems Extension + LSE bool + // ARM v8.0 Cryptographic Extension. It includes the following features: + // * FEAT_AES, which includes the AESD and AESE instructions. + // * FEAT_PMULL, which includes the PMULL, PMULL2 instructions. + // * FEAT_SHA1, which includes the SHA1* instructions. + // * FEAT_SHA256, which includes the SHA256* instructions. + Crypto bool +} + +func (g goarm64Features) String() string { + arm64Str := g.Version + if g.LSE { + arm64Str += ",lse" + } + if g.Crypto { + arm64Str += ",crypto" + } + return arm64Str +} + +func parseGoarm64(v string) (g goarm64Features) { + const ( + lseOpt = ",lse" + cryptoOpt = ",crypto" + ) + + g.LSE = false + g.Crypto = false + // We allow any combination of suffixes, in any order + for { + if strings.HasSuffix(v, lseOpt) { + g.LSE = true + v = v[:len(v)-len(lseOpt)] + continue + } + + if strings.HasSuffix(v, cryptoOpt) { + g.Crypto = true + v = v[:len(v)-len(cryptoOpt)] + continue + } + + break + } + + switch v { + case "v8.0": + g.Version = v + case "v8.1", "v8.2", "v8.3", "v8.4", "v8.5", "v8.6", "v8.7", "v8.8", "v8.9", + "v9.0", "v9.1", "v9.2", "v9.3", "v9.4", "v9.5": + g.Version = v + // LSE extension is mandatory starting from 8.1 + g.LSE = true + default: + Error = fmt.Errorf("invalid GOARM64: must start with v8.{0-9} or v9.{0-5} and may optionally end in %q and/or %q", + lseOpt, cryptoOpt) + g.Version = defaultGOARM64 + } + + return +} + +func goarm64() goarm64Features { + return parseGoarm64(envOr("GOARM64", defaultGOARM64)) +} + +// Returns true if g supports giving ARM64 ISA +// Note that this function doesn't accept / test suffixes (like ",lse" or ",crypto") +func (g goarm64Features) Supports(s string) bool { + // We only accept "v{8-9}.{0-9}. Everything else is malformed. + if len(s) != 4 { + return false + } + + major := s[1] + minor := s[3] + + // We only accept "v{8-9}.{0-9}. Everything else is malformed. + if major < '8' || major > '9' || + minor < '0' || minor > '9' || + s[0] != 'v' || s[2] != '.' { + return false + } + + g_major := g.Version[1] + g_minor := g.Version[3] + + if major == g_major { + return minor <= g_minor + } else if g_major == '9' { + // v9.0 diverged from v8.5. This means we should compare with g_minor increased by five. + return minor <= g_minor+5 + } else { + return false + } +} + func gomips() string { switch v := envOr("GOMIPS", defaultGOMIPS); v { case "hardfloat", "softfloat": @@ -238,6 +339,8 @@ func GOGOARCH() (name, value string) { return "GOAMD64", fmt.Sprintf("v%d", GOAMD64) case "arm": return "GOARM", GOARM.String() + case "arm64": + return "GOARM64", GOARM64.String() case "mips", "mipsle": return "GOMIPS", GOMIPS case "mips64", "mips64le": @@ -266,6 +369,20 @@ func gogoarchTags() []string { list = append(list, fmt.Sprintf("%s.%d", GOARCH, i)) } return list + case "arm64": + var list []string + major := int(GOARM64.Version[1] - '0') + minor := int(GOARM64.Version[3] - '0') + for i := 0; i <= minor; i++ { + list = append(list, fmt.Sprintf("%s.v%d.%d", GOARCH, major, i)) + } + // ARM64 v9.x also includes support of v8.x+5 (i.e. v9.1 includes v8.(1+5) = v8.6). + if major == 9 { + for i := 0; i <= minor+5 && i <= 9; i++ { + list = append(list, fmt.Sprintf("%s.v%d.%d", GOARCH, 8, i)) + } + } + return list case "mips", "mipsle": return []string{GOARCH + "." + GOMIPS} case "mips64", "mips64le": diff --git a/src/internal/buildcfg/cfg_test.go b/src/internal/buildcfg/cfg_test.go index 69eeef24221523..33a9c5e1b8c434 100644 --- a/src/internal/buildcfg/cfg_test.go +++ b/src/internal/buildcfg/cfg_test.go @@ -37,4 +37,89 @@ func TestConfigFlags(t *testing.T) { if _ = goriscv64(); Error == nil { t.Errorf("Wrong parsing of RISCV64=rva22") } + Error = nil + os.Setenv("GOARM64", "v7.0") + if _ = goarm64(); Error == nil { + t.Errorf("Wrong parsing of GOARM64=7.0") + } + Error = nil + os.Setenv("GOARM64", "8.0") + if _ = goarm64(); Error == nil { + t.Errorf("Wrong parsing of GOARM64=8.0") + } + Error = nil + os.Setenv("GOARM64", "v8.0,lsb") + if _ = goarm64(); Error == nil { + t.Errorf("Wrong parsing of GOARM64=v8.0,lsb") + } + os.Setenv("GOARM64", "v8.0,lse") + if goarm64().Version != "v8.0" || goarm64().LSE != true || goarm64().Crypto != false { + t.Errorf("Wrong parsing of GOARM64=v8.0,lse") + } + os.Setenv("GOARM64", "v8.0,crypto") + if goarm64().Version != "v8.0" || goarm64().LSE != false || goarm64().Crypto != true { + t.Errorf("Wrong parsing of GOARM64=v8.0,crypto") + } + os.Setenv("GOARM64", "v8.0,crypto,lse") + if goarm64().Version != "v8.0" || goarm64().LSE != true || goarm64().Crypto != true { + t.Errorf("Wrong parsing of GOARM64=v8.0,crypto,lse") + } + os.Setenv("GOARM64", "v8.0,lse,crypto") + if goarm64().Version != "v8.0" || goarm64().LSE != true || goarm64().Crypto != true { + t.Errorf("Wrong parsing of GOARM64=v8.0,lse,crypto") + } + os.Setenv("GOARM64", "v9.0") + if goarm64().Version != "v9.0" || goarm64().LSE != true || goarm64().Crypto != false { + t.Errorf("Wrong parsing of GOARM64=v9.0") + } +} + +func TestGoarm64FeaturesSupports(t *testing.T) { + g := parseGoarm64("v9.3") + + if !g.Supports("v9.3") { + t.Errorf("Wrong goarm64Features.Supports for v9.3, v9.3") + } + + if g.Supports("v9.4") { + t.Errorf("Wrong goarm64Features.Supports for v9.3, v9.4") + } + + if !g.Supports("v8.8") { + t.Errorf("Wrong goarm64Features.Supports for v9.3, v8.8") + } + + if g.Supports("v8.9") { + t.Errorf("Wrong goarm64Features.Supports for v9.3, v8.9") + } + + if g.Supports(",lse") { + t.Errorf("Wrong goarm64Features.Supports for v9.3, ,lse") + } +} + +func TestGogoarchTags(t *testing.T) { + old_goarch := GOARCH + old_goarm64 := GOARM64 + + GOARCH = "arm64" + + os.Setenv("GOARM64", "v9.5") + GOARM64 = goarm64() + tags := gogoarchTags() + want := []string{"arm64.v9.0", "arm64.v9.1", "arm64.v9.2", "arm64.v9.3", "arm64.v9.4", "arm64.v9.5", + "arm64.v8.0", "arm64.v8.1", "arm64.v8.2", "arm64.v8.3", "arm64.v8.4", "arm64.v8.5", "arm64.v8.6", "arm64.v8.7", "arm64.v8.8", "arm64.v8.9"} + if len(tags) != len(want) { + t.Errorf("Wrong number of tags for GOARM64=v9.5") + } else { + for i, v := range tags { + if v != want[i] { + t.Error("Wrong tags for GOARM64=v9.5") + break + } + } + } + + GOARCH = old_goarch + GOARM64 = old_goarm64 } diff --git a/src/internal/cfg/cfg.go b/src/internal/cfg/cfg.go index a9c99c4b966de1..08d210b797385b 100644 --- a/src/internal/cfg/cfg.go +++ b/src/internal/cfg/cfg.go @@ -36,6 +36,7 @@ const KnownEnv = ` GOAMD64 GOARCH GOARM + GOARM64 GOBIN GOCACHE GOCACHEPROG