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: Keith Randall <khr@golang.org>
// p->pc if extra padding is necessary.
// In rare cases, asmoutnacl might split p into two instructions.
// 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)
// instruction specific
// split it into two instructions:
// ADD $-100004, R13
// MOVW R14, 0(R13)
- q := ctxt.NewProg()
+ q := newprog()
p.Scond &^= C_WBIT
*q = *p
if p.Scond&(C_PBIT|C_WBIT) != 0 {
ctxt.Diag("unsupported instruction (.P/.W): %v", p)
}
- q := ctxt.NewProg()
+ q := newprog()
*q = *p
var a2 *obj.Addr
if p.To.Type == obj.TYPE_MEM {
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 op *obj.Prog
var o *Optab
for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link {
if p == nil {
- if checkpool(ctxt, op, 0) {
+ if checkpool(ctxt, newprog, op, 0) {
p = op
continue
}
if ctxt.Headtype != obj.Hnacl {
m = int(o.size)
} 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
o = oplook(ctxt, p) // asmoutnacl might change p in rare cases
}
// must check literal pool here in case p generates many instructions
if ctxt.Blitrl != nil {
i = m
- if checkpool(ctxt, op, i) {
+ if checkpool(ctxt, newprog, op, i) {
p = op
continue
}
switch o.flag & (LFROM | LTO | LPOOL) {
case LFROM:
- addpool(ctxt, p, &p.From)
+ addpool(ctxt, newprog, p, &p.From)
case LTO:
- addpool(ctxt, p, &p.To)
+ addpool(ctxt, newprog, p, &p.To)
case LPOOL:
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 {
- flushpool(ctxt, p, 0, 0)
+ flushpool(ctxt, newprog, p, 0, 0)
}
c += int32(m)
}
if ctxt.Headtype != obj.Hnacl {
m = int(o.size)
} else {
- m = asmoutnacl(ctxt, c, p, o, nil)
+ m = asmoutnacl(ctxt, newprog, c, p, o, nil)
}
if p.Pc != int64(opc) {
bflag = 1
asmout(ctxt, p, o, out[:])
m = int(o.size)
} else {
- m = asmoutnacl(ctxt, c, p, o, out[:])
+ m = asmoutnacl(ctxt, newprog, c, p, o, out[:])
if int64(opc) != p.Pc {
ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p)
}
* drop the pool now, and branch round it.
* 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 {
- return flushpool(ctxt, p, 1, 0)
+ return flushpool(ctxt, newprog, p, 1, 0)
} else if p.Link == nil {
- return flushpool(ctxt, p, 2, 0)
+ return flushpool(ctxt, newprog, p, 2, 0)
}
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 skip != 0 {
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)
}
- q := ctxt.NewProg()
+ q := newprog()
q.As = AB
q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Link
}
if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 {
// if pool is not multiple of 16 bytes, add an alignment marker
- q := ctxt.NewProg()
+ q := newprog()
q.As = ADATABUNDLEEND
ctxt.Elitrl.Link = q
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
c := aclass(ctxt, a)
if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 {
// start a new data bundle
- q := ctxt.NewProg()
+ q := newprog()
q.As = ADATABUNDLE
q.Pc = int64(pool.size)
pool.size += 4
ctxt.Elitrl = q
}
- q := ctxt.NewProg()
+ q := newprog()
*q = t
q.Pc = int64(pool.size)
var progedit_tlsfallback *obj.LSym
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.From.Class = 0
p.To.Class = 0
p.To.Reg = REGTMP
// BL runtime.read_tls_fallback(SB)
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
p.To.Offset = 0
// MOVW R11, LR
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_REG
}
if ctxt.Flag_dynlink {
- rewriteToUseGot(ctxt, p)
+ rewriteToUseGot(ctxt, p, newprog)
}
}
// Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
// ADUFFxxx $offset
// becomes
p.To.Name = obj.NAME_NONE
p.To.Offset = 0
p.To.Sym = nil
- p1 := obj.Appendp(ctxt, p)
+ p1 := obj.Appendp(p, newprog)
p1.As = AADD
p1.From.Type = obj.TYPE_CONST
p1.From.Offset = offset
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REG_R9
- p2 := obj.Appendp(ctxt, p1)
+ p2 := obj.Appendp(p1, newprog)
p2.As = obj.ACALL
p2.To.Type = obj.TYPE_MEM
p2.To.Reg = REG_R9
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
if p.From.Offset != 0 {
- q := obj.Appendp(ctxt, p)
+ q := obj.Appendp(p, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
if source.Type != obj.TYPE_MEM {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
- p1 := obj.Appendp(ctxt, p)
- p2 := obj.Appendp(ctxt, p1)
+ p1 := obj.Appendp(p, newprog)
+ p2 := obj.Appendp(p1, newprog)
p1.As = AMOVW
p1.From.Type = obj.TYPE_MEM
LEAF = 1 << 2
)
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize := int32(0)
ctxt.Cursym = cursym
return
}
- softfloat(ctxt, cursym)
+ softfloat(ctxt, newprog, cursym)
p := cursym.Text
autoffset := int32(p.To.Offset)
}
if p.From3.Offset&obj.NOSPLIT == 0 {
- p = stacksplit(ctxt, p, autosize) // emit split check
+ p = stacksplit(ctxt, p, newprog, autosize) // emit split check
}
// MOVW.W R14,$-autosize(SP)
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.Scond |= C_WBIT
// The NOP is needed to give the jumps somewhere to land.
// It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = 0
p.Reg = REG_R1
// B.NE checkargp
- bne := obj.Appendp(ctxt, p)
+ bne := obj.Appendp(p, newprog)
bne.As = ABNE
bne.To.Type = obj.TYPE_BRANCH
// end: NOP
- end := obj.Appendp(ctxt, bne)
+ end := obj.Appendp(bne, newprog)
end.As = obj.ANOP
// find end of function
}
// MOVW panic_argp(R1), R2
- mov := obj.Appendp(ctxt, last)
+ mov := obj.Appendp(last, newprog)
mov.As = AMOVW
mov.From.Type = obj.TYPE_MEM
mov.From.Reg = REG_R1
bne.Pcond = mov
// ADD $(autosize+4), R13, R3
- p = obj.Appendp(ctxt, mov)
+ p = obj.Appendp(mov, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(autosize) + 4
p.To.Reg = REG_R3
// CMP R2, R3
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R2
p.Reg = REG_R3
// B.NE end
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ABNE
p.To.Type = obj.TYPE_BRANCH
p.Pcond = end
// ADD $4, R13, R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = 4
p.To.Reg = REG_R4
// MOVW R4, panic_argp(R1)
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R4
p.To.Offset = 0 // Panic.argp
// B end
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AB
p.To.Type = obj.TYPE_BRANCH
p.Pcond = end
// with the same stackframe, so no spadj.
if p.To.Sym != nil { // retjmp
p.To.Reg = REGLINK
- q2 = obj.Appendp(ctxt, p)
+ q2 = obj.Appendp(p, newprog)
q2.As = AB
q2.To.Type = obj.TYPE_BRANCH
q2.To.Sym = p.To.Sym
p.To.Reg = REGTMP
/* MOV a,m_divmod(REGTMP) */
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.Pos = q1.Pos
p.From.Type = obj.TYPE_REG
p.To.Offset = 8 * 4 // offset of m.divmod
/* MOV b, R8 */
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.Pos = q1.Pos
p.From.Type = obj.TYPE_REG
p.To.Offset = 0
/* CALL appropriate */
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ABL
p.Pos = q1.Pos
p.To.Type = obj.TYPE_BRANCH
}
/* MOV REGTMP, b */
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.Pos = q1.Pos
p.From.Type = obj.TYPE_REG
return a.Type == obj.TYPE_REG && REG_F0 <= a.Reg && a.Reg <= REG_F15
}
-func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
+func softfloat(ctxt *obj.Link, newprog obj.ProgAlloc, cursym *obj.LSym) {
if obj.GOARM > 5 {
return
}
soft:
if wasfloat == 0 || (p.Mark&LABEL != 0) {
- next = ctxt.NewProg()
+ next = newprog()
*next = *p
// BL _sfloat(SB)
}
}
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+func stacksplit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, framesize int32) *obj.Prog {
// MOVW g_stackguard(g), R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_MEM
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// CMP stackguard, SP
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
// large stack: SP-framesize < stackguard-StackSmall
// MOVW $-(framesize-StackSmall)(SP), R2
// CMP stackguard, R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
// SUB.NE R1, R2
// MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
// CMP.NE R3, R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
p.Reg = REG_R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Reg = REGSP
p.To.Reg = REG_R2
p.Scond = C_SCOND_NE
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.To.Reg = REG_R2
p.Scond = C_SCOND_NE
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVW
p.From.Type = obj.TYPE_ADDR
p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
p.To.Reg = REG_R3
p.Scond = C_SCOND_NE
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
}
// BLS call-to-morestack
- bls := obj.Appendp(ctxt, p)
+ bls := obj.Appendp(p, newprog)
bls.As = ABLS
bls.To.Type = obj.TYPE_BRANCH
// Now we are at the end of the function, but logically
// we are still in function prologue. We need to fix the
// SP data and PCDATA.
- spfix := obj.Appendp(ctxt, last)
+ spfix := obj.Appendp(last, newprog)
spfix.As = obj.ANOP
spfix.Spadj = -framesize
- pcdata := obj.Appendp(ctxt, spfix)
+ pcdata := obj.Appendp(spfix, newprog)
pcdata.Pos = ctxt.Cursym.Text.Pos
pcdata.As = obj.APCDATA
pcdata.From.Type = obj.TYPE_CONST
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
// MOVW LR, R3
- movw := obj.Appendp(ctxt, pcdata)
+ movw := obj.Appendp(pcdata, newprog)
movw.As = AMOVW
movw.From.Type = obj.TYPE_REG
movw.From.Reg = REGLINK
bls.Pcond = movw
// BL runtime.morestack
- call := obj.Appendp(ctxt, movw)
+ call := obj.Appendp(movw, newprog)
call.As = obj.ACALL
call.To.Type = obj.TYPE_BRANCH
morestack := "runtime.morestack"
call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
// B start
- b := obj.Appendp(ctxt, call)
+ b := obj.Appendp(call, newprog)
b.As = obj.AJMP
b.To.Type = obj.TYPE_BRANCH
b.Pcond = ctxt.Cursym.Text.Link
size uint32
}
-func span7(ctxt *obj.Link, cursym *obj.LSym) {
+func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p := cursym.Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
switch o.flag & (LFROM | LTO) {
case LFROM:
- addpool(ctxt, p, &p.From)
+ addpool(ctxt, newprog, p, &p.From)
case LTO:
- addpool(ctxt, p, &p.To)
+ addpool(ctxt, newprog, p, &p.To)
break
}
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)
if ctxt.Blitrl != nil {
- checkpool(ctxt, p, 1)
+ checkpool(ctxt, newprog, p, 1)
}
}
if (o.type_ == 7 || o.type_ == 39) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like
otxt := p.Pcond.Pc - c
if otxt <= -(1<<18)+10 || otxt >= (1<<18)-10 {
- q := ctxt.NewProg()
+ q := newprog()
q.Link = p.Link
p.Link = q
q.As = AB
q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Pcond
p.Pcond = q
- q = ctxt.NewProg()
+ q = newprog()
q.Link = p.Link
p.Link = q
q.As = AB
* to go out of range of a 1Mb PC-relative offset
* 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)) {
- flushpool(ctxt, p, skip)
+ flushpool(ctxt, newprog, p, skip)
} 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 skip != 0 {
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)
}
- q := ctxt.NewProg()
+ q := newprog()
q.As = AB
q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Link
/*
* 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)
lit := ctxt.Instoffset
- t := *ctxt.NewProg()
+ t := *newprog()
t.As = AWORD
sz := 4
}
}
- q := ctxt.NewProg()
+ q := newprog()
*q = t
q.Pc = int64(pool.size)
if ctxt.Blitrl == nil {
ACMNW: ACMPW,
}
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+func stacksplit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, framesize int32) *obj.Prog {
// MOV g_stackguard(g), R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
// small stack: SP < stackguard
// MOV SP, R2
// CMP stackguard, R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
// large stack: SP-framesize < stackguard-StackSmall
// SUB $(framesize-StackSmall), SP, R2
// CMP stackguard, R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ASUB
p.From.Type = obj.TYPE_CONST
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
// SUB R1, R2
// MOV $(framesize+(StackGuard-StackSmall)), R3
// CMP R3, R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackPreempt
p.Reg = REG_R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
q = p
p.As = ABEQ
p.To.Type = obj.TYPE_BRANCH
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackGuard
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
}
// BLS do-morestack
- bls := obj.Appendp(ctxt, p)
+ bls := obj.Appendp(p, newprog)
bls.As = ABLS
bls.To.Type = obj.TYPE_BRANCH
// Now we are at the end of the function, but logically
// we are still in function prologue. We need to fix the
// SP data and PCDATA.
- spfix := obj.Appendp(ctxt, last)
+ spfix := obj.Appendp(last, newprog)
spfix.As = obj.ANOP
spfix.Spadj = -framesize
- pcdata := obj.Appendp(ctxt, spfix)
+ pcdata := obj.Appendp(spfix, newprog)
pcdata.Pos = ctxt.Cursym.Text.Pos
pcdata.As = obj.APCDATA
pcdata.From.Type = obj.TYPE_CONST
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
// MOV LR, R3
- movlr := obj.Appendp(ctxt, pcdata)
+ movlr := obj.Appendp(pcdata, newprog)
movlr.As = AMOVD
movlr.From.Type = obj.TYPE_REG
movlr.From.Reg = REGLINK
debug := movlr
if false {
- debug = obj.Appendp(ctxt, debug)
+ debug = obj.Appendp(debug, newprog)
debug.As = AMOVD
debug.From.Type = obj.TYPE_CONST
debug.From.Offset = int64(framesize)
}
// BL runtime.morestack(SB)
- call := obj.Appendp(ctxt, debug)
+ call := obj.Appendp(debug, newprog)
call.As = ABL
call.To.Type = obj.TYPE_BRANCH
morestack := "runtime.morestack"
call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
// B start
- jmp := obj.Appendp(ctxt, call)
+ jmp := obj.Appendp(call, newprog)
jmp.As = AB
jmp.To.Type = obj.TYPE_BRANCH
jmp.Pcond = ctxt.Cursym.Text.Link
return bls
}
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.From.Class = 0
p.To.Class = 0
}
if ctxt.Flag_dynlink {
- rewriteToUseGot(ctxt, p)
+ rewriteToUseGot(ctxt, p, newprog)
}
}
// Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
// ADUFFxxx $offset
// becomes
p.To.Name = obj.NAME_NONE
p.To.Offset = 0
p.To.Sym = nil
- p1 := obj.Appendp(ctxt, p)
+ p1 := obj.Appendp(p, newprog)
p1.As = AADD
p1.From.Type = obj.TYPE_CONST
p1.From.Offset = offset
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REGTMP
- p2 := obj.Appendp(ctxt, p1)
+ p2 := obj.Appendp(p1, newprog)
p2.As = obj.ACALL
p2.To.Type = obj.TYPE_REG
p2.To.Reg = REGTMP
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
if p.From.Offset != 0 {
- q := obj.Appendp(ctxt, p)
+ q := obj.Appendp(p, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
if source.Type != obj.TYPE_MEM {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
- p1 := obj.Appendp(ctxt, p)
- p2 := obj.Appendp(ctxt, p1)
+ p1 := obj.Appendp(p, newprog)
+ p2 := obj.Appendp(p1, newprog)
p1.As = AMOVD
p1.From.Type = obj.TYPE_MEM
p1.From.Sym = source.Sym
obj.Nopout(p)
}
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Cursym = cursym
if cursym.Text == nil || cursym.Text.Link == nil {
}
if !(p.From3.Offset&obj.NOSPLIT != 0) {
- p = stacksplit(ctxt, p, ctxt.Autosize) // emit split check
+ p = stacksplit(ctxt, p, newprog, ctxt.Autosize) // emit split check
}
aoffset = ctxt.Autosize
// Store link register before decrementing SP, so if a signal comes
// during the execution of the function prologue, the traceback
// code will not see a half-updated stack frame.
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.Pos = p.Pos
q.As = ASUB
q.From.Type = obj.TYPE_CONST
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.Pos = p.Pos
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.To.Type = obj.TYPE_MEM
q.To.Reg = REGTMP
- q1 = obj.Appendp(ctxt, q)
+ q1 = obj.Appendp(q, newprog)
q1.Pos = p.Pos
q1.As = AMOVD
q1.From.Type = obj.TYPE_REG
q1.Spadj = ctxt.Autosize
} else {
// small frame, update SP and save LR in a single MOVD.W instruction
- q1 = obj.Appendp(ctxt, q)
+ q1 = obj.Appendp(q, newprog)
q1.As = AMOVD
q1.Pos = p.Pos
q1.From.Type = obj.TYPE_REG
// It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes.
q = q1
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R1
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REGZERO
q.Reg = REG_R1
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABEQ
q.To.Type = obj.TYPE_BRANCH
q1 = q
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REG_R1
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R2
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(ctxt.Autosize) + 8
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R2
q.Reg = REG_R3
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABNE
q.To.Type = obj.TYPE_BRANCH
q2 = q
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = 8
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R4
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R4
q.To.Reg = REG_R1
q.To.Offset = 0 // Panic.argp
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = obj.ANOP
q1.Pcond = q
p.To.Reg = REGLINK
p.Spadj = -aoffset
if ctxt.Autosize > aoffset {
- q = ctxt.NewProg()
+ q = newprog()
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(ctxt.Autosize) - int64(aoffset)
}
if p.As != obj.ARET {
- q = ctxt.NewProg()
+ q = newprog()
q.Pos = p.Pos
q.Link = p.Link
p.Link = q
}
}
-func Appendp(ctxt *Link, q *Prog) *Prog {
- p := ctxt.NewProg()
+func Appendp(q *Prog, newprog ProgAlloc) *Prog {
+ p := newprog()
p.Link = q.Link
q.Link = p
p.Pos = q.Pos
// Each Prog is charged to a specific source line in the debug information,
// specified by Pos.Line().
// 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
// be left zeroed by creators of Prog lists.
// LinkArch is the definition of a single architecture.
type LinkArch struct {
*sys.Arch
- Preprocess func(*Link, *LSym)
- Assemble func(*Link, *LSym)
- Progedit func(*Link, *Prog)
+ Preprocess func(*Link, *LSym, ProgAlloc)
+ Assemble func(*Link, *LSym, ProgAlloc)
+ Progedit func(*Link, *Prog, ProgAlloc)
UnaryDst map[As]bool // Instruction takes one operand, a destination.
}
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
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
if o.type_ == 6 && p.Pcond != nil {
otxt = p.Pcond.Pc - c
if otxt < -(1<<17)+10 || otxt >= (1<<17)-10 {
- q = ctxt.NewProg()
+ q = newprog()
q.Link = p.Link
p.Link = q
q.As = AJMP
q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Pcond
p.Pcond = q
- q = ctxt.NewProg()
+ q = newprog()
q.Link = p.Link
p.Link = q
q.As = AJMP
q.To.Type = obj.TYPE_BRANCH
q.Pcond = q.Link.Link
- addnop(ctxt, p.Link)
- addnop(ctxt, p)
+ addnop(ctxt, p.Link, newprog)
+ addnop(ctxt, p, newprog)
bflag = 1
}
}
"math"
)
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.From.Class = 0
p.To.Class = 0
}
}
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// TODO(minux): add morestack short-cuts with small fixed frame-size.
ctxt.Cursym = cursym
p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
if p.From3.Offset&obj.NOSPLIT == 0 {
- p = stacksplit(ctxt, p, autosize) // emit split check
+ p = stacksplit(ctxt, p, newprog, autosize) // emit split check
}
q = p
// Store link register before decrement SP, so if a signal comes
// during the execution of the function prologue, the traceback
// code will not see a half-updated stack frame.
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = mov
q.Pos = p.Pos
q.From.Type = obj.TYPE_REG
q.To.Offset = int64(-autosize)
q.To.Reg = REGSP
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = add
q.Pos = p.Pos
q.From.Type = obj.TYPE_CONST
// The NOP is needed to give the jumps somewhere to land.
// It is a liblink NOP, not an mips NOP: it encodes to 0 instruction bytes.
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = mov
q.From.Type = obj.TYPE_MEM
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R1
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABEQ
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R1
q.Mark |= BRANCH
p1 = q
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = mov
q.From.Type = obj.TYPE_MEM
q.From.Reg = REG_R1
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R2
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = add
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABNE
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R2
q.Mark |= BRANCH
p2 = q
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = add
q.From.Type = obj.TYPE_CONST
q.From.Offset = ctxt.FixedFrameSize()
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R2
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = mov
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R2
q.To.Reg = REG_R1
q.To.Offset = 0 // Panic.argp
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = obj.ANOP
p1.Pcond = q
p.To.Reg = REGSP
p.Spadj = -autosize
- q = ctxt.NewProg()
+ q = newprog()
q.As = AJMP
q.Pos = p.Pos
q.To.Type = obj.TYPE_MEM
}
if autosize != 0 {
- q = ctxt.NewProg()
+ q = newprog()
q.As = add
q.Pos = p.Pos
q.From.Type = obj.TYPE_CONST
p.Link = q
}
- q1 = ctxt.NewProg()
+ q1 = newprog()
q1.As = AJMP
q1.Pos = p.Pos
if retSym != nil { // retjmp
}
p.As = AMOVF
- q = ctxt.NewProg()
+ q = newprog()
*q = *p
q.Link = p.Link
p.Link = q
// NOP after each branch instruction.
for p = cursym.Text; p != nil; p = p.Link {
if p.Mark&BRANCH != 0 {
- addnop(ctxt, p)
+ addnop(ctxt, p, newprog)
}
}
return
o++
if p.Mark&NOSCHED != 0 {
if q1 != p {
- sched(ctxt, q1, q)
+ sched(ctxt, newprog, q1, q)
}
for ; p != nil; p = p.Link {
if p.Mark&NOSCHED == 0 {
}
if p.Mark&(LABEL|SYNC) != 0 {
if q1 != p {
- sched(ctxt, q1, q)
+ sched(ctxt, newprog, q1, q)
}
q1 = p
o = 1
}
if p.Mark&(BRANCH|SYNC) != 0 {
- sched(ctxt, q1, p)
+ sched(ctxt, newprog, q1, p)
q1 = p1
o = 0
}
if o >= NSCHED {
- sched(ctxt, q1, p)
+ sched(ctxt, newprog, q1, p)
q1 = p1
o = 0
}
}
}
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+func stacksplit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, framesize int32) *obj.Prog {
// Leaf function with no frame is effectively NOSPLIT.
if framesize == 0 {
return p
}
// MOV g_stackguard(g), R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = mov
p.From.Type = obj.TYPE_MEM
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// AGTU SP, stackguard, R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ASGTU
p.From.Type = obj.TYPE_REG
// large stack: SP-framesize < stackguard-StackSmall
// ADD $-(framesize-StackSmall), SP, R2
// SGTU R2, stackguard, R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = add
p.From.Type = obj.TYPE_CONST
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ASGTU
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R2
// SUB R1, R2
// MOV $(framesize+(StackGuard-StackSmall)), R1
// SGTU R2, R1, R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = mov
p.From.Type = obj.TYPE_CONST
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
q = p
p.As = ABEQ
p.From.Type = obj.TYPE_REG
p.To.Type = obj.TYPE_BRANCH
p.Mark |= BRANCH
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = add
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackGuard
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = sub
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R1
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = mov
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R1
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ASGTU
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R2
}
// q1: BNE R1, done
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
q1 := p
p.As = ABNE
p.Mark |= BRANCH
// MOV LINK, R3
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = mov
p.From.Type = obj.TYPE_REG
}
// JAL runtime.morestack(SB)
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AJAL
p.To.Type = obj.TYPE_BRANCH
p.Mark |= BRANCH
// JMP start
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AJMP
p.To.Type = obj.TYPE_BRANCH
p.Mark |= BRANCH
// placeholder for q1's jump target
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = obj.ANOP // zero-width place holder
q1.Pcond = p
return p
}
-func addnop(ctxt *obj.Link, p *obj.Prog) {
- q := ctxt.NewProg()
+func addnop(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
+ q := newprog()
// we want to use the canonical NOP (SLL $0,R0,R0) here,
// however, as the assembler will always replace $0
// as R0, we have to resort to manually encode the SLL
comp bool
}
-func sched(ctxt *obj.Link, p0, pe *obj.Prog) {
+func sched(ctxt *obj.Link, newprog obj.ProgAlloc, p0, pe *obj.Prog) {
var sch [NSCHED]Sch
/*
}
for s[0].nop != 0 {
s[0].nop--
- addnop(ctxt, p)
+ addnop(ctxt, p, newprog)
}
}
}
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 name string
var q *Prog
checkaddr(ctxt, p, &p.To)
if ctxt.Arch.Progedit != nil {
- ctxt.Arch.Progedit(ctxt, p)
+ ctxt.Arch.Progedit(ctxt, p, newprog)
}
if p.To.Type != TYPE_BRANCH {
continue
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) {
flushplist(ctxt, plist, !ctxt.Debugasm)
}
etext = p
}
+ newprog := ProgAlloc(ctxt.NewProg)
+
// Add reference to Go arguments for C or assembly functions without them.
for _, s := range text {
if !strings.HasPrefix(s.Name, "\"\".") {
}
if !found {
- p := Appendp(ctxt, s.Text)
+ p := Appendp(s.Text, newprog)
p.As = AFUNCDATA
p.From.Type = TYPE_CONST
p.From.Offset = FUNCDATA_ArgsPointerMaps
// Turn functions into machine code images.
for _, s := range text {
mkfwd(s)
- linkpatch(ctxt, s)
- ctxt.Arch.Preprocess(ctxt, s)
- ctxt.Arch.Assemble(ctxt, s)
+ linkpatch(ctxt, s, newprog)
+ ctxt.Arch.Preprocess(ctxt, s, newprog)
+ ctxt.Arch.Assemble(ctxt, s, newprog)
linkpcln(ctxt, s)
makeFuncDebugEntry(ctxt, plist.Curfn, s)
if freeProgs {
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
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
if (o.type_ == 16 || o.type_ == 17) && p.Pcond != nil {
otxt = p.Pcond.Pc - c
if otxt < -(1<<15)+10 || otxt >= (1<<15)-10 {
- q = ctxt.NewProg()
+ q = newprog()
q.Link = p.Link
p.Link = q
q.As = ABR
q.To.Type = obj.TYPE_BRANCH
q.Pcond = p.Pcond
p.Pcond = q
- q = ctxt.NewProg()
+ q = newprog()
q.Link = p.Link
p.Link = q
q.As = ABR
"math"
)
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.From.Class = 0
p.To.Class = 0
}
}
if ctxt.Flag_dynlink {
- rewriteToUseGot(ctxt, p)
+ rewriteToUseGot(ctxt, p, newprog)
}
}
// Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
// ADUFFxxx $offset
// becomes
p.To.Name = obj.NAME_NONE
p.To.Offset = 0
p.To.Sym = nil
- p1 := obj.Appendp(ctxt, p)
+ p1 := obj.Appendp(p, newprog)
p1.As = AADD
p1.From.Type = obj.TYPE_CONST
p1.From.Offset = offset
p1.To.Type = obj.TYPE_REG
p1.To.Reg = REG_R12
- p2 := obj.Appendp(ctxt, p1)
+ p2 := obj.Appendp(p1, newprog)
p2.As = AMOVD
p2.From.Type = obj.TYPE_REG
p2.From.Reg = REG_R12
p2.To.Type = obj.TYPE_REG
p2.To.Reg = REG_CTR
- p3 := obj.Appendp(ctxt, p2)
+ p3 := obj.Appendp(p2, newprog)
p3.As = obj.ACALL
p3.From.Type = obj.TYPE_REG
p3.From.Reg = REG_R12
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_GOTREF
if p.From.Offset != 0 {
- q := obj.Appendp(ctxt, p)
+ q := obj.Appendp(p, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
if source.Type != obj.TYPE_MEM {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
- p1 := obj.Appendp(ctxt, p)
- p2 := obj.Appendp(ctxt, p1)
+ p1 := obj.Appendp(p, newprog)
+ p2 := obj.Appendp(p1, newprog)
p1.As = AMOVD
p1.From.Type = obj.TYPE_MEM
obj.Nopout(p)
}
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// TODO(minux): add morestack short-cuts with small fixed frame-size.
ctxt.Cursym = cursym
// generate the addis instruction except as part of the
// load of a large constant, and in that case there is no
// way to use r12 as the source.
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AWORD
q.Pos = p.Pos
q.From.Type = obj.TYPE_CONST
q.From.Offset = 0x3c4c0000
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AWORD
q.Pos = p.Pos
q.From.Type = obj.TYPE_CONST
}
if cursym.Text.From3.Offset&obj.NOSPLIT == 0 {
- q = stacksplit(ctxt, q, autosize) // emit split check
+ q = stacksplit(ctxt, q, newprog, autosize) // emit split check
}
if autosize != 0 {
// it is a leaf function, so that traceback works.
if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG {
// Use MOVDU to adjust R1 when saving R31, if autosize is small.
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.Pos = p.Pos
q.From.Type = obj.TYPE_REG
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVDU
q.Pos = p.Pos
q.From.Type = obj.TYPE_REG
// Store link register before decrementing SP, so if a signal comes
// during the execution of the function prologue, the traceback
// code will not see a half-updated stack frame.
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.Pos = p.Pos
q.From.Type = obj.TYPE_REG
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.Pos = p.Pos
q.From.Type = obj.TYPE_REG
q.To.Offset = int64(-autosize)
q.To.Reg = REGSP
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AADD
q.Pos = p.Pos
q.From.Type = obj.TYPE_CONST
}
if ctxt.Flag_shared {
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.Pos = p.Pos
q.From.Type = obj.TYPE_REG
// The NOP is needed to give the jumps somewhere to land.
// It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R0
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABEQ
q.To.Type = obj.TYPE_BRANCH
p1 = q
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REG_R3
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R4
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R5
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R4
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R5
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABNE
q.To.Type = obj.TYPE_BRANCH
p2 = q
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = ctxt.FixedFrameSize()
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R6
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R6
q.To.Reg = REG_R3
q.To.Offset = 0 // Panic.argp
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = obj.ANOP
p1.Pcond = q
p.To.Reg = REGSP
p.Spadj = -autosize
- q = ctxt.NewProg()
+ q = newprog()
q.As = ABR
q.Pos = p.Pos
q.To.Type = obj.TYPE_REG
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
- q = ctxt.NewProg()
+ q = newprog()
q.As = AMOVD
q.Pos = p.Pos
q.From.Type = obj.TYPE_REG
if false {
// Debug bad returns
- q = ctxt.NewProg()
+ q = newprog()
q.As = AMOVD
q.Pos = p.Pos
}
if autosize != 0 {
- q = ctxt.NewProg()
+ q = newprog()
q.As = AADD
q.Pos = p.Pos
q.From.Type = obj.TYPE_CONST
p.Link = q
}
- q1 = ctxt.NewProg()
+ q1 = newprog()
q1.As = ABR
q1.Pos = p.Pos
if retTarget == nil {
q = p;
}
*/
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+func stacksplit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, framesize int32) *obj.Prog {
p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode
// MOVD g_stackguard(g), R3
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
if framesize <= obj.StackSmall {
// small stack: SP < stackguard
// CMP stackguard, SP
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMPU
p.From.Type = obj.TYPE_REG
// large stack: SP-framesize < stackguard-StackSmall
// ADD $-(framesize-StackSmall), SP, R4
// CMP stackguard, R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMPU
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
// SUB R3, R4
// MOVD $(framesize+(StackGuard-StackSmall)), R31
// CMPU R31, R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.To.Type = obj.TYPE_CONST
p.To.Offset = obj.StackPreempt
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
q = p
p.As = ABEQ
p.To.Type = obj.TYPE_BRANCH
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackGuard
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMPU
p.From.Type = obj.TYPE_REG
p.From.Reg = REGTMP
}
// q1: BLT done
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
q1 := p
p.As = ABLT
p.To.Type = obj.TYPE_BRANCH
// MOVD LR, R5
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
// 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
// MOVD R12, 8(SP)
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R2
// seems preferable.
// MOVD $runtime.morestack(SB), R12
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Sym = morestacksym
p.To.Reg = REG_R12
// MOVD R12, CTR
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R12
p.To.Reg = REG_CTR
// BL CTR
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = obj.ACALL
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R12
p.To.Reg = REG_CTR
} else {
// BL runtime.morestack(SB)
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
if ctxt.Flag_shared {
// MOVD 8(SP), R2
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGSP
}
// BR start
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ABR
p.To.Type = obj.TYPE_BRANCH
p.Pcond = p0.Link
// placeholder for q1's jump target
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = obj.ANOP // zero-width place holder
q1.Pcond = p
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
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
"math"
)
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
p.From.Class = 0
p.To.Class = 0
}
if ctxt.Flag_dynlink {
- rewriteToUseGot(ctxt, p)
+ rewriteToUseGot(ctxt, p, newprog)
}
}
// Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
// At the moment EXRL instructions are not emitted by the compiler and only reference local symbols in
// assembly code.
if p.As == AEXRL {
p.From.Name = obj.NAME_GOTREF
q := p
if p.From.Offset != 0 {
- q = obj.Appendp(ctxt, p)
+ q = obj.Appendp(p, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
if source.Type != obj.TYPE_MEM {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
- p1 := obj.Appendp(ctxt, p)
- p2 := obj.Appendp(ctxt, p1)
+ p1 := obj.Appendp(p, newprog)
+ p2 := obj.Appendp(p1, newprog)
p1.As = AMOVD
p1.From.Type = obj.TYPE_MEM
obj.Nopout(p)
}
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// TODO(minux): add morestack short-cuts with small fixed frame-size.
ctxt.Cursym = cursym
q := p
if p.From3.Offset&obj.NOSPLIT == 0 {
- p, pPreempt = stacksplitPre(ctxt, p, autosize) // emit pre part of split check
+ p, pPreempt = stacksplitPre(ctxt, p, newprog, autosize) // emit pre part of split check
pPre = p
wasSplit = true //need post part of split
}
// Store link register before decrementing SP, so if a signal comes
// during the execution of the function prologue, the traceback
// code will not see a half-updated stack frame.
- q = obj.Appendp(ctxt, p)
+ q = obj.Appendp(p, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_LR
q.To.Reg = REGSP
q.To.Offset = int64(-autosize)
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_ADDR
q.From.Offset = int64(-autosize)
// The NOP is needed to give the jumps somewhere to land.
// It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes.
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R3
q.To.Type = obj.TYPE_CONST
q.To.Offset = 0
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABEQ
q.To.Type = obj.TYPE_BRANCH
p1 := q
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Reg = REG_R3
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R4
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R5
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ACMP
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R4
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R5
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABNE
q.To.Type = obj.TYPE_BRANCH
p2 := q
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = ctxt.FixedFrameSize()
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R6
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R6
q.To.Reg = REG_R3
q.To.Offset = 0 // Panic.argp
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = obj.ANOP
p1.Pcond = q
p.To.Reg = REGSP
p.Spadj = -autosize
- q = obj.Appendp(ctxt, p)
+ q = obj.Appendp(p, newprog)
q.As = ABR
q.From = obj.Addr{}
q.To.Type = obj.TYPE_REG
q = p
if autosize != 0 {
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(autosize)
q.Spadj = -autosize
}
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = ABR
q.From = obj.Addr{}
if retTarget == nil {
}
}
if wasSplit {
- stacksplitPost(ctxt, pLast, pPre, pPreempt, autosize) // emit post part of split check
+ stacksplitPost(ctxt, pLast, pPre, pPreempt, newprog, autosize) // emit post part of split check
}
}
-func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
+func stacksplitPre(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, framesize int32) (*obj.Prog, *obj.Prog) {
var q *obj.Prog
// MOVD g_stackguard(g), R3
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_MEM
// q1: BLT done
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
//q1 = p
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
// large stack: SP-framesize < stackguard-StackSmall
// ADD $-(framesize-StackSmall), SP, R4
// CMP stackguard, R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.Reg = REG_R4
// SUB R3, R4
// MOVD $(framesize+(StackGuard-StackSmall)), TEMP
// CMPUBGE TEMP, R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMP
p.From.Type = obj.TYPE_REG
p.To.Type = obj.TYPE_CONST
p.To.Offset = obj.StackPreempt
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
q = p
p.As = ABEQ
p.To.Type = obj.TYPE_BRANCH
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackGuard
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ASUB
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
p.To.Type = obj.TYPE_REG
p.To.Reg = REGTMP
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.From.Type = obj.TYPE_REG
p.From.Reg = REGTMP
p.Reg = REG_R4
return p, q
}
-func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog {
+func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, newprog obj.ProgAlloc, framesize int32) *obj.Prog {
// Now we are at the end of the function, but logically
// we are still in function prologue. We need to fix the
// SP data and PCDATA.
- spfix := obj.Appendp(ctxt, p)
+ spfix := obj.Appendp(p, newprog)
spfix.As = obj.ANOP
spfix.Spadj = -framesize
- pcdata := obj.Appendp(ctxt, spfix)
+ pcdata := obj.Appendp(spfix, newprog)
pcdata.Pos = ctxt.Cursym.Text.Pos
pcdata.As = obj.APCDATA
pcdata.From.Type = obj.TYPE_CONST
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
// MOVD LR, R5
- p = obj.Appendp(ctxt, pcdata)
+ p = obj.Appendp(pcdata, newprog)
pPre.Pcond = p
p.As = AMOVD
p.From.Type = obj.TYPE_REG
}
// BL runtime.morestack(SB)
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
}
// BR start
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ABR
p.To.Type = obj.TYPE_BRANCH
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 {
return
}
return true
}
-func progedit(ctxt *obj.Link, p *obj.Prog) {
+func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
// Thread-local storage references use the TLS pseudo-register.
// As a register, TLS refers to the thread-local storage base, and it
// can only be loaded into another register:
// MOVQ TLS, BX
// MOVQ 0(BX)(TLS*1), BX
if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
- q := obj.Appendp(ctxt, p)
+ q := obj.Appendp(p, newprog)
q.As = p.As
q.From = p.From
q.From.Type = obj.TYPE_MEM
}
if ctxt.Flag_dynlink {
- rewriteToUseGot(ctxt, p)
+ rewriteToUseGot(ctxt, p, newprog)
}
if ctxt.Flag_shared && ctxt.Arch.Family == sys.I386 {
- rewriteToPcrel(ctxt, p)
+ rewriteToPcrel(ctxt, p, newprog)
}
}
// Rewrite p, if necessary, to access global data via the global offset table.
-func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
var add, lea, mov obj.As
var reg int16
if ctxt.Arch.Family == sys.AMD64 {
p.To.Reg = reg
p.To.Offset = 0
p.To.Sym = nil
- p1 := obj.Appendp(ctxt, p)
+ p1 := obj.Appendp(p, newprog)
p1.As = add
p1.From.Type = obj.TYPE_CONST
p1.From.Offset = offset
p1.To.Type = obj.TYPE_REG
p1.To.Reg = reg
- p2 := obj.Appendp(ctxt, p1)
+ p2 := obj.Appendp(p1, newprog)
p2.As = obj.ACALL
p2.To.Type = obj.TYPE_REG
p2.To.Reg = reg
p.From.Name = obj.NAME_GOTREF
q := p
if p.From.Offset != 0 {
- q = obj.Appendp(ctxt, p)
+ q = obj.Appendp(p, newprog)
q.As = lea
q.From.Type = obj.TYPE_MEM
q.From.Reg = p.To.Reg
p.From.Offset = 0
}
if cmplxdest {
- q = obj.Appendp(ctxt, q)
+ q = obj.Appendp(q, newprog)
q.As = pAs
q.To = dest
q.From.Type = obj.TYPE_REG
if ctxt.Arch.Family == sys.AMD64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
return
}
- p1 := obj.Appendp(ctxt, p)
- p2 := obj.Appendp(ctxt, p1)
+ p1 := obj.Appendp(p, newprog)
+ p2 := obj.Appendp(p1, newprog)
p1.As = ALEAL
p1.From.Type = obj.TYPE_MEM
if source.Type != obj.TYPE_MEM {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
- p1 := obj.Appendp(ctxt, p)
- p2 := obj.Appendp(ctxt, p1)
+ p1 := obj.Appendp(p, newprog)
+ p2 := obj.Appendp(p1, newprog)
p1.As = mov
p1.From.Type = obj.TYPE_MEM
obj.Nopout(p)
}
-func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
+func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
// RegTo2 is set on the instructions we insert here so they don't get
// processed twice.
if p.RegTo2 != 0 {
// to "MOVL $sym, CX; MOVL CX, (SP)" or "MOVL $sym, CX; PUSHL CX"
// respectively.
if p.To.Type != obj.TYPE_REG {
- q := obj.Appendp(ctxt, p)
+ q := obj.Appendp(p, newprog)
q.As = p.As
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_CX
// Why? See the comment near the top of rewriteToUseGot above.
// AMOVLs might be introduced by the GOT rewrites.
}
- q := obj.Appendp(ctxt, p)
+ q := obj.Appendp(p, newprog)
q.RegTo2 = 1
- r := obj.Appendp(ctxt, q)
+ r := obj.Appendp(q, newprog)
r.RegTo2 = 1
q.As = obj.ACALL
q.To.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk."+strings.ToLower(rconv(int(dst))), 0)
}
}
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
if ctxt.Headtype == obj.Hplan9 && ctxt.Plan9privates == nil {
ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
}
}
if p.From3Offset()&obj.NOSPLIT == 0 || p.From3Offset()&obj.WRAPPER != 0 {
- p = obj.Appendp(ctxt, p)
- p = load_g_cx(ctxt, p) // load g into CX
+ p = obj.Appendp(p, newprog)
+ p = load_g_cx(ctxt, p, newprog) // load g into CX
}
if cursym.Text.From3Offset()&obj.NOSPLIT == 0 {
- p = stacksplit(ctxt, cursym, p, autoffset, int32(textarg)) // emit split check
+ p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg)) // emit split check
}
if autoffset != 0 {
if autoffset%int32(ctxt.Arch.RegSize) != 0 {
ctxt.Diag("unaligned stack size %d", autoffset)
}
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AADJSP
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(autoffset)
if bpsize > 0 {
// Save caller's BP
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVQ
p.From.Type = obj.TYPE_REG
p.To.Offset = int64(autoffset) - int64(bpsize)
// Move current frame to BP
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ALEAQ
p.From.Type = obj.TYPE_MEM
// Both conditional jumps are unlikely, so they are arranged to be forward jumps.
// MOVQ g_panic(CX), BX
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVQ
p.From.Type = obj.TYPE_MEM
p.From.Reg = REG_CX
}
// TESTQ BX, BX
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ATESTQ
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_BX
}
// JNE checkargp (checkargp to be resolved later)
- jne := obj.Appendp(ctxt, p)
+ jne := obj.Appendp(p, newprog)
jne.As = AJNE
jne.To.Type = obj.TYPE_BRANCH
// end:
// NOP
- end := obj.Appendp(ctxt, jne)
+ end := obj.Appendp(jne, newprog)
end.As = obj.ANOP
// Fast forward to end of function.
}
// LEAQ (autoffset+8)(SP), DI
- p = obj.Appendp(ctxt, last)
+ p = obj.Appendp(last, newprog)
p.As = ALEAQ
p.From.Type = obj.TYPE_MEM
p.From.Reg = REG_SP
jne.Pcond = p
// CMPQ panic_argp(BX), DI
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = ACMPQ
p.From.Type = obj.TYPE_MEM
p.From.Reg = REG_BX
}
// JNE end
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AJNE
p.To.Type = obj.TYPE_BRANCH
p.Pcond = end
// MOVQ SP, panic_argp(BX)
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AMOVQ
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_SP
}
// JMP end
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = obj.AJMP
p.To.Type = obj.TYPE_BRANCH
p.Pcond = end
p.From.Offset = int64(autoffset) - int64(bpsize)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_BP
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
}
p.As = AADJSP
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(-autoffset)
p.Spadj = -autoffset
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = obj.ARET
// If there are instructions following
// Overwriting p is unusual but it lets use this in both the
// prologue (caller must call appendp first) and in the epilogue.
// Returns last new instruction.
-func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
+func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog {
p.As = AMOVQ
if ctxt.Arch.PtrSize == 4 {
p.As = AMOVL
p.To.Reg = REG_CX
next := p.Link
- progedit(ctxt, p)
+ progedit(ctxt, p, newprog)
for p.Link != next {
p = p.Link
}
// Appends to (does not overwrite) p.
// Assumes g is in CX.
// Returns last new instruction.
-func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, framesize int32, textarg int32) *obj.Prog {
+func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) *obj.Prog {
cmp := ACMPQ
lea := ALEAQ
mov := AMOVQ
if framesize <= obj.StackSmall {
// small stack: SP <= stackguard
// CMPQ SP, stackguard
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = cmp
p.From.Type = obj.TYPE_REG
// large stack: SP-framesize <= stackguard-StackSmall
// LEAQ -xxx(SP), AX
// CMPQ AX, stackguard
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = lea
p.From.Type = obj.TYPE_MEM
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_AX
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = cmp
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_AX
// SUBQ CX, AX
// CMPQ AX, $(framesize+(StackGuard-StackSmall))
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = mov
indir_cx(ctxt, p, &p.From)
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_SI
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = cmp
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_SI
p.To.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
}
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = AJEQ
p.To.Type = obj.TYPE_BRANCH
q1 = p
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = lea
p.From.Type = obj.TYPE_MEM
p.From.Reg = REG_SP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_AX
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = sub
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_SI
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_AX
- p = obj.Appendp(ctxt, p)
+ p = obj.Appendp(p, newprog)
p.As = cmp
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_AX
}
// common
- jls := obj.Appendp(ctxt, p)
+ jls := obj.Appendp(p, newprog)
jls.As = AJLS
jls.To.Type = obj.TYPE_BRANCH
// Now we are at the end of the function, but logically
// we are still in function prologue. We need to fix the
// SP data and PCDATA.
- spfix := obj.Appendp(ctxt, last)
+ spfix := obj.Appendp(last, newprog)
spfix.As = obj.ANOP
spfix.Spadj = -framesize
- pcdata := obj.Appendp(ctxt, spfix)
+ pcdata := obj.Appendp(spfix, newprog)
pcdata.Pos = cursym.Text.Pos
pcdata.As = obj.APCDATA
pcdata.From.Type = obj.TYPE_CONST
pcdata.To.Type = obj.TYPE_CONST
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
- call := obj.Appendp(ctxt, pcdata)
+ call := obj.Appendp(pcdata, newprog)
call.Pos = cursym.Text.Pos
call.As = obj.ACALL
call.To.Type = obj.TYPE_BRANCH
// to keep track of the start of the call (where the jump will be to) and the
// end (which following instructions are appended to).
callend := call
- progedit(ctxt, callend)
+ progedit(ctxt, callend, newprog)
for ; callend.Link != nil; callend = callend.Link {
- progedit(ctxt, callend.Link)
+ progedit(ctxt, callend.Link, newprog)
}
- jmp := obj.Appendp(ctxt, callend)
+ jmp := obj.Appendp(callend, newprog)
jmp.As = obj.AJMP
jmp.To.Type = obj.TYPE_BRANCH
jmp.Pcond = cursym.Text.Link