2015-09-05 20:27:00 -04:00
|
|
|
// cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
|
|
|
|
|
//
|
|
|
|
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
|
|
|
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
|
|
|
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
|
|
|
|
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
|
|
|
|
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
|
|
|
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
|
|
|
|
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
|
2016-04-10 14:32:26 -07:00
|
|
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
2015-09-05 20:27:00 -04:00
|
|
|
//
|
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
// in the Software without restriction, including without limitation the rights
|
|
|
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
// furnished to do so, subject to the following conditions:
|
|
|
|
|
//
|
|
|
|
|
// The above copyright notice and this permission notice shall be included in
|
|
|
|
|
// all copies or substantial portions of the Software.
|
|
|
|
|
//
|
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
|
// THE SOFTWARE.
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
package mips
|
2015-09-05 20:27:00 -04:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"cmd/internal/obj"
|
2017-04-18 12:53:25 -07:00
|
|
|
"cmd/internal/objabi"
|
2016-04-06 12:01:40 -07:00
|
|
|
"cmd/internal/sys"
|
2016-12-09 00:13:43 -05:00
|
|
|
"encoding/binary"
|
2015-09-05 20:27:00 -04:00
|
|
|
"fmt"
|
cmd/asm, cmd/link, runtime: introduce FuncInfo flag bits
The runtime traceback code has its own definition of which functions
mark the top frame of a stack, separate from the TOPFRAME bits that
exist in the assembly and are passed along in DWARF information.
It's error-prone and redundant to have two different sources of truth.
This CL provides the actual TOPFRAME bits to the runtime, so that
the runtime can use those bits instead of reinventing its own category.
This CL also adds a new bit, SPWRITE, which marks functions that
write directly to SP (anything but adding and subtracting constants).
Such functions must stop a traceback, because the traceback has no
way to rederive the SP on entry. Again, the runtime has its own definition
which is mostly correct, but also missing some functions. During ordinary
goroutine context switches, such functions do not appear on the stack,
so the incompleteness in the runtime usually doesn't matter.
But profiling signals can arrive at any moment, and the runtime may
crash during traceback if it attempts to unwind an SP-writing frame
and gets out-of-sync with the actual stack. The runtime contains code
to try to detect likely candidates but again it is incomplete.
Deriving the SPWRITE bit automatically from the actual assembly code
provides the complete truth, and passing it to the runtime lets the
runtime use it.
This CL is part of a stack adding windows/arm64
support (#36439), intended to land in the Go 1.17 cycle.
This CL is, however, not windows/arm64-specific.
It is cleanup meant to make the port (and future ports) easier.
Change-Id: I227f53b23ac5b3dabfcc5e8ee3f00df4e113cf58
Reviewed-on: https://go-review.googlesource.com/c/go/+/288800
Trust: Russ Cox <rsc@golang.org>
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-01-28 15:21:33 -05:00
|
|
|
"log"
|
2015-09-05 20:27:00 -04:00
|
|
|
"math"
|
|
|
|
|
)
|
|
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
|
2017-04-10 14:15:57 -07:00
|
|
|
c := ctxt0{ctxt: ctxt, newprog: newprog}
|
|
|
|
|
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Class = 0
|
|
|
|
|
p.To.Class = 0
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
// Rewrite JMP/JAL to symbol as TYPE_BRANCH.
|
2015-09-05 20:27:00 -04:00
|
|
|
switch p.As {
|
2015-09-10 11:13:00 -04:00
|
|
|
case AJMP,
|
|
|
|
|
AJAL,
|
|
|
|
|
ARET,
|
2015-09-05 20:27:00 -04:00
|
|
|
obj.ADUFFZERO,
|
|
|
|
|
obj.ADUFFCOPY:
|
|
|
|
|
if p.To.Sym != nil {
|
|
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rewrite float constants to values stored in memory.
|
|
|
|
|
switch p.As {
|
2015-09-10 11:13:00 -04:00
|
|
|
case AMOVF:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.From.Type == obj.TYPE_FCONST {
|
|
|
|
|
f32 := float32(p.From.Val.(float64))
|
2017-04-06 10:29:29 -07:00
|
|
|
if math.Float32bits(f32) == 0 {
|
2016-10-18 23:50:37 +02:00
|
|
|
p.As = AMOVW
|
2016-10-27 17:52:53 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = REGZERO
|
|
|
|
|
break
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
2017-04-06 10:29:29 -07:00
|
|
|
p.From.Sym = ctxt.Float32Sym(f32)
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Name = obj.NAME_EXTERN
|
|
|
|
|
p.From.Offset = 0
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
case AMOVD:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.From.Type == obj.TYPE_FCONST {
|
2017-04-06 10:29:29 -07:00
|
|
|
f64 := p.From.Val.(float64)
|
2017-04-10 14:15:57 -07:00
|
|
|
if math.Float64bits(f64) == 0 && c.ctxt.Arch.Family == sys.MIPS64 {
|
2016-10-27 17:52:53 -04:00
|
|
|
p.As = AMOVV
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = REGZERO
|
|
|
|
|
break
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
2017-04-06 10:29:29 -07:00
|
|
|
p.From.Sym = ctxt.Float64Sym(f64)
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Name = obj.NAME_EXTERN
|
|
|
|
|
p.From.Offset = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Put >32-bit constants in memory and load them
|
2015-09-10 11:13:00 -04:00
|
|
|
case AMOVV:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
2017-04-06 10:29:29 -07:00
|
|
|
p.From.Sym = ctxt.Int64Sym(p.From.Offset)
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Name = obj.NAME_EXTERN
|
|
|
|
|
p.From.Offset = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Rewrite SUB constants into ADD.
|
|
|
|
|
switch p.As {
|
2015-09-10 11:13:00 -04:00
|
|
|
case ASUB:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.From.Type == obj.TYPE_CONST {
|
|
|
|
|
p.From.Offset = -p.From.Offset
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = AADD
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
case ASUBU:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.From.Type == obj.TYPE_CONST {
|
|
|
|
|
p.From.Offset = -p.From.Offset
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = AADDU
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
case ASUBV:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.From.Type == obj.TYPE_CONST {
|
|
|
|
|
p.From.Offset = -p.From.Offset
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = AADDV
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case ASUBVU:
|
|
|
|
|
if p.From.Type == obj.TYPE_CONST {
|
|
|
|
|
p.From.Offset = -p.From.Offset
|
|
|
|
|
p.As = AADDVU
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
2015-09-05 20:27:00 -04:00
|
|
|
// TODO(minux): add morestack short-cuts with small fixed frame-size.
|
2017-04-10 14:15:57 -07:00
|
|
|
c := ctxt0{ctxt: ctxt, newprog: newprog, cursym: cursym}
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
// a switch for enabling/disabling instruction scheduling
|
|
|
|
|
nosched := true
|
|
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
if c.cursym.Func().Text == nil || c.cursym.Func().Text.Link == nil {
|
2015-09-05 20:27:00 -04:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
p := c.cursym.Func().Text
|
2015-09-05 20:27:00 -04:00
|
|
|
textstksiz := p.To.Offset
|
2018-01-24 17:17:38 -05:00
|
|
|
if textstksiz == -ctxt.FixedFrameSize() {
|
|
|
|
|
// Historical way to mark NOFRAME.
|
|
|
|
|
p.From.Sym.Set(obj.AttrNoFrame, true)
|
|
|
|
|
textstksiz = 0
|
|
|
|
|
}
|
|
|
|
|
if textstksiz < 0 {
|
|
|
|
|
c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
|
|
|
|
|
}
|
|
|
|
|
if p.From.Sym.NoFrame() {
|
|
|
|
|
if textstksiz != 0 {
|
|
|
|
|
c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
c.cursym.Func().Args = p.To.Val.(int32)
|
|
|
|
|
c.cursym.Func().Locals = int32(textstksiz)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* find leaf subroutines
|
|
|
|
|
* expand RET
|
|
|
|
|
* expand BECOME pseudo
|
|
|
|
|
*/
|
|
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
for p := c.cursym.Func().Text; p != nil; p = p.Link {
|
2015-09-05 20:27:00 -04:00
|
|
|
switch p.As {
|
|
|
|
|
/* too hard, just leave alone */
|
|
|
|
|
case obj.ATEXT:
|
|
|
|
|
p.Mark |= LABEL | LEAF | SYNC
|
|
|
|
|
if p.Link != nil {
|
|
|
|
|
p.Link.Mark |= LABEL
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
/* too hard, just leave alone */
|
|
|
|
|
case AMOVW,
|
|
|
|
|
AMOVV:
|
|
|
|
|
if p.To.Type == obj.TYPE_REG && p.To.Reg >= REG_SPECIAL {
|
|
|
|
|
p.Mark |= LABEL | SYNC
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if p.From.Type == obj.TYPE_REG && p.From.Reg >= REG_SPECIAL {
|
|
|
|
|
p.Mark |= LABEL | SYNC
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
/* too hard, just leave alone */
|
|
|
|
|
case ASYSCALL,
|
2015-09-05 20:27:00 -04:00
|
|
|
AWORD,
|
2015-09-10 11:13:00 -04:00
|
|
|
ATLBWR,
|
|
|
|
|
ATLBWI,
|
|
|
|
|
ATLBP,
|
|
|
|
|
ATLBR:
|
2015-09-05 20:27:00 -04:00
|
|
|
p.Mark |= LABEL | SYNC
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
case ANOR:
|
|
|
|
|
if p.To.Type == obj.TYPE_REG {
|
|
|
|
|
if p.To.Reg == REGZERO {
|
|
|
|
|
p.Mark |= LABEL | SYNC
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
case ABGEZAL,
|
|
|
|
|
ABLTZAL,
|
|
|
|
|
AJAL,
|
2015-09-05 20:27:00 -04:00
|
|
|
obj.ADUFFZERO,
|
|
|
|
|
obj.ADUFFCOPY:
|
2020-07-19 00:30:12 -04:00
|
|
|
c.cursym.Func().Text.Mark &^= LEAF
|
2015-09-05 20:27:00 -04:00
|
|
|
fallthrough
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
case AJMP,
|
2015-09-05 20:27:00 -04:00
|
|
|
ABEQ,
|
2015-09-10 11:13:00 -04:00
|
|
|
ABGEZ,
|
|
|
|
|
ABGTZ,
|
|
|
|
|
ABLEZ,
|
|
|
|
|
ABLTZ,
|
2015-09-05 20:27:00 -04:00
|
|
|
ABNE,
|
2015-09-10 11:13:00 -04:00
|
|
|
ABFPT, ABFPF:
|
|
|
|
|
if p.As == ABFPT || p.As == ABFPF {
|
|
|
|
|
// We don't treat ABFPT and ABFPF as branches here,
|
|
|
|
|
// so that we will always fill nop (0x0) in their
|
|
|
|
|
// delay slot during assembly.
|
|
|
|
|
// This is to workaround a kernel FPU emulator bug
|
|
|
|
|
// where it uses the user stack to simulate the
|
|
|
|
|
// instruction in the delay slot if it's not 0x0,
|
|
|
|
|
// and somehow that leads to SIGSEGV when the kernel
|
|
|
|
|
// jump to the stack.
|
|
|
|
|
p.Mark |= SYNC
|
|
|
|
|
} else {
|
|
|
|
|
p.Mark |= BRANCH
|
|
|
|
|
}
|
2020-08-28 17:10:32 +00:00
|
|
|
q1 := p.To.Target()
|
2015-09-05 20:27:00 -04:00
|
|
|
if q1 != nil {
|
|
|
|
|
for q1.As == obj.ANOP {
|
|
|
|
|
q1 = q1.Link
|
2020-08-28 17:10:32 +00:00
|
|
|
p.To.SetTarget(q1)
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if q1.Mark&LEAF == 0 {
|
|
|
|
|
q1.Mark |= LABEL
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-10 11:13:00 -04:00
|
|
|
//else {
|
|
|
|
|
// p.Mark |= LABEL
|
|
|
|
|
//}
|
2015-09-05 20:27:00 -04:00
|
|
|
q1 = p.Link
|
|
|
|
|
if q1 != nil {
|
|
|
|
|
q1.Mark |= LABEL
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
case ARET:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.Link != nil {
|
|
|
|
|
p.Link.Mark |= LABEL
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
var mov, add obj.As
|
2017-04-10 14:15:57 -07:00
|
|
|
if c.ctxt.Arch.Family == sys.MIPS64 {
|
2016-10-18 23:50:37 +02:00
|
|
|
add = AADDV
|
|
|
|
|
mov = AMOVV
|
|
|
|
|
} else {
|
|
|
|
|
add = AADDU
|
|
|
|
|
mov = AMOVW
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-15 08:08:37 -07:00
|
|
|
var q *obj.Prog
|
|
|
|
|
var q1 *obj.Prog
|
2015-09-05 20:27:00 -04:00
|
|
|
autosize := int32(0)
|
|
|
|
|
var p1 *obj.Prog
|
|
|
|
|
var p2 *obj.Prog
|
2020-07-19 00:30:12 -04:00
|
|
|
for p := c.cursym.Func().Text; p != nil; p = p.Link {
|
2016-03-07 18:00:08 -08:00
|
|
|
o := p.As
|
2015-09-05 20:27:00 -04:00
|
|
|
switch o {
|
|
|
|
|
case obj.ATEXT:
|
2018-01-24 17:17:38 -05:00
|
|
|
autosize = int32(textstksiz)
|
|
|
|
|
|
|
|
|
|
if p.Mark&LEAF != 0 && autosize == 0 {
|
|
|
|
|
// A leaf function with no locals has no frame.
|
|
|
|
|
p.From.Sym.Set(obj.AttrNoFrame, true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !p.From.Sym.NoFrame() {
|
|
|
|
|
// If there is a stack frame at all, it includes
|
|
|
|
|
// space to save the LR.
|
|
|
|
|
autosize += int32(c.ctxt.FixedFrameSize())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if autosize&4 != 0 && c.ctxt.Arch.Family == sys.MIPS64 {
|
2015-09-05 20:27:00 -04:00
|
|
|
autosize += 4
|
|
|
|
|
}
|
2016-10-18 23:50:37 +02:00
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
if autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
|
|
|
|
|
if c.cursym.Func().Text.From.Sym.NoSplit() {
|
2018-01-24 17:17:38 -05:00
|
|
|
if ctxt.Debugvlog {
|
|
|
|
|
ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
c.cursym.Func().Text.Mark |= LEAF
|
2018-01-24 17:17:38 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
if c.cursym.Func().Text.Mark&LEAF != 0 {
|
2018-01-24 17:17:38 -05:00
|
|
|
c.cursym.Set(obj.AttrLeaf, true)
|
|
|
|
|
if p.From.Sym.NoFrame() {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cmd/internal/obj: stop storing Text flags in From3
Prior to this CL, flags such as NOSPLIT
on ATEXT Progs were stored in From3.Offset.
Some but not all of those flags were also
duplicated into From.Sym.Attribute.
This CL migrates all of those flags into
From.Sym.Attribute and stops creating a From3.
A side-effect of this is that printing an
ATEXT Prog can no longer simply dump From3.Offset.
That's kind of good, since the raw flag value
wasn't very informative anyway, but it did
necessitate a bunch of updates to the cmd/asm tests.
The reason I'm doing this work now is that
avoiding storing flags in both From.Sym and From3.Offset
simplifies some other changes to fix the data
race first described in CL 40254.
This CL almost passes toolstash-check -all.
The only changes are in cases where the assembler
has decided that a function's flags may be altered,
e.g. to make a function with no calls in it NOSPLIT.
Prior to this CL, that information was not printed.
Sample before:
"".Ctz64 t=1 size=63 args=0x10 locals=0x0
0x0000 00000 (/Users/josh/go/tip/src/runtime/internal/sys/intrinsics.go:35) TEXT "".Ctz64(SB), $0-16
0x0000 00000 (/Users/josh/go/tip/src/runtime/internal/sys/intrinsics.go:35) FUNCDATA $0, gclocals·f207267fbf96a0178e8758c6e3e0ce28(SB)
Sample after:
"".Ctz64 t=1 nosplit size=63 args=0x10 locals=0x0
0x0000 00000 (/Users/josh/go/tip/src/runtime/internal/sys/intrinsics.go:35) TEXT "".Ctz64(SB), NOSPLIT, $0-16
0x0000 00000 (/Users/josh/go/tip/src/runtime/internal/sys/intrinsics.go:35) FUNCDATA $0, gclocals·f207267fbf96a0178e8758c6e3e0ce28(SB)
Observe the additional "nosplit" in the first line
and the additional "NOSPLIT" in the second line.
Updates #15756
Change-Id: I5c59bd8f3bdc7c780361f801d94a261f0aef3d13
Reviewed-on: https://go-review.googlesource.com/40495
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-04-11 15:15:04 -07:00
|
|
|
if !p.From.Sym.NoSplit() {
|
2017-04-10 14:15:57 -07:00
|
|
|
p = c.stacksplit(p, autosize) // emit split check
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
q = p
|
|
|
|
|
|
|
|
|
|
if autosize != 0 {
|
2016-10-21 18:22:13 -04:00
|
|
|
// Make sure to save link register for non-empty frame, even if
|
|
|
|
|
// it is a leaf function, so that traceback works.
|
|
|
|
|
// 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.
|
2019-10-26 22:49:13 -04:00
|
|
|
// This sequence is not async preemptible, as if we open a frame
|
|
|
|
|
// at the current SP, it will clobber the saved LR.
|
|
|
|
|
q = c.ctxt.StartUnsafePoint(q, c.newprog)
|
|
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2016-10-18 23:50:37 +02:00
|
|
|
q.As = mov
|
2016-12-09 14:30:40 -05:00
|
|
|
q.Pos = p.Pos
|
2016-10-21 18:22:13 -04:00
|
|
|
q.From.Type = obj.TYPE_REG
|
|
|
|
|
q.From.Reg = REGLINK
|
|
|
|
|
q.To.Type = obj.TYPE_MEM
|
|
|
|
|
q.To.Offset = int64(-autosize)
|
|
|
|
|
q.To.Reg = REGSP
|
|
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2016-10-18 23:50:37 +02:00
|
|
|
q.As = add
|
2016-12-09 14:30:40 -05:00
|
|
|
q.Pos = p.Pos
|
2015-09-10 11:13:00 -04:00
|
|
|
q.From.Type = obj.TYPE_CONST
|
|
|
|
|
q.From.Offset = int64(-autosize)
|
|
|
|
|
q.To.Type = obj.TYPE_REG
|
|
|
|
|
q.To.Reg = REGSP
|
|
|
|
|
q.Spadj = +autosize
|
2019-10-26 22:49:13 -04:00
|
|
|
|
|
|
|
|
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 {
|
2015-09-05 20:27:00 -04:00
|
|
|
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
|
|
|
|
|
//
|
2016-10-18 23:50:37 +02:00
|
|
|
// 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)
|
2015-09-05 20:27:00 -04:00
|
|
|
// end:
|
|
|
|
|
// NOP
|
|
|
|
|
//
|
|
|
|
|
// The NOP is needed to give the jumps somewhere to land.
|
2015-09-10 11:13:00 -04:00
|
|
|
// It is a liblink NOP, not an mips NOP: it encodes to 0 instruction bytes.
|
2018-01-24 17:17:38 -05:00
|
|
|
//
|
|
|
|
|
// We don't generate this for leafs because that means the wrapped
|
|
|
|
|
// function was inlined into the wrapper.
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
q.As = mov
|
2015-09-05 20:27:00 -04:00
|
|
|
q.From.Type = obj.TYPE_MEM
|
|
|
|
|
q.From.Reg = REGG
|
2017-04-10 14:15:57 -07:00
|
|
|
q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
|
2015-09-05 20:27:00 -04:00
|
|
|
q.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
q.To.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
q.As = ABEQ
|
2015-09-10 11:13:00 -04:00
|
|
|
q.From.Type = obj.TYPE_REG
|
|
|
|
|
q.From.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
q.To.Type = obj.TYPE_BRANCH
|
2015-09-10 11:13:00 -04:00
|
|
|
q.Mark |= BRANCH
|
2015-09-05 20:27:00 -04:00
|
|
|
p1 = q
|
|
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2016-10-18 23:50:37 +02:00
|
|
|
q.As = mov
|
2015-09-05 20:27:00 -04:00
|
|
|
q.From.Type = obj.TYPE_MEM
|
2015-09-10 11:13:00 -04:00
|
|
|
q.From.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
q.From.Offset = 0 // Panic.argp
|
|
|
|
|
q.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
q.To.Reg = REG_R2
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2016-10-18 23:50:37 +02:00
|
|
|
q.As = add
|
2015-09-05 20:27:00 -04:00
|
|
|
q.From.Type = obj.TYPE_CONST
|
2016-10-18 23:50:37 +02:00
|
|
|
q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
|
2015-09-05 20:27:00 -04:00
|
|
|
q.Reg = REGSP
|
|
|
|
|
q.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
q.To.Reg = REG_R3
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
q.As = ABNE
|
2015-09-10 11:13:00 -04:00
|
|
|
q.From.Type = obj.TYPE_REG
|
|
|
|
|
q.From.Reg = REG_R2
|
|
|
|
|
q.Reg = REG_R3
|
2015-09-05 20:27:00 -04:00
|
|
|
q.To.Type = obj.TYPE_BRANCH
|
2015-09-10 11:13:00 -04:00
|
|
|
q.Mark |= BRANCH
|
2015-09-05 20:27:00 -04:00
|
|
|
p2 = q
|
|
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2016-10-18 23:50:37 +02:00
|
|
|
q.As = add
|
2015-09-05 20:27:00 -04:00
|
|
|
q.From.Type = obj.TYPE_CONST
|
2016-10-18 23:50:37 +02:00
|
|
|
q.From.Offset = ctxt.FixedFrameSize()
|
2015-09-05 20:27:00 -04:00
|
|
|
q.Reg = REGSP
|
|
|
|
|
q.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
q.To.Reg = REG_R2
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2016-10-18 23:50:37 +02:00
|
|
|
q.As = mov
|
2015-09-05 20:27:00 -04:00
|
|
|
q.From.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
q.From.Reg = REG_R2
|
2015-09-05 20:27:00 -04:00
|
|
|
q.To.Type = obj.TYPE_MEM
|
2015-09-10 11:13:00 -04:00
|
|
|
q.To.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
q.To.Offset = 0 // Panic.argp
|
|
|
|
|
|
2017-04-04 14:31:55 -07:00
|
|
|
q = obj.Appendp(q, newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
|
|
|
|
q.As = obj.ANOP
|
2020-08-28 17:10:32 +00:00
|
|
|
p1.To.SetTarget(q)
|
|
|
|
|
p2.To.SetTarget(q)
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
case ARET:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.From.Type == obj.TYPE_CONST {
|
|
|
|
|
ctxt.Diag("using BECOME (%v) is not supported!", p)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-22 12:25:23 -04:00
|
|
|
retSym := p.To.Sym
|
|
|
|
|
p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
|
|
|
|
|
p.To.Sym = nil
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2020-07-19 00:30:12 -04:00
|
|
|
if c.cursym.Func().Text.Mark&LEAF != 0 {
|
2015-09-05 20:27:00 -04:00
|
|
|
if autosize == 0 {
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = AJMP
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From = obj.Addr{}
|
2016-08-22 12:25:23 -04:00
|
|
|
if retSym != nil { // retjmp
|
|
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
p.To.Name = obj.NAME_EXTERN
|
|
|
|
|
p.To.Sym = retSym
|
|
|
|
|
} else {
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Reg = REGLINK
|
|
|
|
|
p.To.Offset = 0
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
p.Mark |= BRANCH
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
p.As = add
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = int64(autosize)
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = REGSP
|
|
|
|
|
p.Spadj = -autosize
|
|
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
q = c.newprog()
|
2015-09-10 11:13:00 -04:00
|
|
|
q.As = AJMP
|
2016-12-09 14:30:40 -05:00
|
|
|
q.Pos = p.Pos
|
2021-12-13 10:24:07 -05:00
|
|
|
if retSym != nil { // retjmp
|
|
|
|
|
q.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
q.To.Name = obj.NAME_EXTERN
|
|
|
|
|
q.To.Sym = retSym
|
|
|
|
|
} else {
|
|
|
|
|
q.To.Type = obj.TYPE_MEM
|
|
|
|
|
q.To.Reg = REGLINK
|
|
|
|
|
q.To.Offset = 0
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
q.Mark |= BRANCH
|
|
|
|
|
q.Spadj = +autosize
|
|
|
|
|
|
|
|
|
|
q.Link = p.Link
|
|
|
|
|
p.Link = q
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
p.As = mov
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Offset = 0
|
|
|
|
|
p.From.Reg = REGSP
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2017-11-21 09:25:29 -05:00
|
|
|
p.To.Reg = REGLINK
|
2015-09-05 20:27:00 -04:00
|
|
|
|
|
|
|
|
if autosize != 0 {
|
2017-04-10 14:15:57 -07:00
|
|
|
q = c.newprog()
|
2016-10-18 23:50:37 +02:00
|
|
|
q.As = add
|
2016-12-09 14:30:40 -05:00
|
|
|
q.Pos = p.Pos
|
2015-09-05 20:27:00 -04:00
|
|
|
q.From.Type = obj.TYPE_CONST
|
|
|
|
|
q.From.Offset = int64(autosize)
|
|
|
|
|
q.To.Type = obj.TYPE_REG
|
|
|
|
|
q.To.Reg = REGSP
|
|
|
|
|
q.Spadj = -autosize
|
|
|
|
|
|
|
|
|
|
q.Link = p.Link
|
|
|
|
|
p.Link = q
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
q1 = c.newprog()
|
2015-09-10 11:13:00 -04:00
|
|
|
q1.As = AJMP
|
2016-12-09 14:30:40 -05:00
|
|
|
q1.Pos = p.Pos
|
2016-08-22 12:25:23 -04:00
|
|
|
if retSym != nil { // retjmp
|
|
|
|
|
q1.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
q1.To.Name = obj.NAME_EXTERN
|
|
|
|
|
q1.To.Sym = retSym
|
|
|
|
|
} else {
|
|
|
|
|
q1.To.Type = obj.TYPE_MEM
|
|
|
|
|
q1.To.Offset = 0
|
2017-11-21 09:25:29 -05:00
|
|
|
q1.To.Reg = REGLINK
|
2016-08-22 12:25:23 -04:00
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
q1.Mark |= BRANCH
|
|
|
|
|
q1.Spadj = +autosize
|
|
|
|
|
|
|
|
|
|
q1.Link = q.Link
|
|
|
|
|
q.Link = q1
|
|
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
case AADD,
|
|
|
|
|
AADDU,
|
|
|
|
|
AADDV,
|
2015-09-10 11:13:00 -04:00
|
|
|
AADDVU:
|
2015-09-05 20:27:00 -04:00
|
|
|
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
|
|
|
|
|
p.Spadj = int32(-p.From.Offset)
|
|
|
|
|
}
|
2018-05-02 14:25:00 +08:00
|
|
|
|
|
|
|
|
case obj.AGETCALLERPC:
|
|
|
|
|
if cursym.Leaf() {
|
|
|
|
|
/* MOV LR, Rd */
|
|
|
|
|
p.As = mov
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = REGLINK
|
|
|
|
|
} else {
|
|
|
|
|
/* MOV (RSP), Rd */
|
|
|
|
|
p.As = mov
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = REGSP
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
cmd/asm, cmd/link, runtime: introduce FuncInfo flag bits
The runtime traceback code has its own definition of which functions
mark the top frame of a stack, separate from the TOPFRAME bits that
exist in the assembly and are passed along in DWARF information.
It's error-prone and redundant to have two different sources of truth.
This CL provides the actual TOPFRAME bits to the runtime, so that
the runtime can use those bits instead of reinventing its own category.
This CL also adds a new bit, SPWRITE, which marks functions that
write directly to SP (anything but adding and subtracting constants).
Such functions must stop a traceback, because the traceback has no
way to rederive the SP on entry. Again, the runtime has its own definition
which is mostly correct, but also missing some functions. During ordinary
goroutine context switches, such functions do not appear on the stack,
so the incompleteness in the runtime usually doesn't matter.
But profiling signals can arrive at any moment, and the runtime may
crash during traceback if it attempts to unwind an SP-writing frame
and gets out-of-sync with the actual stack. The runtime contains code
to try to detect likely candidates but again it is incomplete.
Deriving the SPWRITE bit automatically from the actual assembly code
provides the complete truth, and passing it to the runtime lets the
runtime use it.
This CL is part of a stack adding windows/arm64
support (#36439), intended to land in the Go 1.17 cycle.
This CL is, however, not windows/arm64-specific.
It is cleanup meant to make the port (and future ports) easier.
Change-Id: I227f53b23ac5b3dabfcc5e8ee3f00df4e113cf58
Reviewed-on: https://go-review.googlesource.com/c/go/+/288800
Trust: Russ Cox <rsc@golang.org>
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-01-28 15:21:33 -05:00
|
|
|
|
|
|
|
|
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
|
|
|
|
|
f := c.cursym.Func()
|
|
|
|
|
if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
|
|
|
|
|
c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
|
|
|
|
|
if ctxt.Debugvlog || !ctxt.IsAsm {
|
|
|
|
|
ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
|
|
|
|
|
if !ctxt.IsAsm {
|
|
|
|
|
ctxt.Diag("invalid auto-SPWRITE in non-assembly")
|
|
|
|
|
ctxt.DiagFlush()
|
|
|
|
|
log.Fatalf("bad SPWRITE")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
2015-09-10 11:13:00 -04:00
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
if c.ctxt.Arch.Family == sys.MIPS {
|
2016-12-09 00:13:43 -05:00
|
|
|
// rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
|
2020-07-19 00:30:12 -04:00
|
|
|
for p = c.cursym.Func().Text; p != nil; p = p1 {
|
2016-12-09 00:13:43 -05:00
|
|
|
p1 = p.Link
|
|
|
|
|
|
|
|
|
|
if p.As != AMOVD {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if p.From.Type != obj.TYPE_MEM && p.To.Type != obj.TYPE_MEM {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p.As = AMOVF
|
2017-04-10 14:15:57 -07:00
|
|
|
q = c.newprog()
|
2016-12-09 00:13:43 -05:00
|
|
|
*q = *p
|
|
|
|
|
q.Link = p.Link
|
|
|
|
|
p.Link = q
|
|
|
|
|
p1 = q.Link
|
|
|
|
|
|
2018-02-28 16:10:14 +00:00
|
|
|
var addrOff int64
|
2017-04-10 14:15:57 -07:00
|
|
|
if c.ctxt.Arch.ByteOrder == binary.BigEndian {
|
2018-02-28 16:10:14 +00:00
|
|
|
addrOff = 4 // swap load/save order
|
2016-12-09 00:13:43 -05:00
|
|
|
}
|
|
|
|
|
if p.From.Type == obj.TYPE_MEM {
|
|
|
|
|
reg := REG_F0 + (p.To.Reg-REG_F0)&^1
|
2018-02-28 16:10:14 +00:00
|
|
|
p.To.Reg = reg
|
|
|
|
|
q.To.Reg = reg + 1
|
|
|
|
|
p.From.Offset += addrOff
|
|
|
|
|
q.From.Offset += 4 - addrOff
|
2016-12-09 00:13:43 -05:00
|
|
|
} else if p.To.Type == obj.TYPE_MEM {
|
|
|
|
|
reg := REG_F0 + (p.From.Reg-REG_F0)&^1
|
2018-02-28 16:10:14 +00:00
|
|
|
p.From.Reg = reg
|
|
|
|
|
q.From.Reg = reg + 1
|
|
|
|
|
p.To.Offset += addrOff
|
|
|
|
|
q.To.Offset += 4 - addrOff
|
2016-12-09 00:13:43 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
if nosched {
|
|
|
|
|
// if we don't do instruction scheduling, simply add
|
|
|
|
|
// NOP after each branch instruction.
|
2020-07-19 00:30:12 -04:00
|
|
|
for p = c.cursym.Func().Text; p != nil; p = p.Link {
|
2015-09-10 11:13:00 -04:00
|
|
|
if p.Mark&BRANCH != 0 {
|
2017-04-10 14:15:57 -07:00
|
|
|
c.addnop(p)
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// instruction scheduling
|
2020-07-19 00:30:12 -04:00
|
|
|
q = nil // p - 1
|
|
|
|
|
q1 = c.cursym.Func().Text // top of block
|
|
|
|
|
o := 0 // count of instructions
|
|
|
|
|
for p = c.cursym.Func().Text; p != nil; p = p1 {
|
2015-09-10 11:13:00 -04:00
|
|
|
p1 = p.Link
|
|
|
|
|
o++
|
|
|
|
|
if p.Mark&NOSCHED != 0 {
|
|
|
|
|
if q1 != p {
|
2017-04-10 14:15:57 -07:00
|
|
|
c.sched(q1, q)
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
for ; p != nil; p = p.Link {
|
|
|
|
|
if p.Mark&NOSCHED == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
q = p
|
|
|
|
|
}
|
|
|
|
|
p1 = p
|
|
|
|
|
q1 = p
|
|
|
|
|
o = 0
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if p.Mark&(LABEL|SYNC) != 0 {
|
|
|
|
|
if q1 != p {
|
2017-04-10 14:15:57 -07:00
|
|
|
c.sched(q1, q)
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
q1 = p
|
|
|
|
|
o = 1
|
|
|
|
|
}
|
|
|
|
|
if p.Mark&(BRANCH|SYNC) != 0 {
|
2017-04-10 14:15:57 -07:00
|
|
|
c.sched(q1, p)
|
2015-09-10 11:13:00 -04:00
|
|
|
q1 = p1
|
|
|
|
|
o = 0
|
|
|
|
|
}
|
|
|
|
|
if o >= NSCHED {
|
2017-04-10 14:15:57 -07:00
|
|
|
c.sched(q1, p)
|
2015-09-10 11:13:00 -04:00
|
|
|
q1 = p1
|
|
|
|
|
o = 0
|
|
|
|
|
}
|
|
|
|
|
q = p
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
|
2021-04-02 17:20:15 -04:00
|
|
|
var mov, add obj.As
|
2016-10-18 23:50:37 +02:00
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
if c.ctxt.Arch.Family == sys.MIPS64 {
|
2016-10-18 23:50:37 +02:00
|
|
|
add = AADDV
|
|
|
|
|
mov = AMOVV
|
|
|
|
|
} else {
|
|
|
|
|
add = AADDU
|
|
|
|
|
mov = AMOVW
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 17:39:09 -04:00
|
|
|
if c.ctxt.Flag_maymorestack != "" {
|
|
|
|
|
// Save LR and REGCTXT.
|
|
|
|
|
frameSize := 2 * c.ctxt.Arch.PtrSize
|
|
|
|
|
|
|
|
|
|
p = c.ctxt.StartUnsafePoint(p, c.newprog)
|
|
|
|
|
|
|
|
|
|
// MOV REGLINK, -8/-16(SP)
|
|
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
p.As = mov
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = REGLINK
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Offset = int64(-frameSize)
|
|
|
|
|
p.To.Reg = REGSP
|
|
|
|
|
|
|
|
|
|
// MOV REGCTXT, -4/-8(SP)
|
|
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
p.As = mov
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = REGCTXT
|
|
|
|
|
p.To.Type = obj.TYPE_MEM
|
|
|
|
|
p.To.Offset = -int64(c.ctxt.Arch.PtrSize)
|
|
|
|
|
p.To.Reg = REGSP
|
|
|
|
|
|
|
|
|
|
// ADD $-8/$-16, SP
|
|
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
p.As = add
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = int64(-frameSize)
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = REGSP
|
|
|
|
|
p.Spadj = int32(frameSize)
|
|
|
|
|
|
|
|
|
|
// JAL maymorestack
|
|
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
p.As = AJAL
|
|
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
// See ../x86/obj6.go
|
|
|
|
|
p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
|
|
|
|
|
p.Mark |= BRANCH
|
|
|
|
|
|
|
|
|
|
// Restore LR and REGCTXT.
|
|
|
|
|
|
|
|
|
|
// MOV 0(SP), REGLINK
|
|
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
p.As = mov
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Offset = 0
|
|
|
|
|
p.From.Reg = REGSP
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = REGLINK
|
|
|
|
|
|
|
|
|
|
// MOV 4/8(SP), REGCTXT
|
|
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
p.As = mov
|
|
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Offset = int64(c.ctxt.Arch.PtrSize)
|
|
|
|
|
p.From.Reg = REGSP
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = REGCTXT
|
|
|
|
|
|
|
|
|
|
// ADD $8/$16, SP
|
|
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
p.As = add
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = int64(frameSize)
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = REGSP
|
|
|
|
|
p.Spadj = int32(-frameSize)
|
|
|
|
|
|
|
|
|
|
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Jump back to here after morestack returns.
|
|
|
|
|
startPred := p
|
|
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
// MOV g_stackguard(g), R1
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
p.As = mov
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_MEM
|
|
|
|
|
p.From.Reg = REGG
|
2017-04-10 14:15:57 -07:00
|
|
|
p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
|
|
|
|
|
if c.cursym.CFunc() {
|
|
|
|
|
p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
p.To.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
|
cmd/internal/obj: mark split-stack prologue nonpreemptible
When there are both a synchronous preemption request (by
clobbering the stack guard) and an asynchronous one (by signal),
the running goroutine may observe the synchronous request first
in stack bounds check, and go to the path of calling morestack.
If the preemption signal arrives at this point before the call to
morestack, the goroutine will be asynchronously preempted,
entering the scheduler. When it is resumed, the scheduler clears
the preemption request, unclobbers the stack guard. But the
resumed goroutine will still call morestack, as it is already on
its way. morestack will, as there is no preemption request,
double the stack unnecessarily. If this happens multiple times,
the stack may grow too big, although only a small amount is
actually used.
To fix this, we mark the stack bounds check and the call to
morestack async-nonpreemptible, starting after the memory
instruction (mostly a load, on x86 CMP with memory).
Not done for Wasm as it does not support async preemption.
Fixes #35470.
Change-Id: Ibd7f3d935a3649b80f47539116ec9b9556680cf2
Reviewed-on: https://go-review.googlesource.com/c/go/+/207350
Reviewed-by: David Chase <drchase@google.com>
2019-11-14 20:23:17 -05:00
|
|
|
// Mark the stack bound check and morestack call async nonpreemptible.
|
|
|
|
|
// If we get preempted here, when resumed the preemption request is
|
|
|
|
|
// cleared, but we'll still call morestack, which will double the stack
|
|
|
|
|
// unnecessarily. See issue #35470.
|
|
|
|
|
p = c.ctxt.StartUnsafePoint(p, c.newprog)
|
|
|
|
|
|
2015-09-05 20:27:00 -04:00
|
|
|
var q *obj.Prog
|
2017-04-18 12:53:25 -07:00
|
|
|
if framesize <= objabi.StackSmall {
|
2015-09-05 20:27:00 -04:00
|
|
|
// small stack: SP < stackguard
|
2015-09-10 11:13:00 -04:00
|
|
|
// AGTU SP, stackguard, R1
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = ASGTU
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
p.From.Reg = REGSP
|
|
|
|
|
p.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
p.To.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
} else {
|
2021-04-02 17:20:15 -04:00
|
|
|
// large stack: SP-framesize < stackguard-StackSmall
|
|
|
|
|
offset := int64(framesize) - objabi.StackSmall
|
|
|
|
|
if framesize > objabi.StackBig {
|
|
|
|
|
// Such a large stack we need to protect against underflow.
|
|
|
|
|
// The runtime guarantees SP > objabi.StackBig, but
|
|
|
|
|
// framesize is large enough that SP-framesize may
|
|
|
|
|
// underflow, causing a direct comparison with the
|
|
|
|
|
// stack guard to incorrectly succeed. We explicitly
|
|
|
|
|
// guard against underflow.
|
|
|
|
|
//
|
|
|
|
|
// SGTU $(framesize-StackSmall), SP, R2
|
|
|
|
|
// BNE R2, label-of-call-to-morestack
|
|
|
|
|
|
|
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
p.As = ASGTU
|
|
|
|
|
p.From.Type = obj.TYPE_CONST
|
|
|
|
|
p.From.Offset = offset
|
|
|
|
|
p.Reg = REGSP
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
|
|
|
|
p.To.Reg = REG_R2
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2021-04-02 17:20:15 -04:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
|
|
|
|
q = p
|
|
|
|
|
p.As = ABNE
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = REG_R2
|
|
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
|
|
|
|
p.Mark |= BRANCH
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2021-04-02 17:20:15 -04:00
|
|
|
// Check against the stack guard. We've ensured this won't underflow.
|
|
|
|
|
// ADD $-(framesize-StackSmall), SP, R2
|
|
|
|
|
// SGTU R2, stackguard, R1
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
p.As = add
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_CONST
|
2021-04-02 17:20:15 -04:00
|
|
|
p.From.Offset = -offset
|
2015-09-05 20:27:00 -04:00
|
|
|
p.Reg = REGSP
|
|
|
|
|
p.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
p.To.Reg = REG_R2
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = ASGTU
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
p.From.Reg = REG_R2
|
|
|
|
|
p.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
p.To.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
// q1: BNE R1, done
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
q1 := p
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = ABNE
|
|
|
|
|
p.From.Type = obj.TYPE_REG
|
|
|
|
|
p.From.Reg = REG_R1
|
2015-09-05 20:27:00 -04:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
2015-09-10 11:13:00 -04:00
|
|
|
p.Mark |= BRANCH
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
// MOV LINK, R3
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2016-10-18 23:50:37 +02:00
|
|
|
p.As = mov
|
2015-09-05 20:27:00 -04:00
|
|
|
p.From.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
p.From.Reg = REGLINK
|
2015-09-05 20:27:00 -04:00
|
|
|
p.To.Type = obj.TYPE_REG
|
2015-09-10 11:13:00 -04:00
|
|
|
p.To.Reg = REG_R3
|
2015-09-05 20:27:00 -04:00
|
|
|
if q != nil {
|
2020-08-28 17:10:32 +00:00
|
|
|
q.To.SetTarget(p)
|
2015-09-10 11:13:00 -04:00
|
|
|
p.Mark |= LABEL
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
cmd/internal/obj: mark split-stack prologue nonpreemptible
When there are both a synchronous preemption request (by
clobbering the stack guard) and an asynchronous one (by signal),
the running goroutine may observe the synchronous request first
in stack bounds check, and go to the path of calling morestack.
If the preemption signal arrives at this point before the call to
morestack, the goroutine will be asynchronously preempted,
entering the scheduler. When it is resumed, the scheduler clears
the preemption request, unclobbers the stack guard. But the
resumed goroutine will still call morestack, as it is already on
its way. morestack will, as there is no preemption request,
double the stack unnecessarily. If this happens multiple times,
the stack may grow too big, although only a small amount is
actually used.
To fix this, we mark the stack bounds check and the call to
morestack async-nonpreemptible, starting after the memory
instruction (mostly a load, on x86 CMP with memory).
Not done for Wasm as it does not support async preemption.
Fixes #35470.
Change-Id: Ibd7f3d935a3649b80f47539116ec9b9556680cf2
Reviewed-on: https://go-review.googlesource.com/c/go/+/207350
Reviewed-by: David Chase <drchase@google.com>
2019-11-14 20:23:17 -05:00
|
|
|
p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
|
2018-04-21 21:13:56 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
// JAL runtime.morestack(SB)
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = AJAL
|
2015-09-05 20:27:00 -04:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
2017-04-10 14:15:57 -07:00
|
|
|
if c.cursym.CFunc() {
|
2017-04-20 07:13:02 -07:00
|
|
|
p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
|
2020-07-19 00:30:12 -04:00
|
|
|
} else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
|
2017-04-20 07:13:02 -07:00
|
|
|
p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
|
2015-09-05 20:27:00 -04:00
|
|
|
} else {
|
2017-04-20 07:13:02 -07:00
|
|
|
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
2015-09-10 11:13:00 -04:00
|
|
|
p.Mark |= BRANCH
|
2015-09-05 20:27:00 -04:00
|
|
|
|
cmd/internal/obj: mark split-stack prologue nonpreemptible
When there are both a synchronous preemption request (by
clobbering the stack guard) and an asynchronous one (by signal),
the running goroutine may observe the synchronous request first
in stack bounds check, and go to the path of calling morestack.
If the preemption signal arrives at this point before the call to
morestack, the goroutine will be asynchronously preempted,
entering the scheduler. When it is resumed, the scheduler clears
the preemption request, unclobbers the stack guard. But the
resumed goroutine will still call morestack, as it is already on
its way. morestack will, as there is no preemption request,
double the stack unnecessarily. If this happens multiple times,
the stack may grow too big, although only a small amount is
actually used.
To fix this, we mark the stack bounds check and the call to
morestack async-nonpreemptible, starting after the memory
instruction (mostly a load, on x86 CMP with memory).
Not done for Wasm as it does not support async preemption.
Fixes #35470.
Change-Id: Ibd7f3d935a3649b80f47539116ec9b9556680cf2
Reviewed-on: https://go-review.googlesource.com/c/go/+/207350
Reviewed-by: David Chase <drchase@google.com>
2019-11-14 20:23:17 -05:00
|
|
|
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
// JMP start
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
p.As = AJMP
|
2015-09-05 20:27:00 -04:00
|
|
|
p.To.Type = obj.TYPE_BRANCH
|
2019-08-20 17:39:09 -04:00
|
|
|
p.To.SetTarget(startPred.Link)
|
|
|
|
|
startPred.Link.Mark |= LABEL
|
2015-09-10 11:13:00 -04:00
|
|
|
p.Mark |= BRANCH
|
2015-09-05 20:27:00 -04:00
|
|
|
|
|
|
|
|
// placeholder for q1's jump target
|
2017-04-10 14:15:57 -07:00
|
|
|
p = obj.Appendp(p, c.newprog)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
|
|
|
|
p.As = obj.ANOP // zero-width place holder
|
2020-08-28 17:10:32 +00:00
|
|
|
q1.To.SetTarget(p)
|
2015-09-05 20:27:00 -04:00
|
|
|
|
|
|
|
|
return p
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
func (c *ctxt0) addnop(p *obj.Prog) {
|
|
|
|
|
q := c.newprog()
|
2017-04-11 10:39:55 -04:00
|
|
|
q.As = ANOOP
|
2016-12-09 14:30:40 -05:00
|
|
|
q.Pos = p.Pos
|
2015-09-10 11:13:00 -04:00
|
|
|
q.Link = p.Link
|
|
|
|
|
p.Link = q
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
const (
|
|
|
|
|
E_HILO = 1 << 0
|
|
|
|
|
E_FCR = 1 << 1
|
|
|
|
|
E_MCR = 1 << 2
|
|
|
|
|
E_MEM = 1 << 3
|
|
|
|
|
E_MEMSP = 1 << 4 /* uses offset and size */
|
|
|
|
|
E_MEMSB = 1 << 5 /* uses offset and size */
|
|
|
|
|
ANYMEM = E_MEM | E_MEMSP | E_MEMSB
|
|
|
|
|
//DELAY = LOAD|BRANCH|FCMP
|
|
|
|
|
DELAY = BRANCH /* only schedule branch */
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Dep struct {
|
|
|
|
|
ireg uint32
|
|
|
|
|
freg uint32
|
|
|
|
|
cc uint32
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Sch struct {
|
|
|
|
|
p obj.Prog
|
|
|
|
|
set Dep
|
|
|
|
|
used Dep
|
|
|
|
|
soffset int32
|
|
|
|
|
size uint8
|
|
|
|
|
nop uint8
|
|
|
|
|
comp bool
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
func (c *ctxt0) sched(p0, pe *obj.Prog) {
|
2015-09-10 11:13:00 -04:00
|
|
|
var sch [NSCHED]Sch
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
/*
|
|
|
|
|
* build side structure
|
|
|
|
|
*/
|
|
|
|
|
s := sch[:]
|
|
|
|
|
for p := p0; ; p = p.Link {
|
|
|
|
|
s[0].p = *p
|
2017-04-10 14:15:57 -07:00
|
|
|
c.markregused(&s[0])
|
2015-09-10 11:13:00 -04:00
|
|
|
if p == pe {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
s = s[1:]
|
|
|
|
|
}
|
|
|
|
|
se := s
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
for i := cap(sch) - cap(se); i >= 0; i-- {
|
|
|
|
|
s = sch[i:]
|
|
|
|
|
if s[0].p.Mark&DELAY == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if -cap(s) < -cap(se) {
|
|
|
|
|
if !conflict(&s[0], &s[1]) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-05 20:27:00 -04:00
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
var t []Sch
|
|
|
|
|
var j int
|
|
|
|
|
for j = cap(sch) - cap(s) - 1; j >= 0; j-- {
|
|
|
|
|
t = sch[j:]
|
|
|
|
|
if t[0].comp {
|
|
|
|
|
if s[0].p.Mark&BRANCH != 0 {
|
2018-04-29 22:17:23 +09:00
|
|
|
continue
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if t[0].p.Mark&DELAY != 0 {
|
|
|
|
|
if -cap(s) >= -cap(se) || conflict(&t[0], &s[1]) {
|
2018-04-29 22:17:23 +09:00
|
|
|
continue
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for u := t[1:]; -cap(u) <= -cap(s); u = u[1:] {
|
2017-04-10 14:15:57 -07:00
|
|
|
if c.depend(&u[0], &t[0]) {
|
2018-04-29 22:17:23 +09:00
|
|
|
continue
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
goto out2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if s[0].p.Mark&BRANCH != 0 {
|
|
|
|
|
s[0].nop = 1
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
out2:
|
|
|
|
|
// t[0] is the instruction being moved to fill the delay
|
|
|
|
|
stmp := t[0]
|
|
|
|
|
copy(t[:i-j], t[1:i-j+1])
|
|
|
|
|
s[0] = stmp
|
|
|
|
|
|
|
|
|
|
if t[i-j-1].p.Mark&BRANCH != 0 {
|
|
|
|
|
// t[i-j] is being put into a branch delay slot
|
|
|
|
|
// combine its Spadj with the branch instruction
|
|
|
|
|
t[i-j-1].p.Spadj += t[i-j].p.Spadj
|
|
|
|
|
t[i-j].p.Spadj = 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i--
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* put it all back
|
|
|
|
|
*/
|
|
|
|
|
var p *obj.Prog
|
|
|
|
|
var q *obj.Prog
|
|
|
|
|
for s, p = sch[:], p0; -cap(s) <= -cap(se); s, p = s[1:], q {
|
|
|
|
|
q = p.Link
|
|
|
|
|
if q != s[0].p.Link {
|
|
|
|
|
*p = s[0].p
|
|
|
|
|
p.Link = q
|
|
|
|
|
}
|
|
|
|
|
for s[0].nop != 0 {
|
|
|
|
|
s[0].nop--
|
2017-04-10 14:15:57 -07:00
|
|
|
c.addnop(p)
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
func (c *ctxt0) markregused(s *Sch) {
|
2015-09-10 11:13:00 -04:00
|
|
|
p := &s.p
|
2017-04-10 14:15:57 -07:00
|
|
|
s.comp = c.compound(p)
|
2015-09-10 11:13:00 -04:00
|
|
|
s.nop = 0
|
|
|
|
|
if s.comp {
|
|
|
|
|
s.set.ireg |= 1 << (REGTMP - REG_R0)
|
|
|
|
|
s.used.ireg |= 1 << (REGTMP - REG_R0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ar := 0 /* dest is really reference */
|
|
|
|
|
ad := 0 /* source/dest is really address */
|
|
|
|
|
ld := 0 /* opcode is load instruction */
|
|
|
|
|
sz := 20 /* size of load/store for overlap computation */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* flags based on opcode
|
|
|
|
|
*/
|
|
|
|
|
switch p.As {
|
|
|
|
|
case obj.ATEXT:
|
2017-04-10 14:15:57 -07:00
|
|
|
c.autosize = int32(p.To.Offset + 8)
|
2015-09-10 11:13:00 -04:00
|
|
|
ad = 1
|
|
|
|
|
|
|
|
|
|
case AJAL:
|
2017-04-10 07:31:23 -07:00
|
|
|
r := p.Reg
|
|
|
|
|
if r == 0 {
|
|
|
|
|
r = REGLINK
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
2017-04-10 07:31:23 -07:00
|
|
|
s.set.ireg |= 1 << uint(r-REG_R0)
|
2015-09-10 11:13:00 -04:00
|
|
|
ar = 1
|
|
|
|
|
ad = 1
|
|
|
|
|
|
|
|
|
|
case ABGEZAL,
|
|
|
|
|
ABLTZAL:
|
|
|
|
|
s.set.ireg |= 1 << (REGLINK - REG_R0)
|
|
|
|
|
fallthrough
|
|
|
|
|
case ABEQ,
|
|
|
|
|
ABGEZ,
|
|
|
|
|
ABGTZ,
|
|
|
|
|
ABLEZ,
|
|
|
|
|
ABLTZ,
|
|
|
|
|
ABNE:
|
|
|
|
|
ar = 1
|
|
|
|
|
ad = 1
|
|
|
|
|
|
|
|
|
|
case ABFPT,
|
|
|
|
|
ABFPF:
|
|
|
|
|
ad = 1
|
|
|
|
|
s.used.cc |= E_FCR
|
|
|
|
|
|
|
|
|
|
case ACMPEQD,
|
|
|
|
|
ACMPEQF,
|
|
|
|
|
ACMPGED,
|
|
|
|
|
ACMPGEF,
|
|
|
|
|
ACMPGTD,
|
|
|
|
|
ACMPGTF:
|
|
|
|
|
ar = 1
|
|
|
|
|
s.set.cc |= E_FCR
|
|
|
|
|
p.Mark |= FCMP
|
|
|
|
|
|
|
|
|
|
case AJMP:
|
|
|
|
|
ar = 1
|
|
|
|
|
ad = 1
|
|
|
|
|
|
|
|
|
|
case AMOVB,
|
|
|
|
|
AMOVBU:
|
|
|
|
|
sz = 1
|
|
|
|
|
ld = 1
|
|
|
|
|
|
|
|
|
|
case AMOVH,
|
|
|
|
|
AMOVHU:
|
|
|
|
|
sz = 2
|
|
|
|
|
ld = 1
|
|
|
|
|
|
|
|
|
|
case AMOVF,
|
|
|
|
|
AMOVW,
|
|
|
|
|
AMOVWL,
|
|
|
|
|
AMOVWR:
|
|
|
|
|
sz = 4
|
|
|
|
|
ld = 1
|
|
|
|
|
|
|
|
|
|
case AMOVD,
|
|
|
|
|
AMOVV,
|
|
|
|
|
AMOVVL,
|
|
|
|
|
AMOVVR:
|
|
|
|
|
sz = 8
|
|
|
|
|
ld = 1
|
|
|
|
|
|
|
|
|
|
case ADIV,
|
|
|
|
|
ADIVU,
|
|
|
|
|
AMUL,
|
|
|
|
|
AMULU,
|
|
|
|
|
AREM,
|
|
|
|
|
AREMU,
|
|
|
|
|
ADIVV,
|
|
|
|
|
ADIVVU,
|
|
|
|
|
AMULV,
|
|
|
|
|
AMULVU,
|
|
|
|
|
AREMV,
|
|
|
|
|
AREMVU:
|
|
|
|
|
s.set.cc = E_HILO
|
|
|
|
|
fallthrough
|
|
|
|
|
case AADD,
|
|
|
|
|
AADDU,
|
|
|
|
|
AADDV,
|
|
|
|
|
AADDVU,
|
|
|
|
|
AAND,
|
|
|
|
|
ANOR,
|
|
|
|
|
AOR,
|
|
|
|
|
ASGT,
|
|
|
|
|
ASGTU,
|
|
|
|
|
ASLL,
|
|
|
|
|
ASRA,
|
|
|
|
|
ASRL,
|
|
|
|
|
ASLLV,
|
|
|
|
|
ASRAV,
|
|
|
|
|
ASRLV,
|
|
|
|
|
ASUB,
|
|
|
|
|
ASUBU,
|
|
|
|
|
ASUBV,
|
|
|
|
|
ASUBVU,
|
|
|
|
|
AXOR,
|
|
|
|
|
|
|
|
|
|
AADDD,
|
|
|
|
|
AADDF,
|
|
|
|
|
AADDW,
|
|
|
|
|
ASUBD,
|
|
|
|
|
ASUBF,
|
|
|
|
|
ASUBW,
|
|
|
|
|
AMULF,
|
|
|
|
|
AMULD,
|
|
|
|
|
AMULW,
|
|
|
|
|
ADIVF,
|
|
|
|
|
ADIVD,
|
|
|
|
|
ADIVW:
|
|
|
|
|
if p.Reg == 0 {
|
|
|
|
|
if p.To.Type == obj.TYPE_REG {
|
|
|
|
|
p.Reg = p.To.Reg
|
|
|
|
|
}
|
|
|
|
|
//if(p->reg == NREG)
|
|
|
|
|
// print("botch %P\n", p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* flags based on 'to' field
|
|
|
|
|
*/
|
2017-04-10 07:31:23 -07:00
|
|
|
cls := int(p.To.Class)
|
|
|
|
|
if cls == 0 {
|
2017-04-10 14:15:57 -07:00
|
|
|
cls = c.aclass(&p.To) + 1
|
2017-04-10 07:31:23 -07:00
|
|
|
p.To.Class = int8(cls)
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
2017-04-10 07:31:23 -07:00
|
|
|
cls--
|
|
|
|
|
switch cls {
|
2015-09-10 11:13:00 -04:00
|
|
|
default:
|
2017-04-10 07:31:23 -07:00
|
|
|
fmt.Printf("unknown class %d %v\n", cls, p)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
case C_ZCON,
|
|
|
|
|
C_SCON,
|
|
|
|
|
C_ADD0CON,
|
|
|
|
|
C_AND0CON,
|
|
|
|
|
C_ADDCON,
|
|
|
|
|
C_ANDCON,
|
|
|
|
|
C_UCON,
|
|
|
|
|
C_LCON,
|
|
|
|
|
C_NONE,
|
|
|
|
|
C_SBRA,
|
|
|
|
|
C_LBRA,
|
|
|
|
|
C_ADDR,
|
|
|
|
|
C_TEXTSIZE:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case C_HI,
|
|
|
|
|
C_LO:
|
|
|
|
|
s.set.cc |= E_HILO
|
|
|
|
|
|
|
|
|
|
case C_FCREG:
|
|
|
|
|
s.set.cc |= E_FCR
|
|
|
|
|
|
|
|
|
|
case C_MREG:
|
|
|
|
|
s.set.cc |= E_MCR
|
|
|
|
|
|
|
|
|
|
case C_ZOREG,
|
|
|
|
|
C_SOREG,
|
|
|
|
|
C_LOREG:
|
2017-04-10 07:31:23 -07:00
|
|
|
cls = int(p.To.Reg)
|
|
|
|
|
s.used.ireg |= 1 << uint(cls-REG_R0)
|
2015-09-10 11:13:00 -04:00
|
|
|
if ad != 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
s.size = uint8(sz)
|
2017-04-10 14:15:57 -07:00
|
|
|
s.soffset = c.regoff(&p.To)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
m := uint32(ANYMEM)
|
2017-04-10 07:31:23 -07:00
|
|
|
if cls == REGSB {
|
2015-09-10 11:13:00 -04:00
|
|
|
m = E_MEMSB
|
|
|
|
|
}
|
2017-04-10 07:31:23 -07:00
|
|
|
if cls == REGSP {
|
2015-09-10 11:13:00 -04:00
|
|
|
m = E_MEMSP
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ar != 0 {
|
|
|
|
|
s.used.cc |= m
|
|
|
|
|
} else {
|
|
|
|
|
s.set.cc |= m
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case C_SACON,
|
|
|
|
|
C_LACON:
|
|
|
|
|
s.used.ireg |= 1 << (REGSP - REG_R0)
|
|
|
|
|
|
|
|
|
|
case C_SECON,
|
|
|
|
|
C_LECON:
|
|
|
|
|
s.used.ireg |= 1 << (REGSB - REG_R0)
|
|
|
|
|
|
|
|
|
|
case C_REG:
|
|
|
|
|
if ar != 0 {
|
|
|
|
|
s.used.ireg |= 1 << uint(p.To.Reg-REG_R0)
|
|
|
|
|
} else {
|
|
|
|
|
s.set.ireg |= 1 << uint(p.To.Reg-REG_R0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case C_FREG:
|
|
|
|
|
if ar != 0 {
|
|
|
|
|
s.used.freg |= 1 << uint(p.To.Reg-REG_F0)
|
|
|
|
|
} else {
|
|
|
|
|
s.set.freg |= 1 << uint(p.To.Reg-REG_F0)
|
|
|
|
|
}
|
|
|
|
|
if ld != 0 && p.From.Type == obj.TYPE_REG {
|
|
|
|
|
p.Mark |= LOAD
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case C_SAUTO,
|
|
|
|
|
C_LAUTO:
|
|
|
|
|
s.used.ireg |= 1 << (REGSP - REG_R0)
|
|
|
|
|
if ad != 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
s.size = uint8(sz)
|
2017-04-10 14:15:57 -07:00
|
|
|
s.soffset = c.regoff(&p.To)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
if ar != 0 {
|
|
|
|
|
s.used.cc |= E_MEMSP
|
|
|
|
|
} else {
|
|
|
|
|
s.set.cc |= E_MEMSP
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case C_SEXT,
|
|
|
|
|
C_LEXT:
|
|
|
|
|
s.used.ireg |= 1 << (REGSB - REG_R0)
|
|
|
|
|
if ad != 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
s.size = uint8(sz)
|
2017-04-10 14:15:57 -07:00
|
|
|
s.soffset = c.regoff(&p.To)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
if ar != 0 {
|
|
|
|
|
s.used.cc |= E_MEMSB
|
|
|
|
|
} else {
|
|
|
|
|
s.set.cc |= E_MEMSB
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* flags based on 'from' field
|
|
|
|
|
*/
|
2017-04-10 07:31:23 -07:00
|
|
|
cls = int(p.From.Class)
|
|
|
|
|
if cls == 0 {
|
2017-04-10 14:15:57 -07:00
|
|
|
cls = c.aclass(&p.From) + 1
|
2017-04-10 07:31:23 -07:00
|
|
|
p.From.Class = int8(cls)
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
2017-04-10 07:31:23 -07:00
|
|
|
cls--
|
|
|
|
|
switch cls {
|
2015-09-10 11:13:00 -04:00
|
|
|
default:
|
2017-04-10 07:31:23 -07:00
|
|
|
fmt.Printf("unknown class %d %v\n", cls, p)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
case C_ZCON,
|
|
|
|
|
C_SCON,
|
|
|
|
|
C_ADD0CON,
|
|
|
|
|
C_AND0CON,
|
|
|
|
|
C_ADDCON,
|
|
|
|
|
C_ANDCON,
|
|
|
|
|
C_UCON,
|
|
|
|
|
C_LCON,
|
|
|
|
|
C_NONE,
|
|
|
|
|
C_SBRA,
|
|
|
|
|
C_LBRA,
|
|
|
|
|
C_ADDR,
|
|
|
|
|
C_TEXTSIZE:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
case C_HI,
|
|
|
|
|
C_LO:
|
|
|
|
|
s.used.cc |= E_HILO
|
|
|
|
|
|
|
|
|
|
case C_FCREG:
|
|
|
|
|
s.used.cc |= E_FCR
|
|
|
|
|
|
|
|
|
|
case C_MREG:
|
|
|
|
|
s.used.cc |= E_MCR
|
|
|
|
|
|
|
|
|
|
case C_ZOREG,
|
|
|
|
|
C_SOREG,
|
|
|
|
|
C_LOREG:
|
2017-04-10 07:31:23 -07:00
|
|
|
cls = int(p.From.Reg)
|
|
|
|
|
s.used.ireg |= 1 << uint(cls-REG_R0)
|
2015-09-10 11:13:00 -04:00
|
|
|
if ld != 0 {
|
|
|
|
|
p.Mark |= LOAD
|
|
|
|
|
}
|
|
|
|
|
s.size = uint8(sz)
|
2017-04-10 14:15:57 -07:00
|
|
|
s.soffset = c.regoff(&p.From)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
m := uint32(ANYMEM)
|
2017-04-10 07:31:23 -07:00
|
|
|
if cls == REGSB {
|
2015-09-10 11:13:00 -04:00
|
|
|
m = E_MEMSB
|
|
|
|
|
}
|
2017-04-10 07:31:23 -07:00
|
|
|
if cls == REGSP {
|
2015-09-10 11:13:00 -04:00
|
|
|
m = E_MEMSP
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s.used.cc |= m
|
|
|
|
|
|
|
|
|
|
case C_SACON,
|
|
|
|
|
C_LACON:
|
2017-04-10 07:31:23 -07:00
|
|
|
cls = int(p.From.Reg)
|
|
|
|
|
if cls == 0 {
|
|
|
|
|
cls = REGSP
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
2017-04-10 07:31:23 -07:00
|
|
|
s.used.ireg |= 1 << uint(cls-REG_R0)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
case C_SECON,
|
|
|
|
|
C_LECON:
|
|
|
|
|
s.used.ireg |= 1 << (REGSB - REG_R0)
|
|
|
|
|
|
|
|
|
|
case C_REG:
|
|
|
|
|
s.used.ireg |= 1 << uint(p.From.Reg-REG_R0)
|
|
|
|
|
|
|
|
|
|
case C_FREG:
|
|
|
|
|
s.used.freg |= 1 << uint(p.From.Reg-REG_F0)
|
|
|
|
|
if ld != 0 && p.To.Type == obj.TYPE_REG {
|
|
|
|
|
p.Mark |= LOAD
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case C_SAUTO,
|
|
|
|
|
C_LAUTO:
|
|
|
|
|
s.used.ireg |= 1 << (REGSP - REG_R0)
|
|
|
|
|
if ld != 0 {
|
|
|
|
|
p.Mark |= LOAD
|
|
|
|
|
}
|
|
|
|
|
if ad != 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
s.size = uint8(sz)
|
2017-04-10 14:15:57 -07:00
|
|
|
s.soffset = c.regoff(&p.From)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
s.used.cc |= E_MEMSP
|
|
|
|
|
|
|
|
|
|
case C_SEXT:
|
|
|
|
|
case C_LEXT:
|
|
|
|
|
s.used.ireg |= 1 << (REGSB - REG_R0)
|
|
|
|
|
if ld != 0 {
|
|
|
|
|
p.Mark |= LOAD
|
|
|
|
|
}
|
|
|
|
|
if ad != 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
s.size = uint8(sz)
|
2017-04-10 14:15:57 -07:00
|
|
|
s.soffset = c.regoff(&p.From)
|
2015-09-10 11:13:00 -04:00
|
|
|
|
|
|
|
|
s.used.cc |= E_MEMSB
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-10 07:31:23 -07:00
|
|
|
cls = int(p.Reg)
|
|
|
|
|
if cls != 0 {
|
|
|
|
|
if REG_F0 <= cls && cls <= REG_F31 {
|
|
|
|
|
s.used.freg |= 1 << uint(cls-REG_F0)
|
2015-09-10 11:13:00 -04:00
|
|
|
} else {
|
2017-04-10 07:31:23 -07:00
|
|
|
s.used.ireg |= 1 << uint(cls-REG_R0)
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
}
|
2016-04-03 12:43:27 +01:00
|
|
|
s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
|
2015-09-10 11:13:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2016-02-24 11:55:20 +01:00
|
|
|
* test to see if two instructions can be
|
2015-09-10 11:13:00 -04:00
|
|
|
* interchanged without changing semantics
|
|
|
|
|
*/
|
2017-04-10 14:15:57 -07:00
|
|
|
func (c *ctxt0) depend(sa, sb *Sch) bool {
|
2015-09-10 11:13:00 -04:00
|
|
|
if sa.set.ireg&(sb.set.ireg|sb.used.ireg) != 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if sb.set.ireg&sa.used.ireg != 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if sa.set.freg&(sb.set.freg|sb.used.freg) != 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if sb.set.freg&sa.used.freg != 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* special case.
|
|
|
|
|
* loads from same address cannot pass.
|
|
|
|
|
* this is for hardware fifo's and the like
|
|
|
|
|
*/
|
|
|
|
|
if sa.used.cc&sb.used.cc&E_MEM != 0 {
|
|
|
|
|
if sa.p.Reg == sb.p.Reg {
|
2017-04-10 14:15:57 -07:00
|
|
|
if c.regoff(&sa.p.From) == c.regoff(&sb.p.From) {
|
2015-09-10 11:13:00 -04:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x := (sa.set.cc & (sb.set.cc | sb.used.cc)) | (sb.set.cc & sa.used.cc)
|
|
|
|
|
if x != 0 {
|
|
|
|
|
/*
|
|
|
|
|
* allow SB and SP to pass each other.
|
|
|
|
|
* allow SB to pass SB iff doffsets are ok
|
|
|
|
|
* anything else conflicts
|
|
|
|
|
*/
|
|
|
|
|
if x != E_MEMSP && x != E_MEMSB {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
x = sa.set.cc | sb.set.cc | sa.used.cc | sb.used.cc
|
|
|
|
|
if x&E_MEM != 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if offoverlap(sa, sb) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func offoverlap(sa, sb *Sch) bool {
|
|
|
|
|
if sa.soffset < sb.soffset {
|
|
|
|
|
if sa.soffset+int32(sa.size) > sb.soffset {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if sb.soffset+int32(sb.size) > sa.soffset {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* test 2 adjacent instructions
|
|
|
|
|
* and find out if inserted instructions
|
|
|
|
|
* are desired to prevent stalls.
|
|
|
|
|
*/
|
|
|
|
|
func conflict(sa, sb *Sch) bool {
|
|
|
|
|
if sa.set.ireg&sb.used.ireg != 0 {
|
|
|
|
|
return true
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
2015-09-10 11:13:00 -04:00
|
|
|
if sa.set.freg&sb.used.freg != 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if sa.set.cc&sb.used.cc != 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-10 14:15:57 -07:00
|
|
|
func (c *ctxt0) compound(p *obj.Prog) bool {
|
|
|
|
|
o := c.oplook(p)
|
2015-09-10 11:13:00 -04:00
|
|
|
if o.size != 4 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSB {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var Linkmips64 = obj.LinkArch{
|
2018-03-07 16:21:47 -05:00
|
|
|
Arch: sys.ArchMIPS64,
|
|
|
|
|
Init: buildop,
|
|
|
|
|
Preprocess: preprocess,
|
|
|
|
|
Assemble: span0,
|
|
|
|
|
Progedit: progedit,
|
|
|
|
|
DWARFRegisters: MIPSDWARFRegisters,
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:13:00 -04:00
|
|
|
var Linkmips64le = obj.LinkArch{
|
2018-03-07 16:21:47 -05:00
|
|
|
Arch: sys.ArchMIPS64LE,
|
|
|
|
|
Init: buildop,
|
|
|
|
|
Preprocess: preprocess,
|
|
|
|
|
Assemble: span0,
|
|
|
|
|
Progedit: progedit,
|
|
|
|
|
DWARFRegisters: MIPSDWARFRegisters,
|
2015-09-05 20:27:00 -04:00
|
|
|
}
|
2016-10-18 23:50:37 +02:00
|
|
|
|
|
|
|
|
var Linkmips = obj.LinkArch{
|
2018-03-07 16:21:47 -05:00
|
|
|
Arch: sys.ArchMIPS,
|
|
|
|
|
Init: buildop,
|
|
|
|
|
Preprocess: preprocess,
|
|
|
|
|
Assemble: span0,
|
|
|
|
|
Progedit: progedit,
|
|
|
|
|
DWARFRegisters: MIPSDWARFRegisters,
|
2016-10-18 23:50:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var Linkmipsle = obj.LinkArch{
|
2018-03-07 16:21:47 -05:00
|
|
|
Arch: sys.ArchMIPSLE,
|
|
|
|
|
Init: buildop,
|
|
|
|
|
Preprocess: preprocess,
|
|
|
|
|
Assemble: span0,
|
|
|
|
|
Progedit: progedit,
|
|
|
|
|
DWARFRegisters: MIPSDWARFRegisters,
|
2016-10-18 23:50:37 +02:00
|
|
|
}
|