mirror of
https://github.com/golang/go
synced 2024-09-04 15:34:21 +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
|
||||
stack string
|
||||
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
|
||||
sizes types.Sizes
|
||||
intSize int
|
||||
|
@ -79,8 +84,8 @@ type asmVar struct {
|
|||
var (
|
||||
asmArch386 = asmArch{name: "386", bigEndian: false, stack: "SP", lr: false}
|
||||
asmArchArm = asmArch{name: "arm", bigEndian: false, stack: "R13", lr: true}
|
||||
asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true}
|
||||
asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false}
|
||||
asmArchArm64 = asmArch{name: "arm64", bigEndian: false, stack: "RSP", lr: true, retRegs: []string{"R0", "F0"}}
|
||||
asmArchAmd64 = asmArch{name: "amd64", bigEndian: false, stack: "SP", lr: false, retRegs: []string{"AX", "X0"}}
|
||||
asmArchMips = asmArch{name: "mips", bigEndian: true, stack: "R29", lr: true}
|
||||
asmArchMipsLE = asmArch{name: "mipsle", bigEndian: false, 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]+)\))`)
|
||||
asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
|
||||
ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`)
|
||||
abiSuff = re(`^(.+)<ABI.+>$`)
|
||||
abiSuff = re(`^(.+)<(ABI.+)>$`)
|
||||
)
|
||||
|
||||
func run(pass *analysis.Pass) (interface{}, error) {
|
||||
|
@ -185,6 +190,7 @@ Files:
|
|||
var (
|
||||
fn *asmFunc
|
||||
fnName string
|
||||
abi string
|
||||
localSize, argSize int
|
||||
wroteSP bool
|
||||
noframe bool
|
||||
|
@ -195,18 +201,22 @@ Files:
|
|||
flushRet := func() {
|
||||
if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
trimABI := func(fnName string) string {
|
||||
trimABI := func(fnName string) (string, string) {
|
||||
m := abiSuff.FindStringSubmatch(fnName)
|
||||
if m != nil {
|
||||
return m[1]
|
||||
return m[1], m[2]
|
||||
}
|
||||
return fnName
|
||||
return fnName, ""
|
||||
}
|
||||
for lineno, line := range lines {
|
||||
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)
|
||||
fn = nil
|
||||
fnName = ""
|
||||
abi = ""
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Trim off optional ABI selector.
|
||||
fnName := trimABI(fnName)
|
||||
fnName, abi = trimABI(fnName)
|
||||
flag := m[3]
|
||||
fn = knownFunc[fnName][arch]
|
||||
if fn != nil {
|
||||
|
@ -305,6 +316,7 @@ Files:
|
|||
flushRet()
|
||||
fn = nil
|
||||
fnName = ""
|
||||
abi = ""
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -335,6 +347,15 @@ Files:
|
|||
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) {
|
||||
if m[3] != archDef.stack || wroteSP || noframe {
|
||||
continue
|
||||
|
|
|
@ -52,4 +52,7 @@ func pickStableABI(x int)
|
|||
func pickInternalABI(x int)
|
||||
func pickFutureABI(x int)
|
||||
|
||||
func returnABIInternal() int
|
||||
func returnmissingABIInternal() int
|
||||
|
||||
func retjmp() int
|
||||
|
|
|
@ -346,6 +346,14 @@ TEXT ·pickFutureABI<ABISomethingNotyetInvented>(SB), NOSPLIT, $32
|
|||
MOVQ x+0(FP), AX
|
||||
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
|
||||
TEXT ·retjmp(SB), NOSPLIT, $0-8
|
||||
RET retjmp1(SB) // It's okay to not write results if there's a tail call.
|
||||
|
|
Loading…
Reference in a new issue