mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00:00
go/analysis/passes/asmdecl: support in-register result in ABIInternal
With register ABI, for an ABIInternal function, understand that the result may be written to a register instead of to memory. TODO: argument area size calculation is still not fixed for register ABI. Change-Id: I109a5dc03ff0acc4bc04502710daf32efd1b08f6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/339250 Trust: Cherry Mui <cherryyz@google.com> Run-TryBot: Cherry Mui <cherryyz@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
fcc905b221
commit
337cebd2c1
|
@ -51,6 +51,11 @@ type asmArch struct {
|
||||||
bigEndian bool
|
bigEndian bool
|
||||||
stack string
|
stack string
|
||||||
lr bool
|
lr bool
|
||||||
|
// retRegs is a list of registers for return value in register ABI (ABIInternal).
|
||||||
|
// For now, as we only check whether we write to any result, here we only need to
|
||||||
|
// include the first integer register and first floating-point register. Accessing
|
||||||
|
// any of them counts as writing to result.
|
||||||
|
retRegs []string
|
||||||
// calculated during initialization
|
// calculated during initialization
|
||||||
sizes types.Sizes
|
sizes types.Sizes
|
||||||
intSize int
|
intSize int
|
||||||
|
@ -79,8 +84,8 @@ type asmVar struct {
|
||||||
var (
|
var (
|
||||||
asmArch386 = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false}
|
asmArch386 = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false}
|
||||||
asmArchArm = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true}
|
asmArchArm = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true}
|
||||||
asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true}
|
asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true, retRegs: []string{"R0", "F0"}}
|
||||||
asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false}
|
asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false, retRegs: []string{"AX", "X0"}}
|
||||||
asmArchMips = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true}
|
asmArchMips = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true}
|
||||||
asmArchMipsLE = asmArch{name: "mipsle", bigEndian: false, stack: "R29", lr: true}
|
asmArchMipsLE = asmArch{name: "mipsle", bigEndian: false, stack: "R29", lr: true}
|
||||||
asmArchMips64 = asmArch{name: "mips64", bigEndian: true, stack: "R29", lr: true}
|
asmArchMips64 = asmArch{name: "mips64", bigEndian: true, stack: "R29", lr: true}
|
||||||
|
@ -137,7 +142,7 @@ var (
|
||||||
asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
|
asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
|
||||||
asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
|
asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
|
||||||
ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`)
|
ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`)
|
||||||
abiSuff = re(`^(.+)<ABI.+>$`)
|
abiSuff = re(`^(.+)<(ABI.+)>$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func run(pass *analysis.Pass) (interface{}, error) {
|
func run(pass *analysis.Pass) (interface{}, error) {
|
||||||
|
@ -185,6 +190,7 @@ Files:
|
||||||
var (
|
var (
|
||||||
fn *asmFunc
|
fn *asmFunc
|
||||||
fnName string
|
fnName string
|
||||||
|
abi string
|
||||||
localSize, argSize int
|
localSize, argSize int
|
||||||
wroteSP bool
|
wroteSP bool
|
||||||
noframe bool
|
noframe bool
|
||||||
|
@ -195,18 +201,22 @@ Files:
|
||||||
flushRet := func() {
|
flushRet := func() {
|
||||||
if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 {
|
if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 {
|
||||||
v := fn.vars["ret"]
|
v := fn.vars["ret"]
|
||||||
|
resultStr := fmt.Sprintf("%d-byte ret+%d(FP)", v.size, v.off)
|
||||||
|
if abi == "ABIInternal" {
|
||||||
|
resultStr = "result register"
|
||||||
|
}
|
||||||
for _, line := range retLine {
|
for _, line := range retLine {
|
||||||
pass.Reportf(analysisutil.LineStart(tf, line), "[%s] %s: RET without writing to %d-byte ret+%d(FP)", arch, fnName, v.size, v.off)
|
pass.Reportf(analysisutil.LineStart(tf, line), "[%s] %s: RET without writing to %s", arch, fnName, resultStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retLine = nil
|
retLine = nil
|
||||||
}
|
}
|
||||||
trimABI := func(fnName string) string {
|
trimABI := func(fnName string) (string, string) {
|
||||||
m := abiSuff.FindStringSubmatch(fnName)
|
m := abiSuff.FindStringSubmatch(fnName)
|
||||||
if m != nil {
|
if m != nil {
|
||||||
return m[1]
|
return m[1], m[2]
|
||||||
}
|
}
|
||||||
return fnName
|
return fnName, ""
|
||||||
}
|
}
|
||||||
for lineno, line := range lines {
|
for lineno, line := range lines {
|
||||||
lineno++
|
lineno++
|
||||||
|
@ -273,11 +283,12 @@ Files:
|
||||||
// log.Printf("%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", fname, lineno, arch, fnName, pkgPath)
|
// log.Printf("%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", fname, lineno, arch, fnName, pkgPath)
|
||||||
fn = nil
|
fn = nil
|
||||||
fnName = ""
|
fnName = ""
|
||||||
|
abi = ""
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Trim off optional ABI selector.
|
// Trim off optional ABI selector.
|
||||||
fnName := trimABI(fnName)
|
fnName, abi = trimABI(fnName)
|
||||||
flag := m[3]
|
flag := m[3]
|
||||||
fn = knownFunc[fnName][arch]
|
fn = knownFunc[fnName][arch]
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
|
@ -305,6 +316,7 @@ Files:
|
||||||
flushRet()
|
flushRet()
|
||||||
fn = nil
|
fn = nil
|
||||||
fnName = ""
|
fnName = ""
|
||||||
|
abi = ""
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,6 +347,15 @@ Files:
|
||||||
haveRetArg = true
|
haveRetArg = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if abi == "ABIInternal" && !haveRetArg {
|
||||||
|
for _, reg := range archDef.retRegs {
|
||||||
|
if strings.Contains(line, reg) {
|
||||||
|
haveRetArg = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, m := range asmSP.FindAllStringSubmatch(line, -1) {
|
for _, m := range asmSP.FindAllStringSubmatch(line, -1) {
|
||||||
if m[3] != archDef.stack || wroteSP || noframe {
|
if m[3] != archDef.stack || wroteSP || noframe {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -52,4 +52,7 @@ func pickStableABI(x int)
|
||||||
func pickInternalABI(x int)
|
func pickInternalABI(x int)
|
||||||
func pickFutureABI(x int)
|
func pickFutureABI(x int)
|
||||||
|
|
||||||
|
func returnABIInternal() int
|
||||||
|
func returnmissingABIInternal() int
|
||||||
|
|
||||||
func retjmp() int
|
func retjmp() int
|
||||||
|
|
|
@ -346,6 +346,14 @@ TEXT ·pickFutureABI<ABISomethingNotyetInvented>(SB), NOSPLIT, $32
|
||||||
MOVQ x+0(FP), AX
|
MOVQ x+0(FP), AX
|
||||||
RET
|
RET
|
||||||
|
|
||||||
|
// writing to result in ABIInternal function
|
||||||
|
TEXT ·returnABIInternal<ABIInternal>(SB), NOSPLIT, $32
|
||||||
|
MOVQ $123, AX
|
||||||
|
RET
|
||||||
|
TEXT ·returnmissingABIInternal<ABIInternal>(SB), NOSPLIT, $32
|
||||||
|
MOVQ $123, CX
|
||||||
|
RET // want `RET without writing to result register`
|
||||||
|
|
||||||
// return jump
|
// return jump
|
||||||
TEXT ·retjmp(SB), NOSPLIT, $0-8
|
TEXT ·retjmp(SB), NOSPLIT, $0-8
|
||||||
RET retjmp1(SB) // It's okay to not write results if there's a tail call.
|
RET retjmp1(SB) // It's okay to not write results if there's a tail call.
|
||||||
|
|
Loading…
Reference in a new issue