Commit 5b59b32c authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/compile: teach assemblers to accept a Prog allocator

The existing bulk Prog allocator is not concurrency-safe.
To allow for concurrency-safe bulk allocation of Progs,
I want to move Prog allocation and caching upstream,
to the clients of cmd/internal/obj.

This is a preliminary enabling refactoring.
After this CL, instead of calling Ctxt.NewProg
throughout the assemblers, we thread through
a newprog function that returns a new Prog.

That function is set up to be Ctxt.NewProg,
so there are no real changes in this CL;
this CL only establishes the plumbing.

Passes toolstash-check -all.
Negligible compiler performance impact.

Updates #15756

name        old time/op     new time/op     delta
Template        213ms ± 3%      214ms ± 4%    ~     (p=0.574 n=49+47)
Unicode        90.1ms ± 5%     89.9ms ± 4%    ~     (p=0.417 n=50+49)
GoTypes         585ms ± 4%      584ms ± 3%    ~     (p=0.466 n=49+49)
SSA             6.50s ± 3%      6.52s ± 2%    ~     (p=0.251 n=49+49)
Flate           128ms ± 4%      128ms ± 4%    ~     (p=0.673 n=49+50)
GoParser        152ms ± 3%      152ms ± 3%    ~     (p=0.810 n=48+49)
Reflect         372ms ± 4%      372ms ± 5%    ~     (p=0.778 n=49+50)
Tar             113ms ± 5%      111ms ± 4%  -0.98%  (p=0.016 n=50+49)
XML             208ms ± 3%      208ms ± 2%    ~     (p=0.483 n=47+49)
[Geo mean]      285ms           285ms       -0.17%

name        old user-ns/op  new user-ns/op  delta
Template         253M ± 8%       254M ± 9%    ~     (p=0.899 n=50+50)
Unicode          106M ± 9%       106M ±11%    ~     (p=0.642 n=50+50)
GoTypes          736M ± 4%       740M ± 4%    ~     (p=0.121 n=50+49)
SSA             8.82G ± 3%      8.88G ± 2%  +0.65%  (p=0.006 n=49+48)
Flate            147M ± 4%       147M ± 5%    ~     (p=0.844 n=47+48)
GoParser         179M ± 4%       178M ± 6%    ~     (p=0.785 n=50+50)
Reflect          443M ± 6%       441M ± 5%    ~     (p=0.850 n=48+47)
Tar              126M ± 5%       126M ± 5%    ~     (p=0.734 n=50+50)
XML              244M ± 5%       244M ± 5%    ~     (p=0.594 n=49+50)
[Geo mean]       341M            341M       +0.11%

Change-Id: Ice962f61eb3a524c2db00a166cb582c22caa7d68
Reviewed-on: https://go-review.googlesource.com/39633
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent 7e068895
...@@ -279,7 +279,7 @@ var deferreturn *obj.LSym ...@@ -279,7 +279,7 @@ var deferreturn *obj.LSym
// p->pc if extra padding is necessary. // p->pc if extra padding is necessary.
// In rare cases, asmoutnacl might split p into two instructions. // In rare cases, asmoutnacl might split p into two instructions.
// origPC is the PC for this Prog (no padding is taken into account). // origPC is the PC for this Prog (no padding is taken into account).
func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint32) int { func asmoutnacl(ctxt *obj.Link, newprog obj.ProgAlloc, origPC int32, p *obj.Prog, o *Optab, out []uint32) int {
size := int(o.size) size := int(o.size)
// instruction specific // instruction specific
...@@ -406,7 +406,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3 ...@@ -406,7 +406,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
// split it into two instructions: // split it into two instructions:
// ADD $-100004, R13 // ADD $-100004, R13
// MOVW R14, 0(R13) // MOVW R14, 0(R13)
q := ctxt.NewProg() q := newprog()
p.Scond &^= C_WBIT p.Scond &^= C_WBIT
*q = *p *q = *p
...@@ -486,7 +486,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3 ...@@ -486,7 +486,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
if p.Scond&(C_PBIT|C_WBIT) != 0 { if p.Scond&(C_PBIT|C_WBIT) != 0 {
ctxt.Diag("unsupported instruction (.P/.W): %v", p) ctxt.Diag("unsupported instruction (.P/.W): %v", p)
} }
q := ctxt.NewProg() q := newprog()
*q = *p *q = *p
var a2 *obj.Addr var a2 *obj.Addr
if p.To.Type == obj.TYPE_MEM { if p.To.Type == obj.TYPE_MEM {
...@@ -547,7 +547,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3 ...@@ -547,7 +547,7 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
return size return size
} }
func span5(ctxt *obj.Link, cursym *obj.LSym) { func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
var p *obj.Prog var p *obj.Prog
var op *obj.Prog var op *obj.Prog
...@@ -572,7 +572,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -572,7 +572,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
var o *Optab var o *Optab
for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link { for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link {
if p == nil { if p == nil {
if checkpool(ctxt, op, 0) { if checkpool(ctxt, newprog, op, 0) {
p = op p = op
continue continue
} }
...@@ -588,7 +588,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -588,7 +588,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
if ctxt.Headtype != obj.Hnacl { if ctxt.Headtype != obj.Hnacl {
m = int(o.size) m = int(o.size)
} else { } else {
m = asmoutnacl(ctxt, c, p, o, nil) m = asmoutnacl(ctxt, newprog, c, p, o, nil)
c = int32(p.Pc) // asmoutnacl might change pc for alignment c = int32(p.Pc) // asmoutnacl might change pc for alignment
o = oplook(ctxt, p) // asmoutnacl might change p in rare cases o = oplook(ctxt, p) // asmoutnacl might change p in rare cases
} }
...@@ -600,7 +600,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -600,7 +600,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
// must check literal pool here in case p generates many instructions // must check literal pool here in case p generates many instructions
if ctxt.Blitrl != nil { if ctxt.Blitrl != nil {
i = m i = m
if checkpool(ctxt, op, i) { if checkpool(ctxt, newprog, op, i) {
p = op p = op
continue continue
} }
...@@ -613,19 +613,19 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -613,19 +613,19 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
switch o.flag & (LFROM | LTO | LPOOL) { switch o.flag & (LFROM | LTO | LPOOL) {
case LFROM: case LFROM:
addpool(ctxt, p, &p.From) addpool(ctxt, newprog, p, &p.From)
case LTO: case LTO:
addpool(ctxt, p, &p.To) addpool(ctxt, newprog, p, &p.To)
case LPOOL: case LPOOL:
if p.Scond&C_SCOND == C_SCOND_NONE { if p.Scond&C_SCOND == C_SCOND_NONE {
flushpool(ctxt, p, 0, 0) flushpool(ctxt, newprog, p, 0, 0)
} }
} }
if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE { if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE {
flushpool(ctxt, p, 0, 0) flushpool(ctxt, newprog, p, 0, 0)
} }
c += int32(m) c += int32(m)
} }
...@@ -685,7 +685,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -685,7 +685,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
if ctxt.Headtype != obj.Hnacl { if ctxt.Headtype != obj.Hnacl {
m = int(o.size) m = int(o.size)
} else { } else {
m = asmoutnacl(ctxt, c, p, o, nil) m = asmoutnacl(ctxt, newprog, c, p, o, nil)
} }
if p.Pc != int64(opc) { if p.Pc != int64(opc) {
bflag = 1 bflag = 1
...@@ -746,7 +746,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -746,7 +746,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
asmout(ctxt, p, o, out[:]) asmout(ctxt, p, o, out[:])
m = int(o.size) m = int(o.size)
} else { } else {
m = asmoutnacl(ctxt, c, p, o, out[:]) m = asmoutnacl(ctxt, newprog, c, p, o, out[:])
if int64(opc) != p.Pc { if int64(opc) != p.Pc {
ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p) ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p)
} }
...@@ -795,22 +795,22 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -795,22 +795,22 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
* drop the pool now, and branch round it. * drop the pool now, and branch round it.
* this happens only in extended basic blocks that exceed 4k. * this happens only in extended basic blocks that exceed 4k.
*/ */
func checkpool(ctxt *obj.Link, p *obj.Prog, sz int) bool { func checkpool(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog, sz int) bool {
if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 { if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 {
return flushpool(ctxt, p, 1, 0) return flushpool(ctxt, newprog, p, 1, 0)
} else if p.Link == nil { } else if p.Link == nil {
return flushpool(ctxt, p, 2, 0) return flushpool(ctxt, newprog, p, 2, 0)
} }
return false return false
} }
func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool { func flushpool(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog, skip int, force int) bool {
if ctxt.Blitrl != nil { if ctxt.Blitrl != nil {
if skip != 0 { if skip != 0 {
if false && skip == 1 { if false && skip == 1 {
fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start) fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start)
} }
q := ctxt.NewProg() q := newprog()
q.As = AB q.As = AB
q.To.Type = obj.TYPE_BRANCH q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Link q.Pcond = p.Link
...@@ -822,7 +822,7 @@ func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool { ...@@ -822,7 +822,7 @@ func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool {
} }
if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 { if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 {
// if pool is not multiple of 16 bytes, add an alignment marker // if pool is not multiple of 16 bytes, add an alignment marker
q := ctxt.NewProg() q := newprog()
q.As = ADATABUNDLEEND q.As = ADATABUNDLEEND
ctxt.Elitrl.Link = q ctxt.Elitrl.Link = q
...@@ -850,7 +850,7 @@ func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool { ...@@ -850,7 +850,7 @@ func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool {
return false return false
} }
func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { func addpool(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog, a *obj.Addr) {
var t obj.Prog var t obj.Prog
c := aclass(ctxt, a) c := aclass(ctxt, a)
...@@ -894,7 +894,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { ...@@ -894,7 +894,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 { if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 {
// start a new data bundle // start a new data bundle
q := ctxt.NewProg() q := newprog()
q.As = ADATABUNDLE q.As = ADATABUNDLE
q.Pc = int64(pool.size) q.Pc = int64(pool.size)
pool.size += 4 pool.size += 4
...@@ -908,7 +908,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { ...@@ -908,7 +908,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
ctxt.Elitrl = q ctxt.Elitrl = q
} }
q := ctxt.NewProg() q := newprog()
*q = t *q = t
q.Pc = int64(pool.size) q.Pc = int64(pool.size)
......
This diff is collapsed.
...@@ -524,7 +524,7 @@ var pool struct { ...@@ -524,7 +524,7 @@ var pool struct {
size uint32 size uint32
} }
func span7(ctxt *obj.Link, cursym *obj.LSym) { func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p := cursym.Text p := cursym.Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return return
...@@ -557,19 +557,19 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -557,19 +557,19 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
switch o.flag & (LFROM | LTO) { switch o.flag & (LFROM | LTO) {
case LFROM: case LFROM:
addpool(ctxt, p, &p.From) addpool(ctxt, newprog, p, &p.From)
case LTO: case LTO:
addpool(ctxt, p, &p.To) addpool(ctxt, newprog, p, &p.To)
break break
} }
if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */ if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */
checkpool(ctxt, p, 0) checkpool(ctxt, newprog, p, 0)
} }
c += int64(m) c += int64(m)
if ctxt.Blitrl != nil { if ctxt.Blitrl != nil {
checkpool(ctxt, p, 1) checkpool(ctxt, newprog, p, 1)
} }
} }
...@@ -598,14 +598,14 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -598,14 +598,14 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
if (o.type_ == 7 || o.type_ == 39) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like if (o.type_ == 7 || o.type_ == 39) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like
otxt := p.Pcond.Pc - c otxt := p.Pcond.Pc - c
if otxt <= -(1<<18)+10 || otxt >= (1<<18)-10 { if otxt <= -(1<<18)+10 || otxt >= (1<<18)-10 {
q := ctxt.NewProg() q := newprog()
q.Link = p.Link q.Link = p.Link
p.Link = q p.Link = q
q.As = AB q.As = AB
q.To.Type = obj.TYPE_BRANCH q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Pcond q.Pcond = p.Pcond
p.Pcond = q p.Pcond = q
q = ctxt.NewProg() q = newprog()
q.Link = p.Link q.Link = p.Link
p.Link = q p.Link = q
q.As = AB q.As = AB
...@@ -670,21 +670,21 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -670,21 +670,21 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
* to go out of range of a 1Mb PC-relative offset * to go out of range of a 1Mb PC-relative offset
* drop the pool now, and branch round it. * drop the pool now, and branch round it.
*/ */
func checkpool(ctxt *obj.Link, p *obj.Prog, skip int) { func checkpool(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog, skip int) {
if pool.size >= 0xffff0 || !ispcdisp(int32(p.Pc+4+int64(pool.size)-int64(pool.start)+8)) { if pool.size >= 0xffff0 || !ispcdisp(int32(p.Pc+4+int64(pool.size)-int64(pool.start)+8)) {
flushpool(ctxt, p, skip) flushpool(ctxt, newprog, p, skip)
} else if p.Link == nil { } else if p.Link == nil {
flushpool(ctxt, p, 2) flushpool(ctxt, newprog, p, 2)
} }
} }
func flushpool(ctxt *obj.Link, p *obj.Prog, skip int) { func flushpool(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog, skip int) {
if ctxt.Blitrl != nil { if ctxt.Blitrl != nil {
if skip != 0 { if skip != 0 {
if ctxt.Debugvlog && skip == 1 { if ctxt.Debugvlog && skip == 1 {
fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start) fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start)
} }
q := ctxt.NewProg() q := newprog()
q.As = AB q.As = AB
q.To.Type = obj.TYPE_BRANCH q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Link q.Pcond = p.Link
...@@ -715,10 +715,10 @@ func flushpool(ctxt *obj.Link, p *obj.Prog, skip int) { ...@@ -715,10 +715,10 @@ func flushpool(ctxt *obj.Link, p *obj.Prog, skip int) {
/* /*
* TODO: hash * TODO: hash
*/ */
func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { func addpool(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog, a *obj.Addr) {
c := aclass(ctxt, a) c := aclass(ctxt, a)
lit := ctxt.Instoffset lit := ctxt.Instoffset
t := *ctxt.NewProg() t := *newprog()
t.As = AWORD t.As = AWORD
sz := 4 sz := 4
...@@ -789,7 +789,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { ...@@ -789,7 +789,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
} }
} }
q := ctxt.NewProg() q := newprog()
*q = t *q = t
q.Pc = int64(pool.size) q.Pc = int64(pool.size)
if ctxt.Blitrl == nil { if ctxt.Blitrl == nil {
......
This diff is collapsed.
...@@ -76,8 +76,8 @@ func mkfwd(sym *LSym) { ...@@ -76,8 +76,8 @@ func mkfwd(sym *LSym) {
} }
} }
func Appendp(ctxt *Link, q *Prog) *Prog { func Appendp(q *Prog, newprog ProgAlloc) *Prog {
p := ctxt.NewProg() p := newprog()
p.Link = q.Link p.Link = q.Link
q.Link = p q.Link = p
p.Pos = q.Pos p.Pos = q.Pos
......
...@@ -224,7 +224,8 @@ const ( ...@@ -224,7 +224,8 @@ const (
// Each Prog is charged to a specific source line in the debug information, // Each Prog is charged to a specific source line in the debug information,
// specified by Pos.Line(). // specified by Pos.Line().
// Every Prog has a Ctxt field that defines its context. // Every Prog has a Ctxt field that defines its context.
// Progs should be allocated using ctxt.NewProg(), not new(Prog). // For performance reasons, Progs usually are usually bulk allocated, cached, and reused;
// those bulk allocators should always be used, rather than new(Prog).
// //
// The other fields not yet mentioned are for use by the back ends and should // The other fields not yet mentioned are for use by the back ends and should
// be left zeroed by creators of Prog lists. // be left zeroed by creators of Prog lists.
...@@ -789,9 +790,9 @@ type SymVer struct { ...@@ -789,9 +790,9 @@ type SymVer struct {
// LinkArch is the definition of a single architecture. // LinkArch is the definition of a single architecture.
type LinkArch struct { type LinkArch struct {
*sys.Arch *sys.Arch
Preprocess func(*Link, *LSym) Preprocess func(*Link, *LSym, ProgAlloc)
Assemble func(*Link, *LSym) Assemble func(*Link, *LSym, ProgAlloc)
Progedit func(*Link, *Prog) Progedit func(*Link, *Prog, ProgAlloc)
UnaryDst map[As]bool // Instruction takes one operand, a destination. UnaryDst map[As]bool // Instruction takes one operand, a destination.
} }
......
...@@ -373,7 +373,7 @@ var oprange [ALAST & obj.AMask][]Optab ...@@ -373,7 +373,7 @@ var oprange [ALAST & obj.AMask][]Optab
var xcmp [C_NCLASS][C_NCLASS]bool var xcmp [C_NCLASS][C_NCLASS]bool
func span0(ctxt *obj.Link, cursym *obj.LSym) { func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p := cursym.Text p := cursym.Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return return
...@@ -430,7 +430,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -430,7 +430,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
if o.type_ == 6 && p.Pcond != nil { if o.type_ == 6 && p.Pcond != nil {
otxt = p.Pcond.Pc - c otxt = p.Pcond.Pc - c
if otxt < -(1<<17)+10 || otxt >= (1<<17)-10 { if otxt < -(1<<17)+10 || otxt >= (1<<17)-10 {
q = ctxt.NewProg() q = newprog()
q.Link = p.Link q.Link = p.Link
p.Link = q p.Link = q
q.As = AJMP q.As = AJMP
...@@ -438,7 +438,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -438,7 +438,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
q.To.Type = obj.TYPE_BRANCH q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Pcond q.Pcond = p.Pcond
p.Pcond = q p.Pcond = q
q = ctxt.NewProg() q = newprog()
q.Link = p.Link q.Link = p.Link
p.Link = q p.Link = q
q.As = AJMP q.As = AJMP
...@@ -446,8 +446,8 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -446,8 +446,8 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
q.To.Type = obj.TYPE_BRANCH q.To.Type = obj.TYPE_BRANCH
q.Pcond = q.Link.Link q.Pcond = q.Link.Link
addnop(ctxt, p.Link) addnop(ctxt, p.Link, newprog)
addnop(ctxt, p) addnop(ctxt, p, newprog)
bflag = 1 bflag = 1
} }
} }
......
This diff is collapsed.
...@@ -117,7 +117,7 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) { ...@@ -117,7 +117,7 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) {
ctxt.Diag("invalid encoding for argument %v", p) ctxt.Diag("invalid encoding for argument %v", p)
} }
func linkpatch(ctxt *Link, sym *LSym) { func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
var c int32 var c int32
var name string var name string
var q *Prog var q *Prog
...@@ -130,7 +130,7 @@ func linkpatch(ctxt *Link, sym *LSym) { ...@@ -130,7 +130,7 @@ func linkpatch(ctxt *Link, sym *LSym) {
checkaddr(ctxt, p, &p.To) checkaddr(ctxt, p, &p.To)
if ctxt.Arch.Progedit != nil { if ctxt.Arch.Progedit != nil {
ctxt.Arch.Progedit(ctxt, p) ctxt.Arch.Progedit(ctxt, p, newprog)
} }
if p.To.Type != TYPE_BRANCH { if p.To.Type != TYPE_BRANCH {
continue continue
......
...@@ -15,6 +15,10 @@ type Plist struct { ...@@ -15,6 +15,10 @@ type Plist struct {
Curfn interface{} // holds a *gc.Node, if non-nil Curfn interface{} // holds a *gc.Node, if non-nil
} }
// ProgAlloc is a function that allocates Progs.
// It is used to provide access to cached/bulk-allocated Progs to the assemblers.
type ProgAlloc func() *Prog
func Flushplist(ctxt *Link, plist *Plist) { func Flushplist(ctxt *Link, plist *Plist) {
flushplist(ctxt, plist, !ctxt.Debugasm) flushplist(ctxt, plist, !ctxt.Debugasm)
} }
...@@ -97,6 +101,8 @@ func flushplist(ctxt *Link, plist *Plist, freeProgs bool) { ...@@ -97,6 +101,8 @@ func flushplist(ctxt *Link, plist *Plist, freeProgs bool) {
etext = p etext = p
} }
newprog := ProgAlloc(ctxt.NewProg)
// Add reference to Go arguments for C or assembly functions without them. // Add reference to Go arguments for C or assembly functions without them.
for _, s := range text { for _, s := range text {
if !strings.HasPrefix(s.Name, "\"\".") { if !strings.HasPrefix(s.Name, "\"\".") {
...@@ -111,7 +117,7 @@ func flushplist(ctxt *Link, plist *Plist, freeProgs bool) { ...@@ -111,7 +117,7 @@ func flushplist(ctxt *Link, plist *Plist, freeProgs bool) {
} }
if !found { if !found {
p := Appendp(ctxt, s.Text) p := Appendp(s.Text, newprog)
p.As = AFUNCDATA p.As = AFUNCDATA
p.From.Type = TYPE_CONST p.From.Type = TYPE_CONST
p.From.Offset = FUNCDATA_ArgsPointerMaps p.From.Offset = FUNCDATA_ArgsPointerMaps
...@@ -124,9 +130,9 @@ func flushplist(ctxt *Link, plist *Plist, freeProgs bool) { ...@@ -124,9 +130,9 @@ func flushplist(ctxt *Link, plist *Plist, freeProgs bool) {
// Turn functions into machine code images. // Turn functions into machine code images.
for _, s := range text { for _, s := range text {
mkfwd(s) mkfwd(s)
linkpatch(ctxt, s) linkpatch(ctxt, s, newprog)
ctxt.Arch.Preprocess(ctxt, s) ctxt.Arch.Preprocess(ctxt, s, newprog)
ctxt.Arch.Assemble(ctxt, s) ctxt.Arch.Assemble(ctxt, s, newprog)
linkpcln(ctxt, s) linkpcln(ctxt, s)
makeFuncDebugEntry(ctxt, plist.Curfn, s) makeFuncDebugEntry(ctxt, plist.Curfn, s)
if freeProgs { if freeProgs {
......
...@@ -552,7 +552,7 @@ var oprange [ALAST & obj.AMask][]Optab ...@@ -552,7 +552,7 @@ var oprange [ALAST & obj.AMask][]Optab
var xcmp [C_NCLASS][C_NCLASS]bool var xcmp [C_NCLASS][C_NCLASS]bool
func span9(ctxt *obj.Link, cursym *obj.LSym) { func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p := cursym.Text p := cursym.Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return return
...@@ -609,14 +609,14 @@ func span9(ctxt *obj.Link, cursym *obj.LSym) { ...@@ -609,14 +609,14 @@ func span9(ctxt *obj.Link, cursym *obj.LSym) {
if (o.type_ == 16 || o.type_ == 17) && p.Pcond != nil { if (o.type_ == 16 || o.type_ == 17) && p.Pcond != nil {
otxt = p.Pcond.Pc - c otxt = p.Pcond.Pc - c
if otxt < -(1<<15)+10 || otxt >= (1<<15)-10 { if otxt < -(1<<15)+10 || otxt >= (1<<15)-10 {
q = ctxt.NewProg() q = newprog()
q.Link = p.Link q.Link = p.Link
p.Link = q p.Link = q
q.As = ABR q.As = ABR
q.To.Type = obj.TYPE_BRANCH q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Pcond q.Pcond = p.Pcond
p.Pcond = q p.Pcond = q
q = ctxt.NewProg() q = newprog()
q.Link = p.Link q.Link = p.Link
p.Link = q p.Link = q
q.As = ABR q.As = ABR
......
This diff is collapsed.
...@@ -385,7 +385,7 @@ var oprange [ALAST & obj.AMask][]Optab ...@@ -385,7 +385,7 @@ var oprange [ALAST & obj.AMask][]Optab
var xcmp [C_NCLASS][C_NCLASS]bool var xcmp [C_NCLASS][C_NCLASS]bool
func spanz(ctxt *obj.Link, cursym *obj.LSym) { func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p := cursym.Text p := cursym.Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return return
......
This diff is collapsed.
...@@ -1762,7 +1762,7 @@ func spadjop(ctxt *obj.Link, p *obj.Prog, l, q obj.As) obj.As { ...@@ -1762,7 +1762,7 @@ func spadjop(ctxt *obj.Link, p *obj.Prog, l, q obj.As) obj.As {
return q return q
} }
func span6(ctxt *obj.Link, s *obj.LSym) { func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
if s.P != nil { if s.P != nil {
return return
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment