p.To.Reg = REGSP
p.Spadj = autosize
- if cursym.Func().Text.From.Sym.Wrapper() {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVW g_panic(g), R1
- // CMP $0, R1
- // B.NE checkargp
- // end:
- // NOP
- // ... function ...
- // checkargp:
- // MOVW panic_argp(R1), R2
- // ADD $(autosize+4), R13, R3
- // CMP R2, R3
- // B.NE end
- // ADD $4, R13, R4
- // MOVW R4, panic_argp(R1)
- // B end
- //
- // 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(p, newprog)
- p.As = AMOVW
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REGG
- p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R1
-
- 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(p, newprog)
- bne.As = ABNE
- bne.To.Type = obj.TYPE_BRANCH
-
- // end: NOP
- end := obj.Appendp(bne, newprog)
- end.As = obj.ANOP
-
- // find end of function
- var last *obj.Prog
- for last = end; last.Link != nil; last = last.Link {
- }
-
- // MOVW panic_argp(R1), R2
- mov := obj.Appendp(last, newprog)
- mov.As = AMOVW
- mov.From.Type = obj.TYPE_MEM
- mov.From.Reg = REG_R1
- mov.From.Offset = 0 // Panic.argp
- mov.To.Type = obj.TYPE_REG
- mov.To.Reg = REG_R2
-
- // B.NE branch target is MOVW above
- bne.To.SetTarget(mov)
-
- // ADD $(autosize+4), R13, R3
- p = obj.Appendp(mov, newprog)
- p.As = AADD
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(autosize) + 4
- p.Reg = REG_R13
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R3
-
- // CMP R2, R3
- 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(p, newprog)
- p.As = ABNE
- p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(end)
-
- // ADD $4, R13, R4
- p = obj.Appendp(p, newprog)
- p.As = AADD
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 4
- p.Reg = REG_R13
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_R4
-
- // MOVW R4, panic_argp(R1)
- p = obj.Appendp(p, newprog)
- p.As = AMOVW
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_R4
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = REG_R1
- p.To.Offset = 0 // Panic.argp
-
- // B end
- p = obj.Appendp(p, newprog)
- p.As = AB
- p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(end)
-
- // reset for subsequent passes
- p = end
- }
-
case obj.ARET:
nocache(p)
if cursym.Func().Text.Mark&LEAF != 0 {
q1.To.Type = obj.TYPE_REG
q1.To.Reg = REGFP
- if c.cursym.Func().Text.From.Sym.Wrapper() {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOV g_panic(g), RT1
- // CBNZ checkargp
- // end:
- // NOP
- // ... function body ...
- // checkargp:
- // MOV panic_argp(RT1), RT2
- // ADD $(autosize+8), RSP, R20
- // CMP RT2, R20
- // BNE end
- // ADD $8, RSP, R20
- // MOVD R20, panic_argp(RT1)
- // B end
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not an ARM64 NOP: it encodes to 0 instruction bytes.
- q = q1
-
- // MOV g_panic(g), RT1
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REGG
- q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REGRT1
-
- // CBNZ RT1, checkargp
- cbnz := obj.Appendp(q, c.newprog)
- cbnz.As = ACBNZ
- cbnz.From.Type = obj.TYPE_REG
- cbnz.From.Reg = REGRT1
- cbnz.To.Type = obj.TYPE_BRANCH
-
- // Empty branch target at the top of the function body
- end := obj.Appendp(cbnz, c.newprog)
- end.As = obj.ANOP
-
- // find the end of the function
- var last *obj.Prog
- for last = end; last.Link != nil; last = last.Link {
- }
-
- // MOV panic_argp(RT1), RT2
- mov := obj.Appendp(last, c.newprog)
- mov.As = AMOVD
- mov.From.Type = obj.TYPE_MEM
- mov.From.Reg = REGRT1
- mov.From.Offset = 0 // Panic.argp
- mov.To.Type = obj.TYPE_REG
- mov.To.Reg = REGRT2
-
- // CBNZ branches to the MOV above
- cbnz.To.SetTarget(mov)
-
- // ADD $(autosize+8), SP, R20
- q = obj.Appendp(mov, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(c.autosize) + 8
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R20
-
- // CMP RT2, R20
- q = obj.Appendp(q, c.newprog)
- q.As = ACMP
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REGRT2
- q.Reg = REG_R20
-
- // BNE end
- q = obj.Appendp(q, c.newprog)
- q.As = ABNE
- q.To.Type = obj.TYPE_BRANCH
- q.To.SetTarget(end)
-
- // ADD $8, SP, R20
- q = obj.Appendp(q, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = 8
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R20
-
- // MOV R20, panic_argp(RT1)
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R20
- q.To.Type = obj.TYPE_MEM
- q.To.Reg = REGRT1
- q.To.Offset = 0 // Panic.argp
-
- // B end
- q = obj.Appendp(q, c.newprog)
- q.As = AB
- q.To.Type = obj.TYPE_BRANCH
- q.To.SetTarget(end)
- }
-
case obj.ARET:
nocache(p)
if p.From.Type == obj.TYPE_CONST {
var q *obj.Prog
var q1 *obj.Prog
autosize := int32(0)
- var p1 *obj.Prog
- var p2 *obj.Prog
for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
q.To.Reg = REGSP
}
- if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOV g_panic(g), R20
- // BEQ R20, end
- // MOV panic_argp(R20), R24
- // ADD $(autosize+FIXED_FRAME), R3, R30
- // BNE R24, R30, end
- // ADD $FIXED_FRAME, R3, R24
- // MOV R24, panic_argp(R20)
- // end:
- // NOP
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not a hardware NOP: it encodes to 0 instruction bytes.
- //
- // We don't generate this for leaves because that means the wrapped
- // function was inlined into the wrapper.
-
- q = obj.Appendp(q, newprog)
-
- q.As = mov
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REGG
- q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R20
-
- q = obj.Appendp(q, newprog)
- q.As = ABEQ
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R20
- q.To.Type = obj.TYPE_BRANCH
- q.Mark |= BRANCH
- p1 = q
-
- q = obj.Appendp(q, newprog)
- q.As = mov
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REG_R20
- q.From.Offset = 0 // Panic.argp
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R24
-
- q = obj.Appendp(q, newprog)
- q.As = add
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(autosize) + ctxt.Arch.FixedFrameSize
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R30
-
- q = obj.Appendp(q, newprog)
- q.As = ABNE
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R24
- q.Reg = REG_R30
- q.To.Type = obj.TYPE_BRANCH
- q.Mark |= BRANCH
- p2 = q
-
- q = obj.Appendp(q, newprog)
- q.As = add
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = ctxt.Arch.FixedFrameSize
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R24
-
- q = obj.Appendp(q, newprog)
- q.As = mov
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R24
- q.To.Type = obj.TYPE_MEM
- q.To.Reg = REG_R20
- q.To.Offset = 0 // Panic.argp
-
- q = obj.Appendp(q, newprog)
-
- q.As = obj.ANOP
- p1.To.SetTarget(q)
- p2.To.SetTarget(q)
- }
-
case ARET:
if p.From.Type == obj.TYPE_CONST {
ctxt.Diag("using BECOME (%v) is not supported!", p)
var q1 *obj.Prog
autosize := int32(0)
var p1 *obj.Prog
- var p2 *obj.Prog
for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
q.To.Reg = REGSP
}
- if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOV g_panic(g), R1
- // BEQ R1, end
- // MOV panic_argp(R1), R2
- // ADD $(autosize+FIXED_FRAME), R29, R3
- // BNE R2, R3, end
- // ADD $FIXED_FRAME, R29, R2
- // MOV R2, panic_argp(R1)
- // end:
- // NOP
- //
- // 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.
- //
- // We don't generate this for leafs because that means the wrapped
- // function was inlined into the wrapper.
-
- q = obj.Appendp(q, newprog)
-
- q.As = mov
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REGG
- q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R1
-
- q = obj.Appendp(q, newprog)
- q.As = ABEQ
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R1
- q.To.Type = obj.TYPE_BRANCH
- q.Mark |= BRANCH
- p1 = q
-
- q = obj.Appendp(q, newprog)
- q.As = mov
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REG_R1
- q.From.Offset = 0 // Panic.argp
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R2
-
- q = obj.Appendp(q, newprog)
- q.As = add
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(autosize) + ctxt.Arch.FixedFrameSize
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R3
-
- q = obj.Appendp(q, newprog)
- q.As = ABNE
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R2
- q.Reg = REG_R3
- q.To.Type = obj.TYPE_BRANCH
- q.Mark |= BRANCH
- p2 = q
-
- q = obj.Appendp(q, newprog)
- q.As = add
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = ctxt.Arch.FixedFrameSize
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R2
-
- q = obj.Appendp(q, newprog)
- q.As = mov
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R2
- q.To.Type = obj.TYPE_MEM
- q.To.Reg = REG_R1
- q.To.Offset = 0 // Panic.argp
-
- q = obj.Appendp(q, newprog)
-
- q.As = obj.ANOP
- p1.To.SetTarget(q)
- p2.To.SetTarget(q)
- }
-
case ARET:
if p.From.Type == obj.TYPE_CONST {
ctxt.Diag("using BECOME (%v) is not supported!", p)
}
autosize := int32(0)
- var p1 *obj.Prog
- var p2 *obj.Prog
for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
q.To.Offset = 24
}
- if c.cursym.Func().Text.From.Sym.Wrapper() {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVD g_panic(g), R22
- // CMP R22, $0
- // BEQ end
- // MOVD panic_argp(R22), R23
- // ADD $(autosize+8), R1, R24
- // CMP R23, R24
- // BNE end
- // ADD $8, R1, R25
- // MOVD R25, panic_argp(R22)
- // end:
- // NOP
- //
- // 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(q, c.newprog)
-
- q.As = AMOVD
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REGG
- q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R22
-
- q = obj.Appendp(q, c.newprog)
- q.As = ACMP
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R22
- q.To.Type = obj.TYPE_CONST
- q.To.Offset = 0
-
- q = obj.Appendp(q, c.newprog)
- q.As = ABEQ
- q.To.Type = obj.TYPE_BRANCH
- p1 = q
-
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REG_R22
- q.From.Offset = 0 // Panic.argp
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R23
-
- q = obj.Appendp(q, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(autosize) + c.ctxt.Arch.FixedFrameSize
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R24
-
- q = obj.Appendp(q, c.newprog)
- q.As = ACMP
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R23
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R24
-
- q = obj.Appendp(q, c.newprog)
- q.As = ABNE
- q.To.Type = obj.TYPE_BRANCH
- p2 = q
-
- q = obj.Appendp(q, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = c.ctxt.Arch.FixedFrameSize
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R25
-
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R25
- q.To.Type = obj.TYPE_MEM
- q.To.Reg = REG_R22
- q.To.Offset = 0 // Panic.argp
-
- q = obj.Appendp(q, c.newprog)
-
- q.As = obj.ANOP
- p1.To.SetTarget(q)
- p2.To.SetTarget(q)
- }
-
case obj.ARET:
if p.From.Type == obj.TYPE_CONST {
c.ctxt.Diag("using BECOME (%v) is not supported!", p)
prologue.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_SP, Offset: 0}
}
- if cursym.Func().Text.From.Sym.Wrapper() {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOV g_panic(g), X5
- // BNE X5, ZERO, adjust
- // end:
- // NOP
- // ...rest of function..
- // adjust:
- // MOV panic_argp(X5), X6
- // ADD $(autosize+FIXED_FRAME), SP, X7
- // BNE X6, X7, end
- // ADD $FIXED_FRAME, SP, X6
- // MOV X6, panic_argp(X5)
- // JMP end
- //
- // The NOP is needed to give the jumps somewhere to land.
-
- ldpanic := obj.Appendp(prologue, newprog)
-
- ldpanic.As = AMOV
- ldpanic.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGG, Offset: 4 * int64(ctxt.Arch.PtrSize)} // G.panic
- ldpanic.Reg = obj.REG_NONE
- ldpanic.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X5}
-
- bneadj := obj.Appendp(ldpanic, newprog)
- bneadj.As = ABNE
- bneadj.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X5}
- bneadj.Reg = REG_ZERO
- bneadj.To.Type = obj.TYPE_BRANCH
-
- endadj := obj.Appendp(bneadj, newprog)
- endadj.As = obj.ANOP
-
- last := endadj
- for last.Link != nil {
- last = last.Link
- }
-
- getargp := obj.Appendp(last, newprog)
- getargp.As = AMOV
- getargp.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X5, Offset: 0} // Panic.argp
- getargp.Reg = obj.REG_NONE
- getargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
-
- bneadj.To.SetTarget(getargp)
-
- calcargp := obj.Appendp(getargp, newprog)
- calcargp.As = AADDI
- calcargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: stacksize + ctxt.Arch.FixedFrameSize}
- calcargp.Reg = REG_SP
- calcargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X7}
-
- testargp := obj.Appendp(calcargp, newprog)
- testargp.As = ABNE
- testargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
- testargp.Reg = REG_X7
- testargp.To.Type = obj.TYPE_BRANCH
- testargp.To.SetTarget(endadj)
-
- adjargp := obj.Appendp(testargp, newprog)
- adjargp.As = AADDI
- adjargp.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(ctxt.Arch.PtrSize)}
- adjargp.Reg = REG_SP
- adjargp.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
-
- setargp := obj.Appendp(adjargp, newprog)
- setargp.As = AMOV
- setargp.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_X6}
- setargp.Reg = obj.REG_NONE
- setargp.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REG_X5, Offset: 0} // Panic.argp
-
- godone := obj.Appendp(setargp, newprog)
- godone.As = AJAL
- godone.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
- godone.To.Type = obj.TYPE_BRANCH
- godone.To.SetTarget(endadj)
- }
-
// Update stack-based offsets.
for p := cursym.Func().Text; p != nil; p = p.Link {
stackOffset(&p.From, stacksize)
break
}
- if c.cursym.Func().Text.From.Sym.Wrapper() {
- // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
- //
- // MOVD g_panic(g), R3
- // CMP R3, $0
- // BEQ end
- // MOVD panic_argp(R3), R4
- // ADD $(autosize+8), R1, R5
- // CMP R4, R5
- // BNE end
- // ADD $8, R1, R6
- // MOVD R6, panic_argp(R3)
- // end:
- // NOP
- //
- // 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(q, c.newprog)
-
- q.As = AMOVD
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REGG
- q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R3
-
- q = obj.Appendp(q, c.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(q, c.newprog)
- q.As = ABEQ
- q.To.Type = obj.TYPE_BRANCH
- p1 := q
-
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_MEM
- q.From.Reg = REG_R3
- q.From.Offset = 0 // Panic.argp
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R4
-
- q = obj.Appendp(q, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(autosize) + c.ctxt.Arch.FixedFrameSize
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R5
-
- q = obj.Appendp(q, c.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(q, c.newprog)
- q.As = ABNE
- q.To.Type = obj.TYPE_BRANCH
- p2 := q
-
- q = obj.Appendp(q, c.newprog)
- q.As = AADD
- q.From.Type = obj.TYPE_CONST
- q.From.Offset = c.ctxt.Arch.FixedFrameSize
- q.Reg = REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R6
-
- q = obj.Appendp(q, c.newprog)
- q.As = AMOVD
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R6
- q.To.Type = obj.TYPE_MEM
- q.To.Reg = REG_R3
- q.To.Offset = 0 // Panic.argp
-
- q = obj.Appendp(q, c.newprog)
-
- q.As = obj.ANOP
- p1.To.SetTarget(q)
- p2.To.SetTarget(q)
- }
-
case obj.ARET:
retTarget := p.To.Sym
framesize = 0
} else if s.Func().WasmExport != nil {
genWasmExportWrapper(s, appendp)
- } else if s.Func().Text.From.Sym.Wrapper() {
- // if g._panic != nil && g._panic.argp == FP {
- // g._panic.argp = bottom-of-frame
- // }
- //
- // MOVD g_panic(g), R0
- // Get R0
- // I64Eqz
- // Not
- // If
- // Get SP
- // I64ExtendI32U
- // I64Const $framesize+8
- // I64Add
- // I64Load panic_argp(R0)
- // I64Eq
- // If
- // MOVD SP, panic_argp(R0)
- // End
- // End
-
- gpanic := obj.Addr{
- Type: obj.TYPE_MEM,
- Reg: REGG,
- Offset: 4 * 8, // g_panic
- }
-
- panicargp := obj.Addr{
- Type: obj.TYPE_MEM,
- Reg: REG_R0,
- Offset: 0, // panic.argp
- }
-
- p := s.Func().Text
- p = appendp(p, AMOVD, gpanic, regAddr(REG_R0))
-
- p = appendp(p, AGet, regAddr(REG_R0))
- p = appendp(p, AI64Eqz)
- p = appendp(p, ANot)
- p = appendp(p, AIf)
-
- p = appendp(p, AGet, regAddr(REG_SP))
- p = appendp(p, AI64ExtendI32U)
- p = appendp(p, AI64Const, constAddr(framesize+8))
- p = appendp(p, AI64Add)
- p = appendp(p, AI64Load, panicargp)
-
- p = appendp(p, AI64Eq)
- p = appendp(p, AIf)
- p = appendp(p, AMOVD, regAddr(REG_SP), panicargp)
- p = appendp(p, AEnd)
-
- p = appendp(p, AEnd)
}
if framesize > 0 && s.Func().WasmExport == nil { // genWasmExportWrapper has its own prologue generation
}
}
- var regEntryTmp0, regEntryTmp1 int16
- if ctxt.Arch.Family == sys.AMD64 {
- regEntryTmp0, regEntryTmp1 = REGENTRYTMP0, REGENTRYTMP1
- } else {
- regEntryTmp0, regEntryTmp1 = REG_BX, REG_DI
- }
-
- var regg int16
if !p.From.Sym.NoSplit() {
- // Emit split check and load G register
- p, regg = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg))
- } else if p.From.Sym.Wrapper() {
- // Load G register for the wrapper code
- p, regg = loadG(ctxt, cursym, p, newprog)
+ // Emit split check.
+ p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg))
}
if bpsize > 0 {
p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
}
- if cursym.Func().Text.From.Sym.Wrapper() {
- // if g._panic != nil && g._panic.argp == FP {
- // g._panic.argp = bottom-of-frame
- // }
- //
- // MOVQ g_panic(g), regEntryTmp0
- // TESTQ regEntryTmp0, regEntryTmp0
- // JNE checkargp
- // end:
- // NOP
- // ... rest of function ...
- // checkargp:
- // LEAQ (autoffset+8)(SP), regEntryTmp1
- // CMPQ panic_argp(regEntryTmp0), regEntryTmp1
- // JNE end
- // MOVQ SP, panic_argp(regEntryTmp0)
- // JMP end
- //
- // The NOP is needed to give the jumps somewhere to land.
- // It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
- //
- // The layout is chosen to help static branch prediction:
- // Both conditional jumps are unlikely, so they are arranged to be forward jumps.
-
- // MOVQ g_panic(g), regEntryTmp0
- p = obj.Appendp(p, newprog)
- p.As = AMOVQ
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = regg
- p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // g_panic
- p.To.Type = obj.TYPE_REG
- p.To.Reg = regEntryTmp0
- if ctxt.Arch.Family == sys.I386 {
- p.As = AMOVL
- }
-
- // TESTQ regEntryTmp0, regEntryTmp0
- p = obj.Appendp(p, newprog)
- p.As = ATESTQ
- p.From.Type = obj.TYPE_REG
- p.From.Reg = regEntryTmp0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = regEntryTmp0
- if ctxt.Arch.Family == sys.I386 {
- p.As = ATESTL
- }
-
- // JNE checkargp (checkargp to be resolved later)
- jne := obj.Appendp(p, newprog)
- jne.As = AJNE
- jne.To.Type = obj.TYPE_BRANCH
-
- // end:
- // NOP
- end := obj.Appendp(jne, newprog)
- end.As = obj.ANOP
-
- // Fast forward to end of function.
- var last *obj.Prog
- for last = end; last.Link != nil; last = last.Link {
- }
-
- // LEAQ (autoffset+8)(SP), regEntryTmp1
- p = obj.Appendp(last, newprog)
- p.As = ALEAQ
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = REG_SP
- p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = regEntryTmp1
- if ctxt.Arch.Family == sys.I386 {
- p.As = ALEAL
- }
-
- // Set jne branch target.
- jne.To.SetTarget(p)
-
- // CMPQ panic_argp(regEntryTmp0), regEntryTmp1
- p = obj.Appendp(p, newprog)
- p.As = ACMPQ
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = regEntryTmp0
- p.From.Offset = 0 // Panic.argp
- p.To.Type = obj.TYPE_REG
- p.To.Reg = regEntryTmp1
- if ctxt.Arch.Family == sys.I386 {
- p.As = ACMPL
- }
-
- // JNE end
- p = obj.Appendp(p, newprog)
- p.As = AJNE
- p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(end)
-
- // MOVQ SP, panic_argp(regEntryTmp0)
- p = obj.Appendp(p, newprog)
- p.As = AMOVQ
- p.From.Type = obj.TYPE_REG
- p.From.Reg = REG_SP
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = regEntryTmp0
- p.To.Offset = 0 // Panic.argp
- if ctxt.Arch.Family == sys.I386 {
- p.As = AMOVL
- }
-
- // JMP end
- p = obj.Appendp(p, newprog)
- p.As = obj.AJMP
- p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(end)
-
- // Reset p for following code.
- p = end
- }
-
var deltasp int32
for p = cursym.Func().Text; p != nil; p = p.Link {
pcsize := ctxt.Arch.RegSize
// Append code to p to check for stack split.
// Appends to (does not overwrite) p.
// Assumes g is in rg.
-// Returns last new instruction and G register.
-func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) (*obj.Prog, int16) {
+// Returns last new instruction.
+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
q1.To.SetTarget(spill)
}
- return end, rg
+ return end
}
func isR15(r int16) bool {
}
}
- // The assembler adjusts p.argp in wrapper functions that shouldn't
- // be visible to recover(), so we need to restore it each iteration.
- p.argp = add(p.startSP, sys.MinFrameSize)
-
for {
for p.deferBitsPtr != nil {
bits := *p.deferBitsPtr
//
// A _panic value must only ever live on the stack.
//
-// The argp and link fields are stack pointers, but don't need special
+// The gopanicFP and link fields are stack pointers, but don't need special
// handling during stack growth: because they are pointer-typed and
// _panic values only live on the stack, regular stack pointer
// adjustment takes care of them.
type _panic struct {
- argp unsafe.Pointer // pointer to arguments of deferred call run during panic; cannot move - known to liblink
- arg any // argument to panic
- link *_panic // link to earlier panic
+ arg any // argument to panic
+ link *_panic // link to earlier panic
// startPC and startSP track where _panic.start was called.
startPC uintptr