mirror of
https://github.com/golang/go
synced 2024-11-19 04:44:41 -07:00
cmd/internal/gc: increase registerization limits
Also clean up code a little. Change-Id: I23b7d2b7871b31e0974f1305e54f0c18dcab05d9 Reviewed-on: https://go-review.googlesource.com/7746 Reviewed-by: Dave Cheney <dave@cheney.net> Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
fd38dbc8a1
commit
d47fe8092e
@ -326,7 +326,7 @@ func pushback(r0 *gc.Flow) {
|
||||
}
|
||||
|
||||
if b == nil {
|
||||
if gc.Debug['v'] != 0 {
|
||||
if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
|
||||
fmt.Printf("no pushback: %v\n", r0.Prog)
|
||||
if r != nil {
|
||||
fmt.Printf("\t%v [%d]\n", r.Prog, gc.Uniqs(r) != nil)
|
||||
@ -336,7 +336,7 @@ func pushback(r0 *gc.Flow) {
|
||||
return
|
||||
}
|
||||
|
||||
if gc.Debug['v'] != 0 {
|
||||
if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
|
||||
fmt.Printf("pushback\n")
|
||||
for r := (*gc.Flow)(b); ; r = r.Link {
|
||||
fmt.Printf("\t%v\n", r.Prog)
|
||||
@ -366,7 +366,7 @@ func pushback(r0 *gc.Flow) {
|
||||
p0.From = t.From
|
||||
p0.To = t.To
|
||||
|
||||
if gc.Debug['v'] != 0 {
|
||||
if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
|
||||
fmt.Printf("\tafter\n")
|
||||
for r := (*gc.Flow)(b); ; r = r.Link {
|
||||
fmt.Printf("\t%v\n", r.Prog)
|
||||
|
@ -1,159 +0,0 @@
|
||||
// Inferno utils/cc/bits.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package gc
|
||||
|
||||
import "fmt"
|
||||
|
||||
/*
|
||||
Bits
|
||||
bor(Bits a, Bits b)
|
||||
{
|
||||
Bits c;
|
||||
int i;
|
||||
|
||||
for(i=0; i<BITS; i++)
|
||||
c.b[i] = a.b[i] | b.b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
Bits
|
||||
band(Bits a, Bits b)
|
||||
{
|
||||
Bits c;
|
||||
int i;
|
||||
|
||||
for(i=0; i<BITS; i++)
|
||||
c.b[i] = a.b[i] & b.b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
Bits
|
||||
bnot(Bits a)
|
||||
{
|
||||
Bits c;
|
||||
int i;
|
||||
|
||||
for(i=0; i<BITS; i++)
|
||||
c.b[i] = ~a.b[i];
|
||||
return c;
|
||||
}
|
||||
*/
|
||||
func bany(a *Bits) bool {
|
||||
for i := 0; i < BITS; i++ {
|
||||
if a.b[i] != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/*
|
||||
int
|
||||
beq(Bits a, Bits b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<BITS; i++)
|
||||
if(a.b[i] != b.b[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
func bnum(a Bits) int {
|
||||
var b uint64
|
||||
|
||||
for i := 0; i < BITS; i++ {
|
||||
b = a.b[i]
|
||||
if b != 0 {
|
||||
return 64*i + Bitno(b)
|
||||
}
|
||||
}
|
||||
|
||||
Fatal("bad in bnum")
|
||||
return 0
|
||||
}
|
||||
|
||||
func blsh(n uint) Bits {
|
||||
c := zbits
|
||||
c.b[n/64] = 1 << (n % 64)
|
||||
return c
|
||||
}
|
||||
|
||||
func btest(a *Bits, n uint) bool {
|
||||
return a.b[n/64]&(1<<(n%64)) != 0
|
||||
}
|
||||
|
||||
func biset(a *Bits, n uint) {
|
||||
a.b[n/64] |= 1 << (n % 64)
|
||||
}
|
||||
|
||||
func biclr(a *Bits, n uint) {
|
||||
a.b[n/64] &^= (1 << (n % 64))
|
||||
}
|
||||
|
||||
func Bitno(b uint64) int {
|
||||
for i := 0; i < 64; i++ {
|
||||
if b&(1<<uint(i)) != 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
Fatal("bad in bitno")
|
||||
return 0
|
||||
}
|
||||
|
||||
func Qconv(bits Bits, flag int) string {
|
||||
var fp string
|
||||
|
||||
var i int
|
||||
|
||||
first := 1
|
||||
|
||||
for bany(&bits) {
|
||||
i = bnum(bits)
|
||||
if first != 0 {
|
||||
first = 0
|
||||
} else {
|
||||
fp += " "
|
||||
}
|
||||
if var_[i].node == nil || var_[i].node.Sym == nil {
|
||||
fp += fmt.Sprintf("$%d", i)
|
||||
} else {
|
||||
fp += fmt.Sprintf("%s(%d)", var_[i].node.Sym.Name, i)
|
||||
if var_[i].offset != 0 {
|
||||
fp += fmt.Sprintf("%+d", int64(var_[i].offset))
|
||||
}
|
||||
}
|
||||
|
||||
biclr(&bits, uint(i))
|
||||
}
|
||||
|
||||
return fp
|
||||
}
|
@ -351,30 +351,6 @@ const (
|
||||
Ecomplit = 1 << 11 // type in composite literal
|
||||
)
|
||||
|
||||
const (
|
||||
BITS = 3
|
||||
NVAR = BITS * 64
|
||||
)
|
||||
|
||||
type Bits struct {
|
||||
b [BITS]uint64
|
||||
}
|
||||
|
||||
var zbits Bits
|
||||
|
||||
type Var struct {
|
||||
offset int64
|
||||
node *Node
|
||||
nextinnode *Var
|
||||
width int
|
||||
id int
|
||||
name int8
|
||||
etype int8
|
||||
addr int8
|
||||
}
|
||||
|
||||
var var_ [NVAR]Var
|
||||
|
||||
type Typedef struct {
|
||||
Name string
|
||||
Etype int
|
||||
|
@ -1,44 +1,3 @@
|
||||
// Derived from Inferno utils/6c/reg.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
|
||||
//
|
||||
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
||||
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
||||
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
||||
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
||||
// Portions Copyright © 2004,2006 Bruce Ellis
|
||||
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
||||
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
||||
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package gc
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// "Portable" optimizations.
|
||||
|
||||
// Derived from Inferno utils/6c/gc.h
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
|
||||
//
|
||||
@ -69,92 +28,17 @@ import (
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
const (
|
||||
CLOAD = 5
|
||||
CREF = 5
|
||||
CINF = 1000
|
||||
LOOP = 3
|
||||
// "Portable" optimizations.
|
||||
|
||||
package gc
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Reg struct {
|
||||
set Bits // regopt variables written by this instruction.
|
||||
use1 Bits // regopt variables read by prog->from.
|
||||
use2 Bits // regopt variables read by prog->to.
|
||||
|
||||
// refahead/refbehind are the regopt variables whose current
|
||||
// value may be used in the following/preceding instructions
|
||||
// up to a CALL (or the value is clobbered).
|
||||
refbehind Bits
|
||||
refahead Bits
|
||||
|
||||
// calahead/calbehind are similar, but for variables in
|
||||
// instructions that are reachable after hitting at least one
|
||||
// CALL.
|
||||
calbehind Bits
|
||||
calahead Bits
|
||||
|
||||
regdiff Bits
|
||||
act Bits
|
||||
regu uint64 // register used bitmap
|
||||
}
|
||||
|
||||
type Rgn struct {
|
||||
enter *Flow
|
||||
cost int16
|
||||
varno int16
|
||||
regno int16
|
||||
}
|
||||
|
||||
var Z *Node
|
||||
|
||||
// A Reg is a wrapper around a single Prog (one instruction) that holds
|
||||
// register optimization information while the optimizer runs.
|
||||
// r->prog is the instruction.
|
||||
|
||||
var R *Reg
|
||||
|
||||
const (
|
||||
NRGN = 600
|
||||
)
|
||||
|
||||
// A Rgn represents a single regopt variable over a region of code
|
||||
// where a register could potentially be dedicated to that variable.
|
||||
// The code encompassed by a Rgn is defined by the flow graph,
|
||||
// starting at enter, flood-filling forward while varno is refahead
|
||||
// and backward while varno is refbehind, and following branches. A
|
||||
// single variable may be represented by multiple disjoint Rgns and
|
||||
// each Rgn may choose a different register for that variable.
|
||||
// Registers are allocated to regions greedily in order of descending
|
||||
// cost.
|
||||
|
||||
var zreg Reg
|
||||
|
||||
var region [NRGN]Rgn
|
||||
|
||||
var rgp *Rgn
|
||||
|
||||
var nregion int
|
||||
|
||||
var nvar int
|
||||
|
||||
var regbits uint64
|
||||
|
||||
var externs Bits
|
||||
|
||||
var params Bits
|
||||
|
||||
var consts Bits
|
||||
|
||||
var addrs Bits
|
||||
|
||||
var ivar Bits
|
||||
|
||||
var ovar Bits
|
||||
|
||||
var change int
|
||||
|
||||
var maxnr int32
|
||||
|
||||
type OptStats struct {
|
||||
Ncvtreg int32
|
||||
Nspill int32
|
||||
@ -354,6 +238,11 @@ func fixjmp(firstp *obj.Prog) {
|
||||
|
||||
var flowmark int
|
||||
|
||||
// MaxFlowProg is the maximum size program (counted in instructions)
|
||||
// for which the flow code will build a graph. Functions larger than this limit
|
||||
// will not have flow graphs and consequently will not be optimized.
|
||||
const MaxFlowProg = 50000
|
||||
|
||||
func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
|
||||
// Count and mark instructions to annotate.
|
||||
nf := 0
|
||||
@ -372,8 +261,10 @@ func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
|
||||
return nil
|
||||
}
|
||||
|
||||
if nf >= 20000 {
|
||||
// fatal("%S is too big (%d instructions)", curfn->nname->sym, nf);
|
||||
if nf >= MaxFlowProg {
|
||||
if Debug['v'] != 0 {
|
||||
Warn("%v is too big (%d instructions)", Sconv(Curfn.Nname.Sym, 0), nf)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -678,7 +569,7 @@ func canmerge(n *Node) bool {
|
||||
|
||||
func mergetemp(firstp *obj.Prog) {
|
||||
const (
|
||||
debugmerge = 1
|
||||
debugmerge = 0
|
||||
)
|
||||
|
||||
g := Flowstart(firstp, nil)
|
||||
|
@ -31,14 +31,111 @@
|
||||
package gc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/obj"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var firstf *Flow
|
||||
// A Var represents a single variable that may be stored in a register.
|
||||
// That variable may itself correspond to a hardware register,
|
||||
// to represent the use of registers in the unoptimized instruction stream.
|
||||
type Var struct {
|
||||
offset int64
|
||||
node *Node
|
||||
nextinnode *Var
|
||||
width int
|
||||
id int // index in vars
|
||||
name int8
|
||||
etype int8
|
||||
addr int8
|
||||
}
|
||||
|
||||
var first int = 1
|
||||
// Bits represents a set of Vars, stored as a bit set of var numbers
|
||||
// (the index in vars, or equivalently v.id).
|
||||
type Bits struct {
|
||||
b [BITS]uint64
|
||||
}
|
||||
|
||||
const (
|
||||
BITS = 3
|
||||
NVAR = BITS * 64
|
||||
)
|
||||
|
||||
var (
|
||||
vars [NVAR]Var // variables under consideration
|
||||
nvar int // number of vars
|
||||
|
||||
regbits uint64 // bits for hardware registers
|
||||
|
||||
zbits Bits // zero
|
||||
externs Bits // global variables
|
||||
params Bits // function parameters and results
|
||||
ivar Bits // function parameters (inputs)
|
||||
ovar Bits // function results (outputs)
|
||||
consts Bits // constant values
|
||||
addrs Bits // variables with address taken
|
||||
)
|
||||
|
||||
// A Reg is a wrapper around a single Prog (one instruction) that holds
|
||||
// register optimization information while the optimizer runs.
|
||||
// r->prog is the instruction.
|
||||
type Reg struct {
|
||||
set Bits // regopt variables written by this instruction.
|
||||
use1 Bits // regopt variables read by prog->from.
|
||||
use2 Bits // regopt variables read by prog->to.
|
||||
|
||||
// refahead/refbehind are the regopt variables whose current
|
||||
// value may be used in the following/preceding instructions
|
||||
// up to a CALL (or the value is clobbered).
|
||||
refbehind Bits
|
||||
refahead Bits
|
||||
|
||||
// calahead/calbehind are similar, but for variables in
|
||||
// instructions that are reachable after hitting at least one
|
||||
// CALL.
|
||||
calbehind Bits
|
||||
calahead Bits
|
||||
|
||||
regdiff Bits
|
||||
act Bits
|
||||
regu uint64 // register used bitmap
|
||||
}
|
||||
|
||||
// A Rgn represents a single regopt variable over a region of code
|
||||
// where a register could potentially be dedicated to that variable.
|
||||
// The code encompassed by a Rgn is defined by the flow graph,
|
||||
// starting at enter, flood-filling forward while varno is refahead
|
||||
// and backward while varno is refbehind, and following branches.
|
||||
// A single variable may be represented by multiple disjoint Rgns and
|
||||
// each Rgn may choose a different register for that variable.
|
||||
// Registers are allocated to regions greedily in order of descending
|
||||
// cost.
|
||||
type Rgn struct {
|
||||
enter *Flow
|
||||
cost int16
|
||||
varno int16
|
||||
regno int16
|
||||
}
|
||||
|
||||
// The Plan 9 C compilers used a limit of 600 regions,
|
||||
// but the yacc-generated parser in y.go has 3100 regions.
|
||||
// We set MaxRgn large enough to handle that.
|
||||
// There's not a huge cost to having too many regions:
|
||||
// the main processing traces the live area for each variable,
|
||||
// which is limited by the number of variables times the area,
|
||||
// not the raw region count. If there are many regions, they
|
||||
// are almost certainly small and easy to trace.
|
||||
// The only operation that scales with region count is the
|
||||
// sorting by cost, which uses sort.Sort and is therefore
|
||||
// guaranteed n log n.
|
||||
const MaxRgn = 6000
|
||||
|
||||
var (
|
||||
region []Rgn
|
||||
nregion int
|
||||
)
|
||||
|
||||
type rcmp []Rgn
|
||||
|
||||
@ -75,13 +172,13 @@ func setaddrs(bit Bits) {
|
||||
// convert each bit to a variable
|
||||
i = bnum(bit)
|
||||
|
||||
node = var_[i].node
|
||||
n = int(var_[i].name)
|
||||
node = vars[i].node
|
||||
n = int(vars[i].name)
|
||||
biclr(&bit, uint(i))
|
||||
|
||||
// disable all pieces of that variable
|
||||
for i = 0; i < nvar; i++ {
|
||||
v = &var_[i]
|
||||
v = &vars[i]
|
||||
if v.node == node && int(v.name) == n {
|
||||
v.addr = 2
|
||||
}
|
||||
@ -135,7 +232,7 @@ func addmove(r *Flow, bn int, rn int, f int) {
|
||||
p.Link = p1
|
||||
p1.Lineno = p.Lineno
|
||||
|
||||
v := &var_[bn]
|
||||
v := &vars[bn]
|
||||
|
||||
a := &p1.To
|
||||
a.Offset = v.offset
|
||||
@ -223,7 +320,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
|
||||
fallthrough
|
||||
|
||||
case obj.TYPE_MEM:
|
||||
if r != R {
|
||||
if r != nil {
|
||||
r.use1.b[0] |= Thearch.RtoB(int(a.Reg))
|
||||
}
|
||||
|
||||
@ -233,11 +330,16 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
|
||||
*/
|
||||
switch a.Name {
|
||||
default:
|
||||
// Note: This case handles NAME_EXTERN and NAME_STATIC.
|
||||
// We treat these as requiring eager writes to memory, due to
|
||||
// the possibility of a fault handler looking at them, so there is
|
||||
// not much point in registerizing the loads.
|
||||
// If we later choose the set of candidate variables from a
|
||||
// larger list, these cases could be deprioritized instead of
|
||||
// removed entirely.
|
||||
return zbits
|
||||
|
||||
case obj.NAME_EXTERN,
|
||||
obj.NAME_STATIC,
|
||||
obj.NAME_PARAM,
|
||||
case obj.NAME_PARAM,
|
||||
obj.NAME_AUTO:
|
||||
n = int(a.Name)
|
||||
}
|
||||
@ -264,7 +366,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
|
||||
flag := 0
|
||||
var v *Var
|
||||
for i := 0; i < nvar; i++ {
|
||||
v = &var_[i]
|
||||
v = &vars[i]
|
||||
if v.node == node && int(v.name) == n {
|
||||
if v.offset == o {
|
||||
if int(v.etype) == et {
|
||||
@ -297,6 +399,9 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
|
||||
if Debug['w'] > 1 && node != nil {
|
||||
Fatal("variable not optimized: %v", Nconv(node, obj.FmtSharp))
|
||||
}
|
||||
if Debug['v'] > 0 {
|
||||
Warn("variable not optimized: %v", Nconv(node, obj.FmtSharp))
|
||||
}
|
||||
|
||||
// If we're not tracking a word in a variable, mark the rest as
|
||||
// having its address taken, so that we keep the whole thing
|
||||
@ -304,7 +409,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
|
||||
// a variable but not all of it.
|
||||
var v *Var
|
||||
for i := 0; i < nvar; i++ {
|
||||
v = &var_[i]
|
||||
v = &vars[i]
|
||||
if v.node == node {
|
||||
v.addr = 1
|
||||
}
|
||||
@ -315,7 +420,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
|
||||
|
||||
i := nvar
|
||||
nvar++
|
||||
v = &var_[i]
|
||||
v = &vars[i]
|
||||
v.id = i
|
||||
v.offset = o
|
||||
v.name = int8(n)
|
||||
@ -394,6 +499,8 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
|
||||
return bit
|
||||
}
|
||||
|
||||
var change int
|
||||
|
||||
func prop(f *Flow, ref Bits, cal Bits) {
|
||||
var f1 *Flow
|
||||
var r1 *Reg
|
||||
@ -408,13 +515,13 @@ func prop(f *Flow, ref Bits, cal Bits) {
|
||||
ref.b[z] |= r1.refahead.b[z]
|
||||
if ref.b[z] != r1.refahead.b[z] {
|
||||
r1.refahead.b[z] = ref.b[z]
|
||||
change++
|
||||
change = 1
|
||||
}
|
||||
|
||||
cal.b[z] |= r1.calahead.b[z]
|
||||
if cal.b[z] != r1.calahead.b[z] {
|
||||
r1.calahead.b[z] = cal.b[z]
|
||||
change++
|
||||
change = 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,7 +563,7 @@ func prop(f *Flow, ref Bits, cal Bits) {
|
||||
if z*64+i >= nvar || (cal.b[z]>>uint(i))&1 == 0 {
|
||||
continue
|
||||
}
|
||||
v = &var_[z*64+i]
|
||||
v = &vars[z*64+i]
|
||||
if v.node.Opt == nil { // v represents fixed register, not Go variable
|
||||
continue
|
||||
}
|
||||
@ -527,7 +634,7 @@ func synch(f *Flow, dif Bits) {
|
||||
dif.b[z] = dif.b[z]&^(^r1.refbehind.b[z]&r1.refahead.b[z]) | r1.set.b[z] | r1.regdiff.b[z]
|
||||
if dif.b[z] != r1.regdiff.b[z] {
|
||||
r1.regdiff.b[z] = dif.b[z]
|
||||
change++
|
||||
change = 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -545,7 +652,7 @@ func synch(f *Flow, dif Bits) {
|
||||
}
|
||||
|
||||
func allreg(b uint64, r *Rgn) uint64 {
|
||||
v := &var_[r.varno]
|
||||
v := &vars[r.varno]
|
||||
r.regno = 0
|
||||
switch v.etype {
|
||||
default:
|
||||
@ -591,6 +698,13 @@ func STORE(r *Reg, z int) uint64 {
|
||||
return ^r.calbehind.b[z] & r.calahead.b[z]
|
||||
}
|
||||
|
||||
// Cost parameters
|
||||
const (
|
||||
CLOAD = 5 // cost of load
|
||||
CREF = 5 // cost of reference if not registerized
|
||||
LOOP = 3 // loop execution count (applied in popt.go)
|
||||
)
|
||||
|
||||
func paint1(f *Flow, bn int) {
|
||||
z := bn / 64
|
||||
bb := uint64(1 << uint(bn%64))
|
||||
@ -855,31 +969,31 @@ func dumpone(f *Flow, isreg int) {
|
||||
if bany(&bit) {
|
||||
fmt.Printf("\t")
|
||||
if bany(&r.set) {
|
||||
fmt.Printf(" s:%v", Qconv(r.set, 0))
|
||||
fmt.Printf(" s:%v", &r.set)
|
||||
}
|
||||
if bany(&r.use1) {
|
||||
fmt.Printf(" u1:%v", Qconv(r.use1, 0))
|
||||
fmt.Printf(" u1:%v", &r.use1)
|
||||
}
|
||||
if bany(&r.use2) {
|
||||
fmt.Printf(" u2:%v", Qconv(r.use2, 0))
|
||||
fmt.Printf(" u2:%v", &r.use2)
|
||||
}
|
||||
if bany(&r.refbehind) {
|
||||
fmt.Printf(" rb:%v ", Qconv(r.refbehind, 0))
|
||||
fmt.Printf(" rb:%v ", &r.refbehind)
|
||||
}
|
||||
if bany(&r.refahead) {
|
||||
fmt.Printf(" ra:%v ", Qconv(r.refahead, 0))
|
||||
fmt.Printf(" ra:%v ", &r.refahead)
|
||||
}
|
||||
if bany(&r.calbehind) {
|
||||
fmt.Printf(" cb:%v ", Qconv(r.calbehind, 0))
|
||||
fmt.Printf(" cb:%v ", &r.calbehind)
|
||||
}
|
||||
if bany(&r.calahead) {
|
||||
fmt.Printf(" ca:%v ", Qconv(r.calahead, 0))
|
||||
fmt.Printf(" ca:%v ", &r.calahead)
|
||||
}
|
||||
if bany(&r.regdiff) {
|
||||
fmt.Printf(" d:%v ", Qconv(r.regdiff, 0))
|
||||
fmt.Printf(" d:%v ", &r.regdiff)
|
||||
}
|
||||
if bany(&r.act) {
|
||||
fmt.Printf(" a:%v ", Qconv(r.act, 0))
|
||||
fmt.Printf(" a:%v ", &r.act)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -922,10 +1036,6 @@ func Dumpit(str string, r0 *Flow, isreg int) {
|
||||
}
|
||||
|
||||
func regopt(firstp *obj.Prog) {
|
||||
if first != 0 {
|
||||
first = 0
|
||||
}
|
||||
|
||||
mergetemp(firstp)
|
||||
|
||||
/*
|
||||
@ -938,13 +1048,13 @@ func regopt(firstp *obj.Prog) {
|
||||
|
||||
nvar = nreg
|
||||
for i := 0; i < nreg; i++ {
|
||||
var_[i] = Var{}
|
||||
vars[i] = Var{}
|
||||
}
|
||||
for i := 0; i < nreg; i++ {
|
||||
if regnodes[i] == nil {
|
||||
regnodes[i] = newname(Lookup(regnames[i]))
|
||||
}
|
||||
var_[i].node = regnodes[i]
|
||||
vars[i].node = regnodes[i]
|
||||
}
|
||||
|
||||
regbits = Thearch.Excludedregs()
|
||||
@ -962,15 +1072,14 @@ func regopt(firstp *obj.Prog) {
|
||||
* find use and set of variables
|
||||
*/
|
||||
g := Flowstart(firstp, func() interface{} { return new(Reg) })
|
||||
|
||||
if g == nil {
|
||||
for i := 0; i < nvar; i++ {
|
||||
var_[i].node.Opt = nil
|
||||
vars[i].node.Opt = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
firstf = g.Start
|
||||
firstf := g.Start
|
||||
|
||||
for f := firstf; f != nil; f = f.Link {
|
||||
p := f.Prog
|
||||
@ -1035,7 +1144,7 @@ func regopt(firstp *obj.Prog) {
|
||||
}
|
||||
|
||||
for i := 0; i < nvar; i++ {
|
||||
v := &var_[i]
|
||||
v := &vars[i]
|
||||
if v.addr != 0 {
|
||||
bit := blsh(uint(i))
|
||||
for z := 0; z < BITS; z++ {
|
||||
@ -1176,10 +1285,8 @@ loop2:
|
||||
* isolate regions
|
||||
* calculate costs (paint1)
|
||||
*/
|
||||
f = firstf
|
||||
|
||||
var bit Bits
|
||||
if f != nil {
|
||||
if f := firstf; f != nil {
|
||||
r := f.Data.(*Reg)
|
||||
for z := 0; z < BITS; z++ {
|
||||
bit.b[z] = (r.refahead.b[z] | r.calahead.b[z]) &^ (externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z])
|
||||
@ -1187,7 +1294,7 @@ loop2:
|
||||
if bany(&bit) && f.Refset == 0 {
|
||||
// should never happen - all variables are preset
|
||||
if Debug['w'] != 0 {
|
||||
fmt.Printf("%v: used and not set: %v\n", f.Prog.Line(), Qconv(bit, 0))
|
||||
fmt.Printf("%v: used and not set: %v\n", f.Prog.Line(), &bit)
|
||||
}
|
||||
f.Refset = 1
|
||||
}
|
||||
@ -1197,6 +1304,7 @@ loop2:
|
||||
(f.Data.(*Reg)).act = zbits
|
||||
}
|
||||
nregion = 0
|
||||
region = region[:0]
|
||||
var rgp *Rgn
|
||||
for f := firstf; f != nil; f = f.Link {
|
||||
r := f.Data.(*Reg)
|
||||
@ -1205,7 +1313,7 @@ loop2:
|
||||
}
|
||||
if bany(&bit) && f.Refset == 0 {
|
||||
if Debug['w'] != 0 {
|
||||
fmt.Printf("%v: set and not used: %v\n", f.Prog.Line(), Qconv(bit, 0))
|
||||
fmt.Printf("%v: set and not used: %v\n", f.Prog.Line(), &bit)
|
||||
}
|
||||
f.Refset = 1
|
||||
Thearch.Excise(f)
|
||||
@ -1222,22 +1330,30 @@ loop2:
|
||||
if change <= 0 {
|
||||
continue
|
||||
}
|
||||
if nregion >= NRGN {
|
||||
if Debug['R'] != 0 && Debug['v'] != 0 {
|
||||
fmt.Printf("too many regions\n")
|
||||
}
|
||||
goto brk
|
||||
if nregion >= MaxRgn {
|
||||
nregion++
|
||||
continue
|
||||
}
|
||||
|
||||
rgp = ®ion[nregion]
|
||||
rgp.enter = f
|
||||
rgp.varno = int16(i)
|
||||
rgp.cost = int16(change)
|
||||
region = append(region, Rgn{
|
||||
enter: f,
|
||||
cost: int16(change),
|
||||
varno: int16(i),
|
||||
})
|
||||
nregion++
|
||||
}
|
||||
}
|
||||
|
||||
brk:
|
||||
if Debug['v'] != 0 && strings.Contains(Curfn.Nname.Sym.Name, "Parse") {
|
||||
Warn("regions: %d\n", nregion)
|
||||
}
|
||||
if nregion >= MaxRgn {
|
||||
if Debug['v'] != 0 {
|
||||
Warn("too many regions: %d\n", nregion)
|
||||
}
|
||||
nregion = MaxRgn
|
||||
}
|
||||
|
||||
sort.Sort(rcmp(region[:nregion]))
|
||||
|
||||
if Debug['R'] != 0 && Debug['v'] != 0 {
|
||||
@ -1264,7 +1380,7 @@ brk:
|
||||
vreg = allreg(usedreg, rgp)
|
||||
if rgp.regno != 0 {
|
||||
if Debug['R'] != 0 && Debug['v'] != 0 {
|
||||
v := &var_[rgp.varno]
|
||||
v := &vars[rgp.varno]
|
||||
fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", Nconv(v.node, 0), v.offset, rgp.varno, Econv(int(v.etype), 0), obj.Rconv(int(rgp.regno)), usedreg, vreg)
|
||||
}
|
||||
|
||||
@ -1276,7 +1392,7 @@ brk:
|
||||
* free aux structures. peep allocates new ones.
|
||||
*/
|
||||
for i := 0; i < nvar; i++ {
|
||||
var_[i].node.Opt = nil
|
||||
vars[i].node.Opt = nil
|
||||
}
|
||||
Flowend(g)
|
||||
firstf = nil
|
||||
@ -1284,7 +1400,6 @@ brk:
|
||||
if Debug['R'] != 0 && Debug['v'] != 0 {
|
||||
// Rebuild flow graph, since we inserted instructions
|
||||
g := Flowstart(firstp, nil)
|
||||
|
||||
firstf = g.Start
|
||||
Dumpit("pass6", firstf, 0)
|
||||
Flowend(g)
|
||||
@ -1340,3 +1455,107 @@ brk:
|
||||
Ostats = OptStats{}
|
||||
}
|
||||
}
|
||||
|
||||
// bany reports whether any bits in a are set.
|
||||
func bany(a *Bits) bool {
|
||||
for _, x := range &a.b { // & to avoid making a copy of a.b
|
||||
if x != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// bnum reports the lowest index of a 1 bit in a.
|
||||
func bnum(a Bits) int {
|
||||
for i, x := range &a.b { // & to avoid making a copy of a.b
|
||||
if x != 0 {
|
||||
return 64*i + Bitno(x)
|
||||
}
|
||||
}
|
||||
|
||||
Fatal("bad in bnum")
|
||||
return 0
|
||||
}
|
||||
|
||||
// blsh returns a Bits with 1 at index n, 0 elsewhere (1<<n).
|
||||
func blsh(n uint) Bits {
|
||||
c := zbits
|
||||
c.b[n/64] = 1 << (n % 64)
|
||||
return c
|
||||
}
|
||||
|
||||
// btest reports whether bit n is 1.
|
||||
func btest(a *Bits, n uint) bool {
|
||||
return a.b[n/64]&(1<<(n%64)) != 0
|
||||
}
|
||||
|
||||
// biset sets bit n to 1.
|
||||
func biset(a *Bits, n uint) {
|
||||
a.b[n/64] |= 1 << (n % 64)
|
||||
}
|
||||
|
||||
// biclr sets bit n to 0.
|
||||
func biclr(a *Bits, n uint) {
|
||||
a.b[n/64] &^= (1 << (n % 64))
|
||||
}
|
||||
|
||||
// Bitno reports the lowest index of a 1 bit in b.
|
||||
// It calls Fatal if there is no 1 bit.
|
||||
func Bitno(b uint64) int {
|
||||
if b == 0 {
|
||||
Fatal("bad in bitno")
|
||||
}
|
||||
n := 0
|
||||
if b&(1<<32-1) == 0 {
|
||||
n += 32
|
||||
b >>= 32
|
||||
}
|
||||
if b&(1<<16-1) == 0 {
|
||||
n += 16
|
||||
b >>= 16
|
||||
}
|
||||
if b&(1<<8-1) == 0 {
|
||||
n += 8
|
||||
b >>= 8
|
||||
}
|
||||
if b&(1<<4-1) == 0 {
|
||||
n += 4
|
||||
b >>= 4
|
||||
}
|
||||
if b&(1<<2-1) == 0 {
|
||||
n += 2
|
||||
b >>= 2
|
||||
}
|
||||
if b&1 == 0 {
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// String returns a space-separated list of the variables represented by bits.
|
||||
func (bits Bits) String() string {
|
||||
// Note: This method takes a value receiver, both for convenience
|
||||
// and to make it safe to modify the bits as we process them.
|
||||
// Even so, most prints above use &bits, because then the value
|
||||
// being stored in the interface{} is a pointer and does not require
|
||||
// an allocation and copy to create the interface{}.
|
||||
var buf bytes.Buffer
|
||||
sep := ""
|
||||
for bany(&bits) {
|
||||
i := bnum(bits)
|
||||
buf.WriteString(sep)
|
||||
sep = " "
|
||||
v := &vars[i]
|
||||
if v.node == nil || v.node.Sym == nil {
|
||||
fmt.Fprintf(&buf, "$%d", i)
|
||||
} else {
|
||||
fmt.Fprintf(&buf, "%s(%d)", v.node.Sym.Name, i)
|
||||
if v.offset != 0 {
|
||||
fmt.Fprintf(&buf, "%+d", int64(v.offset))
|
||||
}
|
||||
}
|
||||
biclr(&bits, uint(i))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user