2016-03-01 15:57:46 -07:00
|
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
2015-06-04 13:54:58 -06:00
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
// Identify mismatches between assembly files and Go func declarations.
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"go/ast"
|
2016-07-11 13:19:51 -06:00
|
|
|
|
"go/build"
|
2015-06-04 13:54:58 -06:00
|
|
|
|
"go/token"
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
"go/types"
|
2015-06-04 13:54:58 -06:00
|
|
|
|
"regexp"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// 'kind' is a kind of assembly variable.
|
|
|
|
|
// The kinds 1, 2, 4, 8 stand for values of that size.
|
|
|
|
|
type asmKind int
|
|
|
|
|
|
|
|
|
|
// These special kinds are not valid sizes.
|
|
|
|
|
const (
|
|
|
|
|
asmString asmKind = 100 + iota
|
|
|
|
|
asmSlice
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
asmArray
|
2015-06-04 13:54:58 -06:00
|
|
|
|
asmInterface
|
|
|
|
|
asmEmptyInterface
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
asmStruct
|
|
|
|
|
asmComplex
|
2015-06-04 13:54:58 -06:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// An asmArch describes assembly parameters for an architecture
|
|
|
|
|
type asmArch struct {
|
|
|
|
|
name string
|
|
|
|
|
bigEndian bool
|
|
|
|
|
stack string
|
|
|
|
|
lr bool
|
2017-03-01 22:11:25 -07:00
|
|
|
|
// calculated during initialization
|
|
|
|
|
sizes types.Sizes
|
|
|
|
|
intSize int
|
|
|
|
|
ptrSize int
|
|
|
|
|
maxAlign int
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// An asmFunc describes the expected variables for a function on a given architecture.
|
|
|
|
|
type asmFunc struct {
|
|
|
|
|
arch *asmArch
|
|
|
|
|
size int // size of all arguments
|
|
|
|
|
vars map[string]*asmVar
|
|
|
|
|
varByOffset map[int]*asmVar
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// An asmVar describes a single assembly variable.
|
|
|
|
|
type asmVar struct {
|
|
|
|
|
name string
|
|
|
|
|
kind asmKind
|
|
|
|
|
typ string
|
|
|
|
|
off int
|
|
|
|
|
size int
|
|
|
|
|
inner []*asmVar
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
2017-03-01 22:11:25 -07:00
|
|
|
|
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}
|
|
|
|
|
asmArchAmd64p32 = asmArch{name: "amd64p32", bigEndian: false, stack: "SP", lr: false}
|
|
|
|
|
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}
|
|
|
|
|
asmArchMips64LE = asmArch{name: "mips64le", bigEndian: false, stack: "R29", lr: true}
|
|
|
|
|
asmArchPpc64 = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true}
|
|
|
|
|
asmArchPpc64LE = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true}
|
|
|
|
|
asmArchS390X = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true}
|
2015-06-04 13:54:58 -06:00
|
|
|
|
|
|
|
|
|
arches = []*asmArch{
|
|
|
|
|
&asmArch386,
|
|
|
|
|
&asmArchArm,
|
|
|
|
|
&asmArchArm64,
|
|
|
|
|
&asmArchAmd64,
|
|
|
|
|
&asmArchAmd64p32,
|
2016-10-18 15:51:11 -06:00
|
|
|
|
&asmArchMips,
|
|
|
|
|
&asmArchMipsLE,
|
2016-04-27 11:47:19 -06:00
|
|
|
|
&asmArchMips64,
|
|
|
|
|
&asmArchMips64LE,
|
2015-08-18 07:58:24 -06:00
|
|
|
|
&asmArchPpc64,
|
|
|
|
|
&asmArchPpc64LE,
|
2016-11-02 11:11:56 -06:00
|
|
|
|
&asmArchS390X,
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2017-03-01 22:11:25 -07:00
|
|
|
|
func init() {
|
|
|
|
|
for _, arch := range arches {
|
|
|
|
|
arch.sizes = types.SizesFor("gc", arch.name)
|
|
|
|
|
if arch.sizes == nil {
|
|
|
|
|
panic("missing SizesFor for gc/" + arch.name)
|
|
|
|
|
}
|
|
|
|
|
arch.intSize = int(arch.sizes.Sizeof(types.Typ[types.Int]))
|
|
|
|
|
arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer]))
|
|
|
|
|
arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64]))
|
|
|
|
|
}
|
|
|
|
|
}
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
|
2015-06-04 13:54:58 -06:00
|
|
|
|
var (
|
|
|
|
|
re = regexp.MustCompile
|
|
|
|
|
asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`)
|
2016-07-11 16:20:43 -06:00
|
|
|
|
asmTEXT = re(`\bTEXT\b(.*)·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`)
|
2015-06-04 13:54:58 -06:00
|
|
|
|
asmDATA = re(`\b(DATA|GLOBL)\b`)
|
|
|
|
|
asmNamedFP = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
|
|
|
|
|
asmUnnamedFP = re(`[^+\-0-9](([0-9]+)\(FP\))`)
|
|
|
|
|
asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
|
|
|
|
|
asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
|
2015-08-18 07:58:24 -06:00
|
|
|
|
ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`)
|
2015-06-04 13:54:58 -06:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func asmCheck(pkg *Package) {
|
|
|
|
|
if !vet("asmdecl") {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No work if no assembly files.
|
|
|
|
|
if !pkg.hasFileWithSuffix(".s") {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gather declarations. knownFunc[name][arch] is func description.
|
|
|
|
|
knownFunc := make(map[string]map[string]*asmFunc)
|
|
|
|
|
|
|
|
|
|
for _, f := range pkg.files {
|
|
|
|
|
if f.file != nil {
|
|
|
|
|
for _, decl := range f.file.Decls {
|
|
|
|
|
if decl, ok := decl.(*ast.FuncDecl); ok && decl.Body == nil {
|
|
|
|
|
knownFunc[decl.Name.Name] = f.asmParseDecl(decl)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Files:
|
|
|
|
|
for _, f := range pkg.files {
|
|
|
|
|
if !strings.HasSuffix(f.name, ".s") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
Println("Checking file", f.name)
|
|
|
|
|
|
|
|
|
|
// Determine architecture from file name if possible.
|
|
|
|
|
var arch string
|
|
|
|
|
var archDef *asmArch
|
|
|
|
|
for _, a := range arches {
|
|
|
|
|
if strings.HasSuffix(f.name, "_"+a.name+".s") {
|
|
|
|
|
arch = a.name
|
|
|
|
|
archDef = a
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lines := strings.SplitAfter(string(f.content), "\n")
|
|
|
|
|
var (
|
|
|
|
|
fn *asmFunc
|
|
|
|
|
fnName string
|
|
|
|
|
localSize, argSize int
|
|
|
|
|
wroteSP bool
|
|
|
|
|
haveRetArg bool
|
|
|
|
|
retLine []int
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
flushRet := func() {
|
|
|
|
|
if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 {
|
|
|
|
|
v := fn.vars["ret"]
|
|
|
|
|
for _, line := range retLine {
|
|
|
|
|
f.Badf(token.NoPos, "%s:%d: [%s] %s: RET without writing to %d-byte ret+%d(FP)", f.name, line, arch, fnName, v.size, v.off)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
retLine = nil
|
|
|
|
|
}
|
|
|
|
|
for lineno, line := range lines {
|
|
|
|
|
lineno++
|
|
|
|
|
|
|
|
|
|
badf := func(format string, args ...interface{}) {
|
|
|
|
|
f.Badf(token.NoPos, "%s:%d: [%s] %s: %s", f.name, lineno, arch, fnName, fmt.Sprintf(format, args...))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if arch == "" {
|
|
|
|
|
// Determine architecture from +build line if possible.
|
|
|
|
|
if m := asmPlusBuild.FindStringSubmatch(line); m != nil {
|
2016-07-21 12:40:01 -06:00
|
|
|
|
// There can be multiple architectures in a single +build line,
|
|
|
|
|
// so accumulate them all and then prefer the one that
|
|
|
|
|
// matches build.Default.GOARCH.
|
|
|
|
|
var archCandidates []*asmArch
|
2015-06-04 13:54:58 -06:00
|
|
|
|
for _, fld := range strings.Fields(m[1]) {
|
|
|
|
|
for _, a := range arches {
|
|
|
|
|
if a.name == fld {
|
2016-07-21 12:40:01 -06:00
|
|
|
|
archCandidates = append(archCandidates, a)
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-21 12:40:01 -06:00
|
|
|
|
for _, a := range archCandidates {
|
|
|
|
|
if a.name == build.Default.GOARCH {
|
|
|
|
|
archCandidates = []*asmArch{a}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if len(archCandidates) > 0 {
|
|
|
|
|
arch = archCandidates[0].name
|
|
|
|
|
archDef = archCandidates[0]
|
|
|
|
|
}
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if m := asmTEXT.FindStringSubmatch(line); m != nil {
|
|
|
|
|
flushRet()
|
|
|
|
|
if arch == "" {
|
2016-07-21 12:40:01 -06:00
|
|
|
|
// Arch not specified by filename or build tags.
|
|
|
|
|
// Fall back to build.Default.GOARCH.
|
2016-07-11 13:19:51 -06:00
|
|
|
|
for _, a := range arches {
|
|
|
|
|
if a.name == build.Default.GOARCH {
|
|
|
|
|
arch = a.name
|
|
|
|
|
archDef = a
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if arch == "" {
|
|
|
|
|
f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name)
|
|
|
|
|
continue Files
|
|
|
|
|
}
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
2016-07-11 16:20:43 -06:00
|
|
|
|
fnName = m[2]
|
|
|
|
|
if pkgName := strings.TrimSpace(m[1]); pkgName != "" {
|
|
|
|
|
pathParts := strings.Split(pkgName, "∕")
|
|
|
|
|
pkgName = pathParts[len(pathParts)-1]
|
|
|
|
|
if pkgName != f.pkg.path {
|
|
|
|
|
f.Warnf(token.NoPos, "%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", f.name, lineno, arch, fnName, pkgName)
|
|
|
|
|
fn = nil
|
|
|
|
|
fnName = ""
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fn = knownFunc[fnName][arch]
|
2015-06-04 13:54:58 -06:00
|
|
|
|
if fn != nil {
|
2016-07-11 16:20:43 -06:00
|
|
|
|
size, _ := strconv.Atoi(m[5])
|
|
|
|
|
flag := m[3]
|
|
|
|
|
if size != fn.size && (flag != "7" && !strings.Contains(flag, "NOSPLIT") || size != 0) {
|
2015-06-04 13:54:58 -06:00
|
|
|
|
badf("wrong argument size %d; expected $...-%d", size, fn.size)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-11 16:20:43 -06:00
|
|
|
|
localSize, _ = strconv.Atoi(m[4])
|
2017-03-01 22:11:25 -07:00
|
|
|
|
localSize += archDef.intSize
|
2015-06-04 13:54:58 -06:00
|
|
|
|
if archDef.lr {
|
|
|
|
|
// Account for caller's saved LR
|
2017-03-01 22:11:25 -07:00
|
|
|
|
localSize += archDef.intSize
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
2016-07-11 16:20:43 -06:00
|
|
|
|
argSize, _ = strconv.Atoi(m[5])
|
2015-06-04 13:54:58 -06:00
|
|
|
|
if fn == nil && !strings.Contains(fnName, "<>") {
|
|
|
|
|
badf("function %s missing Go declaration", fnName)
|
|
|
|
|
}
|
|
|
|
|
wroteSP = false
|
|
|
|
|
haveRetArg = false
|
|
|
|
|
continue
|
|
|
|
|
} else if strings.Contains(line, "TEXT") && strings.Contains(line, "SB") {
|
|
|
|
|
// function, but not visible from Go (didn't match asmTEXT), so stop checking
|
|
|
|
|
flushRet()
|
|
|
|
|
fn = nil
|
|
|
|
|
fnName = ""
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.Contains(line, "RET") {
|
|
|
|
|
retLine = append(retLine, lineno)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fnName == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if asmDATA.FindStringSubmatch(line) != nil {
|
|
|
|
|
fn = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if archDef == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.Contains(line, ", "+archDef.stack) || strings.Contains(line, ",\t"+archDef.stack) {
|
|
|
|
|
wroteSP = true
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, m := range asmSP.FindAllStringSubmatch(line, -1) {
|
|
|
|
|
if m[3] != archDef.stack || wroteSP {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
off := 0
|
|
|
|
|
if m[1] != "" {
|
|
|
|
|
off, _ = strconv.Atoi(m[2])
|
|
|
|
|
}
|
|
|
|
|
if off >= localSize {
|
|
|
|
|
if fn != nil {
|
|
|
|
|
v := fn.varByOffset[off-localSize]
|
|
|
|
|
if v != nil {
|
|
|
|
|
badf("%s should be %s+%d(FP)", m[1], v.name, off-localSize)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if off >= localSize+argSize {
|
|
|
|
|
badf("use of %s points beyond argument frame", m[1])
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
badf("use of %s to access argument frame", m[1])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if fn == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, m := range asmUnnamedFP.FindAllStringSubmatch(line, -1) {
|
|
|
|
|
off, _ := strconv.Atoi(m[2])
|
|
|
|
|
v := fn.varByOffset[off]
|
|
|
|
|
if v != nil {
|
|
|
|
|
badf("use of unnamed argument %s; offset %d is %s+%d(FP)", m[1], off, v.name, v.off)
|
|
|
|
|
} else {
|
|
|
|
|
badf("use of unnamed argument %s", m[1])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, m := range asmNamedFP.FindAllStringSubmatch(line, -1) {
|
|
|
|
|
name := m[1]
|
|
|
|
|
off := 0
|
|
|
|
|
if m[2] != "" {
|
|
|
|
|
off, _ = strconv.Atoi(m[2])
|
|
|
|
|
}
|
|
|
|
|
if name == "ret" || strings.HasPrefix(name, "ret_") {
|
|
|
|
|
haveRetArg = true
|
|
|
|
|
}
|
|
|
|
|
v := fn.vars[name]
|
|
|
|
|
if v == nil {
|
|
|
|
|
// Allow argframe+0(FP).
|
|
|
|
|
if name == "argframe" && off == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
v = fn.varByOffset[off]
|
|
|
|
|
if v != nil {
|
|
|
|
|
badf("unknown variable %s; offset %d is %s+%d(FP)", name, off, v.name, v.off)
|
|
|
|
|
} else {
|
|
|
|
|
badf("unknown variable %s", name)
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
asmCheckVar(badf, fn, line, m[0], off, v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
flushRet()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
func asmKindForType(t types.Type, size int) asmKind {
|
|
|
|
|
switch t := t.Underlying().(type) {
|
|
|
|
|
case *types.Basic:
|
|
|
|
|
switch t.Kind() {
|
|
|
|
|
case types.String:
|
|
|
|
|
return asmString
|
|
|
|
|
case types.Complex64, types.Complex128:
|
|
|
|
|
return asmComplex
|
|
|
|
|
}
|
|
|
|
|
return asmKind(size)
|
|
|
|
|
case *types.Pointer, *types.Chan, *types.Map, *types.Signature:
|
|
|
|
|
return asmKind(size)
|
|
|
|
|
case *types.Struct:
|
|
|
|
|
return asmStruct
|
|
|
|
|
case *types.Interface:
|
|
|
|
|
if t.Empty() {
|
|
|
|
|
return asmEmptyInterface
|
|
|
|
|
}
|
|
|
|
|
return asmInterface
|
|
|
|
|
case *types.Array:
|
|
|
|
|
return asmArray
|
|
|
|
|
case *types.Slice:
|
|
|
|
|
return asmSlice
|
|
|
|
|
}
|
|
|
|
|
panic("unreachable")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A component is an assembly-addressable component of a composite type,
|
|
|
|
|
// or a composite type itself.
|
|
|
|
|
type component struct {
|
|
|
|
|
size int
|
|
|
|
|
offset int
|
|
|
|
|
kind asmKind
|
|
|
|
|
typ string
|
|
|
|
|
suffix string // Such as _base for string base, _0_lo for lo half of first element of [1]uint64 on 32 bit machine.
|
|
|
|
|
outer string // The suffix for immediately containing composite type.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newComponent(suffix string, kind asmKind, typ string, offset, size int, outer string) component {
|
|
|
|
|
return component{suffix: suffix, kind: kind, typ: typ, offset: offset, size: size, outer: outer}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// componentsOfType generates a list of components of type t.
|
|
|
|
|
// For example, given string, the components are the string itself, the base, and the length.
|
|
|
|
|
func componentsOfType(arch *asmArch, t types.Type) []component {
|
|
|
|
|
return appendComponentsRecursive(arch, t, nil, "", 0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// appendComponentsRecursive implements componentsOfType.
|
|
|
|
|
// Recursion is required to correct handle structs and arrays,
|
|
|
|
|
// which can contain arbitrary other types.
|
|
|
|
|
func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suffix string, off int) []component {
|
|
|
|
|
s := t.String()
|
|
|
|
|
size := int(arch.sizes.Sizeof(t))
|
|
|
|
|
kind := asmKindForType(t, size)
|
|
|
|
|
cc = append(cc, newComponent(suffix, kind, s, off, size, suffix))
|
|
|
|
|
|
|
|
|
|
switch kind {
|
|
|
|
|
case 8:
|
2017-03-01 22:11:25 -07:00
|
|
|
|
if arch.ptrSize == 4 {
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
w1, w2 := "lo", "hi"
|
|
|
|
|
if arch.bigEndian {
|
|
|
|
|
w1, w2 = w2, w1
|
|
|
|
|
}
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_"+w1, 4, "half "+s, off, 4, suffix))
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_"+w2, 4, "half "+s, off+4, 4, suffix))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case asmEmptyInterface:
|
2017-03-01 22:11:25 -07:00
|
|
|
|
cc = append(cc, newComponent(suffix+"_type", asmKind(arch.ptrSize), "interface type", off, arch.ptrSize, suffix))
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix))
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
|
|
|
|
|
case asmInterface:
|
2017-03-01 22:11:25 -07:00
|
|
|
|
cc = append(cc, newComponent(suffix+"_itable", asmKind(arch.ptrSize), "interface itable", off, arch.ptrSize, suffix))
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_data", asmKind(arch.ptrSize), "interface data", off+arch.ptrSize, arch.ptrSize, suffix))
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
|
|
|
|
|
case asmSlice:
|
2017-03-01 22:11:25 -07:00
|
|
|
|
cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "slice base", off, arch.ptrSize, suffix))
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "slice len", off+arch.ptrSize, arch.intSize, suffix))
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_cap", asmKind(arch.intSize), "slice cap", off+arch.ptrSize+arch.intSize, arch.intSize, suffix))
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
|
|
|
|
|
case asmString:
|
2017-03-01 22:11:25 -07:00
|
|
|
|
cc = append(cc, newComponent(suffix+"_base", asmKind(arch.ptrSize), "string base", off, arch.ptrSize, suffix))
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_len", asmKind(arch.intSize), "string len", off+arch.ptrSize, arch.intSize, suffix))
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
|
|
|
|
|
case asmComplex:
|
|
|
|
|
fsize := size / 2
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_real", asmKind(fsize), fmt.Sprintf("real(complex%d)", size*8), off, fsize, suffix))
|
|
|
|
|
cc = append(cc, newComponent(suffix+"_imag", asmKind(fsize), fmt.Sprintf("imag(complex%d)", size*8), off+fsize, fsize, suffix))
|
|
|
|
|
|
|
|
|
|
case asmStruct:
|
|
|
|
|
tu := t.Underlying().(*types.Struct)
|
|
|
|
|
fields := make([]*types.Var, tu.NumFields())
|
|
|
|
|
for i := 0; i < tu.NumFields(); i++ {
|
|
|
|
|
fields[i] = tu.Field(i)
|
|
|
|
|
}
|
|
|
|
|
offsets := arch.sizes.Offsetsof(fields)
|
|
|
|
|
for i, f := range fields {
|
|
|
|
|
cc = appendComponentsRecursive(arch, f.Type(), cc, suffix+"_"+f.Name(), off+int(offsets[i]))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case asmArray:
|
|
|
|
|
tu := t.Underlying().(*types.Array)
|
|
|
|
|
elem := tu.Elem()
|
|
|
|
|
// Calculate offset of each element array.
|
|
|
|
|
fields := []*types.Var{
|
|
|
|
|
types.NewVar(token.NoPos, nil, "fake0", elem),
|
|
|
|
|
types.NewVar(token.NoPos, nil, "fake1", elem),
|
|
|
|
|
}
|
|
|
|
|
offsets := arch.sizes.Offsetsof(fields)
|
|
|
|
|
elemoff := int(offsets[1])
|
|
|
|
|
for i := 0; i < int(tu.Len()); i++ {
|
|
|
|
|
cc = appendComponentsRecursive(arch, elem, cc, suffix+"_"+strconv.Itoa(i), i*elemoff)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cc
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-04 13:54:58 -06:00
|
|
|
|
// asmParseDecl parses a function decl for expected assembly variables.
|
|
|
|
|
func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
|
|
|
|
|
var (
|
|
|
|
|
arch *asmArch
|
|
|
|
|
fn *asmFunc
|
|
|
|
|
offset int
|
|
|
|
|
)
|
|
|
|
|
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
// addParams adds asmVars for each of the parameters in list.
|
|
|
|
|
// isret indicates whether the list are the arguments or the return values.
|
|
|
|
|
addParams := func(list []*ast.Field, isret bool) {
|
|
|
|
|
argnum := 0
|
|
|
|
|
for _, fld := range list {
|
|
|
|
|
t := f.pkg.types[fld.Type].Type
|
|
|
|
|
align := int(arch.sizes.Alignof(t))
|
|
|
|
|
size := int(arch.sizes.Sizeof(t))
|
2015-06-04 13:54:58 -06:00
|
|
|
|
offset += -offset & (align - 1)
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
cc := componentsOfType(arch, t)
|
2015-06-04 13:54:58 -06:00
|
|
|
|
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
// names is the list of names with this type.
|
|
|
|
|
names := fld.Names
|
2015-06-04 13:54:58 -06:00
|
|
|
|
if len(names) == 0 {
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
// Anonymous args will be called arg, arg1, arg2, ...
|
|
|
|
|
// Similarly so for return values: ret, ret1, ret2, ...
|
|
|
|
|
name := "arg"
|
|
|
|
|
if isret {
|
2015-06-04 13:54:58 -06:00
|
|
|
|
name = "ret"
|
|
|
|
|
}
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
if argnum > 0 {
|
|
|
|
|
name += strconv.Itoa(argnum)
|
|
|
|
|
}
|
|
|
|
|
names = []*ast.Ident{ast.NewIdent(name)}
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
argnum += len(names)
|
|
|
|
|
|
|
|
|
|
// Create variable for each name.
|
2015-06-04 13:54:58 -06:00
|
|
|
|
for _, id := range names {
|
|
|
|
|
name := id.Name
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
for _, c := range cc {
|
|
|
|
|
outer := name + c.outer
|
|
|
|
|
v := asmVar{
|
|
|
|
|
name: name + c.suffix,
|
|
|
|
|
kind: c.kind,
|
|
|
|
|
typ: c.typ,
|
|
|
|
|
off: offset + c.offset,
|
|
|
|
|
size: c.size,
|
|
|
|
|
}
|
|
|
|
|
if vo := fn.vars[outer]; vo != nil {
|
|
|
|
|
vo.inner = append(vo.inner, &v)
|
|
|
|
|
}
|
|
|
|
|
fn.vars[v.name] = &v
|
|
|
|
|
for i := 0; i < v.size; i++ {
|
|
|
|
|
fn.varByOffset[v.off+i] = &v
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
offset += size
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m := make(map[string]*asmFunc)
|
|
|
|
|
for _, arch = range arches {
|
|
|
|
|
fn = &asmFunc{
|
|
|
|
|
arch: arch,
|
|
|
|
|
vars: make(map[string]*asmVar),
|
|
|
|
|
varByOffset: make(map[int]*asmVar),
|
|
|
|
|
}
|
|
|
|
|
offset = 0
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
addParams(decl.Type.Params.List, false)
|
2015-06-04 13:54:58 -06:00
|
|
|
|
if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 {
|
2017-03-01 22:11:25 -07:00
|
|
|
|
offset += -offset & (arch.maxAlign - 1)
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
addParams(decl.Type.Results.List, true)
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
|
|
|
|
fn.size = offset
|
|
|
|
|
m[arch.name] = fn
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// asmCheckVar checks a single variable reference.
|
|
|
|
|
func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar) {
|
|
|
|
|
m := asmOpcode.FindStringSubmatch(line)
|
|
|
|
|
if m == nil {
|
|
|
|
|
if !strings.HasPrefix(strings.TrimSpace(line), "//") {
|
|
|
|
|
badf("cannot find assembly opcode")
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine operand sizes from instruction.
|
|
|
|
|
// Typically the suffix suffices, but there are exceptions.
|
|
|
|
|
var src, dst, kind asmKind
|
|
|
|
|
op := m[1]
|
|
|
|
|
switch fn.arch.name + "." + op {
|
|
|
|
|
case "386.FMOVLP":
|
|
|
|
|
src, dst = 8, 4
|
|
|
|
|
case "arm.MOVD":
|
|
|
|
|
src = 8
|
|
|
|
|
case "arm.MOVW":
|
|
|
|
|
src = 4
|
|
|
|
|
case "arm.MOVH", "arm.MOVHU":
|
|
|
|
|
src = 2
|
|
|
|
|
case "arm.MOVB", "arm.MOVBU":
|
|
|
|
|
src = 1
|
|
|
|
|
// LEA* opcodes don't really read the second arg.
|
|
|
|
|
// They just take the address of it.
|
|
|
|
|
case "386.LEAL":
|
|
|
|
|
dst = 4
|
|
|
|
|
case "amd64.LEAQ":
|
|
|
|
|
dst = 8
|
|
|
|
|
case "amd64p32.LEAL":
|
|
|
|
|
dst = 4
|
|
|
|
|
default:
|
|
|
|
|
switch fn.arch.name {
|
|
|
|
|
case "386", "amd64":
|
|
|
|
|
if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "D") || strings.HasSuffix(op, "DP")) {
|
|
|
|
|
// FMOVDP, FXCHD, etc
|
|
|
|
|
src = 8
|
|
|
|
|
break
|
|
|
|
|
}
|
2016-04-14 10:39:40 -06:00
|
|
|
|
if strings.HasPrefix(op, "P") && strings.HasSuffix(op, "RD") {
|
|
|
|
|
// PINSRD, PEXTRD, etc
|
|
|
|
|
src = 4
|
|
|
|
|
break
|
|
|
|
|
}
|
2015-06-04 13:54:58 -06:00
|
|
|
|
if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) {
|
|
|
|
|
// FMOVFP, FXCHF, etc
|
|
|
|
|
src = 4
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if strings.HasSuffix(op, "SD") {
|
|
|
|
|
// MOVSD, SQRTSD, etc
|
|
|
|
|
src = 8
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if strings.HasSuffix(op, "SS") {
|
|
|
|
|
// MOVSS, SQRTSS, etc
|
|
|
|
|
src = 4
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(op, "SET") {
|
|
|
|
|
// SETEQ, etc
|
|
|
|
|
src = 1
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
switch op[len(op)-1] {
|
|
|
|
|
case 'B':
|
|
|
|
|
src = 1
|
|
|
|
|
case 'W':
|
|
|
|
|
src = 2
|
|
|
|
|
case 'L':
|
|
|
|
|
src = 4
|
|
|
|
|
case 'D', 'Q':
|
|
|
|
|
src = 8
|
|
|
|
|
}
|
2015-08-18 07:58:24 -06:00
|
|
|
|
case "ppc64", "ppc64le":
|
2015-06-04 13:54:58 -06:00
|
|
|
|
// Strip standard suffixes to reveal size letter.
|
2015-08-18 07:58:24 -06:00
|
|
|
|
m := ppc64Suff.FindStringSubmatch(op)
|
2015-06-04 13:54:58 -06:00
|
|
|
|
if m != nil {
|
|
|
|
|
switch m[1][0] {
|
|
|
|
|
case 'B':
|
|
|
|
|
src = 1
|
|
|
|
|
case 'H':
|
|
|
|
|
src = 2
|
|
|
|
|
case 'W':
|
|
|
|
|
src = 4
|
|
|
|
|
case 'D':
|
|
|
|
|
src = 8
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-18 15:51:11 -06:00
|
|
|
|
case "mips", "mipsle", "mips64", "mips64le":
|
2016-04-27 11:47:19 -06:00
|
|
|
|
switch op {
|
|
|
|
|
case "MOVB", "MOVBU":
|
|
|
|
|
src = 1
|
|
|
|
|
case "MOVH", "MOVHU":
|
|
|
|
|
src = 2
|
|
|
|
|
case "MOVW", "MOVWU", "MOVF":
|
|
|
|
|
src = 4
|
|
|
|
|
case "MOVV", "MOVD":
|
|
|
|
|
src = 8
|
|
|
|
|
}
|
2016-11-02 11:11:56 -06:00
|
|
|
|
case "s390x":
|
|
|
|
|
switch op {
|
|
|
|
|
case "MOVB", "MOVBZ":
|
|
|
|
|
src = 1
|
|
|
|
|
case "MOVH", "MOVHZ":
|
|
|
|
|
src = 2
|
|
|
|
|
case "MOVW", "MOVWZ", "FMOVS":
|
|
|
|
|
src = 4
|
|
|
|
|
case "MOVD", "FMOVD":
|
|
|
|
|
src = 8
|
|
|
|
|
}
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if dst == 0 {
|
|
|
|
|
dst = src
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine whether the match we're holding
|
|
|
|
|
// is the first or second argument.
|
|
|
|
|
if strings.Index(line, expr) > strings.Index(line, ",") {
|
|
|
|
|
kind = dst
|
|
|
|
|
} else {
|
|
|
|
|
kind = src
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vk := v.kind
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
vs := v.size
|
2015-06-04 13:54:58 -06:00
|
|
|
|
vt := v.typ
|
|
|
|
|
switch vk {
|
|
|
|
|
case asmInterface, asmEmptyInterface, asmString, asmSlice:
|
|
|
|
|
// allow reference to first word (pointer)
|
|
|
|
|
vk = v.inner[0].kind
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
vs = v.inner[0].size
|
2015-06-04 13:54:58 -06:00
|
|
|
|
vt = v.inner[0].typ
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if off != v.off {
|
|
|
|
|
var inner bytes.Buffer
|
|
|
|
|
for i, vi := range v.inner {
|
|
|
|
|
if len(v.inner) > 1 {
|
|
|
|
|
fmt.Fprintf(&inner, ",")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(&inner, " ")
|
|
|
|
|
if i == len(v.inner)-1 {
|
|
|
|
|
fmt.Fprintf(&inner, "or ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
|
|
|
|
|
}
|
|
|
|
|
badf("invalid offset %s; expected %s+%d(FP)%s", expr, v.name, v.off, inner.String())
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if kind != 0 && kind != vk {
|
|
|
|
|
var inner bytes.Buffer
|
|
|
|
|
if len(v.inner) > 0 {
|
|
|
|
|
fmt.Fprintf(&inner, " containing")
|
|
|
|
|
for i, vi := range v.inner {
|
|
|
|
|
if i > 0 && len(v.inner) > 2 {
|
|
|
|
|
fmt.Fprintf(&inner, ",")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(&inner, " ")
|
|
|
|
|
if i > 0 && i == len(v.inner)-1 {
|
|
|
|
|
fmt.Fprintf(&inner, "and ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
|
|
|
|
|
}
|
|
|
|
|
}
|
cmd/vet: improve asmdecl parameter handling
The asmdecl check had hand-rolled code that
calculated the size and offset of parameters
based only on the AST.
It included a list of known named types.
This CL changes asmdecl to use go/types instead.
This allows us to easily handle named types.
It also adds support for structs, arrays,
and complex parameters.
It improves the default names given to unnamed
parameters. Previously, all anonymous arguments were
called "unnamed", and the first anonymous return
argument was called "ret".
Anonymous arguments are now called arg, arg1, arg2,
etc., depending on the index in the argument list.
Return arguments are ret, ret1, ret2.
This CL also fixes a bug in the printing of
composite data type sizes.
Updates #11041
Change-Id: I1085116a26fe6199480b680eff659eb9ab31769b
Reviewed-on: https://go-review.googlesource.com/27150
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
2016-07-09 18:10:57 -06:00
|
|
|
|
badf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vs, inner.String())
|
2015-06-04 13:54:58 -06:00
|
|
|
|
}
|
|
|
|
|
}
|