2015-03-03 13:38:14 -08:00
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package ssa
|
|
|
|
|
|
2015-08-24 02:16:19 -07:00
|
|
|
import (
|
2015-10-23 12:34:03 -04:00
|
|
|
"cmd/internal/obj"
|
2017-02-21 15:20:38 -05:00
|
|
|
"cmd/internal/obj/s390x"
|
2016-12-03 19:17:16 -05:00
|
|
|
"cmd/internal/obj/x86"
|
2016-12-06 17:08:06 -08:00
|
|
|
"cmd/internal/src"
|
2015-08-24 02:16:19 -07:00
|
|
|
"testing"
|
|
|
|
|
)
|
2015-06-12 11:01:13 -07:00
|
|
|
|
2015-03-03 13:38:14 -08:00
|
|
|
var CheckFunc = checkFunc
|
2015-05-28 16:45:33 -07:00
|
|
|
var Opt = opt
|
2015-03-03 13:38:14 -08:00
|
|
|
var Deadcode = deadcode
|
2016-04-27 16:58:50 -07:00
|
|
|
var Copyelim = copyelim
|
2017-02-06 13:30:40 -08:00
|
|
|
var TestCtxt = obj.Linknew(&x86.Linkamd64)
|
2015-06-04 15:18:27 -07:00
|
|
|
|
2016-04-27 16:58:50 -07:00
|
|
|
func testConfig(t testing.TB) *Config {
|
2017-02-06 13:30:40 -08:00
|
|
|
return NewConfig("amd64", DummyFrontend{t}, TestCtxt, true)
|
2015-07-30 11:03:05 -07:00
|
|
|
}
|
|
|
|
|
|
2017-02-21 15:20:38 -05:00
|
|
|
func testConfigS390X(t testing.TB) *Config {
|
|
|
|
|
return NewConfig("s390x", DummyFrontend{t}, obj.Linknew(&s390x.Links390x), true)
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 11:03:05 -07:00
|
|
|
// DummyFrontend is a test-only frontend.
|
|
|
|
|
// It assumes 64 bit integers and pointers.
|
2015-06-12 11:01:13 -07:00
|
|
|
type DummyFrontend struct {
|
2015-06-25 14:04:55 -07:00
|
|
|
t testing.TB
|
2015-06-12 11:01:13 -07:00
|
|
|
}
|
2015-06-04 15:18:27 -07:00
|
|
|
|
2017-02-02 11:53:41 -05:00
|
|
|
type DummyAuto struct {
|
|
|
|
|
t Type
|
|
|
|
|
s string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *DummyAuto) Typ() Type {
|
|
|
|
|
return d.t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *DummyAuto) String() string {
|
|
|
|
|
return d.s
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-24 11:28:12 -07:00
|
|
|
func (DummyFrontend) StringData(s string) interface{} {
|
2015-06-04 15:18:27 -07:00
|
|
|
return nil
|
|
|
|
|
}
|
2015-10-22 14:22:38 -07:00
|
|
|
func (DummyFrontend) Auto(t Type) GCNode {
|
2017-02-02 11:53:41 -05:00
|
|
|
return &DummyAuto{t: t, s: "aDummyAuto"}
|
2015-08-24 02:16:19 -07:00
|
|
|
}
|
cmd/compile: better job of naming compound types
Compound AUTO types weren't named previously. That was because live
variable analysis (plive.go) doesn't handle spilling to compound types.
It can't handle them because there is no valid place to put VARDEFs when
regalloc is spilling compound types.
compound types = multiword builtin types: complex, string, slice, and
interface.
Instead, we split named AUTOs into individual one-word variables. For
example, a string s gets split into a byte ptr s.ptr and an integer
s.len. Those two variables can be spilled to / restored from
independently. As a result, live variable analysis can handle them
because they are one-word objects.
This CL will change how AUTOs are described in DWARF information.
Consider the code:
func f(s string, i int) int {
x := s[i:i+5]
g()
return lookup(x)
}
The old compiler would spill x to two consecutive slots on the stack,
both named x (at offsets 0 and 8). The new compiler spills the pointer
of x to a slot named x.ptr. It doesn't spill x.len at all, as it is a
constant (5) and can be rematerialized for the call to lookup.
So compound objects may not be spilled in their entirety, and even if
they are they won't necessarily be contiguous. Such is the price of
optimization.
Re-enable live variable analysis tests. One test remains disabled, it
fails because of #14904.
Change-Id: I8ef2b5ab91e43a0d2136bfc231c05d100ec0b801
Reviewed-on: https://go-review.googlesource.com/21233
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-03-28 11:25:17 -07:00
|
|
|
func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
|
|
|
|
|
return LocalSlot{s.N, d.TypeBytePtr(), s.Off}, LocalSlot{s.N, d.TypeInt(), s.Off + 8}
|
|
|
|
|
}
|
|
|
|
|
func (d DummyFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) {
|
|
|
|
|
return LocalSlot{s.N, d.TypeBytePtr(), s.Off}, LocalSlot{s.N, d.TypeBytePtr(), s.Off + 8}
|
|
|
|
|
}
|
|
|
|
|
func (d DummyFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
|
|
|
|
|
return LocalSlot{s.N, s.Type.ElemType().PtrTo(), s.Off},
|
|
|
|
|
LocalSlot{s.N, d.TypeInt(), s.Off + 8},
|
|
|
|
|
LocalSlot{s.N, d.TypeInt(), s.Off + 16}
|
|
|
|
|
}
|
|
|
|
|
func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
|
|
|
|
|
if s.Type.Size() == 16 {
|
|
|
|
|
return LocalSlot{s.N, d.TypeFloat64(), s.Off}, LocalSlot{s.N, d.TypeFloat64(), s.Off + 8}
|
|
|
|
|
}
|
|
|
|
|
return LocalSlot{s.N, d.TypeFloat32(), s.Off}, LocalSlot{s.N, d.TypeFloat32(), s.Off + 4}
|
|
|
|
|
}
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
|
|
|
|
|
if s.Type.IsSigned() {
|
|
|
|
|
return LocalSlot{s.N, d.TypeInt32(), s.Off + 4}, LocalSlot{s.N, d.TypeUInt32(), s.Off}
|
|
|
|
|
}
|
|
|
|
|
return LocalSlot{s.N, d.TypeUInt32(), s.Off + 4}, LocalSlot{s.N, d.TypeUInt32(), s.Off}
|
|
|
|
|
}
|
2016-03-31 21:24:10 -07:00
|
|
|
func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
|
|
|
|
|
return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
|
|
|
|
|
}
|
2016-10-30 21:10:03 -07:00
|
|
|
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
|
|
|
|
|
return LocalSlot{s.N, s.Type.ElemType(), s.Off}
|
|
|
|
|
}
|
2016-12-15 17:17:01 -08:00
|
|
|
func (DummyFrontend) Line(_ src.XPos) string {
|
2016-01-14 16:02:23 -08:00
|
|
|
return "unknown.go:0"
|
|
|
|
|
}
|
2016-10-03 12:26:25 -07:00
|
|
|
func (DummyFrontend) AllocFrame(f *Func) {
|
|
|
|
|
}
|
2017-02-06 13:30:40 -08:00
|
|
|
func (DummyFrontend) Syslook(s string) *obj.LSym {
|
|
|
|
|
return obj.Linklookup(TestCtxt, s, 0)
|
2016-10-13 06:57:00 -04:00
|
|
|
}
|
2017-02-05 23:43:31 -05:00
|
|
|
func (DummyFrontend) UseWriteBarrier() bool {
|
|
|
|
|
return true // only writebarrier_test cares
|
|
|
|
|
}
|
2015-06-12 11:01:13 -07:00
|
|
|
|
2016-01-13 11:14:57 -08:00
|
|
|
func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
|
2016-01-29 14:44:15 -05:00
|
|
|
func (d DummyFrontend) Log() bool { return true }
|
2016-01-13 11:14:57 -08:00
|
|
|
|
2016-12-15 17:17:01 -08:00
|
|
|
func (d DummyFrontend) Fatalf(_ src.XPos, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
|
|
|
|
|
func (d DummyFrontend) Warnl(_ src.XPos, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
|
|
|
|
|
func (d DummyFrontend) Debug_checknil() bool { return false }
|
|
|
|
|
func (d DummyFrontend) Debug_wb() bool { return false }
|
2015-07-30 11:03:05 -07:00
|
|
|
|
cmd/compile: de-virtualize interface calls
With this change, code like
h := sha1.New()
h.Write(buf)
sum := h.Sum()
gets compiled into static calls rather than
interface calls, because the compiler is able
to prove that 'h' is really a *sha1.digest.
The InterCall re-write rule hits a few dozen times
during make.bash, and hundreds of times during all.bash.
The most common pattern identified by the compiler
is a constructor like
func New() Interface { return &impl{...} }
where the constructor gets inlined into the caller,
and the result is used immediately. Examples include
{sha1,md5,crc32,crc64,...}.New, base64.NewEncoder,
base64.NewDecoder, errors.New, net.Pipe, and so on.
Some existing benchmarks that change on darwin/amd64:
Crc64/ISO4KB-8 2.67µs ± 1% 2.66µs ± 0% -0.36% (p=0.015 n=10+10)
Crc64/ISO1KB-8 694ns ± 0% 690ns ± 1% -0.59% (p=0.001 n=10+10)
Adler32KB-8 473ns ± 1% 471ns ± 0% -0.39% (p=0.010 n=10+9)
On architectures like amd64, the reduction in code size
appears to contribute more to benchmark improvements than just
removing the indirect call, since that branch gets predicted
accurately when called in a loop.
Updates #19361
Change-Id: I57d4dc21ef40a05ec0fbd55a9bb0eb74cdc67a3d
Reviewed-on: https://go-review.googlesource.com/38139
Run-TryBot: Philip Hofer <phofer@umich.edu>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2017-03-13 15:03:17 -07:00
|
|
|
func (d DummyFrontend) TypeBool() Type { return TypeBool }
|
|
|
|
|
func (d DummyFrontend) TypeInt8() Type { return TypeInt8 }
|
|
|
|
|
func (d DummyFrontend) TypeInt16() Type { return TypeInt16 }
|
|
|
|
|
func (d DummyFrontend) TypeInt32() Type { return TypeInt32 }
|
|
|
|
|
func (d DummyFrontend) TypeInt64() Type { return TypeInt64 }
|
|
|
|
|
func (d DummyFrontend) TypeUInt8() Type { return TypeUInt8 }
|
|
|
|
|
func (d DummyFrontend) TypeUInt16() Type { return TypeUInt16 }
|
|
|
|
|
func (d DummyFrontend) TypeUInt32() Type { return TypeUInt32 }
|
|
|
|
|
func (d DummyFrontend) TypeUInt64() Type { return TypeUInt64 }
|
|
|
|
|
func (d DummyFrontend) TypeFloat32() Type { return TypeFloat32 }
|
|
|
|
|
func (d DummyFrontend) TypeFloat64() Type { return TypeFloat64 }
|
|
|
|
|
func (d DummyFrontend) TypeInt() Type { return TypeInt64 }
|
|
|
|
|
func (d DummyFrontend) TypeUintptr() Type { return TypeUInt64 }
|
|
|
|
|
func (d DummyFrontend) TypeString() Type { panic("unimplemented") }
|
|
|
|
|
func (d DummyFrontend) TypeBytePtr() Type { return TypeBytePtr }
|
|
|
|
|
func (d DummyFrontend) DerefItab(sym *obj.LSym, off int64) *obj.LSym { return nil }
|
2015-09-18 22:58:10 -07:00
|
|
|
|
|
|
|
|
func (d DummyFrontend) CanSSA(t Type) bool {
|
|
|
|
|
// There are no un-SSAable types in dummy land.
|
|
|
|
|
return true
|
|
|
|
|
}
|