2016-07-13 13:43:08 -07:00
|
|
|
// Copyright 2016 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 x86
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"math"
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
"cmd/compile/internal/base"
|
[dev.regabi] cmd/compile: group known symbols, packages, names [generated]
There are a handful of pre-computed magic symbols known by
package gc, and we need a place to store them.
If we keep them together, the need for type *ir.Name means that
package ir is the lowest package in the import hierarchy that they
can go in. And package ir needs gopkg for methodSymSuffix
(in a later CL), so they can't go any higher either, at least not all together.
So package ir it is.
Rather than dump them all into the top-level package ir
namespace, however, we introduce global structs, Syms, Pkgs, and Names,
and make the known symbols, packages, and names fields of those.
[git-generate]
cd src/cmd/compile/internal/gc
rf '
add go.go:$ \
// Names holds known names. \
var Names struct{} \
\
// Syms holds known symbols. \
var Syms struct {} \
\
// Pkgs holds known packages. \
var Pkgs struct {} \
mv staticuint64s Names.Staticuint64s
mv zerobase Names.Zerobase
mv assertE2I Syms.AssertE2I
mv assertE2I2 Syms.AssertE2I2
mv assertI2I Syms.AssertI2I
mv assertI2I2 Syms.AssertI2I2
mv deferproc Syms.Deferproc
mv deferprocStack Syms.DeferprocStack
mv Deferreturn Syms.Deferreturn
mv Duffcopy Syms.Duffcopy
mv Duffzero Syms.Duffzero
mv gcWriteBarrier Syms.GCWriteBarrier
mv goschedguarded Syms.Goschedguarded
mv growslice Syms.Growslice
mv msanread Syms.Msanread
mv msanwrite Syms.Msanwrite
mv msanmove Syms.Msanmove
mv newobject Syms.Newobject
mv newproc Syms.Newproc
mv panicdivide Syms.Panicdivide
mv panicshift Syms.Panicshift
mv panicdottypeE Syms.PanicdottypeE
mv panicdottypeI Syms.PanicdottypeI
mv panicnildottype Syms.Panicnildottype
mv panicoverflow Syms.Panicoverflow
mv raceread Syms.Raceread
mv racereadrange Syms.Racereadrange
mv racewrite Syms.Racewrite
mv racewriterange Syms.Racewriterange
mv SigPanic Syms.SigPanic
mv typedmemclr Syms.Typedmemclr
mv typedmemmove Syms.Typedmemmove
mv Udiv Syms.Udiv
mv writeBarrier Syms.WriteBarrier
mv zerobaseSym Syms.Zerobase
mv arm64HasATOMICS Syms.ARM64HasATOMICS
mv armHasVFPv4 Syms.ARMHasVFPv4
mv x86HasFMA Syms.X86HasFMA
mv x86HasPOPCNT Syms.X86HasPOPCNT
mv x86HasSSE41 Syms.X86HasSSE41
mv WasmDiv Syms.WasmDiv
mv WasmMove Syms.WasmMove
mv WasmZero Syms.WasmZero
mv WasmTruncS Syms.WasmTruncS
mv WasmTruncU Syms.WasmTruncU
mv gopkg Pkgs.Go
mv itabpkg Pkgs.Itab
mv itablinkpkg Pkgs.Itablink
mv mappkg Pkgs.Map
mv msanpkg Pkgs.Msan
mv racepkg Pkgs.Race
mv Runtimepkg Pkgs.Runtime
mv trackpkg Pkgs.Track
mv unsafepkg Pkgs.Unsafe
mv Names Syms Pkgs symtab.go
mv symtab.go cmd/compile/internal/ir
'
Change-Id: Ic143862148569a3bcde8e70b26d75421aa2d00f3
Reviewed-on: https://go-review.googlesource.com/c/go/+/279235
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 00:10:25 -05:00
|
|
|
"cmd/compile/internal/ir"
|
2019-10-29 14:24:43 -04:00
|
|
|
"cmd/compile/internal/logopt"
|
2016-07-13 13:43:08 -07:00
|
|
|
"cmd/compile/internal/ssa"
|
2020-12-23 00:57:10 -05:00
|
|
|
"cmd/compile/internal/ssagen"
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
"cmd/compile/internal/types"
|
2016-07-13 13:43:08 -07:00
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"cmd/internal/obj/x86"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
|
2020-12-23 00:57:10 -05:00
|
|
|
func ssaMarkMoves(s *ssagen.State, b *ssa.Block) {
|
2016-07-13 13:43:08 -07:00
|
|
|
flive := b.FlagsLiveAtEnd
|
2019-08-12 20:19:58 +01:00
|
|
|
for _, c := range b.ControlValues() {
|
|
|
|
|
flive = c.Type.IsFlags() || flive
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
for i := len(b.Values) - 1; i >= 0; i-- {
|
|
|
|
|
v := b.Values[i]
|
|
|
|
|
if flive && v.Op == ssa.Op386MOVLconst {
|
|
|
|
|
// The "mark" is any non-nil Aux value.
|
|
|
|
|
v.Aux = v
|
|
|
|
|
}
|
|
|
|
|
if v.Type.IsFlags() {
|
|
|
|
|
flive = false
|
|
|
|
|
}
|
|
|
|
|
for _, a := range v.Args {
|
|
|
|
|
if a.Type.IsFlags() {
|
|
|
|
|
flive = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// loadByType returns the load instruction of the given type.
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
func loadByType(t *types.Type) obj.As {
|
2016-07-13 13:43:08 -07:00
|
|
|
// Avoid partial register write
|
2020-10-30 11:55:18 +01:00
|
|
|
if !t.IsFloat() {
|
|
|
|
|
switch t.Size() {
|
|
|
|
|
case 1:
|
2016-07-13 13:43:08 -07:00
|
|
|
return x86.AMOVBLZX
|
2020-10-30 11:55:18 +01:00
|
|
|
case 2:
|
2016-07-13 13:43:08 -07:00
|
|
|
return x86.AMOVWLZX
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Otherwise, there's no difference between load and store opcodes.
|
|
|
|
|
return storeByType(t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// storeByType returns the store instruction of the given type.
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
func storeByType(t *types.Type) obj.As {
|
2017-04-28 00:19:49 +00:00
|
|
|
width := t.Size()
|
2016-07-13 13:43:08 -07:00
|
|
|
if t.IsFloat() {
|
|
|
|
|
switch width {
|
|
|
|
|
case 4:
|
|
|
|
|
return x86.AMOVSS
|
|
|
|
|
case 8:
|
|
|
|
|
return x86.AMOVSD
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
switch width {
|
|
|
|
|
case 1:
|
|
|
|
|
return x86.AMOVB
|
|
|
|
|
case 2:
|
|
|
|
|
return x86.AMOVW
|
|
|
|
|
case 4:
|
|
|
|
|
return x86.AMOVL
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
panic("bad store type")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// moveByType returns the reg->reg move instruction of the given type.
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
func moveByType(t *types.Type) obj.As {
|
2016-07-13 13:43:08 -07:00
|
|
|
if t.IsFloat() {
|
2017-04-28 00:19:49 +00:00
|
|
|
switch t.Size() {
|
2016-07-18 15:52:59 -07:00
|
|
|
case 4:
|
|
|
|
|
return x86.AMOVSS
|
|
|
|
|
case 8:
|
|
|
|
|
return x86.AMOVSD
|
|
|
|
|
default:
|
2017-04-28 00:19:49 +00:00
|
|
|
panic(fmt.Sprintf("bad float register width %d:%s", t.Size(), t))
|
2016-07-18 15:52:59 -07:00
|
|
|
}
|
2016-07-13 13:43:08 -07:00
|
|
|
} else {
|
2017-04-28 00:19:49 +00:00
|
|
|
switch t.Size() {
|
2016-07-13 13:43:08 -07:00
|
|
|
case 1:
|
|
|
|
|
// Avoids partial register write
|
|
|
|
|
return x86.AMOVL
|
|
|
|
|
case 2:
|
|
|
|
|
return x86.AMOVL
|
|
|
|
|
case 4:
|
|
|
|
|
return x86.AMOVL
|
|
|
|
|
default:
|
2017-04-28 00:19:49 +00:00
|
|
|
panic(fmt.Sprintf("bad int register width %d:%s", t.Size(), t))
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// opregreg emits instructions for
|
|
|
|
|
// dest := dest(To) op src(From)
|
|
|
|
|
// and also returns the created obj.Prog so it
|
|
|
|
|
// may be further adjusted (offset, scale, etc).
|
2020-12-23 00:57:10 -05:00
|
|
|
func opregreg(s *ssagen.State, op obj.As, dest, src int16) *obj.Prog {
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(op)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = dest
|
|
|
|
|
p.From.Reg = src
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 00:57:10 -05:00
|
|
|
func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
2016-07-13 13:43:08 -07:00
|
|
|
switch v.Op {
|
|
|
|
|
case ssa.Op386ADDL:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg()
|
|
|
|
|
r1 := v.Args[0].Reg()
|
|
|
|
|
r2 := v.Args[1].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
switch {
|
|
|
|
|
case r == r1:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = r2
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
case r == r2:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = r1
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
default:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.ALEAL)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = r1
|
|
|
|
|
p.From.Scale = 1
|
|
|
|
|
p.From.Index = r2
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
}
|
2016-07-13 16:15:54 -07:00
|
|
|
|
2016-07-13 13:43:08 -07:00
|
|
|
// 2-address opcode arithmetic
|
|
|
|
|
case ssa.Op386SUBL,
|
|
|
|
|
ssa.Op386MULL,
|
|
|
|
|
ssa.Op386ANDL,
|
|
|
|
|
ssa.Op386ORL,
|
|
|
|
|
ssa.Op386XORL,
|
|
|
|
|
ssa.Op386SHLL,
|
|
|
|
|
ssa.Op386SHRL, ssa.Op386SHRW, ssa.Op386SHRB,
|
|
|
|
|
ssa.Op386SARL, ssa.Op386SARW, ssa.Op386SARB,
|
|
|
|
|
ssa.Op386ADDSS, ssa.Op386ADDSD, ssa.Op386SUBSS, ssa.Op386SUBSD,
|
|
|
|
|
ssa.Op386MULSS, ssa.Op386MULSD, ssa.Op386DIVSS, ssa.Op386DIVSD,
|
2016-07-13 16:15:54 -07:00
|
|
|
ssa.Op386PXOR,
|
2016-07-18 11:51:48 -07:00
|
|
|
ssa.Op386ADCL,
|
|
|
|
|
ssa.Op386SBBL:
|
2021-01-07 19:08:37 -08:00
|
|
|
opregreg(s, v.Op.Asm(), v.Reg(), v.Args[1].Reg())
|
2016-07-13 13:43:08 -07:00
|
|
|
|
2016-07-18 11:51:48 -07:00
|
|
|
case ssa.Op386ADDLcarry, ssa.Op386SUBLcarry:
|
|
|
|
|
// output 0 is carry/borrow, output 1 is the low 32 bits.
|
2021-01-07 19:08:37 -08:00
|
|
|
opregreg(s, v.Op.Asm(), v.Reg0(), v.Args[1].Reg())
|
2016-07-13 16:15:54 -07:00
|
|
|
|
2016-07-18 11:51:48 -07:00
|
|
|
case ssa.Op386ADDLconstcarry, ssa.Op386SUBLconstcarry:
|
|
|
|
|
// output 0 is carry/borrow, output 1 is the low 32 bits.
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-18 11:51:48 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2021-01-07 19:08:37 -08:00
|
|
|
p.To.Reg = v.Reg0()
|
2016-07-18 11:51:48 -07:00
|
|
|
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386DIVL, ssa.Op386DIVW,
|
|
|
|
|
ssa.Op386DIVLU, ssa.Op386DIVWU,
|
|
|
|
|
ssa.Op386MODL, ssa.Op386MODW,
|
|
|
|
|
ssa.Op386MODLU, ssa.Op386MODWU:
|
|
|
|
|
|
|
|
|
|
// Arg[0] is already in AX as it's the only register we allow
|
|
|
|
|
// and AX is the only output
|
2016-09-16 09:36:00 -07:00
|
|
|
x := v.Args[1].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
// CPU faults upon signed overflow, which occurs when most
|
|
|
|
|
// negative int is divided by -1.
|
|
|
|
|
var j *obj.Prog
|
|
|
|
|
if v.Op == ssa.Op386DIVL || v.Op == ssa.Op386DIVW ||
|
|
|
|
|
v.Op == ssa.Op386MODL || v.Op == ssa.Op386MODW {
|
|
|
|
|
|
2020-01-23 22:18:30 -08:00
|
|
|
if ssa.DivisionNeedsFixUp(v) {
|
2018-08-06 19:50:38 +10:00
|
|
|
var c *obj.Prog
|
|
|
|
|
switch v.Op {
|
|
|
|
|
case ssa.Op386DIVL, ssa.Op386MODL:
|
|
|
|
|
c = s.Prog(x86.ACMPL)
|
|
|
|
|
j = s.Prog(x86.AJEQ)
|
|
|
|
|
|
|
|
|
|
case ssa.Op386DIVW, ssa.Op386MODW:
|
|
|
|
|
c = s.Prog(x86.ACMPW)
|
|
|
|
|
j = s.Prog(x86.AJEQ)
|
|
|
|
|
}
|
|
|
|
|
c.From.Type = obj.TYPE_REG
|
|
|
|
|
c.From.Reg = x
|
|
|
|
|
c.To.Type = obj.TYPE_CONST
|
|
|
|
|
c.To.Offset = -1
|
|
|
|
|
|
|
|
|
|
j.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
}
|
|
|
|
|
// sign extend the dividend
|
2016-07-13 13:43:08 -07:00
|
|
|
switch v.Op {
|
|
|
|
|
case ssa.Op386DIVL, ssa.Op386MODL:
|
2018-08-06 19:50:38 +10:00
|
|
|
s.Prog(x86.ACDQ)
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386DIVW, ssa.Op386MODW:
|
2017-03-20 08:01:28 -07:00
|
|
|
s.Prog(x86.ACWD)
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for unsigned ints, we sign extend by setting DX = 0
|
|
|
|
|
// signed ints were sign extended above
|
|
|
|
|
if v.Op == ssa.Op386DIVLU || v.Op == ssa.Op386MODLU ||
|
|
|
|
|
v.Op == ssa.Op386DIVWU || v.Op == ssa.Op386MODWU {
|
2017-03-20 08:01:28 -07:00
|
|
|
c := s.Prog(x86.AXORL)
|
2016-07-13 13:43:08 -07:00
|
|
|
c.From.Type = obj.TYPE_REG
|
|
|
|
|
c.From.Reg = x86.REG_DX
|
|
|
|
|
c.To.Type = obj.TYPE_REG
|
|
|
|
|
c.To.Reg = x86.REG_DX
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = x
|
|
|
|
|
|
|
|
|
|
// signed division, rest of the check for -1 case
|
|
|
|
|
if j != nil {
|
2017-03-20 08:01:28 -07:00
|
|
|
j2 := s.Prog(obj.AJMP)
|
2016-07-13 13:43:08 -07:00
|
|
|
j2.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
|
|
|
|
|
var n *obj.Prog
|
|
|
|
|
if v.Op == ssa.Op386DIVL || v.Op == ssa.Op386DIVW {
|
|
|
|
|
// n * -1 = -n
|
2017-03-20 08:01:28 -07:00
|
|
|
n = s.Prog(x86.ANEGL)
|
2016-07-13 13:43:08 -07:00
|
|
|
n.To.Type = obj.TYPE_REG
|
|
|
|
|
n.To.Reg = x86.REG_AX
|
|
|
|
|
} else {
|
|
|
|
|
// n % -1 == 0
|
2017-03-20 08:01:28 -07:00
|
|
|
n = s.Prog(x86.AXORL)
|
2016-07-13 13:43:08 -07:00
|
|
|
n.From.Type = obj.TYPE_REG
|
|
|
|
|
n.From.Reg = x86.REG_DX
|
|
|
|
|
n.To.Type = obj.TYPE_REG
|
|
|
|
|
n.To.Reg = x86.REG_DX
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-28 17:10:32 +00:00
|
|
|
j.To.SetTarget(n)
|
|
|
|
|
j2.To.SetTarget(s.Pc())
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
|
2017-03-03 11:35:44 -08:00
|
|
|
case ssa.Op386HMULL, ssa.Op386HMULLU:
|
2016-07-13 13:43:08 -07:00
|
|
|
// the frontend rewrites constant division by 8/16/32 bit integers into
|
|
|
|
|
// HMUL by a constant
|
|
|
|
|
// SSA rewrites generate the 64 bit versions
|
|
|
|
|
|
|
|
|
|
// Arg[0] is already in AX as it's the only register we allow
|
|
|
|
|
// and DX is the only output we care about (the high bits)
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[1].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
// IMULB puts the high portion in AH instead of DL,
|
|
|
|
|
// so move it to DL for consistency
|
2017-04-28 00:19:49 +00:00
|
|
|
if v.Type.Size() == 1 {
|
2017-03-20 08:01:28 -07:00
|
|
|
m := s.Prog(x86.AMOVB)
|
2016-07-13 13:43:08 -07:00
|
|
|
m.From.Type = obj.TYPE_REG
|
|
|
|
|
m.From.Reg = x86.REG_AH
|
|
|
|
|
m.To.Type = obj.TYPE_REG
|
|
|
|
|
m.To.Reg = x86.REG_DX
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-27 11:55:34 +01:00
|
|
|
case ssa.Op386MULLU:
|
|
|
|
|
// Arg[0] is already in AX as it's the only register we allow
|
|
|
|
|
// results lo in AX
|
|
|
|
|
p := s.Prog(v.Op.Asm())
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = v.Args[1].Reg()
|
|
|
|
|
|
2016-07-18 11:51:48 -07:00
|
|
|
case ssa.Op386MULLQU:
|
|
|
|
|
// AX * args[1], high 32 bits in DX (result[0]), low 32 bits in AX (result[1]).
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-18 11:51:48 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[1].Reg()
|
2016-07-18 11:51:48 -07:00
|
|
|
|
2017-02-13 16:00:09 -08:00
|
|
|
case ssa.Op386AVGLU:
|
|
|
|
|
// compute (x+y)/2 unsigned.
|
|
|
|
|
// Do a 32-bit add, the overflow goes into the carry.
|
|
|
|
|
// Shift right once and pull the carry back into the 31st bit.
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.AADDL)
|
2017-02-13 16:00:09 -08:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2021-01-07 19:08:37 -08:00
|
|
|
p.To.Reg = v.Reg()
|
2017-02-13 16:00:09 -08:00
|
|
|
p.From.Reg = v.Args[1].Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p = s.Prog(x86.ARCRL)
|
2017-02-13 16:00:09 -08:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = 1
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2021-01-07 19:08:37 -08:00
|
|
|
p.To.Reg = v.Reg()
|
2017-02-13 16:00:09 -08:00
|
|
|
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386ADDLconst:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg()
|
|
|
|
|
a := v.Args[0].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
if r == a {
|
|
|
|
|
if v.AuxInt == 1 {
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.AINCL)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if v.AuxInt == -1 {
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.ADECL)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
return
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
return
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.ALEAL)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = a
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
|
|
|
|
|
case ssa.Op386MULLconst:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
2021-01-07 14:01:29 -08:00
|
|
|
p.SetFrom3Reg(v.Args[0].Reg())
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
case ssa.Op386SUBLconst,
|
2016-07-18 11:51:48 -07:00
|
|
|
ssa.Op386ADCLconst,
|
|
|
|
|
ssa.Op386SBBLconst,
|
2016-07-13 13:43:08 -07:00
|
|
|
ssa.Op386ANDLconst,
|
|
|
|
|
ssa.Op386ORLconst,
|
|
|
|
|
ssa.Op386XORLconst,
|
|
|
|
|
ssa.Op386SHLLconst,
|
|
|
|
|
ssa.Op386SHRLconst, ssa.Op386SHRWconst, ssa.Op386SHRBconst,
|
|
|
|
|
ssa.Op386SARLconst, ssa.Op386SARWconst, ssa.Op386SARBconst,
|
|
|
|
|
ssa.Op386ROLLconst, ssa.Op386ROLWconst, ssa.Op386ROLBconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2021-01-07 19:08:37 -08:00
|
|
|
p.To.Reg = v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386SBBLcarrymask:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = r
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
case ssa.Op386LEAL1, ssa.Op386LEAL2, ssa.Op386LEAL4, ssa.Op386LEAL8:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Args[0].Reg()
|
|
|
|
|
i := v.Args[1].Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.ALEAL)
|
2016-07-13 13:43:08 -07:00
|
|
|
switch v.Op {
|
|
|
|
|
case ssa.Op386LEAL1:
|
|
|
|
|
p.From.Scale = 1
|
|
|
|
|
if i == x86.REG_SP {
|
|
|
|
|
r, i = i, r
|
|
|
|
|
}
|
|
|
|
|
case ssa.Op386LEAL2:
|
|
|
|
|
p.From.Scale = 2
|
|
|
|
|
case ssa.Op386LEAL4:
|
|
|
|
|
p.From.Scale = 4
|
|
|
|
|
case ssa.Op386LEAL8:
|
|
|
|
|
p.From.Scale = 8
|
|
|
|
|
}
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = r
|
|
|
|
|
p.From.Index = i
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.From, v)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386LEAL:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.ALEAL)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.From, v)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386CMPL, ssa.Op386CMPW, ssa.Op386CMPB,
|
|
|
|
|
ssa.Op386TESTL, ssa.Op386TESTW, ssa.Op386TESTB:
|
2017-03-20 08:01:28 -07:00
|
|
|
opregreg(s, v.Op.Asm(), v.Args[1].Reg(), v.Args[0].Reg())
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
|
|
|
|
|
// Go assembler has swapped operands for UCOMISx relative to CMP,
|
|
|
|
|
// must account for that right here.
|
2017-03-20 08:01:28 -07:00
|
|
|
opregreg(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg())
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386CMPLconst, ssa.Op386CMPWconst, ssa.Op386CMPBconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_CONST
|
|
|
|
|
p.To.Offset = v.AuxInt
|
|
|
|
|
case ssa.Op386TESTLconst, ssa.Op386TESTWconst, ssa.Op386TESTBconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Args[0].Reg()
|
2018-07-29 12:50:50 +00:00
|
|
|
case ssa.Op386CMPLload, ssa.Op386CMPWload, ssa.Op386CMPBload:
|
|
|
|
|
p := s.Prog(v.Op.Asm())
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.From, v)
|
2018-07-29 12:50:50 +00:00
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = v.Args[1].Reg()
|
|
|
|
|
case ssa.Op386CMPLconstload, ssa.Op386CMPWconstload, ssa.Op386CMPBconstload:
|
|
|
|
|
sc := v.AuxValAndOff()
|
|
|
|
|
p := s.Prog(v.Op.Asm())
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2021-03-05 11:22:13 +01:00
|
|
|
ssagen.AddAux2(&p.From, v, sc.Off64())
|
2018-07-29 12:50:50 +00:00
|
|
|
p.To.Type = obj.TYPE_CONST
|
2021-03-05 11:22:13 +01:00
|
|
|
p.To.Offset = sc.Val64()
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386MOVLconst:
|
2016-09-16 09:36:00 -07:00
|
|
|
x := v.Reg()
|
2017-10-24 13:24:14 -07:00
|
|
|
|
|
|
|
|
// If flags aren't live (indicated by v.Aux == nil),
|
|
|
|
|
// then we can rewrite MOV $0, AX into XOR AX, AX.
|
|
|
|
|
if v.AuxInt == 0 && v.Aux == nil {
|
|
|
|
|
p := s.Prog(x86.AXORL)
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = x
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = x
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = v.AuxInt
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = x
|
|
|
|
|
case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst:
|
2016-09-16 09:36:00 -07:00
|
|
|
x := v.Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_FCONST
|
|
|
|
|
p.From.Val = math.Float64frombits(uint64(v.AuxInt))
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = x
|
2016-08-11 09:49:48 -07:00
|
|
|
case ssa.Op386MOVSSconst1, ssa.Op386MOVSDconst1:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.ALEAL)
|
2016-08-11 09:49:48 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Name = obj.NAME_EXTERN
|
2017-04-06 10:29:29 -07:00
|
|
|
f := math.Float64frombits(uint64(v.AuxInt))
|
|
|
|
|
if v.Op == ssa.Op386MOVSDconst1 {
|
2020-11-19 20:49:23 -05:00
|
|
|
p.From.Sym = base.Ctxt.Float64Sym(f)
|
2017-04-06 10:29:29 -07:00
|
|
|
} else {
|
2020-11-19 20:49:23 -05:00
|
|
|
p.From.Sym = base.Ctxt.Float32Sym(float32(f))
|
2017-04-06 10:29:29 -07:00
|
|
|
}
|
2016-08-11 09:49:48 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-08-11 09:49:48 -07:00
|
|
|
case ssa.Op386MOVSSconst2, ssa.Op386MOVSDconst2:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-08-11 09:49:48 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-08-11 09:49:48 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-08-11 09:49:48 -07:00
|
|
|
|
2016-07-18 15:52:59 -07:00
|
|
|
case ssa.Op386MOVSSload, ssa.Op386MOVSDload, ssa.Op386MOVLload, ssa.Op386MOVWload, ssa.Op386MOVBload, ssa.Op386MOVBLSXload, ssa.Op386MOVWLSXload:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.From, v)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2018-10-05 12:09:43 +00:00
|
|
|
case ssa.Op386MOVBloadidx1, ssa.Op386MOVWloadidx1, ssa.Op386MOVLloadidx1, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1,
|
|
|
|
|
ssa.Op386MOVSDloadidx8, ssa.Op386MOVLloadidx4, ssa.Op386MOVSSloadidx4, ssa.Op386MOVWloadidx2:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Args[0].Reg()
|
|
|
|
|
i := v.Args[1].Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
2018-10-05 12:09:43 +00:00
|
|
|
switch v.Op {
|
|
|
|
|
case ssa.Op386MOVBloadidx1, ssa.Op386MOVWloadidx1, ssa.Op386MOVLloadidx1, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1:
|
|
|
|
|
if i == x86.REG_SP {
|
|
|
|
|
r, i = i, r
|
|
|
|
|
}
|
|
|
|
|
p.From.Scale = 1
|
|
|
|
|
case ssa.Op386MOVSDloadidx8:
|
|
|
|
|
p.From.Scale = 8
|
|
|
|
|
case ssa.Op386MOVLloadidx4, ssa.Op386MOVSSloadidx4:
|
|
|
|
|
p.From.Scale = 4
|
|
|
|
|
case ssa.Op386MOVWloadidx2:
|
|
|
|
|
p.From.Scale = 2
|
|
|
|
|
}
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Reg = r
|
|
|
|
|
p.From.Index = i
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.From, v)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2018-10-06 13:13:48 +00:00
|
|
|
case ssa.Op386ADDLloadidx4, ssa.Op386SUBLloadidx4, ssa.Op386MULLloadidx4,
|
|
|
|
|
ssa.Op386ANDLloadidx4, ssa.Op386ORLloadidx4, ssa.Op386XORLloadidx4:
|
|
|
|
|
p := s.Prog(v.Op.Asm())
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = v.Args[1].Reg()
|
|
|
|
|
p.From.Index = v.Args[2].Reg()
|
|
|
|
|
p.From.Scale = 4
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.From, v)
|
2018-10-06 13:13:48 +00:00
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = v.Reg()
|
2018-06-24 07:04:21 +00:00
|
|
|
case ssa.Op386ADDLload, ssa.Op386SUBLload, ssa.Op386MULLload,
|
|
|
|
|
ssa.Op386ANDLload, ssa.Op386ORLload, ssa.Op386XORLload,
|
|
|
|
|
ssa.Op386ADDSDload, ssa.Op386ADDSSload, ssa.Op386SUBSDload, ssa.Op386SUBSSload,
|
|
|
|
|
ssa.Op386MULSDload, ssa.Op386MULSSload, ssa.Op386DIVSSload, ssa.Op386DIVSDload:
|
2018-03-22 02:18:50 +00:00
|
|
|
p := s.Prog(v.Op.Asm())
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = v.Args[1].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.From, v)
|
2018-03-22 02:18:50 +00:00
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = v.Reg()
|
2018-04-29 10:42:14 +00:00
|
|
|
case ssa.Op386MOVSSstore, ssa.Op386MOVSDstore, ssa.Op386MOVLstore, ssa.Op386MOVWstore, ssa.Op386MOVBstore,
|
|
|
|
|
ssa.Op386ADDLmodify, ssa.Op386SUBLmodify, ssa.Op386ANDLmodify, ssa.Op386ORLmodify, ssa.Op386XORLmodify:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[1].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Args[0].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.To, v)
|
2018-06-26 02:58:54 +00:00
|
|
|
case ssa.Op386ADDLconstmodify:
|
|
|
|
|
sc := v.AuxValAndOff()
|
|
|
|
|
val := sc.Val()
|
2018-09-20 01:26:17 +00:00
|
|
|
if val == 1 || val == -1 {
|
|
|
|
|
var p *obj.Prog
|
|
|
|
|
if val == 1 {
|
|
|
|
|
p = s.Prog(x86.AINCL)
|
|
|
|
|
} else {
|
|
|
|
|
p = s.Prog(x86.ADECL)
|
|
|
|
|
}
|
2021-03-05 11:22:13 +01:00
|
|
|
off := sc.Off64()
|
2018-09-20 01:26:17 +00:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Reg = v.Args[0].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux2(&p.To, v, off)
|
2018-09-20 01:26:17 +00:00
|
|
|
break
|
2018-06-26 02:58:54 +00:00
|
|
|
}
|
2018-09-20 01:26:17 +00:00
|
|
|
fallthrough
|
2018-06-26 02:58:54 +00:00
|
|
|
case ssa.Op386ANDLconstmodify, ssa.Op386ORLconstmodify, ssa.Op386XORLconstmodify:
|
|
|
|
|
sc := v.AuxValAndOff()
|
2021-03-05 11:22:13 +01:00
|
|
|
off := sc.Off64()
|
|
|
|
|
val := sc.Val64()
|
2018-06-26 02:58:54 +00:00
|
|
|
p := s.Prog(v.Op.Asm())
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = val
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Reg = v.Args[0].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux2(&p.To, v, off)
|
2018-10-05 12:09:43 +00:00
|
|
|
case ssa.Op386MOVBstoreidx1, ssa.Op386MOVWstoreidx1, ssa.Op386MOVLstoreidx1, ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1,
|
2018-10-06 13:13:48 +00:00
|
|
|
ssa.Op386MOVSDstoreidx8, ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4, ssa.Op386MOVWstoreidx2,
|
|
|
|
|
ssa.Op386ADDLmodifyidx4, ssa.Op386SUBLmodifyidx4, ssa.Op386ANDLmodifyidx4, ssa.Op386ORLmodifyidx4, ssa.Op386XORLmodifyidx4:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Args[0].Reg()
|
|
|
|
|
i := v.Args[1].Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[2].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
2018-10-05 12:09:43 +00:00
|
|
|
switch v.Op {
|
|
|
|
|
case ssa.Op386MOVBstoreidx1, ssa.Op386MOVWstoreidx1, ssa.Op386MOVLstoreidx1, ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1:
|
|
|
|
|
if i == x86.REG_SP {
|
|
|
|
|
r, i = i, r
|
|
|
|
|
}
|
|
|
|
|
p.To.Scale = 1
|
|
|
|
|
case ssa.Op386MOVSDstoreidx8:
|
|
|
|
|
p.To.Scale = 8
|
2018-10-06 13:13:48 +00:00
|
|
|
case ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4,
|
|
|
|
|
ssa.Op386ADDLmodifyidx4, ssa.Op386SUBLmodifyidx4, ssa.Op386ANDLmodifyidx4, ssa.Op386ORLmodifyidx4, ssa.Op386XORLmodifyidx4:
|
2018-10-05 12:09:43 +00:00
|
|
|
p.To.Scale = 4
|
|
|
|
|
case ssa.Op386MOVWstoreidx2:
|
|
|
|
|
p.To.Scale = 2
|
|
|
|
|
}
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Reg = r
|
|
|
|
|
p.To.Index = i
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.To, v)
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386MOVLstoreconst, ssa.Op386MOVWstoreconst, ssa.Op386MOVBstoreconst:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
sc := v.AuxValAndOff()
|
2021-03-05 11:22:13 +01:00
|
|
|
p.From.Offset = sc.Val64()
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Args[0].Reg()
|
2021-03-05 11:22:13 +01:00
|
|
|
ssagen.AddAux2(&p.To, v, sc.Off64())
|
2018-10-09 11:01:34 +00:00
|
|
|
case ssa.Op386ADDLconstmodifyidx4:
|
|
|
|
|
sc := v.AuxValAndOff()
|
|
|
|
|
val := sc.Val()
|
|
|
|
|
if val == 1 || val == -1 {
|
|
|
|
|
var p *obj.Prog
|
|
|
|
|
if val == 1 {
|
|
|
|
|
p = s.Prog(x86.AINCL)
|
|
|
|
|
} else {
|
|
|
|
|
p = s.Prog(x86.ADECL)
|
|
|
|
|
}
|
2021-03-05 11:22:13 +01:00
|
|
|
off := sc.Off64()
|
2018-10-09 11:01:34 +00:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Reg = v.Args[0].Reg()
|
|
|
|
|
p.To.Scale = 4
|
|
|
|
|
p.To.Index = v.Args[1].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux2(&p.To, v, off)
|
2018-10-09 11:01:34 +00:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
2018-10-06 13:13:48 +00:00
|
|
|
case ssa.Op386MOVLstoreconstidx1, ssa.Op386MOVLstoreconstidx4, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVWstoreconstidx2, ssa.Op386MOVBstoreconstidx1,
|
2018-10-09 11:01:34 +00:00
|
|
|
ssa.Op386ANDLconstmodifyidx4, ssa.Op386ORLconstmodifyidx4, ssa.Op386XORLconstmodifyidx4:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
sc := v.AuxValAndOff()
|
2021-03-05 11:22:13 +01:00
|
|
|
p.From.Offset = sc.Val64()
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Args[0].Reg()
|
|
|
|
|
i := v.Args[1].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
switch v.Op {
|
|
|
|
|
case ssa.Op386MOVBstoreconstidx1, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVLstoreconstidx1:
|
|
|
|
|
p.To.Scale = 1
|
|
|
|
|
if i == x86.REG_SP {
|
|
|
|
|
r, i = i, r
|
|
|
|
|
}
|
|
|
|
|
case ssa.Op386MOVWstoreconstidx2:
|
|
|
|
|
p.To.Scale = 2
|
2018-10-06 13:13:48 +00:00
|
|
|
case ssa.Op386MOVLstoreconstidx4,
|
|
|
|
|
ssa.Op386ADDLconstmodifyidx4, ssa.Op386ANDLconstmodifyidx4, ssa.Op386ORLconstmodifyidx4, ssa.Op386XORLconstmodifyidx4:
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Scale = 4
|
|
|
|
|
}
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
p.To.Index = i
|
2021-03-05 11:22:13 +01:00
|
|
|
ssagen.AddAux2(&p.To, v, sc.Off64())
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386MOVWLSX, ssa.Op386MOVBLSX, ssa.Op386MOVWLZX, ssa.Op386MOVBLZX,
|
|
|
|
|
ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD,
|
|
|
|
|
ssa.Op386CVTTSS2SL, ssa.Op386CVTTSD2SL,
|
|
|
|
|
ssa.Op386CVTSS2SD, ssa.Op386CVTSD2SS:
|
2017-03-20 08:01:28 -07:00
|
|
|
opregreg(s, v.Op.Asm(), v.Reg(), v.Args[0].Reg())
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386DUFFZERO:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.ADUFFZERO)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_ADDR
|
[dev.regabi] cmd/compile: group known symbols, packages, names [generated]
There are a handful of pre-computed magic symbols known by
package gc, and we need a place to store them.
If we keep them together, the need for type *ir.Name means that
package ir is the lowest package in the import hierarchy that they
can go in. And package ir needs gopkg for methodSymSuffix
(in a later CL), so they can't go any higher either, at least not all together.
So package ir it is.
Rather than dump them all into the top-level package ir
namespace, however, we introduce global structs, Syms, Pkgs, and Names,
and make the known symbols, packages, and names fields of those.
[git-generate]
cd src/cmd/compile/internal/gc
rf '
add go.go:$ \
// Names holds known names. \
var Names struct{} \
\
// Syms holds known symbols. \
var Syms struct {} \
\
// Pkgs holds known packages. \
var Pkgs struct {} \
mv staticuint64s Names.Staticuint64s
mv zerobase Names.Zerobase
mv assertE2I Syms.AssertE2I
mv assertE2I2 Syms.AssertE2I2
mv assertI2I Syms.AssertI2I
mv assertI2I2 Syms.AssertI2I2
mv deferproc Syms.Deferproc
mv deferprocStack Syms.DeferprocStack
mv Deferreturn Syms.Deferreturn
mv Duffcopy Syms.Duffcopy
mv Duffzero Syms.Duffzero
mv gcWriteBarrier Syms.GCWriteBarrier
mv goschedguarded Syms.Goschedguarded
mv growslice Syms.Growslice
mv msanread Syms.Msanread
mv msanwrite Syms.Msanwrite
mv msanmove Syms.Msanmove
mv newobject Syms.Newobject
mv newproc Syms.Newproc
mv panicdivide Syms.Panicdivide
mv panicshift Syms.Panicshift
mv panicdottypeE Syms.PanicdottypeE
mv panicdottypeI Syms.PanicdottypeI
mv panicnildottype Syms.Panicnildottype
mv panicoverflow Syms.Panicoverflow
mv raceread Syms.Raceread
mv racereadrange Syms.Racereadrange
mv racewrite Syms.Racewrite
mv racewriterange Syms.Racewriterange
mv SigPanic Syms.SigPanic
mv typedmemclr Syms.Typedmemclr
mv typedmemmove Syms.Typedmemmove
mv Udiv Syms.Udiv
mv writeBarrier Syms.WriteBarrier
mv zerobaseSym Syms.Zerobase
mv arm64HasATOMICS Syms.ARM64HasATOMICS
mv armHasVFPv4 Syms.ARMHasVFPv4
mv x86HasFMA Syms.X86HasFMA
mv x86HasPOPCNT Syms.X86HasPOPCNT
mv x86HasSSE41 Syms.X86HasSSE41
mv WasmDiv Syms.WasmDiv
mv WasmMove Syms.WasmMove
mv WasmZero Syms.WasmZero
mv WasmTruncS Syms.WasmTruncS
mv WasmTruncU Syms.WasmTruncU
mv gopkg Pkgs.Go
mv itabpkg Pkgs.Itab
mv itablinkpkg Pkgs.Itablink
mv mappkg Pkgs.Map
mv msanpkg Pkgs.Msan
mv racepkg Pkgs.Race
mv Runtimepkg Pkgs.Runtime
mv trackpkg Pkgs.Track
mv unsafepkg Pkgs.Unsafe
mv Names Syms Pkgs symtab.go
mv symtab.go cmd/compile/internal/ir
'
Change-Id: Ic143862148569a3bcde8e70b26d75421aa2d00f3
Reviewed-on: https://go-review.googlesource.com/c/go/+/279235
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 00:10:25 -05:00
|
|
|
p.To.Sym = ir.Syms.Duffzero
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Offset = v.AuxInt
|
|
|
|
|
case ssa.Op386DUFFCOPY:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.ADUFFCOPY)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_ADDR
|
[dev.regabi] cmd/compile: group known symbols, packages, names [generated]
There are a handful of pre-computed magic symbols known by
package gc, and we need a place to store them.
If we keep them together, the need for type *ir.Name means that
package ir is the lowest package in the import hierarchy that they
can go in. And package ir needs gopkg for methodSymSuffix
(in a later CL), so they can't go any higher either, at least not all together.
So package ir it is.
Rather than dump them all into the top-level package ir
namespace, however, we introduce global structs, Syms, Pkgs, and Names,
and make the known symbols, packages, and names fields of those.
[git-generate]
cd src/cmd/compile/internal/gc
rf '
add go.go:$ \
// Names holds known names. \
var Names struct{} \
\
// Syms holds known symbols. \
var Syms struct {} \
\
// Pkgs holds known packages. \
var Pkgs struct {} \
mv staticuint64s Names.Staticuint64s
mv zerobase Names.Zerobase
mv assertE2I Syms.AssertE2I
mv assertE2I2 Syms.AssertE2I2
mv assertI2I Syms.AssertI2I
mv assertI2I2 Syms.AssertI2I2
mv deferproc Syms.Deferproc
mv deferprocStack Syms.DeferprocStack
mv Deferreturn Syms.Deferreturn
mv Duffcopy Syms.Duffcopy
mv Duffzero Syms.Duffzero
mv gcWriteBarrier Syms.GCWriteBarrier
mv goschedguarded Syms.Goschedguarded
mv growslice Syms.Growslice
mv msanread Syms.Msanread
mv msanwrite Syms.Msanwrite
mv msanmove Syms.Msanmove
mv newobject Syms.Newobject
mv newproc Syms.Newproc
mv panicdivide Syms.Panicdivide
mv panicshift Syms.Panicshift
mv panicdottypeE Syms.PanicdottypeE
mv panicdottypeI Syms.PanicdottypeI
mv panicnildottype Syms.Panicnildottype
mv panicoverflow Syms.Panicoverflow
mv raceread Syms.Raceread
mv racereadrange Syms.Racereadrange
mv racewrite Syms.Racewrite
mv racewriterange Syms.Racewriterange
mv SigPanic Syms.SigPanic
mv typedmemclr Syms.Typedmemclr
mv typedmemmove Syms.Typedmemmove
mv Udiv Syms.Udiv
mv writeBarrier Syms.WriteBarrier
mv zerobaseSym Syms.Zerobase
mv arm64HasATOMICS Syms.ARM64HasATOMICS
mv armHasVFPv4 Syms.ARMHasVFPv4
mv x86HasFMA Syms.X86HasFMA
mv x86HasPOPCNT Syms.X86HasPOPCNT
mv x86HasSSE41 Syms.X86HasSSE41
mv WasmDiv Syms.WasmDiv
mv WasmMove Syms.WasmMove
mv WasmZero Syms.WasmZero
mv WasmTruncS Syms.WasmTruncS
mv WasmTruncU Syms.WasmTruncU
mv gopkg Pkgs.Go
mv itabpkg Pkgs.Itab
mv itablinkpkg Pkgs.Itablink
mv mappkg Pkgs.Map
mv msanpkg Pkgs.Msan
mv racepkg Pkgs.Race
mv Runtimepkg Pkgs.Runtime
mv trackpkg Pkgs.Track
mv unsafepkg Pkgs.Unsafe
mv Names Syms Pkgs symtab.go
mv symtab.go cmd/compile/internal/ir
'
Change-Id: Ic143862148569a3bcde8e70b26d75421aa2d00f3
Reviewed-on: https://go-review.googlesource.com/c/go/+/279235
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 00:10:25 -05:00
|
|
|
p.To.Sym = ir.Syms.Duffcopy
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Offset = v.AuxInt
|
|
|
|
|
|
2017-08-24 11:31:58 -07:00
|
|
|
case ssa.OpCopy: // TODO: use MOVLreg for reg->reg copies instead of OpCopy?
|
2016-07-13 13:43:08 -07:00
|
|
|
if v.Type.IsMemory() {
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-09-16 09:36:00 -07:00
|
|
|
x := v.Args[0].Reg()
|
|
|
|
|
y := v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
if x != y {
|
2017-03-20 08:01:28 -07:00
|
|
|
opregreg(s, moveByType(v.Type), y, x)
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
case ssa.OpLoadReg:
|
|
|
|
|
if v.Type.IsFlags() {
|
2016-09-14 10:01:05 -07:00
|
|
|
v.Fatalf("load flags not implemented: %v", v.LongString())
|
2016-07-13 13:43:08 -07:00
|
|
|
return
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(loadByType(v.Type))
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddrAuto(&p.From, v.Args[0])
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
case ssa.OpStoreReg:
|
|
|
|
|
if v.Type.IsFlags() {
|
2016-09-14 10:01:05 -07:00
|
|
|
v.Fatalf("store flags not implemented: %v", v.LongString())
|
2016-07-13 13:43:08 -07:00
|
|
|
return
|
|
|
|
|
}
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(storeByType(v.Type))
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddrAuto(&p.To, v)
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386LoweredGetClosurePtr:
|
|
|
|
|
// Closure pointer is DX.
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.CheckLoweredGetClosurePtr(v)
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386LoweredGetG:
|
2016-09-16 09:36:00 -07:00
|
|
|
r := v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
// See the comments in cmd/internal/obj/x86/obj6.go
|
|
|
|
|
// near CanUse1InsnTLS for a detailed explanation of these instructions.
|
2020-11-19 20:49:23 -05:00
|
|
|
if x86.CanUse1InsnTLS(base.Ctxt) {
|
[dev.ssa] cmd/compile: fix PIC for SSA-generated code
Access to globals requires a 2-instruction sequence on PIC 386.
MOVL foo(SB), AX
is translated by the obj package into:
CALL getPCofNextInstructionInTempRegister(SB)
MOVL (&foo-&thisInstruction)(tmpReg), AX
The call returns the PC of the next instruction in a register.
The next instruction then offsets from that register to get the
address required. The tricky part is the allocation of the
temp register. The legacy compiler always used CX, and forbid
the register allocator from allocating CX when in PIC mode.
We can't easily do that in SSA because CX is actually a required
register for shift instructions. (I think the old backend got away
with this because the register allocator never uses CX, only
codegen knows that shifts must use CX.)
Instead, we allow the temp register to be anything. When the
destination of the MOV (or LEA) is an integer register, we can
use that register. Otherwise, we make sure to compile the
operation using an LEA to reference the global. So
MOVL AX, foo(SB)
is never generated directly. Instead, SSA generates:
LEAL foo(SB), DX
MOVL AX, (DX)
which is then rewritten by the obj package to:
CALL getPcInDX(SB)
LEAL (&foo-&thisInstruction)(DX), AX
MOVL AX, (DX)
So this CL modifies the obj package to use different thunks
to materialize the pc into different registers. We use the
registers that regalloc chose so that SSA can still allocate
the full set of registers.
Change-Id: Ie095644f7164a026c62e95baf9d18a8bcaed0bba
Reviewed-on: https://go-review.googlesource.com/25442
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-08-03 13:00:49 -07:00
|
|
|
// MOVL (TLS), r
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.AMOVL)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = x86.REG_TLS
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
|
|
|
|
} else {
|
[dev.ssa] cmd/compile: fix PIC for SSA-generated code
Access to globals requires a 2-instruction sequence on PIC 386.
MOVL foo(SB), AX
is translated by the obj package into:
CALL getPCofNextInstructionInTempRegister(SB)
MOVL (&foo-&thisInstruction)(tmpReg), AX
The call returns the PC of the next instruction in a register.
The next instruction then offsets from that register to get the
address required. The tricky part is the allocation of the
temp register. The legacy compiler always used CX, and forbid
the register allocator from allocating CX when in PIC mode.
We can't easily do that in SSA because CX is actually a required
register for shift instructions. (I think the old backend got away
with this because the register allocator never uses CX, only
codegen knows that shifts must use CX.)
Instead, we allow the temp register to be anything. When the
destination of the MOV (or LEA) is an integer register, we can
use that register. Otherwise, we make sure to compile the
operation using an LEA to reference the global. So
MOVL AX, foo(SB)
is never generated directly. Instead, SSA generates:
LEAL foo(SB), DX
MOVL AX, (DX)
which is then rewritten by the obj package to:
CALL getPcInDX(SB)
LEAL (&foo-&thisInstruction)(DX), AX
MOVL AX, (DX)
So this CL modifies the obj package to use different thunks
to materialize the pc into different registers. We use the
registers that regalloc chose so that SSA can still allocate
the full set of registers.
Change-Id: Ie095644f7164a026c62e95baf9d18a8bcaed0bba
Reviewed-on: https://go-review.googlesource.com/25442
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-08-03 13:00:49 -07:00
|
|
|
// MOVL TLS, r
|
|
|
|
|
// MOVL (r)(TLS*1), r
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.AMOVL)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = x86.REG_TLS
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = r
|
2017-03-20 08:01:28 -07:00
|
|
|
q := s.Prog(x86.AMOVL)
|
2016-07-13 13:43:08 -07:00
|
|
|
q.From.Type = obj.TYPE_MEM
|
|
|
|
|
q.From.Reg = r
|
|
|
|
|
q.From.Index = x86.REG_TLS
|
|
|
|
|
q.From.Scale = 1
|
|
|
|
|
q.To.Type = obj.TYPE_REG
|
|
|
|
|
q.To.Reg = r
|
|
|
|
|
}
|
2016-10-24 10:25:05 -04:00
|
|
|
|
|
|
|
|
case ssa.Op386LoweredGetCallerPC:
|
|
|
|
|
p := s.Prog(x86.AMOVL)
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Offset = -4 // PC is stored 4 bytes below first parameter.
|
|
|
|
|
p.From.Name = obj.NAME_PARAM
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = v.Reg()
|
|
|
|
|
|
2017-10-09 15:33:29 -04:00
|
|
|
case ssa.Op386LoweredGetCallerSP:
|
|
|
|
|
// caller's SP is the address of the first arg
|
|
|
|
|
p := s.Prog(x86.AMOVL)
|
|
|
|
|
p.From.Type = obj.TYPE_ADDR
|
2020-11-19 20:49:23 -05:00
|
|
|
p.From.Offset = -base.Ctxt.FixedFrameSize() // 0 on 386, just to be consistent with other architectures
|
2017-10-09 15:33:29 -04:00
|
|
|
p.From.Name = obj.NAME_PARAM
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = v.Reg()
|
|
|
|
|
|
2017-11-15 14:54:24 -08:00
|
|
|
case ssa.Op386LoweredWB:
|
|
|
|
|
p := s.Prog(obj.ACALL)
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
|
|
|
|
p.To.Sym = v.Aux.(*obj.LSym)
|
|
|
|
|
|
2019-02-06 14:12:36 -08:00
|
|
|
case ssa.Op386LoweredPanicBoundsA, ssa.Op386LoweredPanicBoundsB, ssa.Op386LoweredPanicBoundsC:
|
|
|
|
|
p := s.Prog(obj.ACALL)
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
2020-12-23 00:57:10 -05:00
|
|
|
p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
|
2019-02-06 14:12:36 -08:00
|
|
|
s.UseArgs(8) // space used in callee args area by assembly stubs
|
|
|
|
|
|
|
|
|
|
case ssa.Op386LoweredPanicExtendA, ssa.Op386LoweredPanicExtendB, ssa.Op386LoweredPanicExtendC:
|
|
|
|
|
p := s.Prog(obj.ACALL)
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
2020-12-23 00:57:10 -05:00
|
|
|
p.To.Sym = ssagen.ExtendCheckFunc[v.AuxInt]
|
2019-02-06 14:12:36 -08:00
|
|
|
s.UseArgs(12) // space used in callee args area by assembly stubs
|
|
|
|
|
|
2017-03-10 18:34:41 -08:00
|
|
|
case ssa.Op386CALLstatic, ssa.Op386CALLclosure, ssa.Op386CALLinter:
|
|
|
|
|
s.Call(v)
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386NEGL,
|
|
|
|
|
ssa.Op386BSWAPL,
|
|
|
|
|
ssa.Op386NOTL:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2021-01-07 19:08:37 -08:00
|
|
|
p.To.Reg = v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386BSFL, ssa.Op386BSFW,
|
|
|
|
|
ssa.Op386BSRL, ssa.Op386BSRW,
|
2020-12-07 19:15:15 +08:00
|
|
|
ssa.Op386SQRTSS, ssa.Op386SQRTSD:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.From.Reg = v.Args[0].Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386SETEQ, ssa.Op386SETNE,
|
|
|
|
|
ssa.Op386SETL, ssa.Op386SETLE,
|
|
|
|
|
ssa.Op386SETG, ssa.Op386SETGE,
|
|
|
|
|
ssa.Op386SETGF, ssa.Op386SETGEF,
|
|
|
|
|
ssa.Op386SETB, ssa.Op386SETBE,
|
|
|
|
|
ssa.Op386SETORD, ssa.Op386SETNAN,
|
2018-01-27 11:55:34 +01:00
|
|
|
ssa.Op386SETA, ssa.Op386SETAE,
|
|
|
|
|
ssa.Op386SETO:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
case ssa.Op386SETNEF:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
q := s.Prog(x86.ASETPS)
|
2016-07-13 13:43:08 -07:00
|
|
|
q.To.Type = obj.TYPE_REG
|
|
|
|
|
q.To.Reg = x86.REG_AX
|
2017-03-20 08:01:28 -07:00
|
|
|
opregreg(s, x86.AORL, v.Reg(), x86.REG_AX)
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
case ssa.Op386SETEQF:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(v.Op.Asm())
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Reg()
|
2017-03-20 08:01:28 -07:00
|
|
|
q := s.Prog(x86.ASETPC)
|
2016-07-13 13:43:08 -07:00
|
|
|
q.To.Type = obj.TYPE_REG
|
|
|
|
|
q.To.Reg = x86.REG_AX
|
2017-03-20 08:01:28 -07:00
|
|
|
opregreg(s, x86.AANDL, v.Reg(), x86.REG_AX)
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
case ssa.Op386InvertFlags:
|
|
|
|
|
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
|
|
|
|
|
case ssa.Op386FlagEQ, ssa.Op386FlagLT_ULT, ssa.Op386FlagLT_UGT, ssa.Op386FlagGT_ULT, ssa.Op386FlagGT_UGT:
|
|
|
|
|
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
|
|
|
|
|
case ssa.Op386REPSTOSL:
|
2017-03-20 08:01:28 -07:00
|
|
|
s.Prog(x86.AREP)
|
|
|
|
|
s.Prog(x86.ASTOSL)
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386REPMOVSL:
|
2017-03-20 08:01:28 -07:00
|
|
|
s.Prog(x86.AREP)
|
|
|
|
|
s.Prog(x86.AMOVSL)
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.Op386LoweredNilCheck:
|
|
|
|
|
// Issue a load which will fault if the input is nil.
|
|
|
|
|
// TODO: We currently use the 2-byte instruction TESTB AX, (reg).
|
2017-08-19 22:33:51 +02:00
|
|
|
// Should we use the 3-byte TESTB $0, (reg) instead? It is larger
|
2016-07-13 13:43:08 -07:00
|
|
|
// but it doesn't have false dependency on AX.
|
|
|
|
|
// Or maybe allocate an output register and use MOVL (reg),reg2 ?
|
|
|
|
|
// That trades clobbering flags for clobbering a register.
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.ATESTB)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = x86.REG_AX
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
2016-09-16 09:36:00 -07:00
|
|
|
p.To.Reg = v.Args[0].Reg()
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.To, v)
|
2019-10-29 14:24:43 -04:00
|
|
|
if logopt.Enabled() {
|
|
|
|
|
logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
|
|
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Debug.Nil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
|
|
|
|
|
base.WarnfAt(v.Pos, "generated nil check")
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
2016-06-08 22:02:08 -07:00
|
|
|
case ssa.OpClobber:
|
|
|
|
|
p := s.Prog(x86.AMOVL)
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = 0xdeaddead
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Reg = x86.REG_SP
|
2020-12-23 00:57:10 -05:00
|
|
|
ssagen.AddAux(&p.To, v)
|
2016-07-13 13:43:08 -07:00
|
|
|
default:
|
2016-09-14 10:01:05 -07:00
|
|
|
v.Fatalf("genValue not implemented: %s", v.LongString())
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var blockJump = [...]struct {
|
|
|
|
|
asm, invasm obj.As
|
|
|
|
|
}{
|
|
|
|
|
ssa.Block386EQ: {x86.AJEQ, x86.AJNE},
|
|
|
|
|
ssa.Block386NE: {x86.AJNE, x86.AJEQ},
|
|
|
|
|
ssa.Block386LT: {x86.AJLT, x86.AJGE},
|
|
|
|
|
ssa.Block386GE: {x86.AJGE, x86.AJLT},
|
|
|
|
|
ssa.Block386LE: {x86.AJLE, x86.AJGT},
|
|
|
|
|
ssa.Block386GT: {x86.AJGT, x86.AJLE},
|
2018-01-27 11:55:34 +01:00
|
|
|
ssa.Block386OS: {x86.AJOS, x86.AJOC},
|
|
|
|
|
ssa.Block386OC: {x86.AJOC, x86.AJOS},
|
2016-07-13 13:43:08 -07:00
|
|
|
ssa.Block386ULT: {x86.AJCS, x86.AJCC},
|
|
|
|
|
ssa.Block386UGE: {x86.AJCC, x86.AJCS},
|
|
|
|
|
ssa.Block386UGT: {x86.AJHI, x86.AJLS},
|
|
|
|
|
ssa.Block386ULE: {x86.AJLS, x86.AJHI},
|
|
|
|
|
ssa.Block386ORD: {x86.AJPC, x86.AJPS},
|
|
|
|
|
ssa.Block386NAN: {x86.AJPS, x86.AJPC},
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 00:57:10 -05:00
|
|
|
var eqfJumps = [2][2]ssagen.IndexJump{
|
2016-07-13 13:43:08 -07:00
|
|
|
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPS, Index: 1}}, // next == b.Succs[0]
|
|
|
|
|
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
|
|
|
|
|
}
|
2020-12-23 00:57:10 -05:00
|
|
|
var nefJumps = [2][2]ssagen.IndexJump{
|
2016-07-13 13:43:08 -07:00
|
|
|
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPC, Index: 1}}, // next == b.Succs[0]
|
|
|
|
|
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 00:57:10 -05:00
|
|
|
func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
|
2016-07-13 13:43:08 -07:00
|
|
|
switch b.Kind {
|
2016-09-13 17:01:01 -07:00
|
|
|
case ssa.BlockPlain:
|
2016-07-13 13:43:08 -07:00
|
|
|
if b.Succs[0].Block() != next {
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.AJMP)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
2020-12-23 00:57:10 -05:00
|
|
|
s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
case ssa.BlockDefer:
|
|
|
|
|
// defer returns in rax:
|
|
|
|
|
// 0 if we should continue executing
|
|
|
|
|
// 1 if we should jump to deferreturn call
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(x86.ATESTL)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = x86.REG_AX
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = x86.REG_AX
|
2017-03-20 08:01:28 -07:00
|
|
|
p = s.Prog(x86.AJNE)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
2020-12-23 00:57:10 -05:00
|
|
|
s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()})
|
2016-07-13 13:43:08 -07:00
|
|
|
if b.Succs[0].Block() != next {
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.AJMP)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
2020-12-23 00:57:10 -05:00
|
|
|
s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
case ssa.BlockExit:
|
|
|
|
|
case ssa.BlockRet:
|
2017-03-20 08:01:28 -07:00
|
|
|
s.Prog(obj.ARET)
|
2016-07-13 13:43:08 -07:00
|
|
|
case ssa.BlockRetJmp:
|
2017-03-20 08:01:28 -07:00
|
|
|
p := s.Prog(obj.AJMP)
|
2016-07-13 13:43:08 -07:00
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
2017-02-06 13:30:40 -08:00
|
|
|
p.To.Sym = b.Aux.(*obj.LSym)
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
case ssa.Block386EQF:
|
cmd/compile: fix incorrect rewriting to if condition
Some ARM64 rewriting rules convert 'comparing to zero' conditions of if
statements to a simplified version utilizing CMN and CMP instructions to
branch over condition flags, in order to save one Add or Sub caculation.
Such optimizations lead to wrong branching in case an overflow/underflow
occurs when executing CMN or CMP.
Fix the issue by introducing new block opcodes that don't honor the
overflow/underflow flag, in the following categories:
Block-Op Meaning ARM condition codes
1. LTnoov less than MI
2. GEnoov greater than or equal PL
3. LEnoov less than or equal MI || EQ
4. GTnoov greater than NEQ & PL
The backend generates two consecutive branch instructions for 'LEnoov'
and 'GTnoov' to model their expected behavior. A slight change to 'gc'
and amd64/386 backends is made to unify the code generation.
Add a test 'TestCondRewrite' as justification, it covers 32 incorrect rules
identified on arm64, more might be needed on other arches, like 32-bit arm.
Add two benchmarks profiling the aforementioned category 1&2 and category
3&4 separetely, we expect the first two categories will show performance
improvement and the second will not result in visible regression compared with
the non-optimized version.
This change also updates TestFormats to support using %#x.
Examples exhibiting where does the issue come from:
1: 'if x + 3 < 0' might be converted to:
before:
CMN $3, R0
BGE <else branch> // wrong branch is taken if 'x+3' overflows
after:
CMN $3, R0
BPL <else branch>
2: 'if y - 3 > 0' might be converted to:
before:
CMP $3, R0
BLE <else branch> // wrong branch is taken if 'y-3' underflows
after:
CMP $3, R0
BMI <else branch>
BEQ <else branch>
Benchmark data from different kinds of arm64 servers, 'old' is the non-optimized
version (not the parent commit), generally the optimization version outperforms.
S1:
name old time/op new time/op delta
CondRewrite/SoloJump 13.6ns ± 0% 12.9ns ± 0% -5.15% (p=0.000 n=10+10)
CondRewrite/CombJump 13.8ns ± 1% 12.9ns ± 0% -6.32% (p=0.000 n=10+10)
S2:
name old time/op new time/op delta
CondRewrite/SoloJump 11.6ns ± 0% 10.9ns ± 0% -6.03% (p=0.000 n=10+10)
CondRewrite/CombJump 11.4ns ± 0% 10.8ns ± 1% -5.53% (p=0.000 n=10+10)
S3:
name old time/op new time/op delta
CondRewrite/SoloJump 7.36ns ± 0% 7.50ns ± 0% +1.79% (p=0.000 n=9+10)
CondRewrite/CombJump 7.35ns ± 0% 7.75ns ± 0% +5.51% (p=0.000 n=8+9)
S4:
name old time/op new time/op delta
CondRewrite/SoloJump-224 11.5ns ± 1% 10.9ns ± 0% -4.97% (p=0.000 n=10+10)
CondRewrite/CombJump-224 11.9ns ± 0% 11.5ns ± 0% -2.95% (p=0.000 n=10+10)
S5:
name old time/op new time/op delta
CondRewrite/SoloJump 10.0ns ± 0% 10.0ns ± 0% -0.45% (p=0.000 n=9+10)
CondRewrite/CombJump 9.93ns ± 0% 9.77ns ± 0% -1.53% (p=0.000 n=10+9)
Go1 perf. data:
name old time/op new time/op delta
BinaryTree17 6.29s ± 1% 6.30s ± 1% ~ (p=1.000 n=5+5)
Fannkuch11 5.40s ± 0% 5.40s ± 0% ~ (p=0.841 n=5+5)
FmtFprintfEmpty 97.9ns ± 0% 98.9ns ± 3% ~ (p=0.937 n=4+5)
FmtFprintfString 171ns ± 3% 171ns ± 2% ~ (p=0.754 n=5+5)
FmtFprintfInt 212ns ± 0% 217ns ± 6% +2.55% (p=0.008 n=5+5)
FmtFprintfIntInt 296ns ± 1% 297ns ± 2% ~ (p=0.516 n=5+5)
FmtFprintfPrefixedInt 371ns ± 2% 374ns ± 7% ~ (p=1.000 n=5+5)
FmtFprintfFloat 435ns ± 1% 439ns ± 2% ~ (p=0.056 n=5+5)
FmtManyArgs 1.37µs ± 1% 1.36µs ± 1% ~ (p=0.730 n=5+5)
GobDecode 14.6ms ± 4% 14.4ms ± 4% ~ (p=0.690 n=5+5)
GobEncode 11.8ms ±20% 11.6ms ±15% ~ (p=1.000 n=5+5)
Gzip 507ms ± 0% 491ms ± 0% -3.22% (p=0.008 n=5+5)
Gunzip 73.8ms ± 0% 73.9ms ± 0% ~ (p=0.690 n=5+5)
HTTPClientServer 116µs ± 0% 116µs ± 0% ~ (p=0.686 n=4+4)
JSONEncode 21.8ms ± 1% 21.6ms ± 2% ~ (p=0.151 n=5+5)
JSONDecode 104ms ± 1% 103ms ± 1% -1.08% (p=0.016 n=5+5)
Mandelbrot200 9.53ms ± 0% 9.53ms ± 0% ~ (p=0.421 n=5+5)
GoParse 7.55ms ± 1% 7.51ms ± 1% ~ (p=0.151 n=5+5)
RegexpMatchEasy0_32 158ns ± 0% 158ns ± 0% ~ (all equal)
RegexpMatchEasy0_1K 606ns ± 1% 608ns ± 3% ~ (p=0.937 n=5+5)
RegexpMatchEasy1_32 143ns ± 0% 144ns ± 1% ~ (p=0.095 n=5+4)
RegexpMatchEasy1_1K 927ns ± 2% 944ns ± 2% ~ (p=0.056 n=5+5)
RegexpMatchMedium_32 16.0ns ± 0% 16.0ns ± 0% ~ (all equal)
RegexpMatchMedium_1K 69.3µs ± 2% 69.7µs ± 0% ~ (p=0.690 n=5+5)
RegexpMatchHard_32 3.73µs ± 0% 3.73µs ± 1% ~ (p=0.984 n=5+5)
RegexpMatchHard_1K 111µs ± 1% 110µs ± 0% ~ (p=0.151 n=5+5)
Revcomp 1.91s ±47% 1.77s ±68% ~ (p=1.000 n=5+5)
Template 138ms ± 1% 138ms ± 1% ~ (p=1.000 n=5+5)
TimeParse 787ns ± 2% 785ns ± 1% ~ (p=0.540 n=5+5)
TimeFormat 729ns ± 1% 726ns ± 1% ~ (p=0.151 n=5+5)
Updates #38740
Change-Id: I06c604874acdc1e63e66452dadee5df053045222
Reviewed-on: https://go-review.googlesource.com/c/go/+/233097
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
2020-05-06 09:54:40 +00:00
|
|
|
s.CombJump(b, next, &eqfJumps)
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
case ssa.Block386NEF:
|
cmd/compile: fix incorrect rewriting to if condition
Some ARM64 rewriting rules convert 'comparing to zero' conditions of if
statements to a simplified version utilizing CMN and CMP instructions to
branch over condition flags, in order to save one Add or Sub caculation.
Such optimizations lead to wrong branching in case an overflow/underflow
occurs when executing CMN or CMP.
Fix the issue by introducing new block opcodes that don't honor the
overflow/underflow flag, in the following categories:
Block-Op Meaning ARM condition codes
1. LTnoov less than MI
2. GEnoov greater than or equal PL
3. LEnoov less than or equal MI || EQ
4. GTnoov greater than NEQ & PL
The backend generates two consecutive branch instructions for 'LEnoov'
and 'GTnoov' to model their expected behavior. A slight change to 'gc'
and amd64/386 backends is made to unify the code generation.
Add a test 'TestCondRewrite' as justification, it covers 32 incorrect rules
identified on arm64, more might be needed on other arches, like 32-bit arm.
Add two benchmarks profiling the aforementioned category 1&2 and category
3&4 separetely, we expect the first two categories will show performance
improvement and the second will not result in visible regression compared with
the non-optimized version.
This change also updates TestFormats to support using %#x.
Examples exhibiting where does the issue come from:
1: 'if x + 3 < 0' might be converted to:
before:
CMN $3, R0
BGE <else branch> // wrong branch is taken if 'x+3' overflows
after:
CMN $3, R0
BPL <else branch>
2: 'if y - 3 > 0' might be converted to:
before:
CMP $3, R0
BLE <else branch> // wrong branch is taken if 'y-3' underflows
after:
CMP $3, R0
BMI <else branch>
BEQ <else branch>
Benchmark data from different kinds of arm64 servers, 'old' is the non-optimized
version (not the parent commit), generally the optimization version outperforms.
S1:
name old time/op new time/op delta
CondRewrite/SoloJump 13.6ns ± 0% 12.9ns ± 0% -5.15% (p=0.000 n=10+10)
CondRewrite/CombJump 13.8ns ± 1% 12.9ns ± 0% -6.32% (p=0.000 n=10+10)
S2:
name old time/op new time/op delta
CondRewrite/SoloJump 11.6ns ± 0% 10.9ns ± 0% -6.03% (p=0.000 n=10+10)
CondRewrite/CombJump 11.4ns ± 0% 10.8ns ± 1% -5.53% (p=0.000 n=10+10)
S3:
name old time/op new time/op delta
CondRewrite/SoloJump 7.36ns ± 0% 7.50ns ± 0% +1.79% (p=0.000 n=9+10)
CondRewrite/CombJump 7.35ns ± 0% 7.75ns ± 0% +5.51% (p=0.000 n=8+9)
S4:
name old time/op new time/op delta
CondRewrite/SoloJump-224 11.5ns ± 1% 10.9ns ± 0% -4.97% (p=0.000 n=10+10)
CondRewrite/CombJump-224 11.9ns ± 0% 11.5ns ± 0% -2.95% (p=0.000 n=10+10)
S5:
name old time/op new time/op delta
CondRewrite/SoloJump 10.0ns ± 0% 10.0ns ± 0% -0.45% (p=0.000 n=9+10)
CondRewrite/CombJump 9.93ns ± 0% 9.77ns ± 0% -1.53% (p=0.000 n=10+9)
Go1 perf. data:
name old time/op new time/op delta
BinaryTree17 6.29s ± 1% 6.30s ± 1% ~ (p=1.000 n=5+5)
Fannkuch11 5.40s ± 0% 5.40s ± 0% ~ (p=0.841 n=5+5)
FmtFprintfEmpty 97.9ns ± 0% 98.9ns ± 3% ~ (p=0.937 n=4+5)
FmtFprintfString 171ns ± 3% 171ns ± 2% ~ (p=0.754 n=5+5)
FmtFprintfInt 212ns ± 0% 217ns ± 6% +2.55% (p=0.008 n=5+5)
FmtFprintfIntInt 296ns ± 1% 297ns ± 2% ~ (p=0.516 n=5+5)
FmtFprintfPrefixedInt 371ns ± 2% 374ns ± 7% ~ (p=1.000 n=5+5)
FmtFprintfFloat 435ns ± 1% 439ns ± 2% ~ (p=0.056 n=5+5)
FmtManyArgs 1.37µs ± 1% 1.36µs ± 1% ~ (p=0.730 n=5+5)
GobDecode 14.6ms ± 4% 14.4ms ± 4% ~ (p=0.690 n=5+5)
GobEncode 11.8ms ±20% 11.6ms ±15% ~ (p=1.000 n=5+5)
Gzip 507ms ± 0% 491ms ± 0% -3.22% (p=0.008 n=5+5)
Gunzip 73.8ms ± 0% 73.9ms ± 0% ~ (p=0.690 n=5+5)
HTTPClientServer 116µs ± 0% 116µs ± 0% ~ (p=0.686 n=4+4)
JSONEncode 21.8ms ± 1% 21.6ms ± 2% ~ (p=0.151 n=5+5)
JSONDecode 104ms ± 1% 103ms ± 1% -1.08% (p=0.016 n=5+5)
Mandelbrot200 9.53ms ± 0% 9.53ms ± 0% ~ (p=0.421 n=5+5)
GoParse 7.55ms ± 1% 7.51ms ± 1% ~ (p=0.151 n=5+5)
RegexpMatchEasy0_32 158ns ± 0% 158ns ± 0% ~ (all equal)
RegexpMatchEasy0_1K 606ns ± 1% 608ns ± 3% ~ (p=0.937 n=5+5)
RegexpMatchEasy1_32 143ns ± 0% 144ns ± 1% ~ (p=0.095 n=5+4)
RegexpMatchEasy1_1K 927ns ± 2% 944ns ± 2% ~ (p=0.056 n=5+5)
RegexpMatchMedium_32 16.0ns ± 0% 16.0ns ± 0% ~ (all equal)
RegexpMatchMedium_1K 69.3µs ± 2% 69.7µs ± 0% ~ (p=0.690 n=5+5)
RegexpMatchHard_32 3.73µs ± 0% 3.73µs ± 1% ~ (p=0.984 n=5+5)
RegexpMatchHard_1K 111µs ± 1% 110µs ± 0% ~ (p=0.151 n=5+5)
Revcomp 1.91s ±47% 1.77s ±68% ~ (p=1.000 n=5+5)
Template 138ms ± 1% 138ms ± 1% ~ (p=1.000 n=5+5)
TimeParse 787ns ± 2% 785ns ± 1% ~ (p=0.540 n=5+5)
TimeFormat 729ns ± 1% 726ns ± 1% ~ (p=0.151 n=5+5)
Updates #38740
Change-Id: I06c604874acdc1e63e66452dadee5df053045222
Reviewed-on: https://go-review.googlesource.com/c/go/+/233097
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
2020-05-06 09:54:40 +00:00
|
|
|
s.CombJump(b, next, &nefJumps)
|
2016-07-13 13:43:08 -07:00
|
|
|
|
|
|
|
|
case ssa.Block386EQ, ssa.Block386NE,
|
|
|
|
|
ssa.Block386LT, ssa.Block386GE,
|
|
|
|
|
ssa.Block386LE, ssa.Block386GT,
|
2018-01-27 11:55:34 +01:00
|
|
|
ssa.Block386OS, ssa.Block386OC,
|
2016-07-13 13:43:08 -07:00
|
|
|
ssa.Block386ULT, ssa.Block386UGT,
|
|
|
|
|
ssa.Block386ULE, ssa.Block386UGE:
|
|
|
|
|
jmp := blockJump[b.Kind]
|
|
|
|
|
switch next {
|
|
|
|
|
case b.Succs[0].Block():
|
2018-04-05 16:14:42 -04:00
|
|
|
s.Br(jmp.invasm, b.Succs[1].Block())
|
2016-07-13 13:43:08 -07:00
|
|
|
case b.Succs[1].Block():
|
2018-04-05 16:14:42 -04:00
|
|
|
s.Br(jmp.asm, b.Succs[0].Block())
|
2016-07-13 13:43:08 -07:00
|
|
|
default:
|
2018-04-05 16:14:42 -04:00
|
|
|
if b.Likely != ssa.BranchUnlikely {
|
|
|
|
|
s.Br(jmp.asm, b.Succs[0].Block())
|
|
|
|
|
s.Br(obj.AJMP, b.Succs[1].Block())
|
|
|
|
|
} else {
|
|
|
|
|
s.Br(jmp.invasm, b.Succs[1].Block())
|
|
|
|
|
s.Br(obj.AJMP, b.Succs[0].Block())
|
|
|
|
|
}
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
default:
|
2019-08-12 20:19:58 +01:00
|
|
|
b.Fatalf("branch not implemented: %s", b.LongString())
|
2016-07-13 13:43:08 -07:00
|
|
|
}
|
|
|
|
|
}
|