Go 1.18 will let you set the version of the "AMD64" architecture to target
The "amd64" architecture is what Go calls 64-bit x86 (often referred to as the more vendor neutral x86-64, although AMD did create it); it's the most common architecture on Unix servers these days. As we all know, the (64-bit) x86 architecture has evolved over the years to add more and more instructions that cover more and more situations. Some of these are various generations of vector/SIMD extensions (eg) and some of them are for common operations, like POPCNT and other bit manipulation instructions. In 2020, a cross-vendor collaboration established a series of x86-64 architecture levels.
Up through Go 1.17, Go's AMD64 support targeted the baseline
architecture level that all ax86-64 CPUs support. The Go compiler
only generated these baseline instructions, although some internal
runtime functions would check for more advanced CPUs and switch to
more efficient implementations on them. In Go 1.18, Go has added
support for a new environment variable, $GOAMD64
, that's described
this way in the current (draft) release notes:
Go 1.18 introduces the new
GOAMD64
environment variable which selects a version of the AMD64 architecture. Allowed values arev1
,v2
,v3
, orv4
. Each higher level requires, and takes advantage of, additional processor features. A detailed description of the versions is here.The
GOAMD64
environment variable defaults tov1
.
(What Go calls v1
is the baseline level. For more background and
discussion, see issue #45453,
and perhaps CL 349595.)
Although it's not mentioned in the release notes, a program compiled with a higher GOAMD64 level than the current CPU supports will fail on startup with a message about this.
If you're a curious person, you might be inclined to wonder both
what GOAMD64 affects and which specific versions make the most
difference. As of today (mid-November 2021), the answer is that
much of the differences currently happen at v3
, although v2
also makes some difference, and there seem to be two forms of
changes.
First, there are some compiler intrinsic functions (such as math.FMA) that normally compile to a guarded
use of instructions like FMA
that's conditional on the CPU being
capable enough. If you build with an appropriate GOAMD64 value, the
guard is omitted and the compiler just directly emits the applicable
instructions. You can see this in ssagen/ssa.go
by searching for uses of buildcfg.GOAMD64
. At the moment,
math.FMA changes for v3
, while math.bits.OnesCount* and
some math rounding functions change for
v2
.
Second, in code generation setting a GOAMD64 level can change some
instructions used for various operations to what are presumably
more efficient versions. This happens in ssa/gen/AMD64.rules,
which will do things like generate TZCNTQ
and TZCNTL
instructions;
again you can see this by searching for buildcfg.GOAMD64
. At
the moment, all of these changes happen for v3
. These conditional
instruction selections appear to ripple through to functions like
some of the math.bits.TrailingZeros* family (see ssagen/ssa.go
again).
(I don't know enough about Go's compiler to know if these SSA pseudo-instructions can be generated through things other than those intrinsic functions.)
|
|