mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.boringcrypto] all: merge master into dev.boringcrypto
Change-Id: Iba19903f0565b11c648e1fa6effc07b8f97dc322
This commit is contained in:
commit
906d6e362b
1114 changed files with 59665 additions and 28332 deletions
228
api/except.txt
228
api/except.txt
|
|
@ -2,12 +2,56 @@ pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error)
|
||||||
pkg math/big, const MaxBase = 36
|
pkg math/big, const MaxBase = 36
|
||||||
pkg math/big, type Word uintptr
|
pkg math/big, type Word uintptr
|
||||||
pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error)
|
pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error)
|
||||||
|
pkg os (linux-arm), const O_SYNC = 1052672
|
||||||
|
pkg os (linux-arm), const O_SYNC = 4096
|
||||||
|
pkg os (linux-arm-cgo), const O_SYNC = 1052672
|
||||||
|
pkg os (linux-arm-cgo), const O_SYNC = 4096
|
||||||
|
pkg os, const ModeAppend FileMode
|
||||||
|
pkg os, const ModeCharDevice FileMode
|
||||||
|
pkg os, const ModeDevice FileMode
|
||||||
|
pkg os, const ModeDir FileMode
|
||||||
|
pkg os, const ModeExclusive FileMode
|
||||||
|
pkg os, const ModeIrregular FileMode
|
||||||
|
pkg os, const ModeNamedPipe FileMode
|
||||||
|
pkg os, const ModePerm FileMode
|
||||||
|
pkg os, const ModeSetgid FileMode
|
||||||
|
pkg os, const ModeSetuid FileMode
|
||||||
|
pkg os, const ModeSocket FileMode
|
||||||
|
pkg os, const ModeSticky FileMode
|
||||||
|
pkg os, const ModeSymlink FileMode
|
||||||
|
pkg os, const ModeTemporary FileMode
|
||||||
pkg os, const ModeType = 2399141888
|
pkg os, const ModeType = 2399141888
|
||||||
pkg os, const ModeType = 2399666176
|
pkg os, const ModeType = 2399666176
|
||||||
pkg os (linux-arm), const O_SYNC = 4096
|
pkg os, const ModeType FileMode
|
||||||
pkg os (linux-arm-cgo), const O_SYNC = 4096
|
pkg os, func Chmod(string, FileMode) error
|
||||||
pkg os (linux-arm), const O_SYNC = 1052672
|
pkg os, func Lstat(string) (FileInfo, error)
|
||||||
pkg os (linux-arm-cgo), const O_SYNC = 1052672
|
pkg os, func Mkdir(string, FileMode) error
|
||||||
|
pkg os, func MkdirAll(string, FileMode) error
|
||||||
|
pkg os, func OpenFile(string, int, FileMode) (*File, error)
|
||||||
|
pkg os, func SameFile(FileInfo, FileInfo) bool
|
||||||
|
pkg os, func Stat(string) (FileInfo, error)
|
||||||
|
pkg os, method (*File) Chmod(FileMode) error
|
||||||
|
pkg os, method (*File) Readdir(int) ([]FileInfo, error)
|
||||||
|
pkg os, method (*File) Stat() (FileInfo, error)
|
||||||
|
pkg os, method (*PathError) Error() string
|
||||||
|
pkg os, method (*PathError) Timeout() bool
|
||||||
|
pkg os, method (*PathError) Unwrap() error
|
||||||
|
pkg os, method (FileMode) IsDir() bool
|
||||||
|
pkg os, method (FileMode) IsRegular() bool
|
||||||
|
pkg os, method (FileMode) Perm() FileMode
|
||||||
|
pkg os, method (FileMode) String() string
|
||||||
|
pkg os, type FileInfo interface { IsDir, ModTime, Mode, Name, Size, Sys }
|
||||||
|
pkg os, type FileInfo interface, IsDir() bool
|
||||||
|
pkg os, type FileInfo interface, ModTime() time.Time
|
||||||
|
pkg os, type FileInfo interface, Mode() FileMode
|
||||||
|
pkg os, type FileInfo interface, Name() string
|
||||||
|
pkg os, type FileInfo interface, Size() int64
|
||||||
|
pkg os, type FileInfo interface, Sys() interface{}
|
||||||
|
pkg os, type FileMode uint32
|
||||||
|
pkg os, type PathError struct
|
||||||
|
pkg os, type PathError struct, Err error
|
||||||
|
pkg os, type PathError struct, Op string
|
||||||
|
pkg os, type PathError struct, Path string
|
||||||
pkg syscall (darwin-amd64), const ImplementsGetwd = false
|
pkg syscall (darwin-amd64), const ImplementsGetwd = false
|
||||||
pkg syscall (darwin-amd64), func Fchflags(string, int) error
|
pkg syscall (darwin-amd64), func Fchflags(string, int) error
|
||||||
pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false
|
pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false
|
||||||
|
|
@ -18,22 +62,72 @@ pkg syscall (freebsd-386), const ELAST = 94
|
||||||
pkg syscall (freebsd-386), const ImplementsGetwd = false
|
pkg syscall (freebsd-386), const ImplementsGetwd = false
|
||||||
pkg syscall (freebsd-386), const O_CLOEXEC = 0
|
pkg syscall (freebsd-386), const O_CLOEXEC = 0
|
||||||
pkg syscall (freebsd-386), func Fchflags(string, int) error
|
pkg syscall (freebsd-386), func Fchflags(string, int) error
|
||||||
|
pkg syscall (freebsd-386), func Mknod(string, uint32, int) error
|
||||||
|
pkg syscall (freebsd-386), type Dirent struct, Fileno uint32
|
||||||
|
pkg syscall (freebsd-386), type Dirent struct, Namlen uint8
|
||||||
|
pkg syscall (freebsd-386), type Stat_t struct, Blksize uint32
|
||||||
|
pkg syscall (freebsd-386), type Stat_t struct, Dev uint32
|
||||||
|
pkg syscall (freebsd-386), type Stat_t struct, Gen uint32
|
||||||
|
pkg syscall (freebsd-386), type Stat_t struct, Ino uint32
|
||||||
|
pkg syscall (freebsd-386), type Stat_t struct, Lspare int32
|
||||||
|
pkg syscall (freebsd-386), type Stat_t struct, Nlink uint16
|
||||||
|
pkg syscall (freebsd-386), type Stat_t struct, Pad_cgo_0 [8]uint8
|
||||||
|
pkg syscall (freebsd-386), type Stat_t struct, Rdev uint32
|
||||||
|
pkg syscall (freebsd-386), type Statfs_t struct, Mntfromname [88]int8
|
||||||
|
pkg syscall (freebsd-386), type Statfs_t struct, Mntonname [88]int8
|
||||||
pkg syscall (freebsd-386-cgo), const AF_MAX = 38
|
pkg syscall (freebsd-386-cgo), const AF_MAX = 38
|
||||||
pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
|
pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
|
||||||
pkg syscall (freebsd-386-cgo), const ELAST = 94
|
pkg syscall (freebsd-386-cgo), const ELAST = 94
|
||||||
pkg syscall (freebsd-386-cgo), const ImplementsGetwd = false
|
pkg syscall (freebsd-386-cgo), const ImplementsGetwd = false
|
||||||
pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
|
pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
|
||||||
|
pkg syscall (freebsd-386-cgo), func Mknod(string, uint32, int) error
|
||||||
|
pkg syscall (freebsd-386-cgo), type Dirent struct, Fileno uint32
|
||||||
|
pkg syscall (freebsd-386-cgo), type Dirent struct, Namlen uint8
|
||||||
|
pkg syscall (freebsd-386-cgo), type Stat_t struct, Blksize uint32
|
||||||
|
pkg syscall (freebsd-386-cgo), type Stat_t struct, Dev uint32
|
||||||
|
pkg syscall (freebsd-386-cgo), type Stat_t struct, Gen uint32
|
||||||
|
pkg syscall (freebsd-386-cgo), type Stat_t struct, Ino uint32
|
||||||
|
pkg syscall (freebsd-386-cgo), type Stat_t struct, Lspare int32
|
||||||
|
pkg syscall (freebsd-386-cgo), type Stat_t struct, Nlink uint16
|
||||||
|
pkg syscall (freebsd-386-cgo), type Stat_t struct, Pad_cgo_0 [8]uint8
|
||||||
|
pkg syscall (freebsd-386-cgo), type Stat_t struct, Rdev uint32
|
||||||
|
pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||||
|
pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||||
pkg syscall (freebsd-amd64), const AF_MAX = 38
|
pkg syscall (freebsd-amd64), const AF_MAX = 38
|
||||||
pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
|
pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
|
||||||
pkg syscall (freebsd-amd64), const ELAST = 94
|
pkg syscall (freebsd-amd64), const ELAST = 94
|
||||||
pkg syscall (freebsd-amd64), const ImplementsGetwd = false
|
pkg syscall (freebsd-amd64), const ImplementsGetwd = false
|
||||||
pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
|
pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
|
||||||
pkg syscall (freebsd-amd64), func Fchflags(string, int) error
|
pkg syscall (freebsd-amd64), func Fchflags(string, int) error
|
||||||
|
pkg syscall (freebsd-amd64), func Mknod(string, uint32, int) error
|
||||||
|
pkg syscall (freebsd-amd64), type Dirent struct, Fileno uint32
|
||||||
|
pkg syscall (freebsd-amd64), type Dirent struct, Namlen uint8
|
||||||
|
pkg syscall (freebsd-amd64), type Stat_t struct, Blksize uint32
|
||||||
|
pkg syscall (freebsd-amd64), type Stat_t struct, Dev uint32
|
||||||
|
pkg syscall (freebsd-amd64), type Stat_t struct, Gen uint32
|
||||||
|
pkg syscall (freebsd-amd64), type Stat_t struct, Ino uint32
|
||||||
|
pkg syscall (freebsd-amd64), type Stat_t struct, Lspare int32
|
||||||
|
pkg syscall (freebsd-amd64), type Stat_t struct, Nlink uint16
|
||||||
|
pkg syscall (freebsd-amd64), type Stat_t struct, Rdev uint32
|
||||||
|
pkg syscall (freebsd-amd64), type Statfs_t struct, Mntfromname [88]int8
|
||||||
|
pkg syscall (freebsd-amd64), type Statfs_t struct, Mntonname [88]int8
|
||||||
pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
|
pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
|
||||||
pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
|
pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
|
||||||
pkg syscall (freebsd-amd64-cgo), const ELAST = 94
|
pkg syscall (freebsd-amd64-cgo), const ELAST = 94
|
||||||
pkg syscall (freebsd-amd64-cgo), const ImplementsGetwd = false
|
pkg syscall (freebsd-amd64-cgo), const ImplementsGetwd = false
|
||||||
pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
|
pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
|
||||||
|
pkg syscall (freebsd-amd64-cgo), func Mknod(string, uint32, int) error
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Dirent struct, Fileno uint32
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Dirent struct, Namlen uint8
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Blksize uint32
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Dev uint32
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Gen uint32
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Ino uint32
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Lspare int32
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Nlink uint16
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Rdev uint32
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||||
|
pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||||
pkg syscall (freebsd-arm), const AF_MAX = 38
|
pkg syscall (freebsd-arm), const AF_MAX = 38
|
||||||
pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
|
pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
|
||||||
pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
|
pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
|
||||||
|
|
@ -62,10 +156,22 @@ pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56
|
||||||
pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
|
pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
|
||||||
pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
|
pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
|
||||||
pkg syscall (freebsd-arm), func Fchflags(string, int) error
|
pkg syscall (freebsd-arm), func Fchflags(string, int) error
|
||||||
|
pkg syscall (freebsd-arm), func Mknod(string, uint32, int) error
|
||||||
pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||||
|
pkg syscall (freebsd-arm), type Dirent struct, Fileno uint32
|
||||||
|
pkg syscall (freebsd-arm), type Dirent struct, Namlen uint8
|
||||||
pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||||
pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||||
|
pkg syscall (freebsd-arm), type Stat_t struct, Blksize uint32
|
||||||
|
pkg syscall (freebsd-arm), type Stat_t struct, Dev uint32
|
||||||
|
pkg syscall (freebsd-arm), type Stat_t struct, Gen uint32
|
||||||
|
pkg syscall (freebsd-arm), type Stat_t struct, Ino uint32
|
||||||
|
pkg syscall (freebsd-arm), type Stat_t struct, Lspare int32
|
||||||
|
pkg syscall (freebsd-arm), type Stat_t struct, Nlink uint16
|
||||||
pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
|
pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||||
|
pkg syscall (freebsd-arm), type Stat_t struct, Rdev uint32
|
||||||
|
pkg syscall (freebsd-arm), type Statfs_t struct, Mntfromname [88]int8
|
||||||
|
pkg syscall (freebsd-arm), type Statfs_t struct, Mntonname [88]int8
|
||||||
pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
|
pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
|
||||||
pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
|
pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
|
||||||
pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
|
pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
|
||||||
|
|
@ -94,10 +200,22 @@ pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56
|
||||||
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
|
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
|
||||||
pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
|
pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
|
||||||
pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error
|
pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error
|
||||||
|
pkg syscall (freebsd-arm-cgo), func Mknod(string, uint32, int) error
|
||||||
pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Dirent struct, Fileno uint32
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Dirent struct, Namlen uint8
|
||||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Blksize uint32
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Dev uint32
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Gen uint32
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Ino uint32
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Lspare int32
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Nlink uint16
|
||||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
|
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||||
|
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||||
pkg syscall (linux-386), type Cmsghdr struct, X__cmsg_data [0]uint8
|
pkg syscall (linux-386), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||||
pkg syscall (linux-386-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
|
pkg syscall (linux-386-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||||
pkg syscall (linux-amd64), type Cmsghdr struct, X__cmsg_data [0]uint8
|
pkg syscall (linux-amd64), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||||
|
|
@ -109,10 +227,10 @@ pkg syscall (netbsd-386-cgo), const ImplementsGetwd = false
|
||||||
pkg syscall (netbsd-amd64), const ImplementsGetwd = false
|
pkg syscall (netbsd-amd64), const ImplementsGetwd = false
|
||||||
pkg syscall (netbsd-amd64-cgo), const ImplementsGetwd = false
|
pkg syscall (netbsd-amd64-cgo), const ImplementsGetwd = false
|
||||||
pkg syscall (netbsd-arm), const ImplementsGetwd = false
|
pkg syscall (netbsd-arm), const ImplementsGetwd = false
|
||||||
pkg syscall (netbsd-arm-cgo), const ImplementsGetwd = false
|
|
||||||
pkg syscall (netbsd-arm), const SizeofIfData = 132
|
pkg syscall (netbsd-arm), const SizeofIfData = 132
|
||||||
pkg syscall (netbsd-arm), func Fchflags(string, int) error
|
pkg syscall (netbsd-arm), func Fchflags(string, int) error
|
||||||
pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||||
|
pkg syscall (netbsd-arm-cgo), const ImplementsGetwd = false
|
||||||
pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
|
pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
|
||||||
pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
|
pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
|
||||||
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||||
|
|
@ -140,6 +258,7 @@ pkg syscall (openbsd-386), const SYS_GETITIMER = 86
|
||||||
pkg syscall (openbsd-386), const SYS_GETRUSAGE = 117
|
pkg syscall (openbsd-386), const SYS_GETRUSAGE = 117
|
||||||
pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116
|
pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116
|
||||||
pkg syscall (openbsd-386), const SYS_KEVENT = 270
|
pkg syscall (openbsd-386), const SYS_KEVENT = 270
|
||||||
|
pkg syscall (openbsd-386), const SYS_KILL = 37
|
||||||
pkg syscall (openbsd-386), const SYS_LSTAT = 293
|
pkg syscall (openbsd-386), const SYS_LSTAT = 293
|
||||||
pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240
|
pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240
|
||||||
pkg syscall (openbsd-386), const SYS_SELECT = 93
|
pkg syscall (openbsd-386), const SYS_SELECT = 93
|
||||||
|
|
@ -193,6 +312,7 @@ pkg syscall (openbsd-386-cgo), const SYS_GETITIMER = 86
|
||||||
pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 117
|
pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 117
|
||||||
pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 116
|
pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 116
|
||||||
pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 270
|
pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 270
|
||||||
|
pkg syscall (openbsd-386-cgo), const SYS_KILL = 37
|
||||||
pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 293
|
pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 293
|
||||||
pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240
|
pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240
|
||||||
pkg syscall (openbsd-386-cgo), const SYS_SELECT = 93
|
pkg syscall (openbsd-386-cgo), const SYS_SELECT = 93
|
||||||
|
|
@ -257,6 +377,7 @@ pkg syscall (openbsd-amd64), const SYS_GETITIMER = 86
|
||||||
pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 117
|
pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 117
|
||||||
pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116
|
pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116
|
||||||
pkg syscall (openbsd-amd64), const SYS_KEVENT = 270
|
pkg syscall (openbsd-amd64), const SYS_KEVENT = 270
|
||||||
|
pkg syscall (openbsd-amd64), const SYS_KILL = 37
|
||||||
pkg syscall (openbsd-amd64), const SYS_LSTAT = 293
|
pkg syscall (openbsd-amd64), const SYS_LSTAT = 293
|
||||||
pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240
|
pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240
|
||||||
pkg syscall (openbsd-amd64), const SYS_SELECT = 93
|
pkg syscall (openbsd-amd64), const SYS_SELECT = 93
|
||||||
|
|
@ -320,6 +441,7 @@ pkg syscall (openbsd-amd64-cgo), const SYS_GETITIMER = 86
|
||||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 117
|
pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 117
|
||||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 116
|
pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 116
|
||||||
pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 270
|
pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 270
|
||||||
|
pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37
|
||||||
pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 293
|
pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 293
|
||||||
pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240
|
pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240
|
||||||
pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 93
|
pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 93
|
||||||
|
|
@ -348,19 +470,6 @@ pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_spare [3]uint32
|
||||||
pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8
|
pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8
|
||||||
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
|
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
|
||||||
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32
|
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32
|
||||||
pkg testing, func RegisterCover(Cover)
|
|
||||||
pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M
|
|
||||||
pkg text/template/parse, type DotNode bool
|
|
||||||
pkg text/template/parse, type Node interface { Copy, String, Type }
|
|
||||||
pkg unicode, const Version = "6.2.0"
|
|
||||||
pkg unicode, const Version = "6.3.0"
|
|
||||||
pkg unicode, const Version = "7.0.0"
|
|
||||||
pkg unicode, const Version = "8.0.0"
|
|
||||||
pkg syscall (openbsd-386), const SYS_KILL = 37
|
|
||||||
pkg syscall (openbsd-386-cgo), const SYS_KILL = 37
|
|
||||||
pkg syscall (openbsd-amd64), const SYS_KILL = 37
|
|
||||||
pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37
|
|
||||||
pkg unicode, const Version = "9.0.0"
|
|
||||||
pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295
|
pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295
|
||||||
pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr
|
pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr
|
||||||
pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara uintptr
|
pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara uintptr
|
||||||
|
|
@ -379,81 +488,16 @@ pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr
|
||||||
pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr
|
pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr
|
||||||
pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr
|
pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr
|
||||||
pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8
|
pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8
|
||||||
pkg syscall (freebsd-386), func Mknod(string, uint32, int) error
|
pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M
|
||||||
pkg syscall (freebsd-386), type Dirent struct, Fileno uint32
|
pkg testing, func RegisterCover(Cover)
|
||||||
pkg syscall (freebsd-386), type Dirent struct, Namlen uint8
|
|
||||||
pkg syscall (freebsd-386), type Stat_t struct, Blksize uint32
|
|
||||||
pkg syscall (freebsd-386), type Stat_t struct, Dev uint32
|
|
||||||
pkg syscall (freebsd-386), type Stat_t struct, Gen uint32
|
|
||||||
pkg syscall (freebsd-386), type Stat_t struct, Ino uint32
|
|
||||||
pkg syscall (freebsd-386), type Stat_t struct, Lspare int32
|
|
||||||
pkg syscall (freebsd-386), type Stat_t struct, Nlink uint16
|
|
||||||
pkg syscall (freebsd-386), type Stat_t struct, Pad_cgo_0 [8]uint8
|
|
||||||
pkg syscall (freebsd-386), type Stat_t struct, Rdev uint32
|
|
||||||
pkg syscall (freebsd-386), type Statfs_t struct, Mntfromname [88]int8
|
|
||||||
pkg syscall (freebsd-386), type Statfs_t struct, Mntonname [88]int8
|
|
||||||
pkg syscall (freebsd-386-cgo), func Mknod(string, uint32, int) error
|
|
||||||
pkg syscall (freebsd-386-cgo), type Dirent struct, Fileno uint32
|
|
||||||
pkg syscall (freebsd-386-cgo), type Dirent struct, Namlen uint8
|
|
||||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Blksize uint32
|
|
||||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Dev uint32
|
|
||||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Gen uint32
|
|
||||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Ino uint32
|
|
||||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Lspare int32
|
|
||||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Nlink uint16
|
|
||||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Pad_cgo_0 [8]uint8
|
|
||||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Rdev uint32
|
|
||||||
pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntfromname [88]int8
|
|
||||||
pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntonname [88]int8
|
|
||||||
pkg syscall (freebsd-amd64), func Mknod(string, uint32, int) error
|
|
||||||
pkg syscall (freebsd-amd64), type Dirent struct, Fileno uint32
|
|
||||||
pkg syscall (freebsd-amd64), type Dirent struct, Namlen uint8
|
|
||||||
pkg syscall (freebsd-amd64), type Stat_t struct, Blksize uint32
|
|
||||||
pkg syscall (freebsd-amd64), type Stat_t struct, Dev uint32
|
|
||||||
pkg syscall (freebsd-amd64), type Stat_t struct, Gen uint32
|
|
||||||
pkg syscall (freebsd-amd64), type Stat_t struct, Ino uint32
|
|
||||||
pkg syscall (freebsd-amd64), type Stat_t struct, Lspare int32
|
|
||||||
pkg syscall (freebsd-amd64), type Stat_t struct, Nlink uint16
|
|
||||||
pkg syscall (freebsd-amd64), type Stat_t struct, Rdev uint32
|
|
||||||
pkg syscall (freebsd-amd64), type Statfs_t struct, Mntfromname [88]int8
|
|
||||||
pkg syscall (freebsd-amd64), type Statfs_t struct, Mntonname [88]int8
|
|
||||||
pkg syscall (freebsd-amd64-cgo), func Mknod(string, uint32, int) error
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Dirent struct, Fileno uint32
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Dirent struct, Namlen uint8
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Blksize uint32
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Dev uint32
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Gen uint32
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Ino uint32
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Lspare int32
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Nlink uint16
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Rdev uint32
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntfromname [88]int8
|
|
||||||
pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntonname [88]int8
|
|
||||||
pkg syscall (freebsd-arm), func Mknod(string, uint32, int) error
|
|
||||||
pkg syscall (freebsd-arm), type Dirent struct, Fileno uint32
|
|
||||||
pkg syscall (freebsd-arm), type Dirent struct, Namlen uint8
|
|
||||||
pkg syscall (freebsd-arm), type Stat_t struct, Blksize uint32
|
|
||||||
pkg syscall (freebsd-arm), type Stat_t struct, Dev uint32
|
|
||||||
pkg syscall (freebsd-arm), type Stat_t struct, Gen uint32
|
|
||||||
pkg syscall (freebsd-arm), type Stat_t struct, Ino uint32
|
|
||||||
pkg syscall (freebsd-arm), type Stat_t struct, Lspare int32
|
|
||||||
pkg syscall (freebsd-arm), type Stat_t struct, Nlink uint16
|
|
||||||
pkg syscall (freebsd-arm), type Stat_t struct, Rdev uint32
|
|
||||||
pkg syscall (freebsd-arm), type Statfs_t struct, Mntfromname [88]int8
|
|
||||||
pkg syscall (freebsd-arm), type Statfs_t struct, Mntonname [88]int8
|
|
||||||
pkg syscall (freebsd-arm-cgo), func Mknod(string, uint32, int) error
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Dirent struct, Fileno uint32
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Dirent struct, Namlen uint8
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Blksize uint32
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Dev uint32
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Gen uint32
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Ino uint32
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Lspare int32
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Nlink uint16
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8
|
|
||||||
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8
|
|
||||||
pkg text/scanner, const GoTokens = 1012
|
pkg text/scanner, const GoTokens = 1012
|
||||||
|
pkg text/template/parse, type DotNode bool
|
||||||
|
pkg text/template/parse, type Node interface { Copy, String, Type }
|
||||||
pkg unicode, const Version = "10.0.0"
|
pkg unicode, const Version = "10.0.0"
|
||||||
pkg unicode, const Version = "11.0.0"
|
pkg unicode, const Version = "11.0.0"
|
||||||
pkg unicode, const Version = "12.0.0"
|
pkg unicode, const Version = "12.0.0"
|
||||||
|
pkg unicode, const Version = "6.2.0"
|
||||||
|
pkg unicode, const Version = "6.3.0"
|
||||||
|
pkg unicode, const Version = "7.0.0"
|
||||||
|
pkg unicode, const Version = "8.0.0"
|
||||||
|
pkg unicode, const Version = "9.0.0"
|
||||||
|
|
|
||||||
443
api/next.txt
443
api/next.txt
|
|
@ -1,8 +1,436 @@
|
||||||
pkg unicode, const Version = "13.0.0"
|
pkg archive/zip, method (*ReadCloser) Open(string) (fs.File, error)
|
||||||
pkg unicode, var Chorasmian *RangeTable
|
pkg archive/zip, method (*Reader) Open(string) (fs.File, error)
|
||||||
pkg unicode, var Dives_Akuru *RangeTable
|
pkg debug/elf, const DT_ADDRRNGHI = 1879047935
|
||||||
pkg unicode, var Khitan_Small_Script *RangeTable
|
pkg debug/elf, const DT_ADDRRNGHI DynTag
|
||||||
pkg unicode, var Yezidi *RangeTable
|
pkg debug/elf, const DT_ADDRRNGLO = 1879047680
|
||||||
|
pkg debug/elf, const DT_ADDRRNGLO DynTag
|
||||||
|
pkg debug/elf, const DT_AUDIT = 1879047932
|
||||||
|
pkg debug/elf, const DT_AUDIT DynTag
|
||||||
|
pkg debug/elf, const DT_AUXILIARY = 2147483645
|
||||||
|
pkg debug/elf, const DT_AUXILIARY DynTag
|
||||||
|
pkg debug/elf, const DT_CHECKSUM = 1879047672
|
||||||
|
pkg debug/elf, const DT_CHECKSUM DynTag
|
||||||
|
pkg debug/elf, const DT_CONFIG = 1879047930
|
||||||
|
pkg debug/elf, const DT_CONFIG DynTag
|
||||||
|
pkg debug/elf, const DT_DEPAUDIT = 1879047931
|
||||||
|
pkg debug/elf, const DT_DEPAUDIT DynTag
|
||||||
|
pkg debug/elf, const DT_FEATURE = 1879047676
|
||||||
|
pkg debug/elf, const DT_FEATURE DynTag
|
||||||
|
pkg debug/elf, const DT_FILTER = 2147483647
|
||||||
|
pkg debug/elf, const DT_FILTER DynTag
|
||||||
|
pkg debug/elf, const DT_FLAGS_1 = 1879048187
|
||||||
|
pkg debug/elf, const DT_FLAGS_1 DynTag
|
||||||
|
pkg debug/elf, const DT_GNU_CONFLICT = 1879047928
|
||||||
|
pkg debug/elf, const DT_GNU_CONFLICT DynTag
|
||||||
|
pkg debug/elf, const DT_GNU_CONFLICTSZ = 1879047670
|
||||||
|
pkg debug/elf, const DT_GNU_CONFLICTSZ DynTag
|
||||||
|
pkg debug/elf, const DT_GNU_HASH = 1879047925
|
||||||
|
pkg debug/elf, const DT_GNU_HASH DynTag
|
||||||
|
pkg debug/elf, const DT_GNU_LIBLIST = 1879047929
|
||||||
|
pkg debug/elf, const DT_GNU_LIBLIST DynTag
|
||||||
|
pkg debug/elf, const DT_GNU_LIBLISTSZ = 1879047671
|
||||||
|
pkg debug/elf, const DT_GNU_LIBLISTSZ DynTag
|
||||||
|
pkg debug/elf, const DT_GNU_PRELINKED = 1879047669
|
||||||
|
pkg debug/elf, const DT_GNU_PRELINKED DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_AUX_DYNAMIC = 1879048241
|
||||||
|
pkg debug/elf, const DT_MIPS_AUX_DYNAMIC DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_BASE_ADDRESS = 1879048198
|
||||||
|
pkg debug/elf, const DT_MIPS_BASE_ADDRESS DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_COMPACT_SIZE = 1879048239
|
||||||
|
pkg debug/elf, const DT_MIPS_COMPACT_SIZE DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_CONFLICT = 1879048200
|
||||||
|
pkg debug/elf, const DT_MIPS_CONFLICT DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_CONFLICTNO = 1879048203
|
||||||
|
pkg debug/elf, const DT_MIPS_CONFLICTNO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_CXX_FLAGS = 1879048226
|
||||||
|
pkg debug/elf, const DT_MIPS_CXX_FLAGS DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_CLASS = 1879048215
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_CLASS DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_CLASSSYM = 1879048224
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_CLASSSYM DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_CLASSSYM_NO = 1879048225
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_CLASSSYM_NO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_CLASS_NO = 1879048216
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_CLASS_NO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_INSTANCE = 1879048217
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_INSTANCE DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_INSTANCE_NO = 1879048218
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_INSTANCE_NO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_RELOC = 1879048219
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_RELOC DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_RELOC_NO = 1879048220
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_RELOC_NO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_SYM = 1879048221
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_SYM DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_SYM_NO = 1879048222
|
||||||
|
pkg debug/elf, const DT_MIPS_DELTA_SYM_NO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_DYNSTR_ALIGN = 1879048235
|
||||||
|
pkg debug/elf, const DT_MIPS_DYNSTR_ALIGN DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_FLAGS = 1879048197
|
||||||
|
pkg debug/elf, const DT_MIPS_FLAGS DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_GOTSYM = 1879048211
|
||||||
|
pkg debug/elf, const DT_MIPS_GOTSYM DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_GP_VALUE = 1879048240
|
||||||
|
pkg debug/elf, const DT_MIPS_GP_VALUE DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_HIDDEN_GOTIDX = 1879048231
|
||||||
|
pkg debug/elf, const DT_MIPS_HIDDEN_GOTIDX DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_HIPAGENO = 1879048212
|
||||||
|
pkg debug/elf, const DT_MIPS_HIPAGENO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_ICHECKSUM = 1879048195
|
||||||
|
pkg debug/elf, const DT_MIPS_ICHECKSUM DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_INTERFACE = 1879048234
|
||||||
|
pkg debug/elf, const DT_MIPS_INTERFACE DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_INTERFACE_SIZE = 1879048236
|
||||||
|
pkg debug/elf, const DT_MIPS_INTERFACE_SIZE DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_IVERSION = 1879048196
|
||||||
|
pkg debug/elf, const DT_MIPS_IVERSION DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_LIBLIST = 1879048201
|
||||||
|
pkg debug/elf, const DT_MIPS_LIBLIST DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_LIBLISTNO = 1879048208
|
||||||
|
pkg debug/elf, const DT_MIPS_LIBLISTNO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_LOCALPAGE_GOTIDX = 1879048229
|
||||||
|
pkg debug/elf, const DT_MIPS_LOCALPAGE_GOTIDX DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_LOCAL_GOTIDX = 1879048230
|
||||||
|
pkg debug/elf, const DT_MIPS_LOCAL_GOTIDX DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_LOCAL_GOTNO = 1879048202
|
||||||
|
pkg debug/elf, const DT_MIPS_LOCAL_GOTNO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_MSYM = 1879048199
|
||||||
|
pkg debug/elf, const DT_MIPS_MSYM DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_OPTIONS = 1879048233
|
||||||
|
pkg debug/elf, const DT_MIPS_OPTIONS DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_PERF_SUFFIX = 1879048238
|
||||||
|
pkg debug/elf, const DT_MIPS_PERF_SUFFIX DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_PIXIE_INIT = 1879048227
|
||||||
|
pkg debug/elf, const DT_MIPS_PIXIE_INIT DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_PLTGOT = 1879048242
|
||||||
|
pkg debug/elf, const DT_MIPS_PLTGOT DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_PROTECTED_GOTIDX = 1879048232
|
||||||
|
pkg debug/elf, const DT_MIPS_PROTECTED_GOTIDX DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_RLD_MAP = 1879048214
|
||||||
|
pkg debug/elf, const DT_MIPS_RLD_MAP DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_RLD_MAP_REL = 1879048245
|
||||||
|
pkg debug/elf, const DT_MIPS_RLD_MAP_REL DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 1879048237
|
||||||
|
pkg debug/elf, const DT_MIPS_RLD_TEXT_RESOLVE_ADDR DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_RLD_VERSION = 1879048193
|
||||||
|
pkg debug/elf, const DT_MIPS_RLD_VERSION DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_RWPLT = 1879048244
|
||||||
|
pkg debug/elf, const DT_MIPS_RWPLT DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_SYMBOL_LIB = 1879048228
|
||||||
|
pkg debug/elf, const DT_MIPS_SYMBOL_LIB DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_SYMTABNO = 1879048209
|
||||||
|
pkg debug/elf, const DT_MIPS_SYMTABNO DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_TIME_STAMP = 1879048194
|
||||||
|
pkg debug/elf, const DT_MIPS_TIME_STAMP DynTag
|
||||||
|
pkg debug/elf, const DT_MIPS_UNREFEXTNO = 1879048210
|
||||||
|
pkg debug/elf, const DT_MIPS_UNREFEXTNO DynTag
|
||||||
|
pkg debug/elf, const DT_MOVEENT = 1879047674
|
||||||
|
pkg debug/elf, const DT_MOVEENT DynTag
|
||||||
|
pkg debug/elf, const DT_MOVESZ = 1879047675
|
||||||
|
pkg debug/elf, const DT_MOVESZ DynTag
|
||||||
|
pkg debug/elf, const DT_MOVETAB = 1879047934
|
||||||
|
pkg debug/elf, const DT_MOVETAB DynTag
|
||||||
|
pkg debug/elf, const DT_PLTPAD = 1879047933
|
||||||
|
pkg debug/elf, const DT_PLTPAD DynTag
|
||||||
|
pkg debug/elf, const DT_PLTPADSZ = 1879047673
|
||||||
|
pkg debug/elf, const DT_PLTPADSZ DynTag
|
||||||
|
pkg debug/elf, const DT_POSFLAG_1 = 1879047677
|
||||||
|
pkg debug/elf, const DT_POSFLAG_1 DynTag
|
||||||
|
pkg debug/elf, const DT_PPC64_GLINK = 1879048192
|
||||||
|
pkg debug/elf, const DT_PPC64_GLINK DynTag
|
||||||
|
pkg debug/elf, const DT_PPC64_OPD = 1879048193
|
||||||
|
pkg debug/elf, const DT_PPC64_OPD DynTag
|
||||||
|
pkg debug/elf, const DT_PPC64_OPDSZ = 1879048194
|
||||||
|
pkg debug/elf, const DT_PPC64_OPDSZ DynTag
|
||||||
|
pkg debug/elf, const DT_PPC64_OPT = 1879048195
|
||||||
|
pkg debug/elf, const DT_PPC64_OPT DynTag
|
||||||
|
pkg debug/elf, const DT_PPC_GOT = 1879048192
|
||||||
|
pkg debug/elf, const DT_PPC_GOT DynTag
|
||||||
|
pkg debug/elf, const DT_PPC_OPT = 1879048193
|
||||||
|
pkg debug/elf, const DT_PPC_OPT DynTag
|
||||||
|
pkg debug/elf, const DT_RELACOUNT = 1879048185
|
||||||
|
pkg debug/elf, const DT_RELACOUNT DynTag
|
||||||
|
pkg debug/elf, const DT_RELCOUNT = 1879048186
|
||||||
|
pkg debug/elf, const DT_RELCOUNT DynTag
|
||||||
|
pkg debug/elf, const DT_SPARC_REGISTER = 1879048193
|
||||||
|
pkg debug/elf, const DT_SPARC_REGISTER DynTag
|
||||||
|
pkg debug/elf, const DT_SYMINENT = 1879047679
|
||||||
|
pkg debug/elf, const DT_SYMINENT DynTag
|
||||||
|
pkg debug/elf, const DT_SYMINFO = 1879047935
|
||||||
|
pkg debug/elf, const DT_SYMINFO DynTag
|
||||||
|
pkg debug/elf, const DT_SYMINSZ = 1879047678
|
||||||
|
pkg debug/elf, const DT_SYMINSZ DynTag
|
||||||
|
pkg debug/elf, const DT_SYMTAB_SHNDX = 34
|
||||||
|
pkg debug/elf, const DT_SYMTAB_SHNDX DynTag
|
||||||
|
pkg debug/elf, const DT_TLSDESC_GOT = 1879047927
|
||||||
|
pkg debug/elf, const DT_TLSDESC_GOT DynTag
|
||||||
|
pkg debug/elf, const DT_TLSDESC_PLT = 1879047926
|
||||||
|
pkg debug/elf, const DT_TLSDESC_PLT DynTag
|
||||||
|
pkg debug/elf, const DT_USED = 2147483646
|
||||||
|
pkg debug/elf, const DT_USED DynTag
|
||||||
|
pkg debug/elf, const DT_VALRNGHI = 1879047679
|
||||||
|
pkg debug/elf, const DT_VALRNGHI DynTag
|
||||||
|
pkg debug/elf, const DT_VALRNGLO = 1879047424
|
||||||
|
pkg debug/elf, const DT_VALRNGLO DynTag
|
||||||
|
pkg debug/elf, const DT_VERDEF = 1879048188
|
||||||
|
pkg debug/elf, const DT_VERDEF DynTag
|
||||||
|
pkg debug/elf, const DT_VERDEFNUM = 1879048189
|
||||||
|
pkg debug/elf, const DT_VERDEFNUM DynTag
|
||||||
|
pkg debug/elf, const PT_AARCH64_ARCHEXT = 1879048192
|
||||||
|
pkg debug/elf, const PT_AARCH64_ARCHEXT ProgType
|
||||||
|
pkg debug/elf, const PT_AARCH64_UNWIND = 1879048193
|
||||||
|
pkg debug/elf, const PT_AARCH64_UNWIND ProgType
|
||||||
|
pkg debug/elf, const PT_ARM_ARCHEXT = 1879048192
|
||||||
|
pkg debug/elf, const PT_ARM_ARCHEXT ProgType
|
||||||
|
pkg debug/elf, const PT_ARM_EXIDX = 1879048193
|
||||||
|
pkg debug/elf, const PT_ARM_EXIDX ProgType
|
||||||
|
pkg debug/elf, const PT_GNU_EH_FRAME = 1685382480
|
||||||
|
pkg debug/elf, const PT_GNU_EH_FRAME ProgType
|
||||||
|
pkg debug/elf, const PT_GNU_MBIND_HI = 1685386580
|
||||||
|
pkg debug/elf, const PT_GNU_MBIND_HI ProgType
|
||||||
|
pkg debug/elf, const PT_GNU_MBIND_LO = 1685382485
|
||||||
|
pkg debug/elf, const PT_GNU_MBIND_LO ProgType
|
||||||
|
pkg debug/elf, const PT_GNU_PROPERTY = 1685382483
|
||||||
|
pkg debug/elf, const PT_GNU_PROPERTY ProgType
|
||||||
|
pkg debug/elf, const PT_GNU_RELRO = 1685382482
|
||||||
|
pkg debug/elf, const PT_GNU_RELRO ProgType
|
||||||
|
pkg debug/elf, const PT_GNU_STACK = 1685382481
|
||||||
|
pkg debug/elf, const PT_GNU_STACK ProgType
|
||||||
|
pkg debug/elf, const PT_MIPS_ABIFLAGS = 1879048195
|
||||||
|
pkg debug/elf, const PT_MIPS_ABIFLAGS ProgType
|
||||||
|
pkg debug/elf, const PT_MIPS_OPTIONS = 1879048194
|
||||||
|
pkg debug/elf, const PT_MIPS_OPTIONS ProgType
|
||||||
|
pkg debug/elf, const PT_MIPS_REGINFO = 1879048192
|
||||||
|
pkg debug/elf, const PT_MIPS_REGINFO ProgType
|
||||||
|
pkg debug/elf, const PT_MIPS_RTPROC = 1879048193
|
||||||
|
pkg debug/elf, const PT_MIPS_RTPROC ProgType
|
||||||
|
pkg debug/elf, const PT_OPENBSD_BOOTDATA = 1705253862
|
||||||
|
pkg debug/elf, const PT_OPENBSD_BOOTDATA ProgType
|
||||||
|
pkg debug/elf, const PT_OPENBSD_RANDOMIZE = 1705237478
|
||||||
|
pkg debug/elf, const PT_OPENBSD_RANDOMIZE ProgType
|
||||||
|
pkg debug/elf, const PT_OPENBSD_WXNEEDED = 1705237479
|
||||||
|
pkg debug/elf, const PT_OPENBSD_WXNEEDED ProgType
|
||||||
|
pkg debug/elf, const PT_PAX_FLAGS = 1694766464
|
||||||
|
pkg debug/elf, const PT_PAX_FLAGS ProgType
|
||||||
|
pkg debug/elf, const PT_S390_PGSTE = 1879048192
|
||||||
|
pkg debug/elf, const PT_S390_PGSTE ProgType
|
||||||
|
pkg debug/elf, const PT_SUNWSTACK = 1879048187
|
||||||
|
pkg debug/elf, const PT_SUNWSTACK ProgType
|
||||||
|
pkg debug/elf, const PT_SUNW_EH_FRAME = 1685382480
|
||||||
|
pkg debug/elf, const PT_SUNW_EH_FRAME ProgType
|
||||||
|
pkg embed, method (FS) Open(string) (fs.File, error)
|
||||||
|
pkg embed, method (FS) ReadDir(string) ([]fs.DirEntry, error)
|
||||||
|
pkg embed, method (FS) ReadFile(string) ([]uint8, error)
|
||||||
|
pkg embed, type FS struct
|
||||||
|
pkg flag, func Func(string, string, func(string) error)
|
||||||
|
pkg flag, method (*FlagSet) Func(string, string, func(string) error)
|
||||||
|
pkg go/build, type Package struct, EmbedPatterns []string
|
||||||
|
pkg go/build, type Package struct, IgnoredOtherFiles []string
|
||||||
|
pkg go/build, type Package struct, TestEmbedPatterns []string
|
||||||
|
pkg go/build, type Package struct, XTestEmbedPatterns []string
|
||||||
|
pkg html/template, func ParseFS(fs.FS, ...string) (*Template, error)
|
||||||
|
pkg html/template, method (*Template) ParseFS(fs.FS, ...string) (*Template, error)
|
||||||
|
pkg io, func NopCloser(Reader) ReadCloser
|
||||||
|
pkg io, func ReadAll(Reader) ([]uint8, error)
|
||||||
|
pkg io, type ReadSeekCloser interface { Close, Read, Seek }
|
||||||
|
pkg io, type ReadSeekCloser interface, Close() error
|
||||||
|
pkg io, type ReadSeekCloser interface, Read([]uint8) (int, error)
|
||||||
|
pkg io, type ReadSeekCloser interface, Seek(int64, int) (int64, error)
|
||||||
|
pkg io, var Discard Writer
|
||||||
|
pkg io/fs, const ModeAppend = 1073741824
|
||||||
|
pkg io/fs, const ModeAppend FileMode
|
||||||
|
pkg io/fs, const ModeCharDevice = 2097152
|
||||||
|
pkg io/fs, const ModeCharDevice FileMode
|
||||||
|
pkg io/fs, const ModeDevice = 67108864
|
||||||
|
pkg io/fs, const ModeDevice FileMode
|
||||||
|
pkg io/fs, const ModeDir = 2147483648
|
||||||
|
pkg io/fs, const ModeDir FileMode
|
||||||
|
pkg io/fs, const ModeExclusive = 536870912
|
||||||
|
pkg io/fs, const ModeExclusive FileMode
|
||||||
|
pkg io/fs, const ModeIrregular = 524288
|
||||||
|
pkg io/fs, const ModeIrregular FileMode
|
||||||
|
pkg io/fs, const ModeNamedPipe = 33554432
|
||||||
|
pkg io/fs, const ModeNamedPipe FileMode
|
||||||
|
pkg io/fs, const ModePerm = 511
|
||||||
|
pkg io/fs, const ModePerm FileMode
|
||||||
|
pkg io/fs, const ModeSetgid = 4194304
|
||||||
|
pkg io/fs, const ModeSetgid FileMode
|
||||||
|
pkg io/fs, const ModeSetuid = 8388608
|
||||||
|
pkg io/fs, const ModeSetuid FileMode
|
||||||
|
pkg io/fs, const ModeSocket = 16777216
|
||||||
|
pkg io/fs, const ModeSocket FileMode
|
||||||
|
pkg io/fs, const ModeSticky = 1048576
|
||||||
|
pkg io/fs, const ModeSticky FileMode
|
||||||
|
pkg io/fs, const ModeSymlink = 134217728
|
||||||
|
pkg io/fs, const ModeSymlink FileMode
|
||||||
|
pkg io/fs, const ModeTemporary = 268435456
|
||||||
|
pkg io/fs, const ModeTemporary FileMode
|
||||||
|
pkg io/fs, const ModeType = 2401763328
|
||||||
|
pkg io/fs, const ModeType FileMode
|
||||||
|
pkg io/fs, func Glob(FS, string) ([]string, error)
|
||||||
|
pkg io/fs, func ReadDir(FS, string) ([]DirEntry, error)
|
||||||
|
pkg io/fs, func ReadFile(FS, string) ([]uint8, error)
|
||||||
|
pkg io/fs, func Stat(FS, string) (FileInfo, error)
|
||||||
|
pkg io/fs, func ValidPath(string) bool
|
||||||
|
pkg io/fs, method (*PathError) Error() string
|
||||||
|
pkg io/fs, method (*PathError) Timeout() bool
|
||||||
|
pkg io/fs, method (*PathError) Unwrap() error
|
||||||
|
pkg io/fs, method (FileMode) IsDir() bool
|
||||||
|
pkg io/fs, method (FileMode) IsRegular() bool
|
||||||
|
pkg io/fs, method (FileMode) Perm() FileMode
|
||||||
|
pkg io/fs, method (FileMode) String() string
|
||||||
|
pkg io/fs, method (FileMode) Type() FileMode
|
||||||
|
pkg io/fs, type DirEntry interface { Info, IsDir, Name, Type }
|
||||||
|
pkg io/fs, type DirEntry interface, Info() (FileInfo, error)
|
||||||
|
pkg io/fs, type DirEntry interface, IsDir() bool
|
||||||
|
pkg io/fs, type DirEntry interface, Name() string
|
||||||
|
pkg io/fs, type DirEntry interface, Type() FileMode
|
||||||
|
pkg io/fs, type FS interface { Open }
|
||||||
|
pkg io/fs, type FS interface, Open(string) (File, error)
|
||||||
|
pkg io/fs, type File interface { Close, Read, Stat }
|
||||||
|
pkg io/fs, type File interface, Close() error
|
||||||
|
pkg io/fs, type File interface, Read([]uint8) (int, error)
|
||||||
|
pkg io/fs, type File interface, Stat() (FileInfo, error)
|
||||||
|
pkg io/fs, type FileInfo interface { IsDir, ModTime, Mode, Name, Size, Sys }
|
||||||
|
pkg io/fs, type FileInfo interface, IsDir() bool
|
||||||
|
pkg io/fs, type FileInfo interface, ModTime() time.Time
|
||||||
|
pkg io/fs, type FileInfo interface, Mode() FileMode
|
||||||
|
pkg io/fs, type FileInfo interface, Name() string
|
||||||
|
pkg io/fs, type FileInfo interface, Size() int64
|
||||||
|
pkg io/fs, type FileInfo interface, Sys() interface{}
|
||||||
|
pkg io/fs, type FileMode uint32
|
||||||
|
pkg io/fs, type GlobFS interface { Glob, Open }
|
||||||
|
pkg io/fs, type GlobFS interface, Glob(string) ([]string, error)
|
||||||
|
pkg io/fs, type GlobFS interface, Open(string) (File, error)
|
||||||
|
pkg io/fs, type PathError struct
|
||||||
|
pkg io/fs, type PathError struct, Err error
|
||||||
|
pkg io/fs, type PathError struct, Op string
|
||||||
|
pkg io/fs, type PathError struct, Path string
|
||||||
|
pkg io/fs, type ReadDirFS interface { Open, ReadDir }
|
||||||
|
pkg io/fs, type ReadDirFS interface, Open(string) (File, error)
|
||||||
|
pkg io/fs, type ReadDirFS interface, ReadDir(string) ([]DirEntry, error)
|
||||||
|
pkg io/fs, type ReadDirFile interface { Close, Read, ReadDir, Stat }
|
||||||
|
pkg io/fs, type ReadDirFile interface, Close() error
|
||||||
|
pkg io/fs, type ReadDirFile interface, Read([]uint8) (int, error)
|
||||||
|
pkg io/fs, type ReadDirFile interface, ReadDir(int) ([]DirEntry, error)
|
||||||
|
pkg io/fs, type ReadDirFile interface, Stat() (FileInfo, error)
|
||||||
|
pkg io/fs, type ReadFileFS interface { Open, ReadFile }
|
||||||
|
pkg io/fs, type ReadFileFS interface, Open(string) (File, error)
|
||||||
|
pkg io/fs, type ReadFileFS interface, ReadFile(string) ([]uint8, error)
|
||||||
|
pkg io/fs, type StatFS interface { Open, Stat }
|
||||||
|
pkg io/fs, type StatFS interface, Open(string) (File, error)
|
||||||
|
pkg io/fs, type StatFS interface, Stat(string) (FileInfo, error)
|
||||||
|
pkg io/fs, var ErrClosed error
|
||||||
|
pkg io/fs, var ErrExist error
|
||||||
|
pkg io/fs, var ErrInvalid error
|
||||||
|
pkg io/fs, var ErrNotExist error
|
||||||
|
pkg io/fs, var ErrPermission error
|
||||||
|
pkg log, func Default() *Logger
|
||||||
|
pkg net, var ErrClosed error
|
||||||
|
pkg net/http, func FS(fs.FS) FileSystem
|
||||||
|
pkg net/http, type Transport struct, GetProxyConnectHeader func(context.Context, *url.URL, string) (Header, error)
|
||||||
|
pkg os, const ModeAppend fs.FileMode
|
||||||
|
pkg os, const ModeCharDevice fs.FileMode
|
||||||
|
pkg os, const ModeDevice fs.FileMode
|
||||||
|
pkg os, const ModeDir fs.FileMode
|
||||||
|
pkg os, const ModeExclusive fs.FileMode
|
||||||
|
pkg os, const ModeIrregular fs.FileMode
|
||||||
|
pkg os, const ModeNamedPipe fs.FileMode
|
||||||
|
pkg os, const ModePerm fs.FileMode
|
||||||
|
pkg os, const ModeSetgid fs.FileMode
|
||||||
|
pkg os, const ModeSetuid fs.FileMode
|
||||||
|
pkg os, const ModeSocket fs.FileMode
|
||||||
|
pkg os, const ModeSticky fs.FileMode
|
||||||
|
pkg os, const ModeSymlink fs.FileMode
|
||||||
|
pkg os, const ModeTemporary fs.FileMode
|
||||||
|
pkg os, const ModeType fs.FileMode
|
||||||
|
pkg os, func Chmod(string, fs.FileMode) error
|
||||||
|
pkg os, func DirFS(string) fs.FS
|
||||||
|
pkg os, func Lstat(string) (fs.FileInfo, error)
|
||||||
|
pkg os, func Mkdir(string, fs.FileMode) error
|
||||||
|
pkg os, func MkdirAll(string, fs.FileMode) error
|
||||||
|
pkg os, func OpenFile(string, int, fs.FileMode) (*File, error)
|
||||||
|
pkg os, func SameFile(fs.FileInfo, fs.FileInfo) bool
|
||||||
|
pkg os, func Stat(string) (fs.FileInfo, error)
|
||||||
|
pkg os, method (*File) Chmod(fs.FileMode) error
|
||||||
|
pkg os, method (*File) ReadDir(int) ([]fs.DirEntry, error)
|
||||||
|
pkg os, method (*File) Readdir(int) ([]fs.FileInfo, error)
|
||||||
|
pkg os, method (*File) Stat() (fs.FileInfo, error)
|
||||||
|
pkg os, type DirEntry = fs.DirEntry
|
||||||
|
pkg os, type FileInfo = fs.FileInfo
|
||||||
|
pkg os, type FileMode = fs.FileMode
|
||||||
|
pkg os, type PathError = fs.PathError
|
||||||
|
pkg os/signal, func NotifyContext(context.Context, ...os.Signal) (context.Context, context.CancelFunc)
|
||||||
|
pkg runtime/metrics, const KindBad = 0
|
||||||
|
pkg runtime/metrics, const KindBad ValueKind
|
||||||
|
pkg runtime/metrics, const KindFloat64 = 2
|
||||||
|
pkg runtime/metrics, const KindFloat64 ValueKind
|
||||||
|
pkg runtime/metrics, const KindFloat64Histogram = 3
|
||||||
|
pkg runtime/metrics, const KindFloat64Histogram ValueKind
|
||||||
|
pkg runtime/metrics, const KindUint64 = 1
|
||||||
|
pkg runtime/metrics, const KindUint64 ValueKind
|
||||||
|
pkg runtime/metrics, func All() []Description
|
||||||
|
pkg runtime/metrics, func Read([]Sample)
|
||||||
|
pkg runtime/metrics, method (Value) Float64() float64
|
||||||
|
pkg runtime/metrics, method (Value) Float64Histogram() *Float64Histogram
|
||||||
|
pkg runtime/metrics, method (Value) Kind() ValueKind
|
||||||
|
pkg runtime/metrics, method (Value) Uint64() uint64
|
||||||
|
pkg runtime/metrics, type Description struct
|
||||||
|
pkg runtime/metrics, type Description struct, Cumulative bool
|
||||||
|
pkg runtime/metrics, type Description struct, Description string
|
||||||
|
pkg runtime/metrics, type Description struct, Kind ValueKind
|
||||||
|
pkg runtime/metrics, type Description struct, Name string
|
||||||
|
pkg runtime/metrics, type Description struct, StopTheWorld bool
|
||||||
|
pkg runtime/metrics, type Float64Histogram struct
|
||||||
|
pkg runtime/metrics, type Float64Histogram struct, Buckets []float64
|
||||||
|
pkg runtime/metrics, type Float64Histogram struct, Counts []uint64
|
||||||
|
pkg runtime/metrics, type Sample struct
|
||||||
|
pkg runtime/metrics, type Sample struct, Name string
|
||||||
|
pkg runtime/metrics, type Sample struct, Value Value
|
||||||
|
pkg runtime/metrics, type Value struct
|
||||||
|
pkg runtime/metrics, type ValueKind int
|
||||||
|
pkg syscall (linux-386), func AllThreadsSyscall(uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-386), func AllThreadsSyscall6(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-386), func Setegid(int) error
|
||||||
|
pkg syscall (linux-386), func Seteuid(int) error
|
||||||
|
pkg syscall (linux-386-cgo), func AllThreadsSyscall(uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-386-cgo), func AllThreadsSyscall6(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-386-cgo), func Setegid(int) error
|
||||||
|
pkg syscall (linux-386-cgo), func Seteuid(int) error
|
||||||
|
pkg syscall (linux-amd64), func AllThreadsSyscall(uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-amd64), func AllThreadsSyscall6(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-amd64), func Setegid(int) error
|
||||||
|
pkg syscall (linux-amd64), func Seteuid(int) error
|
||||||
|
pkg syscall (linux-amd64-cgo), func AllThreadsSyscall(uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-amd64-cgo), func AllThreadsSyscall6(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-amd64-cgo), func Setegid(int) error
|
||||||
|
pkg syscall (linux-amd64-cgo), func Seteuid(int) error
|
||||||
|
pkg syscall (linux-arm), func AllThreadsSyscall(uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-arm), func AllThreadsSyscall6(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-arm), func Setegid(int) error
|
||||||
|
pkg syscall (linux-arm), func Seteuid(int) error
|
||||||
|
pkg syscall (linux-arm-cgo), func AllThreadsSyscall(uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-arm-cgo), func AllThreadsSyscall6(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) (uintptr, uintptr, Errno)
|
||||||
|
pkg syscall (linux-arm-cgo), func Setegid(int) error
|
||||||
|
pkg syscall (linux-arm-cgo), func Seteuid(int) error
|
||||||
|
pkg syscall (windows-386), func RtlGenRandom(*uint8, uint32) error
|
||||||
|
pkg syscall (windows-amd64), func RtlGenRandom(*uint8, uint32) error
|
||||||
|
pkg testing/fstest, func TestFS(fs.FS, ...string) error
|
||||||
|
pkg testing/fstest, method (MapFS) Glob(string) ([]string, error)
|
||||||
|
pkg testing/fstest, method (MapFS) Open(string) (fs.File, error)
|
||||||
|
pkg testing/fstest, method (MapFS) ReadDir(string) ([]fs.DirEntry, error)
|
||||||
|
pkg testing/fstest, method (MapFS) ReadFile(string) ([]uint8, error)
|
||||||
|
pkg testing/fstest, method (MapFS) Stat(string) (fs.FileInfo, error)
|
||||||
|
pkg testing/fstest, type MapFS map[string]*MapFile
|
||||||
|
pkg testing/fstest, type MapFile struct
|
||||||
|
pkg testing/fstest, type MapFile struct, Data []uint8
|
||||||
|
pkg testing/fstest, type MapFile struct, ModTime time.Time
|
||||||
|
pkg testing/fstest, type MapFile struct, Mode fs.FileMode
|
||||||
|
pkg testing/fstest, type MapFile struct, Sys interface{}
|
||||||
|
pkg testing/iotest, func ErrReader(error) io.Reader
|
||||||
|
pkg testing/iotest, func TestReader(io.Reader, []uint8) error
|
||||||
|
pkg text/template, func ParseFS(fs.FS, ...string) (*Template, error)
|
||||||
|
pkg text/template, method (*Template) ParseFS(fs.FS, ...string) (*Template, error)
|
||||||
pkg text/template/parse, const NodeComment = 20
|
pkg text/template/parse, const NodeComment = 20
|
||||||
pkg text/template/parse, const NodeComment NodeType
|
pkg text/template/parse, const NodeComment NodeType
|
||||||
pkg text/template/parse, const ParseComments = 1
|
pkg text/template/parse, const ParseComments = 1
|
||||||
|
|
@ -17,3 +445,8 @@ pkg text/template/parse, type CommentNode struct, embedded NodeType
|
||||||
pkg text/template/parse, type CommentNode struct, embedded Pos
|
pkg text/template/parse, type CommentNode struct, embedded Pos
|
||||||
pkg text/template/parse, type Mode uint
|
pkg text/template/parse, type Mode uint
|
||||||
pkg text/template/parse, type Tree struct, Mode Mode
|
pkg text/template/parse, type Tree struct, Mode Mode
|
||||||
|
pkg unicode, const Version = "13.0.0"
|
||||||
|
pkg unicode, var Chorasmian *RangeTable
|
||||||
|
pkg unicode, var Dives_Akuru *RangeTable
|
||||||
|
pkg unicode, var Khitan_Small_Script *RangeTable
|
||||||
|
pkg unicode, var Yezidi *RangeTable
|
||||||
|
|
|
||||||
|
|
@ -947,10 +947,18 @@ The Gerrit voting system involves an integer in the range -2 to +2:
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
At least two maintainers must approve of the change, and at least one
|
||||||
|
of those maintainers must +2 the change.
|
||||||
|
The second maintainer may cast a vote of Trust+1, meaning that the
|
||||||
|
change looks basically OK, but that the maintainer hasn't done the
|
||||||
|
detailed review required for a +2 vote.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="submit">Submitting an approved change</h3>
|
<h3 id="submit">Submitting an approved change</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
After the code has been +2'ed, an approver will
|
After the code has been +2'ed and Trust+1'ed, an approver will
|
||||||
apply it to the master branch using the Gerrit user interface.
|
apply it to the master branch using the Gerrit user interface.
|
||||||
This is called "submitting the change".
|
This is called "submitting the change".
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
137
doc/go1.16.html
137
doc/go1.16.html
|
|
@ -71,6 +71,16 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
TODO: write and link to blog post
|
TODO: write and link to blog post
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p><!-- golang.org/issue/40276 -->
|
||||||
|
<code>go</code> <code>install</code>, with or without a version suffix (as
|
||||||
|
described above), is now the recommended way to build and install packages in
|
||||||
|
module mode. <code>go</code> <code>get</code> should be used with the
|
||||||
|
<code>-d</code> flag to adjust the current module's dependencies without
|
||||||
|
building packages, and use of <code>go</code> <code>get</code> to build and
|
||||||
|
install packages is deprecated. In a future release, the <code>-d</code> flag
|
||||||
|
will always be enabled.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p><!-- golang.org/issue/24031 -->
|
<p><!-- golang.org/issue/24031 -->
|
||||||
<code>retract</code> directives may now be used in a <code>go.mod</code> file
|
<code>retract</code> directives may now be used in a <code>go.mod</code> file
|
||||||
to indicate that certain published versions of the module should not be used
|
to indicate that certain published versions of the module should not be used
|
||||||
|
|
@ -110,6 +120,16 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
See <code>go</code> <code>help</code> <code>environment</code> for details.
|
See <code>go</code> <code>help</code> <code>environment</code> for details.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h4 id="go-get"><code>go</code> <code>get</code></h4>
|
||||||
|
|
||||||
|
<p><!-- golang.org/cl/263267 -->
|
||||||
|
<code>go</code> <code>get</code> <code>example.com/mod@patch</code> now
|
||||||
|
requires that some version of <code>example.com/mod</code> already be
|
||||||
|
required by the main module.
|
||||||
|
(However, <code>go</code> <code>get</code> <code>-u=patch</code> continues
|
||||||
|
to patch even newly-added dependencies.)
|
||||||
|
</p>
|
||||||
|
|
||||||
<h4 id="all-pattern">The <code>all</code> pattern</h4>
|
<h4 id="all-pattern">The <code>all</code> pattern</h4>
|
||||||
|
|
||||||
<p><!-- golang.org/cl/240623 -->
|
<p><!-- golang.org/cl/240623 -->
|
||||||
|
|
@ -122,6 +142,37 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
by <code>go</code> <code>mod</code> <code>vendor</code> since Go 1.11.
|
by <code>go</code> <code>mod</code> <code>vendor</code> since Go 1.11.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h4 id="toolexec">The <code>-toolexec</code> build flag</h4>
|
||||||
|
|
||||||
|
<p><!-- golang.org/cl/263357 -->
|
||||||
|
When the <code>-toolexec</code> build flag is specified to use a program when
|
||||||
|
invoking toolchain programs like compile or asm, the environment variable
|
||||||
|
<code>TOOLEXEC_IMPORTPATH</code> is now set to the import path of the package
|
||||||
|
being built.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="i-flag">The <code>-i</code> build flag</h4>
|
||||||
|
|
||||||
|
<p><!-- golang.org/issue/41696 -->
|
||||||
|
The <code>-i</code> flag accepted by <code>go</code> <code>build</code>,
|
||||||
|
<code>go</code> <code>install</code>, and <code>go</code> <code>test</code> is
|
||||||
|
now deprecated. The <code>-i</code> flag instructs the <code>go</code> command
|
||||||
|
to install packages imported by packages named on the command line. Since
|
||||||
|
the build cache was introduced in Go 1.10, the <code>-i</code> flag no longer
|
||||||
|
has a significant effect on build times, and it causes errors when the install
|
||||||
|
directory is not writable.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="list-buildid">The <code>list</code> command</h4>
|
||||||
|
|
||||||
|
<p><!-- golang.org/cl/263542 -->
|
||||||
|
When the <code>-export</code> flag is specified, the <code>BuildID</code>
|
||||||
|
field is now set to the build ID of the compiled package. This is equivalent
|
||||||
|
to running <code>go</code> <code>tool</code> <code>buildid</code> on
|
||||||
|
<code>go</code> <code>list</code> <code>-exported</code> <code>-f</code> <code>{{.Export}</code>,
|
||||||
|
but without the extra step.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="cgo">Cgo</h3>
|
<h3 id="cgo">Cgo</h3>
|
||||||
|
|
||||||
<p> <!-- CL 252378 -->
|
<p> <!-- CL 252378 -->
|
||||||
|
|
@ -142,6 +193,18 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
TODO
|
TODO
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p><!-- CL 267100 -->
|
||||||
|
On Linux, the runtime now defaults to releasing memory to the
|
||||||
|
operating system promptly (using <code>MADV_DONTNEED</code>), rather
|
||||||
|
than lazily when the operating system is under memory pressure
|
||||||
|
(using <code>MADV_FREE</code>). This means process-level memory
|
||||||
|
statistics like RSS will more accurately reflect the amount of
|
||||||
|
physical memory being used by Go processes. Systems that are
|
||||||
|
currently using <code>GODEBUG=madvdontneed=1</code> to improve
|
||||||
|
memory monitoring behavior no longer need to set this environment
|
||||||
|
variable.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2 id="compiler">Compiler</h2>
|
<h2 id="compiler">Compiler</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -173,7 +236,10 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
TODO: update with final numbers later in the release.
|
TODO: update with final numbers later in the release.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- CL 255259: https://golang.org/cl/255259: cmd/link: enable ASLR on windows binaries built with -buildmode=c-shared -->
|
<p> <!-- CL 255259 -->
|
||||||
|
On Windows, <code>go build -buildmode=c-shared</code> now generates Windows
|
||||||
|
ASLR DLLs by default. ASLR can be disabled with <code>--ldflags=-aslr=false</code>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2 id="library">Core library</h2>
|
<h2 id="library">Core library</h2>
|
||||||
|
|
||||||
|
|
@ -199,6 +265,27 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
by the <code>Error</code> method with <code>"tls: use of closed connection"</code>.
|
by the <code>Error</code> method with <code>"tls: use of closed connection"</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p><!-- CL 266037 -->
|
||||||
|
A default deadline is set in <a href="/pkg/crypto/tls/#Conn.Close">Close</a>
|
||||||
|
before sending the close notify alert, in order to prevent blocking
|
||||||
|
indefinitely.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><!-- CL 246338 -->
|
||||||
|
<a href="/pkg/crypto/tls#Conn.HandshakeContext">(*Conn).HandshakeContext</a> was added to
|
||||||
|
allow the user to control cancellation of an in-progress TLS Handshake.
|
||||||
|
The context provided is propagated into the
|
||||||
|
<a href="/pkg/crypto/tls#ClientHelloInfo">ClientHelloInfo</a>
|
||||||
|
and <a href="/pkg/crypto/tls#CertificateRequestInfo">CertificateRequestInfo</a>
|
||||||
|
structs and accessible through the new
|
||||||
|
<a href="/pkg/crypto/tls#ClientHelloInfo.Context">(*ClientHelloInfo).Context</a>
|
||||||
|
and
|
||||||
|
<a href="/pkg/crypto/tls#CertificateRequestInfo.Context">
|
||||||
|
(*CertificateRequestInfo).Context
|
||||||
|
</a> methods respectively. Canceling the context after the handshake has finished
|
||||||
|
has no effect.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="crypto/x509"><a href="/pkg/crypto/x509">crypto/x509</a></h3>
|
<h3 id="crypto/x509"><a href="/pkg/crypto/x509">crypto/x509</a></h3>
|
||||||
|
|
||||||
<p><!-- CL 235078 -->
|
<p><!-- CL 235078 -->
|
||||||
|
|
@ -216,6 +303,14 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
of a malformed certificate.
|
of a malformed certificate.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3 id="encoding/json"><a href="/pkg/encoding/json">encoding/json</a></h3>
|
||||||
|
|
||||||
|
<p><!-- CL 263619 -->
|
||||||
|
The error message for
|
||||||
|
<a href="/pkg/encoding/json/#SyntaxError">SyntaxError</a>
|
||||||
|
now begins with "json: ", matching the other errors in the package.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="net"><a href="/pkg/net/">net</a></h3>
|
<h3 id="net"><a href="/pkg/net/">net</a></h3>
|
||||||
|
|
||||||
<p><!-- CL 250357 -->
|
<p><!-- CL 250357 -->
|
||||||
|
|
@ -228,13 +323,10 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
with <code>"use of closed network connection"</code>.
|
with <code>"use of closed network connection"</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 id="reflect"><a href="/pkg/reflect/">reflect</a></h3>
|
<p><!-- CL 255898 -->
|
||||||
|
In previous Go releases the default TCP listener backlog size on Linux systems,
|
||||||
<p><!-- CL 259237, golang.org/issue/22075 -->
|
set by <code>/proc/sys/net/core/somaxconn</code>, was limited to a maximum of <code>65535</code>.
|
||||||
For interface types and values, <a href="/pkg/reflect/#Value.Method">Method</a>,
|
On Linux kernel version 4.1 and above, the maximum is now <code>4294967295</code>.
|
||||||
<a href="/pkg/reflect/#Value.MethodByName">MethodByName</a>, and
|
|
||||||
<a href="/pkg/reflect/#Value.NumMethod">NumMethod</a> now
|
|
||||||
operate on the interface's exported method set, rather than its full method set.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 id="text/template/parse"><a href="/pkg/text/template/parse/">text/template/parse</a></h3>
|
<h3 id="text/template/parse"><a href="/pkg/text/template/parse/">text/template/parse</a></h3>
|
||||||
|
|
@ -288,6 +380,20 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
</dd>
|
</dd>
|
||||||
</dl><!-- crypto/x509 -->
|
</dl><!-- crypto/x509 -->
|
||||||
|
|
||||||
|
<dl id="encoding/xml"><dt><a href="/pkg/encoding/xml/">encoding/xml</a></dt>
|
||||||
|
<dd>
|
||||||
|
<p><!-- CL 264024 -->
|
||||||
|
The encoder has always taken care to avoid using namespace prefixes
|
||||||
|
beginning with <code>xml</code>, which are reserved by the XML
|
||||||
|
specification.
|
||||||
|
Now, following the specification more closely, that check is
|
||||||
|
case-insensitive, so that prefixes beginning
|
||||||
|
with <code>XML</code>, <code>XmL</code>, and so on are also
|
||||||
|
avoided.
|
||||||
|
</p>
|
||||||
|
</dd>
|
||||||
|
</dl><!-- encoding/xml -->
|
||||||
|
|
||||||
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p><!-- CL 233637 -->
|
<p><!-- CL 233637 -->
|
||||||
|
|
@ -314,6 +420,13 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
Cookies set with <code>SameSiteDefaultMode</code> now behave according to the current
|
Cookies set with <code>SameSiteDefaultMode</code> now behave according to the current
|
||||||
spec (no attribute is set) instead of generating a SameSite key without a value.
|
spec (no attribute is set) instead of generating a SameSite key without a value.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p><!-- CL 246338 -->
|
||||||
|
The <a href="/pkg/net/http/"><code>net/http</code></a> package now uses the new
|
||||||
|
<a href="/pkg/crypto/tls#Conn.HandshakeContext"><code>(*tls.Conn).HandshakeContext</code></a>
|
||||||
|
with the <a href="/pkg/net/http/#Request"><code>Request</code></a> context
|
||||||
|
when performing TLS handshakes in the client or server.
|
||||||
|
</p>
|
||||||
</dd>
|
</dd>
|
||||||
</dl><!-- net/http -->
|
</dl><!-- net/http -->
|
||||||
|
|
||||||
|
|
@ -325,6 +438,14 @@ Do not send CLs removing the interior tags from such phrases.
|
||||||
</dd>
|
</dd>
|
||||||
</dl><!-- runtime/debug -->
|
</dl><!-- runtime/debug -->
|
||||||
|
|
||||||
|
<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
|
||||||
|
<dd>
|
||||||
|
<p><!-- CL 261917 -->
|
||||||
|
<a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a> on Windows has a new NoInheritHandles field that disables inheriting handles when creating a new process.
|
||||||
|
</p>
|
||||||
|
</dd>
|
||||||
|
</dl><!-- syscall -->
|
||||||
|
|
||||||
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
|
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p><!-- CL 260858 -->
|
<p><!-- CL 260858 -->
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<!--{
|
<!--{
|
||||||
"Title": "The Go Programming Language Specification",
|
"Title": "The Go Programming Language Specification",
|
||||||
"Subtitle": "Version of Sep 24, 2020",
|
"Subtitle": "Version of Oct 7, 2020",
|
||||||
"Path": "/ref/spec"
|
"Path": "/ref/spec"
|
||||||
}-->
|
}-->
|
||||||
|
|
||||||
|
|
@ -3594,23 +3594,33 @@ replaced by its left operand alone.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
var a [1024]byte
|
||||||
var s uint = 33
|
var s uint = 33
|
||||||
|
|
||||||
|
// The results of the following examples are given for 64-bit ints.
|
||||||
var i = 1<<s // 1 has type int
|
var i = 1<<s // 1 has type int
|
||||||
var j int32 = 1<<s // 1 has type int32; j == 0
|
var j int32 = 1<<s // 1 has type int32; j == 0
|
||||||
var k = uint64(1<<s) // 1 has type uint64; k == 1<<33
|
var k = uint64(1<<s) // 1 has type uint64; k == 1<<33
|
||||||
var m int = 1.0<<s // 1.0 has type int; m == 0 if ints are 32bits in size
|
var m int = 1.0<<s // 1.0 has type int; m == 1<<33
|
||||||
var n = 1.0<<s == j // 1.0 has type int32; n == true
|
var n = 1.0<<s == j // 1.0 has type int; n == true
|
||||||
var o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
|
var o = 1<<s == 2<<s // 1 and 2 have type int; o == false
|
||||||
var p = 1<<s == 1<<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
|
var p = 1<<s == 1<<33 // 1 has type int; p == true
|
||||||
var u = 1.0<<s // illegal: 1.0 has type float64, cannot shift
|
var u = 1.0<<s // illegal: 1.0 has type float64, cannot shift
|
||||||
var u1 = 1.0<<s != 0 // illegal: 1.0 has type float64, cannot shift
|
var u1 = 1.0<<s != 0 // illegal: 1.0 has type float64, cannot shift
|
||||||
var u2 = 1<<s != 1.0 // illegal: 1 has type float64, cannot shift
|
var u2 = 1<<s != 1.0 // illegal: 1 has type float64, cannot shift
|
||||||
var v float32 = 1<<s // illegal: 1 has type float32, cannot shift
|
var v float32 = 1<<s // illegal: 1 has type float32, cannot shift
|
||||||
var w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression
|
var w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression; w == 1<<33
|
||||||
var x = a[1.0<<s] // 1.0 has type int; x == a[0] if ints are 32bits in size
|
var x = a[1.0<<s] // panics: 1.0 has type int, but 1<<33 overflows array bounds
|
||||||
var a = make([]byte, 1.0<<s) // 1.0 has type int; len(a) == 0 if ints are 32bits in size
|
var b = make([]byte, 1.0<<s) // 1.0 has type int; len(b) == 1<<33
|
||||||
</pre>
|
|
||||||
|
|
||||||
|
// The results of the following examples are given for 32-bit ints,
|
||||||
|
// which means the shifts will overflow.
|
||||||
|
var mm int = 1.0<<s // 1.0 has type int; mm == 0
|
||||||
|
var oo = 1<<s == 2<<s // 1 and 2 have type int; oo == true
|
||||||
|
var pp = 1<<s == 1<<33 // illegal: 1 has type int, but 1<<33 overflows int
|
||||||
|
var xx = a[1.0<<s] // 1.0 has type int; xx == a[0]
|
||||||
|
var bb = make([]byte, 1.0<<s) // 1.0 has type int; len(bb) == 0
|
||||||
|
</pre>
|
||||||
|
|
||||||
<h4 id="Operator_precedence">Operator precedence</h4>
|
<h4 id="Operator_precedence">Operator precedence</h4>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
# Consult https://www.iana.org/time-zones for the latest versions.
|
# Consult https://www.iana.org/time-zones for the latest versions.
|
||||||
|
|
||||||
# Versions to use.
|
# Versions to use.
|
||||||
CODE=2020b
|
CODE=2020d
|
||||||
DATA=2020b
|
DATA=2020d
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
rm -rf work
|
rm -rf work
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -181,7 +181,7 @@ func testCallbackCallers(t *testing.T) {
|
||||||
name := []string{
|
name := []string{
|
||||||
"runtime.cgocallbackg1",
|
"runtime.cgocallbackg1",
|
||||||
"runtime.cgocallbackg",
|
"runtime.cgocallbackg",
|
||||||
"runtime.cgocallback_gofunc",
|
"runtime.cgocallback",
|
||||||
"runtime.asmcgocall",
|
"runtime.asmcgocall",
|
||||||
"runtime.cgocall",
|
"runtime.cgocall",
|
||||||
"test._Cfunc_callback",
|
"test._Cfunc_callback",
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,6 @@ func TestSetgid(t *testing.T) {
|
||||||
}
|
}
|
||||||
testSetgid(t)
|
testSetgid(t)
|
||||||
}
|
}
|
||||||
|
func Test1435(t *testing.T) { test1435(t) }
|
||||||
func Test6997(t *testing.T) { test6997(t) }
|
func Test6997(t *testing.T) { test6997(t) }
|
||||||
func TestBuildID(t *testing.T) { testBuildID(t) }
|
func TestBuildID(t *testing.T) { testBuildID(t) }
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,8 @@ func TestCheckConst(t *testing.T) { testCheckConst(t) }
|
||||||
func TestConst(t *testing.T) { testConst(t) }
|
func TestConst(t *testing.T) { testConst(t) }
|
||||||
func TestCthread(t *testing.T) { testCthread(t) }
|
func TestCthread(t *testing.T) { testCthread(t) }
|
||||||
func TestEnum(t *testing.T) { testEnum(t) }
|
func TestEnum(t *testing.T) { testEnum(t) }
|
||||||
|
func TestNamedEnum(t *testing.T) { testNamedEnum(t) }
|
||||||
|
func TestCastToEnum(t *testing.T) { testCastToEnum(t) }
|
||||||
func TestErrno(t *testing.T) { testErrno(t) }
|
func TestErrno(t *testing.T) { testErrno(t) }
|
||||||
func TestFpVar(t *testing.T) { testFpVar(t) }
|
func TestFpVar(t *testing.T) { testFpVar(t) }
|
||||||
func TestHelpers(t *testing.T) { testHelpers(t) }
|
func TestHelpers(t *testing.T) { testHelpers(t) }
|
||||||
|
|
|
||||||
152
misc/cgo/test/issue1435.go
Normal file
152
misc/cgo/test/issue1435.go
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build linux,cgo
|
||||||
|
|
||||||
|
package cgotest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include <stdio.h>
|
||||||
|
// #include <stdlib.h>
|
||||||
|
// #include <pthread.h>
|
||||||
|
// #include <unistd.h>
|
||||||
|
// #include <sys/types.h>
|
||||||
|
//
|
||||||
|
// pthread_t *t = NULL;
|
||||||
|
// pthread_mutex_t mu;
|
||||||
|
// int nts = 0;
|
||||||
|
// int all_done = 0;
|
||||||
|
//
|
||||||
|
// static void *aFn(void *vargp) {
|
||||||
|
// int done = 0;
|
||||||
|
// while (!done) {
|
||||||
|
// usleep(100);
|
||||||
|
// pthread_mutex_lock(&mu);
|
||||||
|
// done = all_done;
|
||||||
|
// pthread_mutex_unlock(&mu);
|
||||||
|
// }
|
||||||
|
// return NULL;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// void trial(int argc) {
|
||||||
|
// int i;
|
||||||
|
// nts = argc;
|
||||||
|
// t = calloc(nts, sizeof(pthread_t));
|
||||||
|
// pthread_mutex_init(&mu, NULL);
|
||||||
|
// for (i = 0; i < nts; i++) {
|
||||||
|
// pthread_create(&t[i], NULL, aFn, NULL);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// void cleanup(void) {
|
||||||
|
// int i;
|
||||||
|
// pthread_mutex_lock(&mu);
|
||||||
|
// all_done = 1;
|
||||||
|
// pthread_mutex_unlock(&mu);
|
||||||
|
// for (i = 0; i < nts; i++) {
|
||||||
|
// pthread_join(t[i], NULL);
|
||||||
|
// }
|
||||||
|
// pthread_mutex_destroy(&mu);
|
||||||
|
// free(t);
|
||||||
|
// }
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// compareStatus is used to confirm the contents of the thread
|
||||||
|
// specific status files match expectations.
|
||||||
|
func compareStatus(filter, expect string) error {
|
||||||
|
expected := filter + "\t" + expect
|
||||||
|
pid := syscall.Getpid()
|
||||||
|
fs, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to find %d tasks: %v", pid, err)
|
||||||
|
}
|
||||||
|
for _, f := range fs {
|
||||||
|
tf := fmt.Sprintf("/proc/%s/status", f.Name())
|
||||||
|
d, err := ioutil.ReadFile(tf)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to read %q: %v", tf, err)
|
||||||
|
}
|
||||||
|
lines := strings.Split(string(d), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.HasPrefix(line, filter) {
|
||||||
|
if line != expected {
|
||||||
|
return fmt.Errorf("%s %s (bad)\n", tf, line)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// test1435 test 9 glibc implemented setuid/gid syscall functions are
|
||||||
|
// mapped. This test is a slightly more expansive test than that of
|
||||||
|
// src/syscall/syscall_linux_test.go:TestSetuidEtc() insofar as it
|
||||||
|
// launches concurrent threads from C code via CGo and validates that
|
||||||
|
// they are subject to the system calls being tested. For the actual
|
||||||
|
// Go functionality being tested here, the syscall_linux_test version
|
||||||
|
// is considered authoritative, but non-trivial improvements to that
|
||||||
|
// should be mirrored here.
|
||||||
|
func test1435(t *testing.T) {
|
||||||
|
if syscall.Getuid() != 0 {
|
||||||
|
t.Skip("skipping root only test")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launch some threads in C.
|
||||||
|
const cts = 5
|
||||||
|
C.trial(cts)
|
||||||
|
defer C.cleanup()
|
||||||
|
|
||||||
|
vs := []struct {
|
||||||
|
call string
|
||||||
|
fn func() error
|
||||||
|
filter, expect string
|
||||||
|
}{
|
||||||
|
{call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "0\t1\t0\t1"},
|
||||||
|
{call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
|
||||||
|
|
||||||
|
{call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "0\t1\t0\t1"},
|
||||||
|
{call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
|
||||||
|
|
||||||
|
{call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "1\t1\t1\t1"},
|
||||||
|
{call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
|
||||||
|
|
||||||
|
{call: "Setgroups([]int{0,1,2,3})", fn: func() error { return syscall.Setgroups([]int{0, 1, 2, 3}) }, filter: "Groups:", expect: "0 1 2 3 "},
|
||||||
|
{call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: " "},
|
||||||
|
{call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "0 "},
|
||||||
|
|
||||||
|
{call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "101\t0\t0\t0"},
|
||||||
|
{call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "0\t102\t102\t102"},
|
||||||
|
{call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
|
||||||
|
|
||||||
|
{call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "1\t0\t0\t0"},
|
||||||
|
{call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "0\t2\t2\t2"},
|
||||||
|
{call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
|
||||||
|
|
||||||
|
{call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "101\t0\t102\t0"},
|
||||||
|
{call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "0\t102\t101\t102"},
|
||||||
|
{call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
|
||||||
|
|
||||||
|
{call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "1\t0\t2\t0"},
|
||||||
|
{call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "0\t2\t1\t2"},
|
||||||
|
{call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range vs {
|
||||||
|
if err := v.fn(); err != nil {
|
||||||
|
t.Errorf("[%d] %q failed: %v", i, v.call, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := compareStatus(v.filter, v.expect); err != nil {
|
||||||
|
t.Errorf("[%d] %q comparison: %v", i, v.call, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !windows,!static
|
// +build !windows,!static
|
||||||
// +build !darwin !internal_pie
|
// +build !darwin !internal_pie,!arm64
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,11 @@
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build !windows,!static
|
// +build !windows,!static
|
||||||
// +build !darwin !internal_pie
|
// +build !darwin !internal_pie,!arm64
|
||||||
|
|
||||||
// Excluded in darwin internal linking PIE mode, as dynamic export is not
|
// Excluded in darwin internal linking PIE mode, as dynamic export is not
|
||||||
// supported.
|
// supported.
|
||||||
|
// Excluded in internal linking mode on darwin/arm64, as it is always PIE.
|
||||||
|
|
||||||
package cgotest
|
package cgotest
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build windows static darwin,internal_pie
|
// +build windows static darwin,internal_pie darwin,arm64
|
||||||
|
|
||||||
package cgotest
|
package cgotest
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1000,6 +1000,32 @@ func testEnum(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testNamedEnum(t *testing.T) {
|
||||||
|
e := new(C.enum_E)
|
||||||
|
|
||||||
|
*e = C.Enum1
|
||||||
|
if *e != 1 {
|
||||||
|
t.Error("bad enum", C.Enum1)
|
||||||
|
}
|
||||||
|
|
||||||
|
*e = C.Enum2
|
||||||
|
if *e != 2 {
|
||||||
|
t.Error("bad enum", C.Enum2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCastToEnum(t *testing.T) {
|
||||||
|
e := C.enum_E(C.Enum1)
|
||||||
|
if e != 1 {
|
||||||
|
t.Error("bad enum", C.Enum1)
|
||||||
|
}
|
||||||
|
|
||||||
|
e = C.enum_E(C.Enum2)
|
||||||
|
if e != 2 {
|
||||||
|
t.Error("bad enum", C.Enum2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testAtol(t *testing.T) {
|
func testAtol(t *testing.T) {
|
||||||
l := Atol("123")
|
l := Atol("123")
|
||||||
if l != 123 {
|
if l != 123 {
|
||||||
|
|
|
||||||
31
misc/cgo/test/testdata/issue9400/asm_riscv64.s
vendored
Normal file
31
misc/cgo/test/testdata/issue9400/asm_riscv64.s
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build riscv64
|
||||||
|
// +build !gccgo
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
TEXT ·RewindAndSetgid(SB),NOSPLIT|NOFRAME,$0-0
|
||||||
|
// Rewind stack pointer so anything that happens on the stack
|
||||||
|
// will clobber the test pattern created by the caller
|
||||||
|
ADD $(1024*8), X2
|
||||||
|
|
||||||
|
// Ask signaller to setgid
|
||||||
|
MOV $1, X5
|
||||||
|
FENCE
|
||||||
|
MOVW X5, ·Baton(SB)
|
||||||
|
FENCE
|
||||||
|
|
||||||
|
// Wait for setgid completion
|
||||||
|
loop:
|
||||||
|
FENCE
|
||||||
|
MOVW ·Baton(SB), X5
|
||||||
|
OR X6, X6, X6 // hint that we're in a spin loop
|
||||||
|
BNE ZERO, X5, loop
|
||||||
|
FENCE
|
||||||
|
|
||||||
|
// Restore stack
|
||||||
|
ADD $(-1024*8), X2
|
||||||
|
RET
|
||||||
|
|
@ -7,6 +7,8 @@ package cshared_test
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
|
"debug/pe"
|
||||||
|
"encoding/binary"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
@ -355,6 +357,101 @@ func TestExportedSymbols(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkNumberOfExportedFunctionsWindows(t *testing.T, exportAllSymbols bool) {
|
||||||
|
const prog = `
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
//export GoFunc
|
||||||
|
func GoFunc() {
|
||||||
|
println(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export GoFunc2
|
||||||
|
func GoFunc2() {
|
||||||
|
println(24)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
tmpdir := t.TempDir()
|
||||||
|
|
||||||
|
srcfile := filepath.Join(tmpdir, "test.go")
|
||||||
|
objfile := filepath.Join(tmpdir, "test.dll")
|
||||||
|
if err := ioutil.WriteFile(srcfile, []byte(prog), 0666); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
argv := []string{"build", "-buildmode=c-shared"}
|
||||||
|
if exportAllSymbols {
|
||||||
|
argv = append(argv, "-ldflags", "-extldflags=-Wl,--export-all-symbols")
|
||||||
|
}
|
||||||
|
argv = append(argv, "-o", objfile, srcfile)
|
||||||
|
out, err := exec.Command("go", argv...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("build failure: %s\n%s\n", err, string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := pe.Open(objfile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("pe.Open failed: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
section := f.Section(".edata")
|
||||||
|
if section == nil {
|
||||||
|
t.Fatalf(".edata section is not present")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
|
||||||
|
type IMAGE_EXPORT_DIRECTORY struct {
|
||||||
|
_ [2]uint32
|
||||||
|
_ [2]uint16
|
||||||
|
_ [2]uint32
|
||||||
|
NumberOfFunctions uint32
|
||||||
|
NumberOfNames uint32
|
||||||
|
_ [3]uint32
|
||||||
|
}
|
||||||
|
var e IMAGE_EXPORT_DIRECTORY
|
||||||
|
if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil {
|
||||||
|
t.Fatalf("binary.Read failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only the two exported functions and _cgo_dummy_export should be exported
|
||||||
|
expectedNumber := uint32(3)
|
||||||
|
|
||||||
|
if exportAllSymbols {
|
||||||
|
if e.NumberOfFunctions <= expectedNumber {
|
||||||
|
t.Fatalf("missing exported functions: %v", e.NumberOfFunctions)
|
||||||
|
}
|
||||||
|
if e.NumberOfNames <= expectedNumber {
|
||||||
|
t.Fatalf("missing exported names: %v", e.NumberOfNames)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if e.NumberOfFunctions != expectedNumber {
|
||||||
|
t.Fatalf("got %d exported functions; want %d", e.NumberOfFunctions, expectedNumber)
|
||||||
|
}
|
||||||
|
if e.NumberOfNames != expectedNumber {
|
||||||
|
t.Fatalf("got %d exported names; want %d", e.NumberOfNames, expectedNumber)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNumberOfExportedFunctions(t *testing.T) {
|
||||||
|
if GOOS != "windows" {
|
||||||
|
t.Skip("skipping windows only test")
|
||||||
|
}
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("OnlyExported", func(t *testing.T) {
|
||||||
|
checkNumberOfExportedFunctionsWindows(t, false)
|
||||||
|
})
|
||||||
|
t.Run("All", func(t *testing.T) {
|
||||||
|
checkNumberOfExportedFunctionsWindows(t, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// test1: shared library can be dynamically loaded and exported symbols are accessible.
|
// test1: shared library can be dynamically loaded and exported symbols are accessible.
|
||||||
func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
|
func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.crypto) {
|
if (!global.crypto && global.require) {
|
||||||
const nodeCrypto = require("crypto");
|
const nodeCrypto = require("crypto");
|
||||||
global.crypto = {
|
global.crypto = {
|
||||||
getRandomValues(b) {
|
getRandomValues(b) {
|
||||||
|
|
@ -110,6 +110,9 @@
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (!global.crypto) {
|
||||||
|
throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
|
||||||
|
}
|
||||||
|
|
||||||
if (!global.performance) {
|
if (!global.performance) {
|
||||||
global.performance = {
|
global.performance = {
|
||||||
|
|
@ -120,13 +123,19 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.TextEncoder) {
|
if (!global.TextEncoder && global.require) {
|
||||||
global.TextEncoder = require("util").TextEncoder;
|
global.TextEncoder = require("util").TextEncoder;
|
||||||
}
|
}
|
||||||
|
if (!global.TextEncoder) {
|
||||||
|
throw new Error("global.TextEncoder is not available, polyfill required");
|
||||||
|
}
|
||||||
|
|
||||||
if (!global.TextDecoder) {
|
if (!global.TextDecoder && global.require) {
|
||||||
global.TextDecoder = require("util").TextDecoder;
|
global.TextDecoder = require("util").TextDecoder;
|
||||||
}
|
}
|
||||||
|
if (!global.TextDecoder) {
|
||||||
|
throw new Error("global.TextDecoder is not available, polyfill required");
|
||||||
|
}
|
||||||
|
|
||||||
// End of polyfills for common API.
|
// End of polyfills for common API.
|
||||||
|
|
||||||
|
|
@ -255,6 +264,7 @@
|
||||||
|
|
||||||
// func wasmExit(code int32)
|
// func wasmExit(code int32)
|
||||||
"runtime.wasmExit": (sp) => {
|
"runtime.wasmExit": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const code = this.mem.getInt32(sp + 8, true);
|
const code = this.mem.getInt32(sp + 8, true);
|
||||||
this.exited = true;
|
this.exited = true;
|
||||||
delete this._inst;
|
delete this._inst;
|
||||||
|
|
@ -267,6 +277,7 @@
|
||||||
|
|
||||||
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
||||||
"runtime.wasmWrite": (sp) => {
|
"runtime.wasmWrite": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const fd = getInt64(sp + 8);
|
const fd = getInt64(sp + 8);
|
||||||
const p = getInt64(sp + 16);
|
const p = getInt64(sp + 16);
|
||||||
const n = this.mem.getInt32(sp + 24, true);
|
const n = this.mem.getInt32(sp + 24, true);
|
||||||
|
|
@ -275,16 +286,19 @@
|
||||||
|
|
||||||
// func resetMemoryDataView()
|
// func resetMemoryDataView()
|
||||||
"runtime.resetMemoryDataView": (sp) => {
|
"runtime.resetMemoryDataView": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
this.mem = new DataView(this._inst.exports.mem.buffer);
|
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func nanotime1() int64
|
// func nanotime1() int64
|
||||||
"runtime.nanotime1": (sp) => {
|
"runtime.nanotime1": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
|
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func walltime1() (sec int64, nsec int32)
|
// func walltime1() (sec int64, nsec int32)
|
||||||
"runtime.walltime1": (sp) => {
|
"runtime.walltime1": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const msec = (new Date).getTime();
|
const msec = (new Date).getTime();
|
||||||
setInt64(sp + 8, msec / 1000);
|
setInt64(sp + 8, msec / 1000);
|
||||||
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
|
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
|
||||||
|
|
@ -292,6 +306,7 @@
|
||||||
|
|
||||||
// func scheduleTimeoutEvent(delay int64) int32
|
// func scheduleTimeoutEvent(delay int64) int32
|
||||||
"runtime.scheduleTimeoutEvent": (sp) => {
|
"runtime.scheduleTimeoutEvent": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const id = this._nextCallbackTimeoutID;
|
const id = this._nextCallbackTimeoutID;
|
||||||
this._nextCallbackTimeoutID++;
|
this._nextCallbackTimeoutID++;
|
||||||
this._scheduledTimeouts.set(id, setTimeout(
|
this._scheduledTimeouts.set(id, setTimeout(
|
||||||
|
|
@ -311,6 +326,7 @@
|
||||||
|
|
||||||
// func clearTimeoutEvent(id int32)
|
// func clearTimeoutEvent(id int32)
|
||||||
"runtime.clearTimeoutEvent": (sp) => {
|
"runtime.clearTimeoutEvent": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const id = this.mem.getInt32(sp + 8, true);
|
const id = this.mem.getInt32(sp + 8, true);
|
||||||
clearTimeout(this._scheduledTimeouts.get(id));
|
clearTimeout(this._scheduledTimeouts.get(id));
|
||||||
this._scheduledTimeouts.delete(id);
|
this._scheduledTimeouts.delete(id);
|
||||||
|
|
@ -318,11 +334,13 @@
|
||||||
|
|
||||||
// func getRandomData(r []byte)
|
// func getRandomData(r []byte)
|
||||||
"runtime.getRandomData": (sp) => {
|
"runtime.getRandomData": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
crypto.getRandomValues(loadSlice(sp + 8));
|
crypto.getRandomValues(loadSlice(sp + 8));
|
||||||
},
|
},
|
||||||
|
|
||||||
// func finalizeRef(v ref)
|
// func finalizeRef(v ref)
|
||||||
"syscall/js.finalizeRef": (sp) => {
|
"syscall/js.finalizeRef": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const id = this.mem.getUint32(sp + 8, true);
|
const id = this.mem.getUint32(sp + 8, true);
|
||||||
this._goRefCounts[id]--;
|
this._goRefCounts[id]--;
|
||||||
if (this._goRefCounts[id] === 0) {
|
if (this._goRefCounts[id] === 0) {
|
||||||
|
|
@ -335,44 +353,51 @@
|
||||||
|
|
||||||
// func stringVal(value string) ref
|
// func stringVal(value string) ref
|
||||||
"syscall/js.stringVal": (sp) => {
|
"syscall/js.stringVal": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
storeValue(sp + 24, loadString(sp + 8));
|
storeValue(sp + 24, loadString(sp + 8));
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueGet(v ref, p string) ref
|
// func valueGet(v ref, p string) ref
|
||||||
"syscall/js.valueGet": (sp) => {
|
"syscall/js.valueGet": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
|
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
|
||||||
sp = this._inst.exports.getsp(); // see comment above
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
storeValue(sp + 32, result);
|
storeValue(sp + 32, result);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueSet(v ref, p string, x ref)
|
// func valueSet(v ref, p string, x ref)
|
||||||
"syscall/js.valueSet": (sp) => {
|
"syscall/js.valueSet": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
|
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueDelete(v ref, p string)
|
// func valueDelete(v ref, p string)
|
||||||
"syscall/js.valueDelete": (sp) => {
|
"syscall/js.valueDelete": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
|
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueIndex(v ref, i int) ref
|
// func valueIndex(v ref, i int) ref
|
||||||
"syscall/js.valueIndex": (sp) => {
|
"syscall/js.valueIndex": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
|
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
|
||||||
},
|
},
|
||||||
|
|
||||||
// valueSetIndex(v ref, i int, x ref)
|
// valueSetIndex(v ref, i int, x ref)
|
||||||
"syscall/js.valueSetIndex": (sp) => {
|
"syscall/js.valueSetIndex": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
|
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||||
"syscall/js.valueCall": (sp) => {
|
"syscall/js.valueCall": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
try {
|
try {
|
||||||
const v = loadValue(sp + 8);
|
const v = loadValue(sp + 8);
|
||||||
const m = Reflect.get(v, loadString(sp + 16));
|
const m = Reflect.get(v, loadString(sp + 16));
|
||||||
const args = loadSliceOfValues(sp + 32);
|
const args = loadSliceOfValues(sp + 32);
|
||||||
const result = Reflect.apply(m, v, args);
|
const result = Reflect.apply(m, v, args);
|
||||||
sp = this._inst.exports.getsp(); // see comment above
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
storeValue(sp + 56, result);
|
storeValue(sp + 56, result);
|
||||||
this.mem.setUint8(sp + 64, 1);
|
this.mem.setUint8(sp + 64, 1);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -383,11 +408,12 @@
|
||||||
|
|
||||||
// func valueInvoke(v ref, args []ref) (ref, bool)
|
// func valueInvoke(v ref, args []ref) (ref, bool)
|
||||||
"syscall/js.valueInvoke": (sp) => {
|
"syscall/js.valueInvoke": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
try {
|
try {
|
||||||
const v = loadValue(sp + 8);
|
const v = loadValue(sp + 8);
|
||||||
const args = loadSliceOfValues(sp + 16);
|
const args = loadSliceOfValues(sp + 16);
|
||||||
const result = Reflect.apply(v, undefined, args);
|
const result = Reflect.apply(v, undefined, args);
|
||||||
sp = this._inst.exports.getsp(); // see comment above
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
storeValue(sp + 40, result);
|
storeValue(sp + 40, result);
|
||||||
this.mem.setUint8(sp + 48, 1);
|
this.mem.setUint8(sp + 48, 1);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -398,11 +424,12 @@
|
||||||
|
|
||||||
// func valueNew(v ref, args []ref) (ref, bool)
|
// func valueNew(v ref, args []ref) (ref, bool)
|
||||||
"syscall/js.valueNew": (sp) => {
|
"syscall/js.valueNew": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
try {
|
try {
|
||||||
const v = loadValue(sp + 8);
|
const v = loadValue(sp + 8);
|
||||||
const args = loadSliceOfValues(sp + 16);
|
const args = loadSliceOfValues(sp + 16);
|
||||||
const result = Reflect.construct(v, args);
|
const result = Reflect.construct(v, args);
|
||||||
sp = this._inst.exports.getsp(); // see comment above
|
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||||
storeValue(sp + 40, result);
|
storeValue(sp + 40, result);
|
||||||
this.mem.setUint8(sp + 48, 1);
|
this.mem.setUint8(sp + 48, 1);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -413,11 +440,13 @@
|
||||||
|
|
||||||
// func valueLength(v ref) int
|
// func valueLength(v ref) int
|
||||||
"syscall/js.valueLength": (sp) => {
|
"syscall/js.valueLength": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
|
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
|
||||||
},
|
},
|
||||||
|
|
||||||
// valuePrepareString(v ref) (ref, int)
|
// valuePrepareString(v ref) (ref, int)
|
||||||
"syscall/js.valuePrepareString": (sp) => {
|
"syscall/js.valuePrepareString": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const str = encoder.encode(String(loadValue(sp + 8)));
|
const str = encoder.encode(String(loadValue(sp + 8)));
|
||||||
storeValue(sp + 16, str);
|
storeValue(sp + 16, str);
|
||||||
setInt64(sp + 24, str.length);
|
setInt64(sp + 24, str.length);
|
||||||
|
|
@ -425,17 +454,20 @@
|
||||||
|
|
||||||
// valueLoadString(v ref, b []byte)
|
// valueLoadString(v ref, b []byte)
|
||||||
"syscall/js.valueLoadString": (sp) => {
|
"syscall/js.valueLoadString": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const str = loadValue(sp + 8);
|
const str = loadValue(sp + 8);
|
||||||
loadSlice(sp + 16).set(str);
|
loadSlice(sp + 16).set(str);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func valueInstanceOf(v ref, t ref) bool
|
// func valueInstanceOf(v ref, t ref) bool
|
||||||
"syscall/js.valueInstanceOf": (sp) => {
|
"syscall/js.valueInstanceOf": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
|
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||||
"syscall/js.copyBytesToGo": (sp) => {
|
"syscall/js.copyBytesToGo": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const dst = loadSlice(sp + 8);
|
const dst = loadSlice(sp + 8);
|
||||||
const src = loadValue(sp + 32);
|
const src = loadValue(sp + 32);
|
||||||
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
||||||
|
|
@ -450,6 +482,7 @@
|
||||||
|
|
||||||
// func copyBytesToJS(dst ref, src []byte) (int, bool)
|
// func copyBytesToJS(dst ref, src []byte) (int, bool)
|
||||||
"syscall/js.copyBytesToJS": (sp) => {
|
"syscall/js.copyBytesToJS": (sp) => {
|
||||||
|
sp >>>= 0;
|
||||||
const dst = loadValue(sp + 8);
|
const dst = loadValue(sp + 8);
|
||||||
const src = loadSlice(sp + 16);
|
const src = loadSlice(sp + 16);
|
||||||
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
||||||
|
|
@ -470,6 +503,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async run(instance) {
|
async run(instance) {
|
||||||
|
if (!(instance instanceof WebAssembly.Instance)) {
|
||||||
|
throw new Error("Go.run: WebAssembly.Instance expected");
|
||||||
|
}
|
||||||
this._inst = instance;
|
this._inst = instance;
|
||||||
this.mem = new DataView(this._inst.exports.mem.buffer);
|
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||||
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ package tar
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -525,12 +525,12 @@ func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err
|
||||||
return format, paxHdrs, err
|
return format, paxHdrs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileInfo returns an os.FileInfo for the Header.
|
// FileInfo returns an fs.FileInfo for the Header.
|
||||||
func (h *Header) FileInfo() os.FileInfo {
|
func (h *Header) FileInfo() fs.FileInfo {
|
||||||
return headerFileInfo{h}
|
return headerFileInfo{h}
|
||||||
}
|
}
|
||||||
|
|
||||||
// headerFileInfo implements os.FileInfo.
|
// headerFileInfo implements fs.FileInfo.
|
||||||
type headerFileInfo struct {
|
type headerFileInfo struct {
|
||||||
h *Header
|
h *Header
|
||||||
}
|
}
|
||||||
|
|
@ -549,57 +549,57 @@ func (fi headerFileInfo) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode returns the permission and mode bits for the headerFileInfo.
|
// Mode returns the permission and mode bits for the headerFileInfo.
|
||||||
func (fi headerFileInfo) Mode() (mode os.FileMode) {
|
func (fi headerFileInfo) Mode() (mode fs.FileMode) {
|
||||||
// Set file permission bits.
|
// Set file permission bits.
|
||||||
mode = os.FileMode(fi.h.Mode).Perm()
|
mode = fs.FileMode(fi.h.Mode).Perm()
|
||||||
|
|
||||||
// Set setuid, setgid and sticky bits.
|
// Set setuid, setgid and sticky bits.
|
||||||
if fi.h.Mode&c_ISUID != 0 {
|
if fi.h.Mode&c_ISUID != 0 {
|
||||||
mode |= os.ModeSetuid
|
mode |= fs.ModeSetuid
|
||||||
}
|
}
|
||||||
if fi.h.Mode&c_ISGID != 0 {
|
if fi.h.Mode&c_ISGID != 0 {
|
||||||
mode |= os.ModeSetgid
|
mode |= fs.ModeSetgid
|
||||||
}
|
}
|
||||||
if fi.h.Mode&c_ISVTX != 0 {
|
if fi.h.Mode&c_ISVTX != 0 {
|
||||||
mode |= os.ModeSticky
|
mode |= fs.ModeSticky
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set file mode bits; clear perm, setuid, setgid, and sticky bits.
|
// Set file mode bits; clear perm, setuid, setgid, and sticky bits.
|
||||||
switch m := os.FileMode(fi.h.Mode) &^ 07777; m {
|
switch m := fs.FileMode(fi.h.Mode) &^ 07777; m {
|
||||||
case c_ISDIR:
|
case c_ISDIR:
|
||||||
mode |= os.ModeDir
|
mode |= fs.ModeDir
|
||||||
case c_ISFIFO:
|
case c_ISFIFO:
|
||||||
mode |= os.ModeNamedPipe
|
mode |= fs.ModeNamedPipe
|
||||||
case c_ISLNK:
|
case c_ISLNK:
|
||||||
mode |= os.ModeSymlink
|
mode |= fs.ModeSymlink
|
||||||
case c_ISBLK:
|
case c_ISBLK:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
case c_ISCHR:
|
case c_ISCHR:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
mode |= os.ModeCharDevice
|
mode |= fs.ModeCharDevice
|
||||||
case c_ISSOCK:
|
case c_ISSOCK:
|
||||||
mode |= os.ModeSocket
|
mode |= fs.ModeSocket
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fi.h.Typeflag {
|
switch fi.h.Typeflag {
|
||||||
case TypeSymlink:
|
case TypeSymlink:
|
||||||
mode |= os.ModeSymlink
|
mode |= fs.ModeSymlink
|
||||||
case TypeChar:
|
case TypeChar:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
mode |= os.ModeCharDevice
|
mode |= fs.ModeCharDevice
|
||||||
case TypeBlock:
|
case TypeBlock:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
case TypeDir:
|
case TypeDir:
|
||||||
mode |= os.ModeDir
|
mode |= fs.ModeDir
|
||||||
case TypeFifo:
|
case TypeFifo:
|
||||||
mode |= os.ModeNamedPipe
|
mode |= fs.ModeNamedPipe
|
||||||
}
|
}
|
||||||
|
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// sysStat, if non-nil, populates h from system-dependent fields of fi.
|
// sysStat, if non-nil, populates h from system-dependent fields of fi.
|
||||||
var sysStat func(fi os.FileInfo, h *Header) error
|
var sysStat func(fi fs.FileInfo, h *Header) error
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Mode constants from the USTAR spec:
|
// Mode constants from the USTAR spec:
|
||||||
|
|
@ -623,10 +623,10 @@ const (
|
||||||
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
||||||
// If fi describes a directory, a slash is appended to the name.
|
// If fi describes a directory, a slash is appended to the name.
|
||||||
//
|
//
|
||||||
// Since os.FileInfo's Name method only returns the base name of
|
// Since fs.FileInfo's Name method only returns the base name of
|
||||||
// the file it describes, it may be necessary to modify Header.Name
|
// the file it describes, it may be necessary to modify Header.Name
|
||||||
// to provide the full path name of the file.
|
// to provide the full path name of the file.
|
||||||
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||||
if fi == nil {
|
if fi == nil {
|
||||||
return nil, errors.New("archive/tar: FileInfo is nil")
|
return nil, errors.New("archive/tar: FileInfo is nil")
|
||||||
}
|
}
|
||||||
|
|
@ -643,29 +643,29 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
||||||
case fi.IsDir():
|
case fi.IsDir():
|
||||||
h.Typeflag = TypeDir
|
h.Typeflag = TypeDir
|
||||||
h.Name += "/"
|
h.Name += "/"
|
||||||
case fm&os.ModeSymlink != 0:
|
case fm&fs.ModeSymlink != 0:
|
||||||
h.Typeflag = TypeSymlink
|
h.Typeflag = TypeSymlink
|
||||||
h.Linkname = link
|
h.Linkname = link
|
||||||
case fm&os.ModeDevice != 0:
|
case fm&fs.ModeDevice != 0:
|
||||||
if fm&os.ModeCharDevice != 0 {
|
if fm&fs.ModeCharDevice != 0 {
|
||||||
h.Typeflag = TypeChar
|
h.Typeflag = TypeChar
|
||||||
} else {
|
} else {
|
||||||
h.Typeflag = TypeBlock
|
h.Typeflag = TypeBlock
|
||||||
}
|
}
|
||||||
case fm&os.ModeNamedPipe != 0:
|
case fm&fs.ModeNamedPipe != 0:
|
||||||
h.Typeflag = TypeFifo
|
h.Typeflag = TypeFifo
|
||||||
case fm&os.ModeSocket != 0:
|
case fm&fs.ModeSocket != 0:
|
||||||
return nil, fmt.Errorf("archive/tar: sockets not supported")
|
return nil, fmt.Errorf("archive/tar: sockets not supported")
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
|
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
|
||||||
}
|
}
|
||||||
if fm&os.ModeSetuid != 0 {
|
if fm&fs.ModeSetuid != 0 {
|
||||||
h.Mode |= c_ISUID
|
h.Mode |= c_ISUID
|
||||||
}
|
}
|
||||||
if fm&os.ModeSetgid != 0 {
|
if fm&fs.ModeSetgid != 0 {
|
||||||
h.Mode |= c_ISGID
|
h.Mode |= c_ISGID
|
||||||
}
|
}
|
||||||
if fm&os.ModeSticky != 0 {
|
if fm&fs.ModeSticky != 0 {
|
||||||
h.Mode |= c_ISVTX
|
h.Mode |= c_ISVTX
|
||||||
}
|
}
|
||||||
// If possible, populate additional fields from OS-specific
|
// If possible, populate additional fields from OS-specific
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ package tar
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -104,7 +103,7 @@ func (tr *Reader) next() (*Header, error) {
|
||||||
continue // This is a meta header affecting the next header
|
continue // This is a meta header affecting the next header
|
||||||
case TypeGNULongName, TypeGNULongLink:
|
case TypeGNULongName, TypeGNULongLink:
|
||||||
format.mayOnlyBe(FormatGNU)
|
format.mayOnlyBe(FormatGNU)
|
||||||
realname, err := ioutil.ReadAll(tr)
|
realname, err := io.ReadAll(tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
|
||||||
// parsePAX parses PAX headers.
|
// parsePAX parses PAX headers.
|
||||||
// If an extended header (type 'x') is invalid, ErrHeader is returned
|
// If an extended header (type 'x') is invalid, ErrHeader is returned
|
||||||
func parsePAX(r io.Reader) (map[string]string, error) {
|
func parsePAX(r io.Reader) (map[string]string, error) {
|
||||||
buf, err := ioutil.ReadAll(r)
|
buf, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -850,7 +849,7 @@ func discard(r io.Reader, n int64) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
copySkipped, err := io.CopyN(ioutil.Discard, r, n-seekSkipped)
|
copySkipped, err := io.CopyN(io.Discard, r, n-seekSkipped)
|
||||||
if err == io.EOF && seekSkipped+copySkipped < n {
|
if err == io.EOF && seekSkipped+copySkipped < n {
|
||||||
err = io.ErrUnexpectedEOF
|
err = io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -865,7 +865,7 @@ func TestReadTruncation(t *testing.T) {
|
||||||
}
|
}
|
||||||
cnt++
|
cnt++
|
||||||
if s2 == "manual" {
|
if s2 == "manual" {
|
||||||
if _, err = tr.writeTo(ioutil.Discard); err != nil {
|
if _, err = tr.writeTo(io.Discard); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
package tar
|
package tar
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"io/fs"
|
||||||
"os/user"
|
"os/user"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -23,7 +23,7 @@ func init() {
|
||||||
// The downside is that renaming uname or gname by the OS never takes effect.
|
// The downside is that renaming uname or gname by the OS never takes effect.
|
||||||
var userMap, groupMap sync.Map // map[int]string
|
var userMap, groupMap sync.Map // map[int]string
|
||||||
|
|
||||||
func statUnix(fi os.FileInfo, h *Header) error {
|
func statUnix(fi fs.FileInfo, h *Header) error {
|
||||||
sys, ok := fi.Sys().(*syscall.Stat_t)
|
sys, ok := fi.Sys().(*syscall.Stat_t)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -327,7 +328,7 @@ func TestRoundTrip(t *testing.T) {
|
||||||
if !reflect.DeepEqual(rHdr, hdr) {
|
if !reflect.DeepEqual(rHdr, hdr) {
|
||||||
t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
|
t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
|
||||||
}
|
}
|
||||||
rData, err := ioutil.ReadAll(tr)
|
rData, err := io.ReadAll(tr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Read: %v", err)
|
t.Fatalf("Read: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -338,7 +339,7 @@ func TestRoundTrip(t *testing.T) {
|
||||||
|
|
||||||
type headerRoundTripTest struct {
|
type headerRoundTripTest struct {
|
||||||
h *Header
|
h *Header
|
||||||
fm os.FileMode
|
fm fs.FileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHeaderRoundTrip(t *testing.T) {
|
func TestHeaderRoundTrip(t *testing.T) {
|
||||||
|
|
@ -361,7 +362,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||||
ModTime: time.Unix(1360600852, 0),
|
ModTime: time.Unix(1360600852, 0),
|
||||||
Typeflag: TypeSymlink,
|
Typeflag: TypeSymlink,
|
||||||
},
|
},
|
||||||
fm: 0777 | os.ModeSymlink,
|
fm: 0777 | fs.ModeSymlink,
|
||||||
}, {
|
}, {
|
||||||
// character device node.
|
// character device node.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
|
|
@ -371,7 +372,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||||
ModTime: time.Unix(1360578951, 0),
|
ModTime: time.Unix(1360578951, 0),
|
||||||
Typeflag: TypeChar,
|
Typeflag: TypeChar,
|
||||||
},
|
},
|
||||||
fm: 0666 | os.ModeDevice | os.ModeCharDevice,
|
fm: 0666 | fs.ModeDevice | fs.ModeCharDevice,
|
||||||
}, {
|
}, {
|
||||||
// block device node.
|
// block device node.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
|
|
@ -381,7 +382,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||||
ModTime: time.Unix(1360578954, 0),
|
ModTime: time.Unix(1360578954, 0),
|
||||||
Typeflag: TypeBlock,
|
Typeflag: TypeBlock,
|
||||||
},
|
},
|
||||||
fm: 0660 | os.ModeDevice,
|
fm: 0660 | fs.ModeDevice,
|
||||||
}, {
|
}, {
|
||||||
// directory.
|
// directory.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
|
|
@ -391,7 +392,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||||
ModTime: time.Unix(1360601116, 0),
|
ModTime: time.Unix(1360601116, 0),
|
||||||
Typeflag: TypeDir,
|
Typeflag: TypeDir,
|
||||||
},
|
},
|
||||||
fm: 0755 | os.ModeDir,
|
fm: 0755 | fs.ModeDir,
|
||||||
}, {
|
}, {
|
||||||
// fifo node.
|
// fifo node.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
|
|
@ -401,7 +402,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||||
ModTime: time.Unix(1360578949, 0),
|
ModTime: time.Unix(1360578949, 0),
|
||||||
Typeflag: TypeFifo,
|
Typeflag: TypeFifo,
|
||||||
},
|
},
|
||||||
fm: 0600 | os.ModeNamedPipe,
|
fm: 0600 | fs.ModeNamedPipe,
|
||||||
}, {
|
}, {
|
||||||
// setuid.
|
// setuid.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
|
|
@ -411,7 +412,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||||
ModTime: time.Unix(1355405093, 0),
|
ModTime: time.Unix(1355405093, 0),
|
||||||
Typeflag: TypeReg,
|
Typeflag: TypeReg,
|
||||||
},
|
},
|
||||||
fm: 0755 | os.ModeSetuid,
|
fm: 0755 | fs.ModeSetuid,
|
||||||
}, {
|
}, {
|
||||||
// setguid.
|
// setguid.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
|
|
@ -421,7 +422,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||||
ModTime: time.Unix(1360602346, 0),
|
ModTime: time.Unix(1360602346, 0),
|
||||||
Typeflag: TypeReg,
|
Typeflag: TypeReg,
|
||||||
},
|
},
|
||||||
fm: 0750 | os.ModeSetgid,
|
fm: 0750 | fs.ModeSetgid,
|
||||||
}, {
|
}, {
|
||||||
// sticky.
|
// sticky.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
|
|
@ -431,7 +432,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||||
ModTime: time.Unix(1360602540, 0),
|
ModTime: time.Unix(1360602540, 0),
|
||||||
Typeflag: TypeReg,
|
Typeflag: TypeReg,
|
||||||
},
|
},
|
||||||
fm: 0600 | os.ModeSticky,
|
fm: 0600 | fs.ModeSticky,
|
||||||
}, {
|
}, {
|
||||||
// hard link.
|
// hard link.
|
||||||
h: &Header{
|
h: &Header{
|
||||||
|
|
@ -804,9 +805,9 @@ func Benchmark(b *testing.B) {
|
||||||
b.Run(v.label, func(b *testing.B) {
|
b.Run(v.label, func(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
// Writing to ioutil.Discard because we want to
|
// Writing to io.Discard because we want to
|
||||||
// test purely the writer code and not bring in disk performance into this.
|
// test purely the writer code and not bring in disk performance into this.
|
||||||
tw := NewWriter(ioutil.Discard)
|
tw := NewWriter(io.Discard)
|
||||||
for _, file := range v.files {
|
for _, file := range v.files {
|
||||||
if err := tw.WriteHeader(file.hdr); err != nil {
|
if err := tw.WriteHeader(file.hdr); err != nil {
|
||||||
b.Errorf("unexpected WriteHeader error: %v", err)
|
b.Errorf("unexpected WriteHeader error: %v", err)
|
||||||
|
|
@ -844,7 +845,7 @@ func Benchmark(b *testing.B) {
|
||||||
if _, err := tr.Next(); err != nil {
|
if _, err := tr.Next(); err != nil {
|
||||||
b.Errorf("unexpected Next error: %v", err)
|
b.Errorf("unexpected Next error: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(ioutil.Discard, tr); err != nil {
|
if _, err := io.Copy(io.Discard, tr); err != nil {
|
||||||
b.Errorf("unexpected Copy error : %v", err)
|
b.Errorf("unexpected Copy error : %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,12 @@ import (
|
||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -21,18 +26,28 @@ var (
|
||||||
ErrChecksum = errors.New("zip: checksum error")
|
ErrChecksum = errors.New("zip: checksum error")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A Reader serves content from a ZIP archive.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
r io.ReaderAt
|
r io.ReaderAt
|
||||||
File []*File
|
File []*File
|
||||||
Comment string
|
Comment string
|
||||||
decompressors map[uint16]Decompressor
|
decompressors map[uint16]Decompressor
|
||||||
|
|
||||||
|
// fileList is a list of files sorted by ename,
|
||||||
|
// for use by the Open method.
|
||||||
|
fileListOnce sync.Once
|
||||||
|
fileList []fileListEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A ReadCloser is a Reader that must be closed when no longer needed.
|
||||||
type ReadCloser struct {
|
type ReadCloser struct {
|
||||||
f *os.File
|
f *os.File
|
||||||
Reader
|
Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A File is a single file in a ZIP archive.
|
||||||
|
// The file information is in the embedded FileHeader.
|
||||||
|
// The file content can be accessed by calling Open.
|
||||||
type File struct {
|
type File struct {
|
||||||
FileHeader
|
FileHeader
|
||||||
zip *Reader
|
zip *Reader
|
||||||
|
|
@ -187,6 +202,10 @@ type checksumReader struct {
|
||||||
err error // sticky error
|
err error // sticky error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *checksumReader) Stat() (fs.FileInfo, error) {
|
||||||
|
return headerFileInfo{&r.f.FileHeader}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *checksumReader) Read(b []byte) (n int, err error) {
|
func (r *checksumReader) Read(b []byte) (n int, err error) {
|
||||||
if r.err != nil {
|
if r.err != nil {
|
||||||
return 0, r.err
|
return 0, r.err
|
||||||
|
|
@ -607,3 +626,173 @@ func (b *readBuf) sub(n int) readBuf {
|
||||||
*b = (*b)[n:]
|
*b = (*b)[n:]
|
||||||
return b2
|
return b2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A fileListEntry is a File and its ename.
|
||||||
|
// If file == nil, the fileListEntry describes a directory, without metadata.
|
||||||
|
type fileListEntry struct {
|
||||||
|
name string
|
||||||
|
file *File // nil for directories
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileInfoDirEntry interface {
|
||||||
|
fs.FileInfo
|
||||||
|
fs.DirEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *fileListEntry) stat() fileInfoDirEntry {
|
||||||
|
if e.file != nil {
|
||||||
|
return headerFileInfo{&e.file.FileHeader}
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only used for directories.
|
||||||
|
func (f *fileListEntry) Name() string { _, elem, _ := split(f.name); return elem }
|
||||||
|
func (f *fileListEntry) Size() int64 { return 0 }
|
||||||
|
func (f *fileListEntry) ModTime() time.Time { return time.Time{} }
|
||||||
|
func (f *fileListEntry) Mode() fs.FileMode { return fs.ModeDir | 0555 }
|
||||||
|
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
|
||||||
|
func (f *fileListEntry) IsDir() bool { return true }
|
||||||
|
func (f *fileListEntry) Sys() interface{} { return nil }
|
||||||
|
|
||||||
|
func (f *fileListEntry) Info() (fs.FileInfo, error) { return f, nil }
|
||||||
|
|
||||||
|
// toValidName coerces name to be a valid name for fs.FS.Open.
|
||||||
|
func toValidName(name string) string {
|
||||||
|
name = strings.ReplaceAll(name, `\`, `/`)
|
||||||
|
p := path.Clean(name)
|
||||||
|
if strings.HasPrefix(p, "/") {
|
||||||
|
p = p[len("/"):]
|
||||||
|
}
|
||||||
|
for strings.HasPrefix(name, "../") {
|
||||||
|
p = p[len("../"):]
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) initFileList() {
|
||||||
|
r.fileListOnce.Do(func() {
|
||||||
|
dirs := make(map[string]bool)
|
||||||
|
for _, file := range r.File {
|
||||||
|
name := toValidName(file.Name)
|
||||||
|
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
||||||
|
dirs[dir] = true
|
||||||
|
}
|
||||||
|
r.fileList = append(r.fileList, fileListEntry{name, file})
|
||||||
|
}
|
||||||
|
for dir := range dirs {
|
||||||
|
r.fileList = append(r.fileList, fileListEntry{dir + "/", nil})
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(r.fileList, func(i, j int) bool { return fileEntryLess(r.fileList[i].name, r.fileList[j].name) })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileEntryLess(x, y string) bool {
|
||||||
|
xdir, xelem, _ := split(x)
|
||||||
|
ydir, yelem, _ := split(y)
|
||||||
|
return xdir < ydir || xdir == ydir && xelem < yelem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open opens the named file in the ZIP archive,
|
||||||
|
// using the semantics of fs.FS.Open:
|
||||||
|
// paths are always slash separated, with no
|
||||||
|
// leading / or ../ elements.
|
||||||
|
func (r *Reader) Open(name string) (fs.File, error) {
|
||||||
|
r.initFileList()
|
||||||
|
|
||||||
|
e := r.openLookup(name)
|
||||||
|
if e == nil || !fs.ValidPath(name) {
|
||||||
|
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
||||||
|
}
|
||||||
|
if e.file == nil || strings.HasSuffix(e.file.Name, "/") {
|
||||||
|
return &openDir{e, r.openReadDir(name), 0}, nil
|
||||||
|
}
|
||||||
|
rc, err := e.file.Open()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rc.(fs.File), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func split(name string) (dir, elem string, isDir bool) {
|
||||||
|
if name[len(name)-1] == '/' {
|
||||||
|
isDir = true
|
||||||
|
name = name[:len(name)-1]
|
||||||
|
}
|
||||||
|
i := len(name) - 1
|
||||||
|
for i >= 0 && name[i] != '/' {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
if i < 0 {
|
||||||
|
return ".", name, isDir
|
||||||
|
}
|
||||||
|
return name[:i], name[i+1:], isDir
|
||||||
|
}
|
||||||
|
|
||||||
|
var dotFile = &fileListEntry{name: "./"}
|
||||||
|
|
||||||
|
func (r *Reader) openLookup(name string) *fileListEntry {
|
||||||
|
if name == "." {
|
||||||
|
return dotFile
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, elem, _ := split(name)
|
||||||
|
files := r.fileList
|
||||||
|
i := sort.Search(len(files), func(i int) bool {
|
||||||
|
idir, ielem, _ := split(files[i].name)
|
||||||
|
return idir > dir || idir == dir && ielem >= elem
|
||||||
|
})
|
||||||
|
if i < len(files) {
|
||||||
|
fname := files[i].name
|
||||||
|
if fname == name || len(fname) == len(name)+1 && fname[len(name)] == '/' && fname[:len(name)] == name {
|
||||||
|
return &files[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reader) openReadDir(dir string) []fileListEntry {
|
||||||
|
files := r.fileList
|
||||||
|
i := sort.Search(len(files), func(i int) bool {
|
||||||
|
idir, _, _ := split(files[i].name)
|
||||||
|
return idir >= dir
|
||||||
|
})
|
||||||
|
j := sort.Search(len(files), func(j int) bool {
|
||||||
|
jdir, _, _ := split(files[j].name)
|
||||||
|
return jdir > dir
|
||||||
|
})
|
||||||
|
return files[i:j]
|
||||||
|
}
|
||||||
|
|
||||||
|
type openDir struct {
|
||||||
|
e *fileListEntry
|
||||||
|
files []fileListEntry
|
||||||
|
offset int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *openDir) Close() error { return nil }
|
||||||
|
func (d *openDir) Stat() (fs.FileInfo, error) { return d.e.stat(), nil }
|
||||||
|
|
||||||
|
func (d *openDir) Read([]byte) (int, error) {
|
||||||
|
return 0, &fs.PathError{Op: "read", Path: d.e.name, Err: errors.New("is a directory")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *openDir) ReadDir(count int) ([]fs.DirEntry, error) {
|
||||||
|
n := len(d.files) - d.offset
|
||||||
|
if count > 0 && n > count {
|
||||||
|
n = count
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
if count <= 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
list := make([]fs.DirEntry, n)
|
||||||
|
for i := range list {
|
||||||
|
list[i] = d.files[d.offset+i].stat()
|
||||||
|
}
|
||||||
|
d.offset += n
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,14 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"internal/obscuretestdata"
|
"internal/obscuretestdata"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"testing/fstest"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -30,7 +32,7 @@ type ZipTest struct {
|
||||||
|
|
||||||
type ZipTestFile struct {
|
type ZipTestFile struct {
|
||||||
Name string
|
Name string
|
||||||
Mode os.FileMode
|
Mode fs.FileMode
|
||||||
NonUTF8 bool
|
NonUTF8 bool
|
||||||
ModTime time.Time
|
ModTime time.Time
|
||||||
Modified time.Time
|
Modified time.Time
|
||||||
|
|
@ -107,7 +109,7 @@ var tests = []ZipTest{
|
||||||
Name: "symlink",
|
Name: "symlink",
|
||||||
Content: []byte("../target"),
|
Content: []byte("../target"),
|
||||||
Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)),
|
Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)),
|
||||||
Mode: 0777 | os.ModeSymlink,
|
Mode: 0777 | fs.ModeSymlink,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -149,7 +151,7 @@ var tests = []ZipTest{
|
||||||
Name: "dir/empty/",
|
Name: "dir/empty/",
|
||||||
Content: []byte{},
|
Content: []byte{},
|
||||||
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC),
|
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC),
|
||||||
Mode: os.ModeDir | 0777,
|
Mode: fs.ModeDir | 0777,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "readonly",
|
Name: "readonly",
|
||||||
|
|
@ -179,7 +181,7 @@ var tests = []ZipTest{
|
||||||
Name: "dir/empty/",
|
Name: "dir/empty/",
|
||||||
Content: []byte{},
|
Content: []byte{},
|
||||||
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)),
|
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)),
|
||||||
Mode: os.ModeDir | 0777,
|
Mode: fs.ModeDir | 0777,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "readonly",
|
Name: "readonly",
|
||||||
|
|
@ -645,7 +647,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFileMode(t *testing.T, f *File, want os.FileMode) {
|
func testFileMode(t *testing.T, f *File, want fs.FileMode) {
|
||||||
mode := f.Mode()
|
mode := f.Mode()
|
||||||
if want == 0 {
|
if want == 0 {
|
||||||
t.Errorf("%s mode: got %v, want none", f.Name, mode)
|
t.Errorf("%s mode: got %v, want none", f.Name, mode)
|
||||||
|
|
@ -928,7 +930,7 @@ func returnBigZipBytes() (r io.ReaderAt, size int64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
b, err = ioutil.ReadAll(f)
|
b, err = io.ReadAll(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -985,7 +987,7 @@ func TestIssue10957(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if f.UncompressedSize64 < 1e6 {
|
if f.UncompressedSize64 < 1e6 {
|
||||||
n, err := io.Copy(ioutil.Discard, r)
|
n, err := io.Copy(io.Discard, r)
|
||||||
if i == 3 && err != io.ErrUnexpectedEOF {
|
if i == 3 && err != io.ErrUnexpectedEOF {
|
||||||
t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
|
t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1027,7 +1029,7 @@ func TestIssue11146(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err = ioutil.ReadAll(r)
|
_, err = io.ReadAll(r)
|
||||||
if err != io.ErrUnexpectedEOF {
|
if err != io.ErrUnexpectedEOF {
|
||||||
t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err)
|
t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1070,3 +1072,13 @@ func TestIssue12449(t *testing.T) {
|
||||||
t.Errorf("Error reading the archive: %v", err)
|
t.Errorf("Error reading the archive: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFS(t *testing.T) {
|
||||||
|
z, err := OpenReader("testdata/unix.zip")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := fstest.TestFS(z, "hello", "dir/bar", "dir/empty", "readonly"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"compress/flate"
|
"compress/flate"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -111,7 +110,7 @@ func init() {
|
||||||
compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
|
compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
|
||||||
compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
|
compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
|
||||||
|
|
||||||
decompressors.Store(Store, Decompressor(ioutil.NopCloser))
|
decompressors.Store(Store, Decompressor(io.NopCloser))
|
||||||
decompressors.Store(Deflate, Decompressor(newFlateReader))
|
decompressors.Store(Deflate, Decompressor(newFlateReader))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ fields must be used instead.
|
||||||
package zip
|
package zip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"io/fs"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -137,12 +137,12 @@ type FileHeader struct {
|
||||||
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileInfo returns an os.FileInfo for the FileHeader.
|
// FileInfo returns an fs.FileInfo for the FileHeader.
|
||||||
func (h *FileHeader) FileInfo() os.FileInfo {
|
func (h *FileHeader) FileInfo() fs.FileInfo {
|
||||||
return headerFileInfo{h}
|
return headerFileInfo{h}
|
||||||
}
|
}
|
||||||
|
|
||||||
// headerFileInfo implements os.FileInfo.
|
// headerFileInfo implements fs.FileInfo.
|
||||||
type headerFileInfo struct {
|
type headerFileInfo struct {
|
||||||
fh *FileHeader
|
fh *FileHeader
|
||||||
}
|
}
|
||||||
|
|
@ -161,17 +161,20 @@ func (fi headerFileInfo) ModTime() time.Time {
|
||||||
}
|
}
|
||||||
return fi.fh.Modified.UTC()
|
return fi.fh.Modified.UTC()
|
||||||
}
|
}
|
||||||
func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
|
func (fi headerFileInfo) Mode() fs.FileMode { return fi.fh.Mode() }
|
||||||
|
func (fi headerFileInfo) Type() fs.FileMode { return fi.fh.Mode().Type() }
|
||||||
func (fi headerFileInfo) Sys() interface{} { return fi.fh }
|
func (fi headerFileInfo) Sys() interface{} { return fi.fh }
|
||||||
|
|
||||||
|
func (fi headerFileInfo) Info() (fs.FileInfo, error) { return fi, nil }
|
||||||
|
|
||||||
// FileInfoHeader creates a partially-populated FileHeader from an
|
// FileInfoHeader creates a partially-populated FileHeader from an
|
||||||
// os.FileInfo.
|
// fs.FileInfo.
|
||||||
// Because os.FileInfo's Name method returns only the base name of
|
// Because fs.FileInfo's Name method returns only the base name of
|
||||||
// the file it describes, it may be necessary to modify the Name field
|
// the file it describes, it may be necessary to modify the Name field
|
||||||
// of the returned header to provide the full path name of the file.
|
// of the returned header to provide the full path name of the file.
|
||||||
// If compression is desired, callers should set the FileHeader.Method
|
// If compression is desired, callers should set the FileHeader.Method
|
||||||
// field; it is unset by default.
|
// field; it is unset by default.
|
||||||
func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
|
func FileInfoHeader(fi fs.FileInfo) (*FileHeader, error) {
|
||||||
size := fi.Size()
|
size := fi.Size()
|
||||||
fh := &FileHeader{
|
fh := &FileHeader{
|
||||||
Name: fi.Name(),
|
Name: fi.Name(),
|
||||||
|
|
@ -280,7 +283,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mode returns the permission and mode bits for the FileHeader.
|
// Mode returns the permission and mode bits for the FileHeader.
|
||||||
func (h *FileHeader) Mode() (mode os.FileMode) {
|
func (h *FileHeader) Mode() (mode fs.FileMode) {
|
||||||
switch h.CreatorVersion >> 8 {
|
switch h.CreatorVersion >> 8 {
|
||||||
case creatorUnix, creatorMacOSX:
|
case creatorUnix, creatorMacOSX:
|
||||||
mode = unixModeToFileMode(h.ExternalAttrs >> 16)
|
mode = unixModeToFileMode(h.ExternalAttrs >> 16)
|
||||||
|
|
@ -288,18 +291,18 @@ func (h *FileHeader) Mode() (mode os.FileMode) {
|
||||||
mode = msdosModeToFileMode(h.ExternalAttrs)
|
mode = msdosModeToFileMode(h.ExternalAttrs)
|
||||||
}
|
}
|
||||||
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
|
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
|
||||||
mode |= os.ModeDir
|
mode |= fs.ModeDir
|
||||||
}
|
}
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMode changes the permission and mode bits for the FileHeader.
|
// SetMode changes the permission and mode bits for the FileHeader.
|
||||||
func (h *FileHeader) SetMode(mode os.FileMode) {
|
func (h *FileHeader) SetMode(mode fs.FileMode) {
|
||||||
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
|
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
|
||||||
h.ExternalAttrs = fileModeToUnixMode(mode) << 16
|
h.ExternalAttrs = fileModeToUnixMode(mode) << 16
|
||||||
|
|
||||||
// set MSDOS attributes too, as the original zip does.
|
// set MSDOS attributes too, as the original zip does.
|
||||||
if mode&os.ModeDir != 0 {
|
if mode&fs.ModeDir != 0 {
|
||||||
h.ExternalAttrs |= msdosDir
|
h.ExternalAttrs |= msdosDir
|
||||||
}
|
}
|
||||||
if mode&0200 == 0 {
|
if mode&0200 == 0 {
|
||||||
|
|
@ -312,9 +315,9 @@ func (h *FileHeader) isZip64() bool {
|
||||||
return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max
|
return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max
|
||||||
}
|
}
|
||||||
|
|
||||||
func msdosModeToFileMode(m uint32) (mode os.FileMode) {
|
func msdosModeToFileMode(m uint32) (mode fs.FileMode) {
|
||||||
if m&msdosDir != 0 {
|
if m&msdosDir != 0 {
|
||||||
mode = os.ModeDir | 0777
|
mode = fs.ModeDir | 0777
|
||||||
} else {
|
} else {
|
||||||
mode = 0666
|
mode = 0666
|
||||||
}
|
}
|
||||||
|
|
@ -324,64 +327,64 @@ func msdosModeToFileMode(m uint32) (mode os.FileMode) {
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileModeToUnixMode(mode os.FileMode) uint32 {
|
func fileModeToUnixMode(mode fs.FileMode) uint32 {
|
||||||
var m uint32
|
var m uint32
|
||||||
switch mode & os.ModeType {
|
switch mode & fs.ModeType {
|
||||||
default:
|
default:
|
||||||
m = s_IFREG
|
m = s_IFREG
|
||||||
case os.ModeDir:
|
case fs.ModeDir:
|
||||||
m = s_IFDIR
|
m = s_IFDIR
|
||||||
case os.ModeSymlink:
|
case fs.ModeSymlink:
|
||||||
m = s_IFLNK
|
m = s_IFLNK
|
||||||
case os.ModeNamedPipe:
|
case fs.ModeNamedPipe:
|
||||||
m = s_IFIFO
|
m = s_IFIFO
|
||||||
case os.ModeSocket:
|
case fs.ModeSocket:
|
||||||
m = s_IFSOCK
|
m = s_IFSOCK
|
||||||
case os.ModeDevice:
|
case fs.ModeDevice:
|
||||||
if mode&os.ModeCharDevice != 0 {
|
if mode&fs.ModeCharDevice != 0 {
|
||||||
m = s_IFCHR
|
m = s_IFCHR
|
||||||
} else {
|
} else {
|
||||||
m = s_IFBLK
|
m = s_IFBLK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mode&os.ModeSetuid != 0 {
|
if mode&fs.ModeSetuid != 0 {
|
||||||
m |= s_ISUID
|
m |= s_ISUID
|
||||||
}
|
}
|
||||||
if mode&os.ModeSetgid != 0 {
|
if mode&fs.ModeSetgid != 0 {
|
||||||
m |= s_ISGID
|
m |= s_ISGID
|
||||||
}
|
}
|
||||||
if mode&os.ModeSticky != 0 {
|
if mode&fs.ModeSticky != 0 {
|
||||||
m |= s_ISVTX
|
m |= s_ISVTX
|
||||||
}
|
}
|
||||||
return m | uint32(mode&0777)
|
return m | uint32(mode&0777)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unixModeToFileMode(m uint32) os.FileMode {
|
func unixModeToFileMode(m uint32) fs.FileMode {
|
||||||
mode := os.FileMode(m & 0777)
|
mode := fs.FileMode(m & 0777)
|
||||||
switch m & s_IFMT {
|
switch m & s_IFMT {
|
||||||
case s_IFBLK:
|
case s_IFBLK:
|
||||||
mode |= os.ModeDevice
|
mode |= fs.ModeDevice
|
||||||
case s_IFCHR:
|
case s_IFCHR:
|
||||||
mode |= os.ModeDevice | os.ModeCharDevice
|
mode |= fs.ModeDevice | fs.ModeCharDevice
|
||||||
case s_IFDIR:
|
case s_IFDIR:
|
||||||
mode |= os.ModeDir
|
mode |= fs.ModeDir
|
||||||
case s_IFIFO:
|
case s_IFIFO:
|
||||||
mode |= os.ModeNamedPipe
|
mode |= fs.ModeNamedPipe
|
||||||
case s_IFLNK:
|
case s_IFLNK:
|
||||||
mode |= os.ModeSymlink
|
mode |= fs.ModeSymlink
|
||||||
case s_IFREG:
|
case s_IFREG:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
case s_IFSOCK:
|
case s_IFSOCK:
|
||||||
mode |= os.ModeSocket
|
mode |= fs.ModeSocket
|
||||||
}
|
}
|
||||||
if m&s_ISGID != 0 {
|
if m&s_ISGID != 0 {
|
||||||
mode |= os.ModeSetgid
|
mode |= fs.ModeSetgid
|
||||||
}
|
}
|
||||||
if m&s_ISUID != 0 {
|
if m&s_ISUID != 0 {
|
||||||
mode |= os.ModeSetuid
|
mode |= fs.ModeSetuid
|
||||||
}
|
}
|
||||||
if m&s_ISVTX != 0 {
|
if m&s_ISVTX != 0 {
|
||||||
mode |= os.ModeSticky
|
mode |= fs.ModeSticky
|
||||||
}
|
}
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -23,7 +23,7 @@ type WriteTest struct {
|
||||||
Name string
|
Name string
|
||||||
Data []byte
|
Data []byte
|
||||||
Method uint16
|
Method uint16
|
||||||
Mode os.FileMode
|
Mode fs.FileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
var writeTests = []WriteTest{
|
var writeTests = []WriteTest{
|
||||||
|
|
@ -43,19 +43,19 @@ var writeTests = []WriteTest{
|
||||||
Name: "setuid",
|
Name: "setuid",
|
||||||
Data: []byte("setuid file"),
|
Data: []byte("setuid file"),
|
||||||
Method: Deflate,
|
Method: Deflate,
|
||||||
Mode: 0755 | os.ModeSetuid,
|
Mode: 0755 | fs.ModeSetuid,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "setgid",
|
Name: "setgid",
|
||||||
Data: []byte("setgid file"),
|
Data: []byte("setgid file"),
|
||||||
Method: Deflate,
|
Method: Deflate,
|
||||||
Mode: 0755 | os.ModeSetgid,
|
Mode: 0755 | fs.ModeSetgid,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "symlink",
|
Name: "symlink",
|
||||||
Data: []byte("../link/target"),
|
Data: []byte("../link/target"),
|
||||||
Method: Deflate,
|
Method: Deflate,
|
||||||
Mode: 0755 | os.ModeSymlink,
|
Mode: 0755 | fs.ModeSymlink,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,7 +301,7 @@ func TestWriterFlush(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriterDir(t *testing.T) {
|
func TestWriterDir(t *testing.T) {
|
||||||
w := NewWriter(ioutil.Discard)
|
w := NewWriter(io.Discard)
|
||||||
dw, err := w.Create("dir/")
|
dw, err := w.Create("dir/")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -380,7 +380,7 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("opening:", err)
|
t.Fatal("opening:", err)
|
||||||
}
|
}
|
||||||
b, err := ioutil.ReadAll(rc)
|
b, err := io.ReadAll(rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("reading:", err)
|
t.Fatal("reading:", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"hash"
|
"hash"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -620,7 +619,7 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
|
||||||
t.Fatal("read:", err)
|
t.Fatal("read:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gotEnd, err := ioutil.ReadAll(rc)
|
gotEnd, err := io.ReadAll(rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("read end:", err)
|
t.Fatal("read end:", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"testing/iotest"
|
"testing/iotest"
|
||||||
|
|
@ -886,7 +885,7 @@ func TestReadEmptyBuffer(t *testing.T) {
|
||||||
|
|
||||||
func TestLinesAfterRead(t *testing.T) {
|
func TestLinesAfterRead(t *testing.T) {
|
||||||
l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
|
l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
|
||||||
_, err := ioutil.ReadAll(l)
|
_, err := io.ReadAll(l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
|
@ -1130,7 +1129,7 @@ func TestWriterReadFromCounts(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A writeCountingDiscard is like ioutil.Discard and counts the number of times
|
// A writeCountingDiscard is like io.Discard and counts the number of times
|
||||||
// Write is called on it.
|
// Write is called on it.
|
||||||
type writeCountingDiscard int
|
type writeCountingDiscard int
|
||||||
|
|
||||||
|
|
@ -1300,7 +1299,7 @@ func TestReaderReset(t *testing.T) {
|
||||||
t.Errorf("buf = %q; want foo", buf)
|
t.Errorf("buf = %q; want foo", buf)
|
||||||
}
|
}
|
||||||
r.Reset(strings.NewReader("bar bar"))
|
r.Reset(strings.NewReader("bar bar"))
|
||||||
all, err := ioutil.ReadAll(r)
|
all, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1645,13 +1644,13 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) {
|
||||||
buf := make([]byte, bufSize)
|
buf := make([]byte, bufSize)
|
||||||
r := bytes.NewReader(buf)
|
r := bytes.NewReader(buf)
|
||||||
srcReader := NewReaderSize(onlyReader{r}, 1<<10)
|
srcReader := NewReaderSize(onlyReader{r}, 1<<10)
|
||||||
if _, ok := ioutil.Discard.(io.ReaderFrom); !ok {
|
if _, ok := io.Discard.(io.ReaderFrom); !ok {
|
||||||
b.Fatal("ioutil.Discard doesn't support ReaderFrom")
|
b.Fatal("io.Discard doesn't support ReaderFrom")
|
||||||
}
|
}
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
r.Seek(0, io.SeekStart)
|
r.Seek(0, io.SeekStart)
|
||||||
srcReader.Reset(onlyReader{r})
|
srcReader.Reset(onlyReader{r})
|
||||||
n, err := srcReader.WriteTo(ioutil.Discard)
|
n, err := srcReader.WriteTo(io.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1722,7 +1721,7 @@ func BenchmarkReaderEmpty(b *testing.B) {
|
||||||
str := strings.Repeat("x", 16<<10)
|
str := strings.Repeat("x", 16<<10)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
br := NewReader(strings.NewReader(str))
|
br := NewReader(strings.NewReader(str))
|
||||||
n, err := io.Copy(ioutil.Discard, br)
|
n, err := io.Copy(io.Discard, br)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -1737,7 +1736,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
|
||||||
str := strings.Repeat("x", 1<<10)
|
str := strings.Repeat("x", 1<<10)
|
||||||
bs := []byte(str)
|
bs := []byte(str)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
bw := NewWriter(ioutil.Discard)
|
bw := NewWriter(io.Discard)
|
||||||
bw.Flush()
|
bw.Flush()
|
||||||
bw.WriteByte('a')
|
bw.WriteByte('a')
|
||||||
bw.Flush()
|
bw.Flush()
|
||||||
|
|
@ -1752,7 +1751,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
|
||||||
|
|
||||||
func BenchmarkWriterFlush(b *testing.B) {
|
func BenchmarkWriterFlush(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
bw := NewWriter(ioutil.Discard)
|
bw := NewWriter(io.Discard)
|
||||||
str := strings.Repeat("x", 50)
|
str := strings.Repeat("x", 50)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
bw.WriteString(str)
|
bw.WriteString(str)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import (
|
||||||
. "bytes"
|
. "bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
@ -235,7 +234,7 @@ func TestReaderCopyNothing(t *testing.T) {
|
||||||
type justWriter struct {
|
type justWriter struct {
|
||||||
io.Writer
|
io.Writer
|
||||||
}
|
}
|
||||||
discard := justWriter{ioutil.Discard} // hide ReadFrom
|
discard := justWriter{io.Discard} // hide ReadFrom
|
||||||
|
|
||||||
var with, withOut nErr
|
var with, withOut nErr
|
||||||
with.n, with.err = io.Copy(discard, NewReader(nil))
|
with.n, with.err = io.Copy(discard, NewReader(nil))
|
||||||
|
|
@ -248,7 +247,7 @@ func TestReaderCopyNothing(t *testing.T) {
|
||||||
// tests that Len is affected by reads, but Size is not.
|
// tests that Len is affected by reads, but Size is not.
|
||||||
func TestReaderLenSize(t *testing.T) {
|
func TestReaderLenSize(t *testing.T) {
|
||||||
r := NewReader([]byte("abc"))
|
r := NewReader([]byte("abc"))
|
||||||
io.CopyN(ioutil.Discard, r, 1)
|
io.CopyN(io.Discard, r, 1)
|
||||||
if r.Len() != 2 {
|
if r.Len() != 2 {
|
||||||
t.Errorf("Len = %d; want 2", r.Len())
|
t.Errorf("Len = %d; want 2", r.Len())
|
||||||
}
|
}
|
||||||
|
|
@ -268,7 +267,7 @@ func TestReaderReset(t *testing.T) {
|
||||||
if err := r.UnreadRune(); err == nil {
|
if err := r.UnreadRune(); err == nil {
|
||||||
t.Errorf("UnreadRune: expected error, got nil")
|
t.Errorf("UnreadRune: expected error, got nil")
|
||||||
}
|
}
|
||||||
buf, err := ioutil.ReadAll(r)
|
buf, err := io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("ReadAll: unexpected error: %v", err)
|
t.Errorf("ReadAll: unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -314,7 +313,7 @@ func TestReaderZero(t *testing.T) {
|
||||||
t.Errorf("UnreadRune: got nil, want error")
|
t.Errorf("UnreadRune: got nil, want error")
|
||||||
}
|
}
|
||||||
|
|
||||||
if n, err := (&Reader{}).WriteTo(ioutil.Discard); n != 0 || err != nil {
|
if n, err := (&Reader{}).WriteTo(io.Discard); n != 0 || err != nil {
|
||||||
t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err)
|
t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -326,6 +326,18 @@ func compareAPI(w io.Writer, features, required, optional, exception []string, a
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// aliasReplacer applies type aliases to earlier API files,
|
||||||
|
// to avoid misleading negative results.
|
||||||
|
// This makes all the references to os.FileInfo in go1.txt
|
||||||
|
// be read as if they said fs.FileInfo, since os.FileInfo is now an alias.
|
||||||
|
// If there are many of these, we could do a more general solution,
|
||||||
|
// but for now the replacer is fine.
|
||||||
|
var aliasReplacer = strings.NewReplacer(
|
||||||
|
"os.FileInfo", "fs.FileInfo",
|
||||||
|
"os.FileMode", "fs.FileMode",
|
||||||
|
"os.PathError", "fs.PathError",
|
||||||
|
)
|
||||||
|
|
||||||
func fileFeatures(filename string) []string {
|
func fileFeatures(filename string) []string {
|
||||||
if filename == "" {
|
if filename == "" {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -334,7 +346,9 @@ func fileFeatures(filename string) []string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error reading file %s: %v", filename, err)
|
log.Fatalf("Error reading file %s: %v", filename, err)
|
||||||
}
|
}
|
||||||
lines := strings.Split(string(bs), "\n")
|
s := string(bs)
|
||||||
|
s = aliasReplacer.Replace(s)
|
||||||
|
lines := strings.Split(s, "\n")
|
||||||
var nonblank []string
|
var nonblank []string
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
|
|
@ -856,6 +870,10 @@ func (w *Walker) emitObj(obj types.Object) {
|
||||||
func (w *Walker) emitType(obj *types.TypeName) {
|
func (w *Walker) emitType(obj *types.TypeName) {
|
||||||
name := obj.Name()
|
name := obj.Name()
|
||||||
typ := obj.Type()
|
typ := obj.Type()
|
||||||
|
if obj.IsAlias() {
|
||||||
|
w.emitf("type %s = %s", name, w.typeString(typ))
|
||||||
|
return
|
||||||
|
}
|
||||||
switch typ := typ.Underlying().(type) {
|
switch typ := typ.Underlying().(type) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
w.emitStructType(name, typ)
|
w.emitStructType(name, typ)
|
||||||
|
|
|
||||||
|
|
@ -535,6 +535,9 @@ func archRISCV64() *Arch {
|
||||||
|
|
||||||
// Standard register names.
|
// Standard register names.
|
||||||
for i := riscv.REG_X0; i <= riscv.REG_X31; i++ {
|
for i := riscv.REG_X0; i <= riscv.REG_X31; i++ {
|
||||||
|
if i == riscv.REG_G {
|
||||||
|
continue
|
||||||
|
}
|
||||||
name := fmt.Sprintf("X%d", i-riscv.REG_X0)
|
name := fmt.Sprintf("X%d", i-riscv.REG_X0)
|
||||||
register[name] = int16(i)
|
register[name] = int16(i)
|
||||||
}
|
}
|
||||||
|
|
@ -571,7 +574,7 @@ func archRISCV64() *Arch {
|
||||||
register["S8"] = riscv.REG_S8
|
register["S8"] = riscv.REG_S8
|
||||||
register["S9"] = riscv.REG_S9
|
register["S9"] = riscv.REG_S9
|
||||||
register["S10"] = riscv.REG_S10
|
register["S10"] = riscv.REG_S10
|
||||||
register["S11"] = riscv.REG_S11
|
// Skip S11 as it is the g register.
|
||||||
register["T3"] = riscv.REG_T3
|
register["T3"] = riscv.REG_T3
|
||||||
register["T4"] = riscv.REG_T4
|
register["T4"] = riscv.REG_T4
|
||||||
register["T5"] = riscv.REG_T5
|
register["T5"] = riscv.REG_T5
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func IsARM64STLXR(op obj.As) bool {
|
||||||
arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
|
arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// atomic instructions
|
// LDADDx/SWPx/CASx atomic instructions
|
||||||
if arm64.IsAtomicInstruction(op) {
|
if arm64.IsAtomicInstruction(op) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -93,6 +93,17 @@ func IsARM64TBL(op obj.As) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsARM64CASP reports whether the op (as defined by an arm64.A*
|
||||||
|
// constant) is one of the CASP-like instructions, and its 2nd
|
||||||
|
// destination is a register pair that require special handling.
|
||||||
|
func IsARM64CASP(op obj.As) bool {
|
||||||
|
switch op {
|
||||||
|
case arm64.ACASPD, arm64.ACASPW:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// ARM64Suffix handles the special suffix for the ARM64.
|
// ARM64Suffix handles the special suffix for the ARM64.
|
||||||
// It returns a boolean to indicate success; failure means
|
// It returns a boolean to indicate success; failure means
|
||||||
// cond was unrecognized.
|
// cond was unrecognized.
|
||||||
|
|
|
||||||
|
|
@ -637,6 +637,18 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.SetFrom3(a[1])
|
prog.SetFrom3(a[1])
|
||||||
prog.To = a[2]
|
prog.To = a[2]
|
||||||
|
case arch.IsARM64CASP(op):
|
||||||
|
prog.From = a[0]
|
||||||
|
prog.To = a[1]
|
||||||
|
// both 1st operand and 3rd operand are (Rs, Rs+1) register pair.
|
||||||
|
// And the register pair must be contiguous.
|
||||||
|
if (a[0].Type != obj.TYPE_REGREG) || (a[2].Type != obj.TYPE_REGREG) {
|
||||||
|
p.errorf("invalid addressing modes for 1st or 3rd operand to %s instruction, must be register pair", op)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// For ARM64 CASP-like instructions, its 2nd destination operand is register pair(Rt, Rt+1) that can
|
||||||
|
// not fit into prog.RegTo2, so save it to the prog.RestArgs.
|
||||||
|
prog.SetTo2(a[2])
|
||||||
default:
|
default:
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||||
|
|
@ -725,7 +737,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||||
}
|
}
|
||||||
if p.arch.Family == sys.AMD64 {
|
if p.arch.Family == sys.AMD64 {
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.RestArgs = []obj.Addr{a[1], a[2]}
|
prog.SetRestArgs([]obj.Addr{a[1], a[2]})
|
||||||
prog.To = a[3]
|
prog.To = a[3]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -808,13 +820,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||||
}
|
}
|
||||||
if p.arch.Family == sys.AMD64 {
|
if p.arch.Family == sys.AMD64 {
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.RestArgs = []obj.Addr{a[1], a[2], a[3]}
|
prog.SetRestArgs([]obj.Addr{a[1], a[2], a[3]})
|
||||||
prog.To = a[4]
|
prog.To = a[4]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if p.arch.Family == sys.S390X {
|
if p.arch.Family == sys.S390X {
|
||||||
prog.From = a[0]
|
prog.From = a[0]
|
||||||
prog.RestArgs = []obj.Addr{a[1], a[2], a[3]}
|
prog.SetRestArgs([]obj.Addr{a[1], a[2], a[3]})
|
||||||
prog.To = a[4]
|
prog.To = a[4]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -390,12 +390,7 @@ func TestARM64Errors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAMD64EndToEnd(t *testing.T) {
|
func TestAMD64EndToEnd(t *testing.T) {
|
||||||
defer func(old string) { objabi.GOAMD64 = old }(objabi.GOAMD64)
|
|
||||||
for _, goamd64 := range []string{"normaljumps", "alignedjumps"} {
|
|
||||||
t.Logf("GOAMD64=%s", goamd64)
|
|
||||||
objabi.GOAMD64 = goamd64
|
|
||||||
testEndToEnd(t, "amd64", "amd64")
|
testEndToEnd(t, "amd64", "amd64")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test386Encoder(t *testing.T) {
|
func Test386Encoder(t *testing.T) {
|
||||||
|
|
|
||||||
693
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
693
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
|
|
@ -10,14 +10,8 @@
|
||||||
|
|
||||||
TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
|
|
||||||
//
|
|
||||||
// ADD
|
// arithmetic operations
|
||||||
//
|
|
||||||
// LTYPE1 imsr ',' spreg ',' reg
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, $4, &$6);
|
|
||||||
// }
|
|
||||||
// imsr comes from the old 7a, we only support immediates and registers
|
|
||||||
ADDW $1, R2, R3
|
ADDW $1, R2, R3
|
||||||
ADDW R1, R2, R3
|
ADDW R1, R2, R3
|
||||||
ADDW R1, ZR, R3
|
ADDW R1, ZR, R3
|
||||||
|
|
@ -25,6 +19,13 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
ADD R1, R2, R3
|
ADD R1, R2, R3
|
||||||
ADD R1, ZR, R3
|
ADD R1, ZR, R3
|
||||||
ADD $1, R2, R3
|
ADD $1, R2, R3
|
||||||
|
ADDW $1, R2
|
||||||
|
ADDW R1, R2
|
||||||
|
ADD $1, R2
|
||||||
|
ADD R1, R2
|
||||||
|
ADD R1>>11, R2
|
||||||
|
ADD R1<<22, R2
|
||||||
|
ADD R1->33, R2
|
||||||
ADD $0x000aaa, R2, R3 // ADD $2730, R2, R3 // 43a82a91
|
ADD $0x000aaa, R2, R3 // ADD $2730, R2, R3 // 43a82a91
|
||||||
ADD $0x000aaa, R2 // ADD $2730, R2 // 42a82a91
|
ADD $0x000aaa, R2 // ADD $2730, R2 // 42a82a91
|
||||||
ADD $0xaaa000, R2, R3 // ADD $11182080, R2, R3 // 43a86a91
|
ADD $0xaaa000, R2, R3 // ADD $11182080, R2, R3 // 43a86a91
|
||||||
|
|
@ -37,6 +38,10 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
SUB $0xaaa000, R2 // SUB $11182080, R2 // 42a86ad1
|
SUB $0xaaa000, R2 // SUB $11182080, R2 // 42a86ad1
|
||||||
SUB $0xaaaaaa, R2, R3 // SUB $11184810, R2, R3 // 43a82ad163a86ad1
|
SUB $0xaaaaaa, R2, R3 // SUB $11184810, R2, R3 // 43a82ad163a86ad1
|
||||||
SUB $0xaaaaaa, R2 // SUB $11184810, R2 // 42a82ad142a86ad1
|
SUB $0xaaaaaa, R2 // SUB $11184810, R2 // 42a82ad142a86ad1
|
||||||
|
ADDW $0x60060, R2 // ADDW $393312, R2 // 4280011142804111
|
||||||
|
ADD $0x186a0, R2, R5 // ADD $100000, R2, R5 // 45801a91a5604091
|
||||||
|
SUB $0xe7791f700, R3, R1 // SUB $62135596800, R3, R1 // 1be09ed23bf2aef2db01c0f261001bcb
|
||||||
|
ADD $0x3fffffffc000, R5 // ADD $70368744161280, R5 // fb7f72b2a5001b8b
|
||||||
ADD R1>>11, R2, R3
|
ADD R1>>11, R2, R3
|
||||||
ADD R1<<22, R2, R3
|
ADD R1<<22, R2, R3
|
||||||
ADD R1->33, R2, R3
|
ADD R1->33, R2, R3
|
||||||
|
|
@ -59,6 +64,30 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
CMN R1.SXTX<<2, R10 // 5fe921ab
|
CMN R1.SXTX<<2, R10 // 5fe921ab
|
||||||
CMPW R2.UXTH<<3, R11 // 7f2d226b
|
CMPW R2.UXTH<<3, R11 // 7f2d226b
|
||||||
CMNW R1.SXTB, R9 // 3f81212b
|
CMNW R1.SXTB, R9 // 3f81212b
|
||||||
|
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
|
||||||
|
CMPW $40960, R0 // 1f284071
|
||||||
|
CMPW $27745, R2 // 3b8c8d525f001b6b
|
||||||
|
CMNW $0x3fffffc0, R2 // CMNW $1073741760, R2 // fb5f1a325f001b2b
|
||||||
|
CMPW $0xffff0, R1 // CMPW $1048560, R1 // fb3f1c323f001b6b
|
||||||
|
CMP $0xffffffffffa0, R3 // CMP $281474976710560, R3 // fb0b80921b00e0f27f001beb
|
||||||
|
CMP $0xf4240, R1 // CMP $1000000, R1 // 1b4888d2fb01a0f23f001beb
|
||||||
|
CMP $3343198598084851058, R3 // 5bae8ed2db8daef23badcdf2bbcce5f27f001beb
|
||||||
|
CMP $3, R2
|
||||||
|
CMP R1, R2
|
||||||
|
CMP R1->11, R2
|
||||||
|
CMP R1>>22, R2
|
||||||
|
CMP R1<<33, R2
|
||||||
|
CMP R22.SXTX, RSP // ffe336eb
|
||||||
|
CMP $0x22220000, RSP // CMP $572653568, RSP // 5b44a4d2ff633beb
|
||||||
|
CMPW $0x22220000, RSP // CMPW $572653568, RSP // 5b44a452ff633b6b
|
||||||
|
CCMN MI, ZR, R1, $4 // e44341ba
|
||||||
|
// MADD Rn,Rm,Ra,Rd
|
||||||
|
MADD R1, R2, R3, R4 // 6408019b
|
||||||
|
// CLS
|
||||||
|
CLSW R1, R2
|
||||||
|
CLS R1, R2
|
||||||
|
|
||||||
|
// fp/simd instructions.
|
||||||
VADDP V1.B16, V2.B16, V3.B16 // 43bc214e
|
VADDP V1.B16, V2.B16, V3.B16 // 43bc214e
|
||||||
VADDP V1.S4, V2.S4, V3.S4 // 43bca14e
|
VADDP V1.S4, V2.S4, V3.S4 // 43bca14e
|
||||||
VADDP V1.D2, V2.D2, V3.D2 // 43bce14e
|
VADDP V1.D2, V2.D2, V3.D2 // 43bce14e
|
||||||
|
|
@ -67,22 +96,6 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
VORR V5.B16, V4.B16, V3.B16 // 831ca54e
|
VORR V5.B16, V4.B16, V3.B16 // 831ca54e
|
||||||
VADD V16.S4, V5.S4, V9.S4 // a984b04e
|
VADD V16.S4, V5.S4, V9.S4 // a984b04e
|
||||||
VEOR V0.B16, V1.B16, V0.B16 // 201c206e
|
VEOR V0.B16, V1.B16, V0.B16 // 201c206e
|
||||||
SHA256H V9.S4, V3, V2 // 6240095e
|
|
||||||
SHA256H2 V9.S4, V4, V3 // 8350095e
|
|
||||||
SHA256SU0 V8.S4, V7.S4 // 0729285e
|
|
||||||
SHA256SU1 V6.S4, V5.S4, V7.S4 // a760065e
|
|
||||||
SHA1SU0 V11.S4, V8.S4, V6.S4 // 06310b5e
|
|
||||||
SHA1SU1 V5.S4, V1.S4 // a118285e
|
|
||||||
SHA1C V1.S4, V2, V3 // 4300015e
|
|
||||||
SHA1H V5, V4 // a408285e
|
|
||||||
SHA1M V8.S4, V7, V6 // e620085e
|
|
||||||
SHA1P V11.S4, V10, V9 // 49110b5e
|
|
||||||
SHA512H V2.D2, V1, V0 // 208062ce
|
|
||||||
SHA512H2 V4.D2, V3, V2 // 628464ce
|
|
||||||
SHA512SU0 V9.D2, V8.D2 // 2881c0ce
|
|
||||||
SHA512SU1 V7.D2, V6.D2, V5.D2 // c58867ce
|
|
||||||
VRAX1 V26.D2, V29.D2, V30.D2 // be8f7ace
|
|
||||||
VXAR $63, V27.D2, V21.D2, V26.D2 // bafe9bce
|
|
||||||
VADDV V0.S4, V0 // 00b8b14e
|
VADDV V0.S4, V0 // 00b8b14e
|
||||||
VMOVI $82, V0.B16 // 40e6024f
|
VMOVI $82, V0.B16 // 40e6024f
|
||||||
VUADDLV V6.B16, V6 // c638306e
|
VUADDLV V6.B16, V6 // c638306e
|
||||||
|
|
@ -96,10 +109,6 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
VFMLS V1.D2, V12.D2, V1.D2 // 81cde14e
|
VFMLS V1.D2, V12.D2, V1.D2 // 81cde14e
|
||||||
VFMLS V1.S2, V12.S2, V1.S2 // 81cda10e
|
VFMLS V1.S2, V12.S2, V1.S2 // 81cda10e
|
||||||
VFMLS V1.S4, V12.S4, V1.S4 // 81cda14e
|
VFMLS V1.S4, V12.S4, V1.S4 // 81cda14e
|
||||||
VPMULL V2.D1, V1.D1, V3.Q1 // 23e0e20e
|
|
||||||
VPMULL2 V2.D2, V1.D2, V4.Q1 // 24e0e24e
|
|
||||||
VPMULL V2.B8, V1.B8, V3.H8 // 23e0220e
|
|
||||||
VPMULL2 V2.B16, V1.B16, V4.H8 // 24e0224e
|
|
||||||
VEXT $4, V2.B8, V1.B8, V3.B8 // 2320022e
|
VEXT $4, V2.B8, V1.B8, V3.B8 // 2320022e
|
||||||
VEXT $8, V2.B16, V1.B16, V3.B16 // 2340026e
|
VEXT $8, V2.B16, V1.B16, V3.B16 // 2340026e
|
||||||
VRBIT V24.B16, V24.B16 // 185b606e
|
VRBIT V24.B16, V24.B16 // 185b606e
|
||||||
|
|
@ -125,6 +134,14 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
VSRI $8, V1.H8, V2.H8 // 2244186f
|
VSRI $8, V1.H8, V2.H8 // 2244186f
|
||||||
VSRI $2, V1.B8, V2.B8 // 22440e2f
|
VSRI $2, V1.B8, V2.B8 // 22440e2f
|
||||||
VSRI $2, V1.B16, V2.B16 // 22440e6f
|
VSRI $2, V1.B16, V2.B16 // 22440e6f
|
||||||
|
VSLI $7, V2.B16, V3.B16 // 43540f6f
|
||||||
|
VSLI $15, V3.H4, V4.H4 // 64541f2f
|
||||||
|
VSLI $31, V5.S4, V6.S4 // a6543f6f
|
||||||
|
VSLI $63, V7.D2, V8.D2 // e8547f6f
|
||||||
|
VUSRA $8, V2.B16, V3.B16 // 4314086f
|
||||||
|
VUSRA $16, V3.H4, V4.H4 // 6414102f
|
||||||
|
VUSRA $32, V5.S4, V6.S4 // a614206f
|
||||||
|
VUSRA $64, V7.D2, V8.D2 // e814406f
|
||||||
VTBL V22.B16, [V28.B16, V29.B16], V11.B16 // 8b23164e
|
VTBL V22.B16, [V28.B16, V29.B16], V11.B16 // 8b23164e
|
||||||
VTBL V18.B8, [V17.B16, V18.B16, V19.B16], V22.B8 // 3642120e
|
VTBL V18.B8, [V17.B16, V18.B16, V19.B16], V22.B8 // 3642120e
|
||||||
VTBL V31.B8, [V14.B16, V15.B16, V16.B16, V17.B16], V15.B8 // cf611f0e
|
VTBL V31.B8, [V14.B16, V15.B16, V16.B16, V17.B16], V15.B8 // cf611f0e
|
||||||
|
|
@ -141,8 +158,6 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
VTBL V14.B16, [V3.B16, V4.B16, V5.B16], V17.B16 // 71400e4e
|
VTBL V14.B16, [V3.B16, V4.B16, V5.B16], V17.B16 // 71400e4e
|
||||||
VTBL V13.B16, [V29.B16, V30.B16, V31.B16, V0.B16], V28.B16 // bc630d4e
|
VTBL V13.B16, [V29.B16, V30.B16, V31.B16, V0.B16], V28.B16 // bc630d4e
|
||||||
VTBL V3.B8, [V27.B16], V8.B8 // 6803030e
|
VTBL V3.B8, [V27.B16], V8.B8 // 6803030e
|
||||||
VEOR3 V2.B16, V7.B16, V12.B16, V25.B16 // 990907ce
|
|
||||||
VBCAX V1.B16, V2.B16, V26.B16, V31.B16 // 5f0722ce
|
|
||||||
VZIP1 V16.H8, V3.H8, V19.H8 // 7338504e
|
VZIP1 V16.H8, V3.H8, V19.H8 // 7338504e
|
||||||
VZIP2 V22.D2, V25.D2, V21.D2 // 357bd64e
|
VZIP2 V22.D2, V25.D2, V21.D2 // 357bd64e
|
||||||
VZIP1 V6.D2, V9.D2, V11.D2 // 2b39c64e
|
VZIP1 V6.D2, V9.D2, V11.D2 // 2b39c64e
|
||||||
|
|
@ -180,105 +195,87 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
VUSHLL2 $31, V30.S4, V2.D2 // c2a73f6f
|
VUSHLL2 $31, V30.S4, V2.D2 // c2a73f6f
|
||||||
VBIF V0.B8, V30.B8, V1.B8 // c11fe02e
|
VBIF V0.B8, V30.B8, V1.B8 // c11fe02e
|
||||||
VBIF V30.B16, V0.B16, V2.B16 // 021cfe6e
|
VBIF V30.B16, V0.B16, V2.B16 // 021cfe6e
|
||||||
MOVD (R2)(R6.SXTW), R4 // 44c866f8
|
|
||||||
MOVD (R3)(R6), R5 // MOVD (R3)(R6*1), R5 // 656866f8
|
|
||||||
MOVD (R2)(R6), R4 // MOVD (R2)(R6*1), R4 // 446866f8
|
|
||||||
MOVWU (R19)(R20<<2), R20 // 747a74b8
|
|
||||||
MOVD (R2)(R6<<3), R4 // 447866f8
|
|
||||||
MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8
|
|
||||||
MOVWU (R5)(R4.UXTW), R10 // aa4864b8
|
|
||||||
MOVBU (R3)(R9.UXTW), R8 // 68486938
|
|
||||||
MOVBU (R5)(R8), R10 // MOVBU (R5)(R8*1), R10 // aa686838
|
|
||||||
MOVHU (R2)(R7.SXTW<<1), R11 // 4bd86778
|
|
||||||
MOVHU (R1)(R2<<1), R5 // 25786278
|
|
||||||
MOVB (R9)(R3.UXTW), R6 // 2649a338
|
|
||||||
MOVB (R10)(R6), R15 // MOVB (R10)(R6*1), R15 // 4f69a638
|
|
||||||
MOVH (R5)(R7.SXTX<<1), R19 // b3f8a778
|
|
||||||
MOVH (R8)(R4<<1), R10 // 0a79a478
|
|
||||||
MOVW (R9)(R8.SXTW<<2), R19 // 33d9a8b8
|
|
||||||
MOVW (R1)(R4.SXTX), R11 // 2be8a4b8
|
|
||||||
MOVW (R1)(R4.SXTX), ZR // 3fe8a4b8
|
|
||||||
MOVW (R2)(R5), R12 // MOVW (R2)(R5*1), R12 // 4c68a5b8
|
|
||||||
MOVD R5, (R2)(R6<<3) // 457826f8
|
|
||||||
MOVD R9, (R6)(R7.SXTX<<3) // c9f827f8
|
|
||||||
MOVD ZR, (R6)(R7.SXTX<<3) // dff827f8
|
|
||||||
MOVW R8, (R2)(R3.UXTW<<2) // 485823b8
|
|
||||||
MOVW R7, (R3)(R4.SXTW) // 67c824b8
|
|
||||||
MOVB R4, (R2)(R6.SXTX) // 44e82638
|
|
||||||
MOVB R8, (R3)(R9.UXTW) // 68482938
|
|
||||||
MOVB R10, (R5)(R8) // MOVB R10, (R5)(R8*1) // aa682838
|
|
||||||
MOVH R11, (R2)(R7.SXTW<<1) // 4bd82778
|
|
||||||
MOVH R5, (R1)(R2<<1) // 25782278
|
|
||||||
MOVH R7, (R2)(R5.SXTX<<1) // 47f82578
|
|
||||||
MOVH R8, (R3)(R6.UXTW) // 68482678
|
|
||||||
MOVB (R29)(R30<<0), R14 // ae7bbe38
|
|
||||||
MOVB (R29)(R30), R14 // MOVB (R29)(R30*1), R14 // ae6bbe38
|
|
||||||
MOVB R4, (R2)(R6.SXTX) // 44e82638
|
|
||||||
FMOVS $(4.0), F0 // 0010221e
|
FMOVS $(4.0), F0 // 0010221e
|
||||||
FMOVD $(4.0), F0 // 0010621e
|
FMOVD $(4.0), F0 // 0010621e
|
||||||
FMOVS $(0.265625), F1 // 01302a1e
|
FMOVS $(0.265625), F1 // 01302a1e
|
||||||
FMOVD $(0.1796875), F2 // 02f0681e
|
FMOVD $(0.1796875), F2 // 02f0681e
|
||||||
FMOVS $(0.96875), F3 // 03f02d1e
|
FMOVS $(0.96875), F3 // 03f02d1e
|
||||||
FMOVD $(28.0), F4 // 0490671e
|
FMOVD $(28.0), F4 // 0490671e
|
||||||
|
VUADDW V9.B8, V12.H8, V14.H8 // 8e11292e
|
||||||
|
VUADDW V13.H4, V10.S4, V11.S4 // 4b116d2e
|
||||||
|
VUADDW V21.S2, V24.D2, V29.D2 // 1d13b52e
|
||||||
|
VUADDW2 V9.B16, V12.H8, V14.H8 // 8e11296e
|
||||||
|
VUADDW2 V13.H8, V20.S4, V30.S4 // 9e126d6e
|
||||||
|
VUADDW2 V21.S4, V24.D2, V29.D2 // 1d13b56e
|
||||||
|
FCCMPS LT, F1, F2, $1 // 41b4211e
|
||||||
|
FMADDS F1, F3, F2, F4 // 440c011f
|
||||||
|
FMADDD F4, F5, F4, F4 // 8414441f
|
||||||
|
FMSUBS F13, F21, F13, F19 // b3d50d1f
|
||||||
|
FMSUBD F11, F7, F15, F31 // ff9d4b1f
|
||||||
|
FNMADDS F1, F3, F2, F4 // 440c211f
|
||||||
|
FNMADDD F1, F3, F2, F4 // 440c611f
|
||||||
|
FNMSUBS F1, F3, F2, F4 // 448c211f
|
||||||
|
FNMSUBD F1, F3, F2, F4 // 448c611f
|
||||||
|
FADDS F2, F3, F4 // 6428221e
|
||||||
|
FADDD F1, F2 // 4228611e
|
||||||
|
VDUP V19.S[0], V17.S4 // 7106044e
|
||||||
|
|
||||||
// move a large constant to a Vd.
|
|
||||||
VMOVS $0x80402010, V11 // VMOVS $2151686160, V11
|
|
||||||
VMOVD $0x8040201008040201, V20 // VMOVD $-9205322385119247871, V20
|
|
||||||
VMOVQ $0x7040201008040201, $0x8040201008040201, V10 // VMOVQ $8088500183983456769, $-9205322385119247871, V10
|
|
||||||
VMOVQ $0x8040201008040202, $0x7040201008040201, V20 // VMOVQ $-9205322385119247870, $8088500183983456769, V20
|
|
||||||
|
|
||||||
FMOVS (R2)(R6), F4 // FMOVS (R2)(R6*1), F4 // 446866bc
|
// special
|
||||||
FMOVS (R2)(R6<<2), F4 // 447866bc
|
PRFM (R2), PLDL1KEEP // 400080f9
|
||||||
FMOVD (R2)(R6), F4 // FMOVD (R2)(R6*1), F4 // 446866fc
|
PRFM 16(R2), PLDL1KEEP // 400880f9
|
||||||
FMOVD (R2)(R6<<3), F4 // 447866fc
|
PRFM 48(R6), PSTL2STRM // d31880f9
|
||||||
FMOVS F4, (R2)(R6) // FMOVS F4, (R2)(R6*1) // 446826bc
|
PRFM 8(R12), PLIL3STRM // 8d0580f9
|
||||||
FMOVS F4, (R2)(R6<<2) // 447826bc
|
PRFM (R8), $25 // 190180f9
|
||||||
FMOVD F4, (R2)(R6) // FMOVD F4, (R2)(R6*1) // 446826fc
|
PRFM 8(R9), $30 // 3e0580f9
|
||||||
FMOVD F4, (R2)(R6<<3) // 447826fc
|
NOOP // 1f2003d5
|
||||||
|
HINT $0 // 1f2003d5
|
||||||
|
DMB $1
|
||||||
|
SVC
|
||||||
|
|
||||||
CMPW $40960, R0 // 1f284071
|
// encryption
|
||||||
CMPW $27745, R2 // 3b8c8d525f001b6b
|
SHA256H V9.S4, V3, V2 // 6240095e
|
||||||
CMNW $0x3fffffc0, R2 // CMNW $1073741760, R2 // fb5f1a325f001b2b
|
SHA256H2 V9.S4, V4, V3 // 8350095e
|
||||||
CMPW $0xffff0, R1 // CMPW $1048560, R1 // fb3f1c323f001b6b
|
SHA256SU0 V8.S4, V7.S4 // 0729285e
|
||||||
CMP $0xffffffffffa0, R3 // CMP $281474976710560, R3 // fb0b80921b00e0f27f001beb
|
SHA256SU1 V6.S4, V5.S4, V7.S4 // a760065e
|
||||||
CMP $0xf4240, R1 // CMP $1000000, R1 // 1b4888d2fb01a0f23f001beb
|
SHA1SU0 V11.S4, V8.S4, V6.S4 // 06310b5e
|
||||||
ADD $0x186a0, R2, R5 // ADD $100000, R2, R5 // 45801a91a5604091
|
SHA1SU1 V5.S4, V1.S4 // a118285e
|
||||||
SUB $0xe7791f700, R3, R1 // SUB $62135596800, R3, R1 // 1be09ed23bf2aef2db01c0f261001bcb
|
SHA1C V1.S4, V2, V3 // 4300015e
|
||||||
CMP $3343198598084851058, R3 // 5bae8ed2db8daef23badcdf2bbcce5f27f001beb
|
SHA1H V5, V4 // a408285e
|
||||||
ADD $0x3fffffffc000, R5 // ADD $70368744161280, R5 // fb7f72b2a5001b8b
|
SHA1M V8.S4, V7, V6 // e620085e
|
||||||
// LTYPE1 imsr ',' spreg ','
|
SHA1P V11.S4, V10, V9 // 49110b5e
|
||||||
// {
|
SHA512H V2.D2, V1, V0 // 208062ce
|
||||||
// outcode($1, &$2, $4, &nullgen);
|
SHA512H2 V4.D2, V3, V2 // 628464ce
|
||||||
// }
|
SHA512SU0 V9.D2, V8.D2 // 2881c0ce
|
||||||
// LTYPE1 imsr ',' reg
|
SHA512SU1 V7.D2, V6.D2, V5.D2 // c58867ce
|
||||||
// {
|
VRAX1 V26.D2, V29.D2, V30.D2 // be8f7ace
|
||||||
// outcode($1, &$2, NREG, &$4);
|
VXAR $63, V27.D2, V21.D2, V26.D2 // bafe9bce
|
||||||
// }
|
VPMULL V2.D1, V1.D1, V3.Q1 // 23e0e20e
|
||||||
ADDW $1, R2
|
VPMULL2 V2.D2, V1.D2, V4.Q1 // 24e0e24e
|
||||||
ADDW R1, R2
|
VPMULL V2.B8, V1.B8, V3.H8 // 23e0220e
|
||||||
ADD $1, R2
|
VPMULL2 V2.B16, V1.B16, V4.H8 // 24e0224e
|
||||||
ADD R1, R2
|
VEOR3 V2.B16, V7.B16, V12.B16, V25.B16 // 990907ce
|
||||||
ADD R1>>11, R2
|
VBCAX V1.B16, V2.B16, V26.B16, V31.B16 // 5f0722ce
|
||||||
ADD R1<<22, R2
|
VREV32 V5.B16, V5.B16 // a508206e
|
||||||
ADD R1->33, R2
|
VREV64 V2.S2, V3.S2 // 4308a00e
|
||||||
AND R1@>33, R2
|
VREV64 V2.S4, V3.S4 // 4308a04e
|
||||||
|
|
||||||
// logical ops
|
// logical ops
|
||||||
|
//
|
||||||
// make sure constants get encoded into an instruction when it could
|
// make sure constants get encoded into an instruction when it could
|
||||||
|
AND R1@>33, R2
|
||||||
AND $(1<<63), R1 // AND $-9223372036854775808, R1 // 21004192
|
AND $(1<<63), R1 // AND $-9223372036854775808, R1 // 21004192
|
||||||
AND $(1<<63-1), R1 // AND $9223372036854775807, R1 // 21f84092
|
AND $(1<<63-1), R1 // AND $9223372036854775807, R1 // 21f84092
|
||||||
ORR $(1<<63), R1 // ORR $-9223372036854775808, R1 // 210041b2
|
ORR $(1<<63), R1 // ORR $-9223372036854775808, R1 // 210041b2
|
||||||
ORR $(1<<63-1), R1 // ORR $9223372036854775807, R1 // 21f840b2
|
ORR $(1<<63-1), R1 // ORR $9223372036854775807, R1 // 21f840b2
|
||||||
EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2
|
EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2
|
||||||
EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2
|
EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2
|
||||||
|
|
||||||
ANDW $0x3ff00000, R2 // ANDW $1072693248, R2 // 42240c12
|
ANDW $0x3ff00000, R2 // ANDW $1072693248, R2 // 42240c12
|
||||||
BICW $0x3ff00000, R2 // BICW $1072693248, R2 // 42540212
|
BICW $0x3ff00000, R2 // BICW $1072693248, R2 // 42540212
|
||||||
ORRW $0x3ff00000, R2 // ORRW $1072693248, R2 // 42240c32
|
ORRW $0x3ff00000, R2 // ORRW $1072693248, R2 // 42240c32
|
||||||
ORNW $0x3ff00000, R2 // ORNW $1072693248, R2 // 42540232
|
ORNW $0x3ff00000, R2 // ORNW $1072693248, R2 // 42540232
|
||||||
EORW $0x3ff00000, R2 // EORW $1072693248, R2 // 42240c52
|
EORW $0x3ff00000, R2 // EORW $1072693248, R2 // 42240c52
|
||||||
EONW $0x3ff00000, R2 // EONW $1072693248, R2 // 42540252
|
EONW $0x3ff00000, R2 // EONW $1072693248, R2 // 42540252
|
||||||
|
|
||||||
AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a
|
AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a
|
||||||
ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa
|
ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa
|
||||||
EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca
|
EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca
|
||||||
|
|
@ -287,7 +284,6 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
EON $0x22220000, R3, R4 // EON $572653568, R3, R4 // 5b44a4d264003bca
|
EON $0x22220000, R3, R4 // EON $572653568, R3, R4 // 5b44a4d264003bca
|
||||||
ANDS $0x22220000, R3, R4 // ANDS $572653568, R3, R4 // 5b44a4d264001bea
|
ANDS $0x22220000, R3, R4 // ANDS $572653568, R3, R4 // 5b44a4d264001bea
|
||||||
BICS $0x22220000, R3, R4 // BICS $572653568, R3, R4 // 5b44a4d264003bea
|
BICS $0x22220000, R3, R4 // BICS $572653568, R3, R4 // 5b44a4d264003bea
|
||||||
|
|
||||||
EOR $0xe03fffffffffffff, R20, R22 // EOR $-2287828610704211969, R20, R22 // 96e243d2
|
EOR $0xe03fffffffffffff, R20, R22 // EOR $-2287828610704211969, R20, R22 // 96e243d2
|
||||||
TSTW $0x600000006, R1 // TSTW $25769803782, R1 // 3f041f72
|
TSTW $0x600000006, R1 // TSTW $25769803782, R1 // 3f041f72
|
||||||
TST $0x4900000049, R0 // TST $313532612681, R0 // 3b0980d23b09c0f21f001bea
|
TST $0x4900000049, R0 // TST $313532612681, R0 // 3b0980d23b09c0f21f001bea
|
||||||
|
|
@ -316,19 +312,22 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
EONW $0x6006000060060, R5 // EONW $1689262177517664, R5 // 1b0c8052db00a072a5003b4a
|
EONW $0x6006000060060, R5 // EONW $1689262177517664, R5 // 1b0c8052db00a072a5003b4a
|
||||||
ORNW $0x6006000060060, R5 // ORNW $1689262177517664, R5 // 1b0c8052db00a072a5003b2a
|
ORNW $0x6006000060060, R5 // ORNW $1689262177517664, R5 // 1b0c8052db00a072a5003b2a
|
||||||
BICSW $0x6006000060060, R5 // BICSW $1689262177517664, R5 // 1b0c8052db00a072a5003b6a
|
BICSW $0x6006000060060, R5 // BICSW $1689262177517664, R5 // 1b0c8052db00a072a5003b6a
|
||||||
ADDW $0x60060, R2 // ADDW $393312, R2 // 4280011142804111
|
|
||||||
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
|
|
||||||
|
|
||||||
// TODO: this could have better encoding
|
// TODO: this could have better encoding
|
||||||
ANDW $-1, R10 // 1b0080124a011b0a
|
ANDW $-1, R10 // 1b0080124a011b0a
|
||||||
|
|
||||||
AND $8, R0, RSP // 1f007d92
|
AND $8, R0, RSP // 1f007d92
|
||||||
ORR $8, R0, RSP // 1f007db2
|
ORR $8, R0, RSP // 1f007db2
|
||||||
EOR $8, R0, RSP // 1f007dd2
|
EOR $8, R0, RSP // 1f007dd2
|
||||||
BIC $8, R0, RSP // 1ff87c92
|
BIC $8, R0, RSP // 1ff87c92
|
||||||
ORN $8, R0, RSP // 1ff87cb2
|
ORN $8, R0, RSP // 1ff87cb2
|
||||||
EON $8, R0, RSP // 1ff87cd2
|
EON $8, R0, RSP // 1ff87cd2
|
||||||
|
TST $15, R2 // 5f0c40f2
|
||||||
|
TST R1, R2 // 5f0001ea
|
||||||
|
TST R1->11, R2 // 5f2c81ea
|
||||||
|
TST R1>>22, R2 // 5f5841ea
|
||||||
|
TST R1<<33, R2 // 5f8401ea
|
||||||
|
TST $0x22220000, R3 // TST $572653568, R3 // 5b44a4d27f001bea
|
||||||
|
|
||||||
|
// move an immediate to a Rn.
|
||||||
MOVD $0x3fffffffc000, R0 // MOVD $70368744161280, R0 // e07f72b2
|
MOVD $0x3fffffffc000, R0 // MOVD $70368744161280, R0 // e07f72b2
|
||||||
MOVW $1000000, R4 // 04488852e401a072
|
MOVW $1000000, R4 // 04488852e401a072
|
||||||
MOVW $0xaaaa0000, R1 // MOVW $2863267840, R1 // 4155b552
|
MOVW $0xaaaa0000, R1 // MOVW $2863267840, R1 // 4155b552
|
||||||
|
|
@ -348,46 +347,37 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
MOVD $-1, R1 // 01008092
|
MOVD $-1, R1 // 01008092
|
||||||
MOVD $0x210000, R0 // MOVD $2162688, R0 // 2004a0d2
|
MOVD $0x210000, R0 // MOVD $2162688, R0 // 2004a0d2
|
||||||
MOVD $0xffffffffffffaaaa, R1 // MOVD $-21846, R1 // a1aa8a92
|
MOVD $0xffffffffffffaaaa, R1 // MOVD $-21846, R1 // a1aa8a92
|
||||||
|
MOVW $1, ZR
|
||||||
|
MOVW $1, R1
|
||||||
|
MOVD $1, ZR
|
||||||
|
MOVD $1, R1
|
||||||
|
MOVK $1, R1
|
||||||
|
|
||||||
|
// move a large constant to a Vd.
|
||||||
|
VMOVS $0x80402010, V11 // VMOVS $2151686160, V11
|
||||||
|
VMOVD $0x8040201008040201, V20 // VMOVD $-9205322385119247871, V20
|
||||||
|
VMOVQ $0x7040201008040201, $0x8040201008040201, V10 // VMOVQ $8088500183983456769, $-9205322385119247871, V10
|
||||||
|
VMOVQ $0x8040201008040202, $0x7040201008040201, V20 // VMOVQ $-9205322385119247870, $8088500183983456769, V20
|
||||||
|
|
||||||
|
// mov(to/from sp)
|
||||||
MOVD $0x1002(RSP), R1 // MOVD $4098(RSP), R1 // fb074091610b0091
|
MOVD $0x1002(RSP), R1 // MOVD $4098(RSP), R1 // fb074091610b0091
|
||||||
MOVD $0x1708(RSP), RSP // MOVD $5896(RSP), RSP // fb0740917f231c91
|
MOVD $0x1708(RSP), RSP // MOVD $5896(RSP), RSP // fb0740917f231c91
|
||||||
MOVD $0x2001(R7), R1 // MOVD $8193(R7), R1 // fb08409161070091
|
MOVD $0x2001(R7), R1 // MOVD $8193(R7), R1 // fb08409161070091
|
||||||
MOVD $0xffffff(R7), R1 // MOVD $16777215(R7), R1 // fbfc7f9161ff3f91
|
MOVD $0xffffff(R7), R1 // MOVD $16777215(R7), R1 // fbfc7f9161ff3f91
|
||||||
|
|
||||||
MOVD $-0x1(R7), R1 // MOVD $-1(R7), R1 // e10400d1
|
MOVD $-0x1(R7), R1 // MOVD $-1(R7), R1 // e10400d1
|
||||||
MOVD $-0x30(R7), R1 // MOVD $-48(R7), R1 // e1c000d1
|
MOVD $-0x30(R7), R1 // MOVD $-48(R7), R1 // e1c000d1
|
||||||
MOVD $-0x708(R7), R1 // MOVD $-1800(R7), R1 // e1201cd1
|
MOVD $-0x708(R7), R1 // MOVD $-1800(R7), R1 // e1201cd1
|
||||||
MOVD $-0x2000(RSP), R1 // MOVD $-8192(RSP), R1 // e10b40d1
|
MOVD $-0x2000(RSP), R1 // MOVD $-8192(RSP), R1 // e10b40d1
|
||||||
MOVD $-0x10000(RSP), RSP // MOVD $-65536(RSP), RSP // ff4340d1
|
MOVD $-0x10000(RSP), RSP // MOVD $-65536(RSP), RSP // ff4340d1
|
||||||
|
|
||||||
//
|
|
||||||
// CLS
|
|
||||||
//
|
|
||||||
// LTYPE2 imsr ',' reg
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, NREG, &$4);
|
|
||||||
// }
|
|
||||||
CLSW R1, R2
|
|
||||||
CLS R1, R2
|
|
||||||
|
|
||||||
//
|
|
||||||
// MOV
|
|
||||||
//
|
|
||||||
// LTYPE3 addr ',' addr
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, NREG, &$4);
|
|
||||||
// }
|
|
||||||
MOVW R1, R2
|
MOVW R1, R2
|
||||||
MOVW ZR, R1
|
MOVW ZR, R1
|
||||||
MOVW R1, ZR
|
MOVW R1, ZR
|
||||||
MOVW $1, ZR
|
|
||||||
MOVW $1, R1
|
|
||||||
MOVW ZR, (R1)
|
|
||||||
MOVD R1, R2
|
MOVD R1, R2
|
||||||
MOVD ZR, R1
|
MOVD ZR, R1
|
||||||
MOVD $1, ZR
|
|
||||||
MOVD $1, R1
|
// store and load
|
||||||
MOVD ZR, (R1)
|
//
|
||||||
|
// LD1/ST1
|
||||||
VLD1 (R8), [V1.B16, V2.B16] // 01a1404c
|
VLD1 (R8), [V1.B16, V2.B16] // 01a1404c
|
||||||
VLD1.P (R3), [V31.H8, V0.H8] // 7fa4df4c
|
VLD1.P (R3), [V31.H8, V0.H8] // 7fa4df4c
|
||||||
VLD1.P (R8)(R20), [V21.B16, V22.B16] // VLD1.P (R8)(R20*1), [V21.B16,V22.B16] // 15a1d44c
|
VLD1.P (R8)(R20), [V21.B16, V22.B16] // VLD1.P (R8)(R20*1), [V21.B16,V22.B16] // 15a1d44c
|
||||||
|
|
@ -445,34 +435,21 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
VST4 [V22.D2, V23.D2, V24.D2, V25.D2], (R3) // 760c004c
|
VST4 [V22.D2, V23.D2, V24.D2, V25.D2], (R3) // 760c004c
|
||||||
VST4.P [V14.D2, V15.D2, V16.D2, V17.D2], 64(R15) // ee0d9f4c
|
VST4.P [V14.D2, V15.D2, V16.D2, V17.D2], 64(R15) // ee0d9f4c
|
||||||
VST4.P [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23) // VST4.P [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23*1) // 7800970c
|
VST4.P [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23) // VST4.P [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23*1) // 7800970c
|
||||||
FMOVS F20, (R0) // 140000bd
|
|
||||||
|
// pre/post-indexed
|
||||||
FMOVS.P F20, 4(R0) // 144400bc
|
FMOVS.P F20, 4(R0) // 144400bc
|
||||||
FMOVS.W F20, 4(R0) // 144c00bc
|
FMOVS.W F20, 4(R0) // 144c00bc
|
||||||
FMOVS (R0), F20 // 140040bd
|
FMOVD.P F20, 8(R1) // 348400fc
|
||||||
|
FMOVQ.P F13, 11(R10) // 4db5803c
|
||||||
|
FMOVQ.W F15, 11(R20) // 8fbe803c
|
||||||
|
|
||||||
FMOVS.P 8(R0), F20 // 148440bc
|
FMOVS.P 8(R0), F20 // 148440bc
|
||||||
FMOVS.W 8(R0), F20 // 148c40bc
|
FMOVS.W 8(R0), F20 // 148c40bc
|
||||||
FMOVD F20, (R2) // 540000fd
|
|
||||||
FMOVD.P F20, 8(R1) // 348400fc
|
|
||||||
FMOVD.W 8(R1), F20 // 348c40fc
|
FMOVD.W 8(R1), F20 // 348c40fc
|
||||||
PRFM (R2), PLDL1KEEP // 400080f9
|
FMOVQ.P 11(R10), F13 // 4db5c03c
|
||||||
PRFM 16(R2), PLDL1KEEP // 400880f9
|
FMOVQ.W 11(R20), F15 // 8fbec03c
|
||||||
PRFM 48(R6), PSTL2STRM // d31880f9
|
|
||||||
PRFM 8(R12), PLIL3STRM // 8d0580f9
|
|
||||||
PRFM (R8), $25 // 190180f9
|
|
||||||
PRFM 8(R9), $30 // 3e0580f9
|
|
||||||
|
|
||||||
// small offset fits into instructions
|
// small offset fits into instructions
|
||||||
MOVB 1(R1), R2 // 22048039
|
|
||||||
MOVH 1(R1), R2 // 22108078
|
|
||||||
MOVH 2(R1), R2 // 22048079
|
|
||||||
MOVW 1(R1), R2 // 221080b8
|
|
||||||
MOVW 4(R1), R2 // 220480b9
|
|
||||||
MOVD 1(R1), R2 // 221040f8
|
|
||||||
MOVD 8(R1), R2 // 220440f9
|
|
||||||
FMOVS 1(R1), F2 // 221040bc
|
|
||||||
FMOVS 4(R1), F2 // 220440bd
|
|
||||||
FMOVD 1(R1), F2 // 221040fc
|
|
||||||
FMOVD 8(R1), F2 // 220440fd
|
|
||||||
MOVB R1, 1(R2) // 41040039
|
MOVB R1, 1(R2) // 41040039
|
||||||
MOVH R1, 1(R2) // 41100078
|
MOVH R1, 1(R2) // 41100078
|
||||||
MOVH R1, 2(R2) // 41040079
|
MOVH R1, 2(R2) // 41040079
|
||||||
|
|
@ -480,18 +457,37 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
MOVW R1, 4(R2) // 410400b9
|
MOVW R1, 4(R2) // 410400b9
|
||||||
MOVD R1, 1(R2) // 411000f8
|
MOVD R1, 1(R2) // 411000f8
|
||||||
MOVD R1, 8(R2) // 410400f9
|
MOVD R1, 8(R2) // 410400f9
|
||||||
|
MOVD ZR, (R1)
|
||||||
|
MOVW ZR, (R1)
|
||||||
FMOVS F1, 1(R2) // 411000bc
|
FMOVS F1, 1(R2) // 411000bc
|
||||||
FMOVS F1, 4(R2) // 410400bd
|
FMOVS F1, 4(R2) // 410400bd
|
||||||
|
FMOVS F20, (R0) // 140000bd
|
||||||
FMOVD F1, 1(R2) // 411000fc
|
FMOVD F1, 1(R2) // 411000fc
|
||||||
FMOVD F1, 8(R2) // 410400fd
|
FMOVD F1, 8(R2) // 410400fd
|
||||||
|
FMOVD F20, (R2) // 540000fd
|
||||||
|
FMOVQ F0, 32(R5)// a008803d
|
||||||
|
FMOVQ F10, 65520(R10) // 4afdbf3d
|
||||||
|
FMOVQ F11, 64(RSP) // eb13803d
|
||||||
|
FMOVQ F11, 8(R20) // 8b82803c
|
||||||
|
FMOVQ F11, 4(R20) // 8b42803c
|
||||||
|
|
||||||
// large aligned offset, use two instructions
|
MOVB 1(R1), R2 // 22048039
|
||||||
MOVB 0x1001(R1), R2 // MOVB 4097(R1), R2 // 3b04409162078039
|
MOVH 1(R1), R2 // 22108078
|
||||||
MOVH 0x2002(R1), R2 // MOVH 8194(R1), R2 // 3b08409162078079
|
MOVH 2(R1), R2 // 22048079
|
||||||
MOVW 0x4004(R1), R2 // MOVW 16388(R1), R2 // 3b104091620780b9
|
MOVW 1(R1), R2 // 221080b8
|
||||||
MOVD 0x8008(R1), R2 // MOVD 32776(R1), R2 // 3b204091620740f9
|
MOVW 4(R1), R2 // 220480b9
|
||||||
FMOVS 0x4004(R1), F2 // FMOVS 16388(R1), F2 // 3b104091620740bd
|
MOVD 1(R1), R2 // 221040f8
|
||||||
FMOVD 0x8008(R1), F2 // FMOVD 32776(R1), F2 // 3b204091620740fd
|
MOVD 8(R1), R2 // 220440f9
|
||||||
|
FMOVS (R0), F20 // 140040bd
|
||||||
|
FMOVS 1(R1), F2 // 221040bc
|
||||||
|
FMOVS 4(R1), F2 // 220440bd
|
||||||
|
FMOVD 1(R1), F2 // 221040fc
|
||||||
|
FMOVD 8(R1), F2 // 220440fd
|
||||||
|
FMOVQ 32(R5), F2 // a208c03d
|
||||||
|
FMOVQ 65520(R10), F10 // 4afdff3d
|
||||||
|
FMOVQ 64(RSP), F11 // eb13c03d
|
||||||
|
|
||||||
|
// large aligned offset, use two instructions(add+ldr/store).
|
||||||
MOVB R1, 0x1001(R2) // MOVB R1, 4097(R2) // 5b04409161070039
|
MOVB R1, 0x1001(R2) // MOVB R1, 4097(R2) // 5b04409161070039
|
||||||
MOVH R1, 0x2002(R2) // MOVH R1, 8194(R2) // 5b08409161070079
|
MOVH R1, 0x2002(R2) // MOVH R1, 8194(R2) // 5b08409161070079
|
||||||
MOVW R1, 0x4004(R2) // MOVW R1, 16388(R2) // 5b104091610700b9
|
MOVW R1, 0x4004(R2) // MOVW R1, 16388(R2) // 5b104091610700b9
|
||||||
|
|
@ -499,15 +495,16 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
FMOVS F1, 0x4004(R2) // FMOVS F1, 16388(R2) // 5b104091610700bd
|
FMOVS F1, 0x4004(R2) // FMOVS F1, 16388(R2) // 5b104091610700bd
|
||||||
FMOVD F1, 0x8008(R2) // FMOVD F1, 32776(R2) // 5b204091610700fd
|
FMOVD F1, 0x8008(R2) // FMOVD F1, 32776(R2) // 5b204091610700fd
|
||||||
|
|
||||||
// very large or unaligned offset uses constant pool
|
MOVB 0x1001(R1), R2 // MOVB 4097(R1), R2 // 3b04409162078039
|
||||||
// the encoding cannot be checked as the address of the constant pool is unknown.
|
MOVH 0x2002(R1), R2 // MOVH 8194(R1), R2 // 3b08409162078079
|
||||||
// here we only test that they can be assembled.
|
MOVW 0x4004(R1), R2 // MOVW 16388(R1), R2 // 3b104091620780b9
|
||||||
MOVB 0x44332211(R1), R2 // MOVB 1144201745(R1), R2
|
MOVD 0x8008(R1), R2 // MOVD 32776(R1), R2 // 3b204091620740f9
|
||||||
MOVH 0x44332211(R1), R2 // MOVH 1144201745(R1), R2
|
FMOVS 0x4004(R1), F2 // FMOVS 16388(R1), F2 // 3b104091620740bd
|
||||||
MOVW 0x44332211(R1), R2 // MOVW 1144201745(R1), R2
|
FMOVD 0x8008(R1), F2 // FMOVD 32776(R1), F2 // 3b204091620740fd
|
||||||
MOVD 0x44332211(R1), R2 // MOVD 1144201745(R1), R2
|
|
||||||
FMOVS 0x44332211(R1), F2 // FMOVS 1144201745(R1), F2
|
// very large or unaligned offset uses constant pool.
|
||||||
FMOVD 0x44332211(R1), F2 // FMOVD 1144201745(R1), F2
|
// the encoding cannot be checked as the address of the constant pool is unknown.
|
||||||
|
// here we only test that they can be assembled.
|
||||||
MOVB R1, 0x44332211(R2) // MOVB R1, 1144201745(R2)
|
MOVB R1, 0x44332211(R2) // MOVB R1, 1144201745(R2)
|
||||||
MOVH R1, 0x44332211(R2) // MOVH R1, 1144201745(R2)
|
MOVH R1, 0x44332211(R2) // MOVH R1, 1144201745(R2)
|
||||||
MOVW R1, 0x44332211(R2) // MOVW R1, 1144201745(R2)
|
MOVW R1, 0x44332211(R2) // MOVW R1, 1144201745(R2)
|
||||||
|
|
@ -515,14 +512,59 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
FMOVS F1, 0x44332211(R2) // FMOVS F1, 1144201745(R2)
|
FMOVS F1, 0x44332211(R2) // FMOVS F1, 1144201745(R2)
|
||||||
FMOVD F1, 0x44332211(R2) // FMOVD F1, 1144201745(R2)
|
FMOVD F1, 0x44332211(R2) // FMOVD F1, 1144201745(R2)
|
||||||
|
|
||||||
//
|
MOVB 0x44332211(R1), R2 // MOVB 1144201745(R1), R2
|
||||||
// MOVK
|
MOVH 0x44332211(R1), R2 // MOVH 1144201745(R1), R2
|
||||||
//
|
MOVW 0x44332211(R1), R2 // MOVW 1144201745(R1), R2
|
||||||
// LMOVK imm ',' reg
|
MOVD 0x44332211(R1), R2 // MOVD 1144201745(R1), R2
|
||||||
// {
|
FMOVS 0x44332211(R1), F2 // FMOVS 1144201745(R1), F2
|
||||||
// outcode($1, &$2, NREG, &$4);
|
FMOVD 0x44332211(R1), F2 // FMOVD 1144201745(R1), F2
|
||||||
// }
|
|
||||||
MOVK $1, R1
|
// shifted or extended register offset.
|
||||||
|
MOVD (R2)(R6.SXTW), R4 // 44c866f8
|
||||||
|
MOVD (R3)(R6), R5 // MOVD (R3)(R6*1), R5 // 656866f8
|
||||||
|
MOVD (R2)(R6), R4 // MOVD (R2)(R6*1), R4 // 446866f8
|
||||||
|
MOVWU (R19)(R20<<2), R20 // 747a74b8
|
||||||
|
MOVD (R2)(R6<<3), R4 // 447866f8
|
||||||
|
MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8
|
||||||
|
MOVWU (R5)(R4.UXTW), R10 // aa4864b8
|
||||||
|
MOVBU (R3)(R9.UXTW), R8 // 68486938
|
||||||
|
MOVBU (R5)(R8), R10 // MOVBU (R5)(R8*1), R10 // aa686838
|
||||||
|
MOVHU (R2)(R7.SXTW<<1), R11 // 4bd86778
|
||||||
|
MOVHU (R1)(R2<<1), R5 // 25786278
|
||||||
|
MOVB (R9)(R3.UXTW), R6 // 2649a338
|
||||||
|
MOVB (R10)(R6), R15 // MOVB (R10)(R6*1), R15 // 4f69a638
|
||||||
|
MOVB (R29)(R30<<0), R14 // ae7bbe38
|
||||||
|
MOVB (R29)(R30), R14 // MOVB (R29)(R30*1), R14 // ae6bbe38
|
||||||
|
MOVH (R5)(R7.SXTX<<1), R19 // b3f8a778
|
||||||
|
MOVH (R8)(R4<<1), R10 // 0a79a478
|
||||||
|
MOVW (R9)(R8.SXTW<<2), R19 // 33d9a8b8
|
||||||
|
MOVW (R1)(R4.SXTX), R11 // 2be8a4b8
|
||||||
|
MOVW (R1)(R4.SXTX), ZR // 3fe8a4b8
|
||||||
|
MOVW (R2)(R5), R12 // MOVW (R2)(R5*1), R12 // 4c68a5b8
|
||||||
|
FMOVS (R2)(R6), F4 // FMOVS (R2)(R6*1), F4 // 446866bc
|
||||||
|
FMOVS (R2)(R6<<2), F4 // 447866bc
|
||||||
|
FMOVD (R2)(R6), F4 // FMOVD (R2)(R6*1), F4 // 446866fc
|
||||||
|
FMOVD (R2)(R6<<3), F4 // 447866fc
|
||||||
|
|
||||||
|
MOVD R5, (R2)(R6<<3) // 457826f8
|
||||||
|
MOVD R9, (R6)(R7.SXTX<<3) // c9f827f8
|
||||||
|
MOVD ZR, (R6)(R7.SXTX<<3) // dff827f8
|
||||||
|
MOVW R8, (R2)(R3.UXTW<<2) // 485823b8
|
||||||
|
MOVW R7, (R3)(R4.SXTW) // 67c824b8
|
||||||
|
MOVB R4, (R2)(R6.SXTX) // 44e82638
|
||||||
|
MOVB R8, (R3)(R9.UXTW) // 68482938
|
||||||
|
MOVB R10, (R5)(R8) // MOVB R10, (R5)(R8*1) // aa682838
|
||||||
|
MOVH R11, (R2)(R7.SXTW<<1) // 4bd82778
|
||||||
|
MOVH R5, (R1)(R2<<1) // 25782278
|
||||||
|
MOVH R7, (R2)(R5.SXTX<<1) // 47f82578
|
||||||
|
MOVH R8, (R3)(R6.UXTW) // 68482678
|
||||||
|
MOVB R4, (R2)(R6.SXTX) // 44e82638
|
||||||
|
FMOVS F4, (R2)(R6) // FMOVS F4, (R2)(R6*1) // 446826bc
|
||||||
|
FMOVS F4, (R2)(R6<<2) // 447826bc
|
||||||
|
FMOVD F4, (R2)(R6) // FMOVD F4, (R2)(R6*1) // 446826fc
|
||||||
|
FMOVD F4, (R2)(R6<<3) // 447826fc
|
||||||
|
|
||||||
|
// vmov
|
||||||
VMOV V8.S[1], R1 // 013d0c0e
|
VMOV V8.S[1], R1 // 013d0c0e
|
||||||
VMOV V0.D[0], R11 // 0b3c084e
|
VMOV V0.D[0], R11 // 0b3c084e
|
||||||
VMOV V0.D[1], R11 // 0b3c184e
|
VMOV V0.D[1], R11 // 0b3c184e
|
||||||
|
|
@ -537,205 +579,28 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||||
VMOV V9.H[0], V12.H[1] // 2c05066e
|
VMOV V9.H[0], V12.H[1] // 2c05066e
|
||||||
VMOV V8.B[0], V12.B[1] // 0c05036e
|
VMOV V8.B[0], V12.B[1] // 0c05036e
|
||||||
VMOV V8.B[7], V4.B[8] // 043d116e
|
VMOV V8.B[7], V4.B[8] // 043d116e
|
||||||
VREV32 V5.B16, V5.B16 // a508206e
|
|
||||||
VREV64 V2.S2, V3.S2 // 4308a00e
|
|
||||||
VREV64 V2.S4, V3.S4 // 4308a04e
|
|
||||||
VDUP V19.S[0], V17.S4 // 7106044e
|
|
||||||
//
|
|
||||||
// B/BL
|
|
||||||
//
|
|
||||||
// LTYPE4 comma rel
|
|
||||||
// {
|
|
||||||
// outcode($1, &nullgen, NREG, &$3);
|
|
||||||
// }
|
|
||||||
BL 1(PC) // CALL 1(PC)
|
|
||||||
|
|
||||||
// LTYPE4 comma nireg
|
|
||||||
// {
|
|
||||||
// outcode($1, &nullgen, NREG, &$3);
|
|
||||||
// }
|
|
||||||
BL (R2) // CALL (R2)
|
|
||||||
BL foo(SB) // CALL foo(SB)
|
|
||||||
BL bar<>(SB) // CALL bar<>(SB)
|
|
||||||
//
|
|
||||||
// BEQ
|
|
||||||
//
|
|
||||||
// LTYPE5 comma rel
|
|
||||||
// {
|
|
||||||
// outcode($1, &nullgen, NREG, &$3);
|
|
||||||
// }
|
|
||||||
BEQ 1(PC)
|
|
||||||
//
|
|
||||||
// SVC
|
|
||||||
//
|
|
||||||
// LTYPE6
|
|
||||||
// {
|
|
||||||
// outcode($1, &nullgen, NREG, &nullgen);
|
|
||||||
// }
|
|
||||||
SVC
|
|
||||||
|
|
||||||
//
|
|
||||||
// CMP
|
|
||||||
//
|
|
||||||
// LTYPE7 imsr ',' spreg comma
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, $4, &nullgen);
|
|
||||||
// }
|
|
||||||
CMP $3, R2
|
|
||||||
CMP R1, R2
|
|
||||||
CMP R1->11, R2
|
|
||||||
CMP R1>>22, R2
|
|
||||||
CMP R1<<33, R2
|
|
||||||
CMP R22.SXTX, RSP // ffe336eb
|
|
||||||
|
|
||||||
CMP $0x22220000, RSP // CMP $572653568, RSP // 5b44a4d2ff633beb
|
|
||||||
CMPW $0x22220000, RSP // CMPW $572653568, RSP // 5b44a452ff633b6b
|
|
||||||
|
|
||||||
// TST
|
|
||||||
TST $15, R2 // 5f0c40f2
|
|
||||||
TST R1, R2 // 5f0001ea
|
|
||||||
TST R1->11, R2 // 5f2c81ea
|
|
||||||
TST R1>>22, R2 // 5f5841ea
|
|
||||||
TST R1<<33, R2 // 5f8401ea
|
|
||||||
TST $0x22220000, R3 // TST $572653568, R3 // 5b44a4d27f001bea
|
|
||||||
|
|
||||||
//
|
|
||||||
// CBZ
|
// CBZ
|
||||||
//
|
|
||||||
// LTYPE8 reg ',' rel
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, NREG, &$4);
|
|
||||||
// }
|
|
||||||
again:
|
again:
|
||||||
CBZ R1, again // CBZ R1
|
CBZ R1, again // CBZ R1
|
||||||
|
|
||||||
//
|
// conditional operations
|
||||||
// CSET
|
|
||||||
//
|
|
||||||
// LTYPER cond ',' reg
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, NREG, &$4);
|
|
||||||
// }
|
|
||||||
CSET GT, R1 // e1d79f9a
|
CSET GT, R1 // e1d79f9a
|
||||||
CSETW HI, R2 // e2979f1a
|
CSETW HI, R2 // e2979f1a
|
||||||
//
|
|
||||||
// CSEL/CSINC/CSNEG/CSINV
|
|
||||||
//
|
|
||||||
// LTYPES cond ',' reg ',' reg ',' reg
|
|
||||||
// {
|
|
||||||
// outgcode($1, &$2, $6.reg, &$4, &$8);
|
|
||||||
// }
|
|
||||||
CSEL LT, R1, R2, ZR // 3fb0829a
|
CSEL LT, R1, R2, ZR // 3fb0829a
|
||||||
CSELW LT, R2, R3, R4 // 44b0831a
|
CSELW LT, R2, R3, R4 // 44b0831a
|
||||||
CSINC GT, R1, ZR, R3 // 23c49f9a
|
CSINC GT, R1, ZR, R3 // 23c49f9a
|
||||||
CSNEG MI, R1, R2, R3 // 234482da
|
CSNEG MI, R1, R2, R3 // 234482da
|
||||||
CSINV CS, R1, R2, R3 // CSINV HS, R1, R2, R3 // 232082da
|
CSINV CS, R1, R2, R3 // CSINV HS, R1, R2, R3 // 232082da
|
||||||
CSINVW MI, R2, ZR, R2 // 42409f5a
|
CSINVW MI, R2, ZR, R2 // 42409f5a
|
||||||
|
|
||||||
// LTYPES cond ',' reg ',' reg
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, $4.reg, &$6);
|
|
||||||
// }
|
|
||||||
CINC EQ, R4, R9 // 8914849a
|
CINC EQ, R4, R9 // 8914849a
|
||||||
CINCW PL, R2, ZR // 5f44821a
|
CINCW PL, R2, ZR // 5f44821a
|
||||||
CINV PL, R11, R22 // 76418bda
|
CINV PL, R11, R22 // 76418bda
|
||||||
CINVW LS, R7, R13 // ed80875a
|
CINVW LS, R7, R13 // ed80875a
|
||||||
CNEG LS, R13, R7 // a7858dda
|
CNEG LS, R13, R7 // a7858dda
|
||||||
CNEGW EQ, R8, R13 // 0d15885a
|
CNEGW EQ, R8, R13 // 0d15885a
|
||||||
//
|
|
||||||
// CCMN
|
|
||||||
//
|
|
||||||
// LTYPEU cond ',' imsr ',' reg ',' imm comma
|
|
||||||
// {
|
|
||||||
// outgcode($1, &$2, $6.reg, &$4, &$8);
|
|
||||||
// }
|
|
||||||
CCMN MI, ZR, R1, $4 // e44341ba
|
|
||||||
|
|
||||||
//
|
// atomic ops
|
||||||
// FADDD
|
|
||||||
//
|
|
||||||
// LTYPEK frcon ',' freg
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, NREG, &$4);
|
|
||||||
// }
|
|
||||||
// FADDD $0.5, F1 // FADDD $(0.5), F1
|
|
||||||
FADDD F1, F2
|
|
||||||
|
|
||||||
// LTYPEK frcon ',' freg ',' freg
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, $4.reg, &$6);
|
|
||||||
// }
|
|
||||||
// FADDD $0.7, F1, F2 // FADDD $(0.69999999999999996), F1, F2
|
|
||||||
FADDD F1, F2, F3
|
|
||||||
|
|
||||||
//
|
|
||||||
// FCMP
|
|
||||||
//
|
|
||||||
// LTYPEL frcon ',' freg comma
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, $4.reg, &nullgen);
|
|
||||||
// }
|
|
||||||
// FCMP $0.2, F1
|
|
||||||
// FCMP F1, F2
|
|
||||||
|
|
||||||
//
|
|
||||||
// FCCMP
|
|
||||||
//
|
|
||||||
// LTYPEF cond ',' freg ',' freg ',' imm comma
|
|
||||||
// {
|
|
||||||
// outgcode($1, &$2, $6.reg, &$4, &$8);
|
|
||||||
// }
|
|
||||||
FCCMPS LT, F1, F2, $1 // 41b4211e
|
|
||||||
|
|
||||||
//
|
|
||||||
// FMULA
|
|
||||||
//
|
|
||||||
// LTYPE9 freg ',' freg ',' freg ',' freg comma
|
|
||||||
// {
|
|
||||||
// outgcode($1, &$2, $4.reg, &$6, &$8);
|
|
||||||
// }
|
|
||||||
// FMULA F1, F2, F3, F4
|
|
||||||
|
|
||||||
//
|
|
||||||
// FCSEL
|
|
||||||
//
|
|
||||||
// LFCSEL cond ',' freg ',' freg ',' freg
|
|
||||||
// {
|
|
||||||
// outgcode($1, &$2, $6.reg, &$4, &$8);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// MADD Rn,Rm,Ra,Rd
|
|
||||||
//
|
|
||||||
// LTYPEM reg ',' reg ',' sreg ',' reg
|
|
||||||
// {
|
|
||||||
// outgcode($1, &$2, $6, &$4, &$8);
|
|
||||||
// }
|
|
||||||
// MADD R1, R2, R3, R4
|
|
||||||
|
|
||||||
FMADDS F1, F3, F2, F4 // 440c011f
|
|
||||||
FMADDD F4, F5, F4, F4 // 8414441f
|
|
||||||
FMSUBS F13, F21, F13, F19 // b3d50d1f
|
|
||||||
FMSUBD F11, F7, F15, F31 // ff9d4b1f
|
|
||||||
FNMADDS F1, F3, F2, F4 // 440c211f
|
|
||||||
FNMADDD F1, F3, F2, F4 // 440c611f
|
|
||||||
FNMSUBS F1, F3, F2, F4 // 448c211f
|
|
||||||
FNMSUBD F1, F3, F2, F4 // 448c611f
|
|
||||||
|
|
||||||
// DMB, HINT
|
|
||||||
//
|
|
||||||
// LDMB imm
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, NREG, &nullgen);
|
|
||||||
// }
|
|
||||||
DMB $1
|
|
||||||
|
|
||||||
//
|
|
||||||
// STXR
|
|
||||||
//
|
|
||||||
// LSTXR reg ',' addr ',' reg
|
|
||||||
// {
|
|
||||||
// outcode($1, &$2, &$4, &$6);
|
|
||||||
// }
|
|
||||||
LDARB (R25), R2 // 22ffdf08
|
LDARB (R25), R2 // 22ffdf08
|
||||||
LDARH (R5), R7 // a7fcdf48
|
LDARH (R5), R7 // a7fcdf48
|
||||||
LDAXPW (R10), (R20, R16) // 54c17f88
|
LDAXPW (R10), (R20, R16) // 54c17f88
|
||||||
|
|
@ -816,38 +681,38 @@ again:
|
||||||
LDADDLH R5, (RSP), R7 // e7036578
|
LDADDLH R5, (RSP), R7 // e7036578
|
||||||
LDADDLB R5, (R6), R7 // c7006538
|
LDADDLB R5, (R6), R7 // c7006538
|
||||||
LDADDLB R5, (RSP), R7 // e7036538
|
LDADDLB R5, (RSP), R7 // e7036538
|
||||||
LDANDAD R5, (R6), R7 // c710a5f8
|
LDCLRAD R5, (R6), R7 // c710a5f8
|
||||||
LDANDAD R5, (RSP), R7 // e713a5f8
|
LDCLRAD R5, (RSP), R7 // e713a5f8
|
||||||
LDANDAW R5, (R6), R7 // c710a5b8
|
LDCLRAW R5, (R6), R7 // c710a5b8
|
||||||
LDANDAW R5, (RSP), R7 // e713a5b8
|
LDCLRAW R5, (RSP), R7 // e713a5b8
|
||||||
LDANDAH R5, (R6), R7 // c710a578
|
LDCLRAH R5, (R6), R7 // c710a578
|
||||||
LDANDAH R5, (RSP), R7 // e713a578
|
LDCLRAH R5, (RSP), R7 // e713a578
|
||||||
LDANDAB R5, (R6), R7 // c710a538
|
LDCLRAB R5, (R6), R7 // c710a538
|
||||||
LDANDAB R5, (RSP), R7 // e713a538
|
LDCLRAB R5, (RSP), R7 // e713a538
|
||||||
LDANDALD R5, (R6), R7 // c710e5f8
|
LDCLRALD R5, (R6), R7 // c710e5f8
|
||||||
LDANDALD R5, (RSP), R7 // e713e5f8
|
LDCLRALD R5, (RSP), R7 // e713e5f8
|
||||||
LDANDALW R5, (R6), R7 // c710e5b8
|
LDCLRALW R5, (R6), R7 // c710e5b8
|
||||||
LDANDALW R5, (RSP), R7 // e713e5b8
|
LDCLRALW R5, (RSP), R7 // e713e5b8
|
||||||
LDANDALH R5, (R6), R7 // c710e578
|
LDCLRALH R5, (R6), R7 // c710e578
|
||||||
LDANDALH R5, (RSP), R7 // e713e578
|
LDCLRALH R5, (RSP), R7 // e713e578
|
||||||
LDANDALB R5, (R6), R7 // c710e538
|
LDCLRALB R5, (R6), R7 // c710e538
|
||||||
LDANDALB R5, (RSP), R7 // e713e538
|
LDCLRALB R5, (RSP), R7 // e713e538
|
||||||
LDANDD R5, (R6), R7 // c71025f8
|
LDCLRD R5, (R6), R7 // c71025f8
|
||||||
LDANDD R5, (RSP), R7 // e71325f8
|
LDCLRD R5, (RSP), R7 // e71325f8
|
||||||
LDANDW R5, (R6), R7 // c71025b8
|
LDCLRW R5, (R6), R7 // c71025b8
|
||||||
LDANDW R5, (RSP), R7 // e71325b8
|
LDCLRW R5, (RSP), R7 // e71325b8
|
||||||
LDANDH R5, (R6), R7 // c7102578
|
LDCLRH R5, (R6), R7 // c7102578
|
||||||
LDANDH R5, (RSP), R7 // e7132578
|
LDCLRH R5, (RSP), R7 // e7132578
|
||||||
LDANDB R5, (R6), R7 // c7102538
|
LDCLRB R5, (R6), R7 // c7102538
|
||||||
LDANDB R5, (RSP), R7 // e7132538
|
LDCLRB R5, (RSP), R7 // e7132538
|
||||||
LDANDLD R5, (R6), R7 // c71065f8
|
LDCLRLD R5, (R6), R7 // c71065f8
|
||||||
LDANDLD R5, (RSP), R7 // e71365f8
|
LDCLRLD R5, (RSP), R7 // e71365f8
|
||||||
LDANDLW R5, (R6), R7 // c71065b8
|
LDCLRLW R5, (R6), R7 // c71065b8
|
||||||
LDANDLW R5, (RSP), R7 // e71365b8
|
LDCLRLW R5, (RSP), R7 // e71365b8
|
||||||
LDANDLH R5, (R6), R7 // c7106578
|
LDCLRLH R5, (R6), R7 // c7106578
|
||||||
LDANDLH R5, (RSP), R7 // e7136578
|
LDCLRLH R5, (RSP), R7 // e7136578
|
||||||
LDANDLB R5, (R6), R7 // c7106538
|
LDCLRLB R5, (R6), R7 // c7106538
|
||||||
LDANDLB R5, (RSP), R7 // e7136538
|
LDCLRLB R5, (RSP), R7 // e7136538
|
||||||
LDEORAD R5, (R6), R7 // c720a5f8
|
LDEORAD R5, (R6), R7 // c720a5f8
|
||||||
LDEORAD R5, (RSP), R7 // e723a5f8
|
LDEORAD R5, (RSP), R7 // e723a5f8
|
||||||
LDEORAW R5, (R6), R7 // c720a5b8
|
LDEORAW R5, (R6), R7 // c720a5b8
|
||||||
|
|
@ -912,21 +777,36 @@ again:
|
||||||
LDORLH R5, (RSP), R7 // e7336578
|
LDORLH R5, (RSP), R7 // e7336578
|
||||||
LDORLB R5, (R6), R7 // c7306538
|
LDORLB R5, (R6), R7 // c7306538
|
||||||
LDORLB R5, (RSP), R7 // e7336538
|
LDORLB R5, (RSP), R7 // e7336538
|
||||||
|
CASD R1, (R2), ZR // 5f7ca1c8
|
||||||
|
CASW R1, (RSP), ZR // ff7fa188
|
||||||
|
CASB ZR, (R5), R3 // a37cbf08
|
||||||
|
CASH R3, (RSP), ZR // ff7fa348
|
||||||
|
CASW R5, (R7), R6 // e67ca588
|
||||||
|
CASLD ZR, (RSP), R8 // e8ffbfc8
|
||||||
|
CASLW R9, (R10), ZR // 5ffda988
|
||||||
|
CASAD R7, (R11), R15 // 6f7de7c8
|
||||||
|
CASAW R10, (RSP), R19 // f37fea88
|
||||||
|
CASALD R5, (R6), R7 // c7fce5c8
|
||||||
|
CASALD R5, (RSP), R7 // e7ffe5c8
|
||||||
|
CASALW R5, (R6), R7 // c7fce588
|
||||||
|
CASALW R5, (RSP), R7 // e7ffe588
|
||||||
|
CASALH ZR, (R5), R8 // a8fcff48
|
||||||
|
CASALB R8, (R9), ZR // 3ffde808
|
||||||
|
CASPD (R30, ZR), (RSP), (R8, R9) // e87f3e48
|
||||||
|
CASPW (R6, R7), (R8), (R4, R5) // 047d2608
|
||||||
|
CASPD (R2, R3), (R2), (R8, R9) // 487c2248
|
||||||
|
|
||||||
// RET
|
// RET
|
||||||
//
|
|
||||||
// LTYPEA comma
|
|
||||||
// {
|
|
||||||
// outcode($1, &nullgen, NREG, &nullgen);
|
|
||||||
// }
|
|
||||||
BEQ 2(PC)
|
|
||||||
RET
|
RET
|
||||||
RET foo(SB)
|
RET foo(SB)
|
||||||
|
|
||||||
// More B/BL cases, and canonical names JMP, CALL.
|
// B/BL/B.cond cases, and canonical names JMP, CALL.
|
||||||
|
BL 1(PC) // CALL 1(PC)
|
||||||
BEQ 2(PC)
|
BL (R2) // CALL (R2)
|
||||||
B foo(SB) // JMP foo(SB)
|
|
||||||
BL foo(SB) // CALL foo(SB)
|
BL foo(SB) // CALL foo(SB)
|
||||||
|
BL bar<>(SB) // CALL bar<>(SB)
|
||||||
|
B foo(SB) // JMP foo(SB)
|
||||||
|
BEQ 1(PC)
|
||||||
BEQ 2(PC)
|
BEQ 2(PC)
|
||||||
TBZ $1, R1, 2(PC)
|
TBZ $1, R1, 2(PC)
|
||||||
TBNZ $2, R2, 2(PC)
|
TBNZ $2, R2, 2(PC)
|
||||||
|
|
@ -1101,8 +981,6 @@ again:
|
||||||
FSTPS (F3, F4), 1024(RSP) // fb0310916313002d
|
FSTPS (F3, F4), 1024(RSP) // fb0310916313002d
|
||||||
FSTPS (F3, F4), x(SB)
|
FSTPS (F3, F4), x(SB)
|
||||||
FSTPS (F3, F4), x+8(SB)
|
FSTPS (F3, F4), x+8(SB)
|
||||||
NOOP // 1f2003d5
|
|
||||||
HINT $0 // 1f2003d5
|
|
||||||
|
|
||||||
// System Register
|
// System Register
|
||||||
MSR $1, SPSel // bf4100d5
|
MSR $1, SPSel // bf4100d5
|
||||||
|
|
@ -1664,11 +1542,4 @@ again:
|
||||||
MSR R13, ZCR_EL1 // 0d1218d5
|
MSR R13, ZCR_EL1 // 0d1218d5
|
||||||
MRS ZCR_EL1, R23 // 171238d5
|
MRS ZCR_EL1, R23 // 171238d5
|
||||||
MSR R17, ZCR_EL1 // 111218d5
|
MSR R17, ZCR_EL1 // 111218d5
|
||||||
|
|
||||||
// END
|
|
||||||
//
|
|
||||||
// LTYPEE comma
|
|
||||||
// {
|
|
||||||
// outcode($1, &nullgen, NREG, &nullgen);
|
|
||||||
// }
|
|
||||||
END
|
END
|
||||||
|
|
|
||||||
68
src/cmd/asm/internal/asm/testdata/arm64error.s
vendored
68
src/cmd/asm/internal/asm/testdata/arm64error.s
vendored
|
|
@ -87,13 +87,13 @@ TEXT errors(SB),$0
|
||||||
VLD1.P 32(R1), [V8.S4, V9.S4, V10.S4] // ERROR "invalid post-increment offset"
|
VLD1.P 32(R1), [V8.S4, V9.S4, V10.S4] // ERROR "invalid post-increment offset"
|
||||||
VLD1.P 48(R1), [V7.S4, V8.S4, V9.S4, V10.S4] // ERROR "invalid post-increment offset"
|
VLD1.P 48(R1), [V7.S4, V8.S4, V9.S4, V10.S4] // ERROR "invalid post-increment offset"
|
||||||
VPMULL V1.D1, V2.H4, V3.Q1 // ERROR "invalid arrangement"
|
VPMULL V1.D1, V2.H4, V3.Q1 // ERROR "invalid arrangement"
|
||||||
VPMULL V1.H4, V2.H4, V3.Q1 // ERROR "invalid arrangement"
|
VPMULL V1.H4, V2.H4, V3.Q1 // ERROR "operand mismatch"
|
||||||
VPMULL V1.D2, V2.D2, V3.Q1 // ERROR "invalid arrangement"
|
VPMULL V1.D2, V2.D2, V3.Q1 // ERROR "operand mismatch"
|
||||||
VPMULL V1.B16, V2.B16, V3.H8 // ERROR "invalid arrangement"
|
VPMULL V1.B16, V2.B16, V3.H8 // ERROR "operand mismatch"
|
||||||
VPMULL2 V1.D2, V2.H4, V3.Q1 // ERROR "invalid arrangement"
|
VPMULL2 V1.D2, V2.H4, V3.Q1 // ERROR "invalid arrangement"
|
||||||
VPMULL2 V1.H4, V2.H4, V3.Q1 // ERROR "invalid arrangement"
|
VPMULL2 V1.H4, V2.H4, V3.Q1 // ERROR "operand mismatch"
|
||||||
VPMULL2 V1.D1, V2.D1, V3.Q1 // ERROR "invalid arrangement"
|
VPMULL2 V1.D1, V2.D1, V3.Q1 // ERROR "operand mismatch"
|
||||||
VPMULL2 V1.B8, V2.B8, V3.H8 // ERROR "invalid arrangement"
|
VPMULL2 V1.B8, V2.B8, V3.H8 // ERROR "operand mismatch"
|
||||||
VEXT $8, V1.B16, V2.B8, V2.B16 // ERROR "invalid arrangement"
|
VEXT $8, V1.B16, V2.B8, V2.B16 // ERROR "invalid arrangement"
|
||||||
VEXT $8, V1.H8, V2.H8, V2.H8 // ERROR "invalid arrangement"
|
VEXT $8, V1.H8, V2.H8, V2.H8 // ERROR "invalid arrangement"
|
||||||
VRBIT V1.B16, V2.B8 // ERROR "invalid arrangement"
|
VRBIT V1.B16, V2.B8 // ERROR "invalid arrangement"
|
||||||
|
|
@ -123,14 +123,14 @@ TEXT errors(SB),$0
|
||||||
LDADDLW R5, (R6), ZR // ERROR "illegal destination register"
|
LDADDLW R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDADDLH R5, (R6), ZR // ERROR "illegal destination register"
|
LDADDLH R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDADDLB R5, (R6), ZR // ERROR "illegal destination register"
|
LDADDLB R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDANDD R5, (R6), ZR // ERROR "illegal destination register"
|
LDCLRD R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDANDW R5, (R6), ZR // ERROR "illegal destination register"
|
LDCLRW R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDANDH R5, (R6), ZR // ERROR "illegal destination register"
|
LDCLRH R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDANDB R5, (R6), ZR // ERROR "illegal destination register"
|
LDCLRB R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDANDLD R5, (R6), ZR // ERROR "illegal destination register"
|
LDCLRLD R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDANDLW R5, (R6), ZR // ERROR "illegal destination register"
|
LDCLRLW R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDANDLH R5, (R6), ZR // ERROR "illegal destination register"
|
LDCLRLH R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDANDLB R5, (R6), ZR // ERROR "illegal destination register"
|
LDCLRLB R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDEORD R5, (R6), ZR // ERROR "illegal destination register"
|
LDEORD R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDEORW R5, (R6), ZR // ERROR "illegal destination register"
|
LDEORW R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
LDEORH R5, (R6), ZR // ERROR "illegal destination register"
|
LDEORH R5, (R6), ZR // ERROR "illegal destination register"
|
||||||
|
|
@ -163,22 +163,22 @@ TEXT errors(SB),$0
|
||||||
LDADDLW R5, (R6), RSP // ERROR "illegal destination register"
|
LDADDLW R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDADDLH R5, (R6), RSP // ERROR "illegal destination register"
|
LDADDLH R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDADDLB R5, (R6), RSP // ERROR "illegal destination register"
|
LDADDLB R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDAD R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRAD R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDAW R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRAW R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDAH R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRAH R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDAB R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRAB R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDALD R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRALD R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDALW R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRALW R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDALH R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRALH R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDALB R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRALB R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDD R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRD R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDW R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRW R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDH R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRH R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDB R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRB R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDLD R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRLD R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDLW R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRLW R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDLH R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRLH R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDANDLB R5, (R6), RSP // ERROR "illegal destination register"
|
LDCLRLB R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDEORAD R5, (R6), RSP // ERROR "illegal destination register"
|
LDEORAD R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDEORAW R5, (R6), RSP // ERROR "illegal destination register"
|
LDEORAW R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
LDEORAH R5, (R6), RSP // ERROR "illegal destination register"
|
LDEORAH R5, (R6), RSP // ERROR "illegal destination register"
|
||||||
|
|
@ -353,4 +353,12 @@ TEXT errors(SB),$0
|
||||||
VUSHLL2 $32, V30.S4, V2.D2 // ERROR "shift amount out of range"
|
VUSHLL2 $32, V30.S4, V2.D2 // ERROR "shift amount out of range"
|
||||||
VBIF V0.B8, V1.B8, V2.B16 // ERROR "operand mismatch"
|
VBIF V0.B8, V1.B8, V2.B16 // ERROR "operand mismatch"
|
||||||
VBIF V0.D2, V1.D2, V2.D2 // ERROR "invalid arrangement"
|
VBIF V0.D2, V1.D2, V2.D2 // ERROR "invalid arrangement"
|
||||||
|
VUADDW V9.B8, V12.H8, V14.B8 // ERROR "invalid arrangement"
|
||||||
|
VUADDW2 V9.B8, V12.S4, V14.S4 // ERROR "operand mismatch"
|
||||||
|
VSLI $64, V7.D2, V8.D2 // ERROR "shift out of range"
|
||||||
|
VUSRA $0, V7.D2, V8.D2 // ERROR "shift out of range"
|
||||||
|
CASPD (R3, R4), (R2), (R8, R9) // ERROR "source register pair must start from even register"
|
||||||
|
CASPD (R2, R3), (R2), (R9, R10) // ERROR "destination register pair must start from even register"
|
||||||
|
CASPD (R2, R4), (R2), (R8, R9) // ERROR "source register pair must be contiguous"
|
||||||
|
CASPD (R2, R3), (R2), (R8, R10) // ERROR "destination register pair must be contiguous"
|
||||||
RET
|
RET
|
||||||
|
|
|
||||||
2
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
2
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
|
|
@ -282,7 +282,9 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||||
RLWMI $7, R3, $65535, R6 // 50663c3e
|
RLWMI $7, R3, $65535, R6 // 50663c3e
|
||||||
RLWMICC $7, R3, $65535, R6 // 50663c3f
|
RLWMICC $7, R3, $65535, R6 // 50663c3f
|
||||||
RLWNM $3, R4, $7, R6 // 54861f7e
|
RLWNM $3, R4, $7, R6 // 54861f7e
|
||||||
|
RLWNM R3, R4, $7, R6 // 5c861f7e
|
||||||
RLWNMCC $3, R4, $7, R6 // 54861f7f
|
RLWNMCC $3, R4, $7, R6 // 54861f7f
|
||||||
|
RLWNMCC R3, R4, $7, R6 // 5c861f7f
|
||||||
RLDMI $0, R4, $7, R6 // 7886076c
|
RLDMI $0, R4, $7, R6 // 7886076c
|
||||||
RLDMICC $0, R4, $7, R6 // 7886076d
|
RLDMICC $0, R4, $7, R6 // 7886076d
|
||||||
RLDIMI $0, R4, $7, R6 // 788601cc
|
RLDIMI $0, R4, $7, R6 // 788601cc
|
||||||
|
|
|
||||||
29
src/cmd/asm/internal/asm/testdata/riscvenc.s
vendored
29
src/cmd/asm/internal/asm/testdata/riscvenc.s
vendored
|
|
@ -297,6 +297,13 @@ start:
|
||||||
MOVW X5, (X6) // 23205300
|
MOVW X5, (X6) // 23205300
|
||||||
MOVW X5, 4(X6) // 23225300
|
MOVW X5, 4(X6) // 23225300
|
||||||
|
|
||||||
|
MOVB X5, X6 // 1393820313538343
|
||||||
|
MOVH X5, X6 // 1393020313530343
|
||||||
|
MOVW X5, X6 // 1b830200
|
||||||
|
MOVBU X5, X6 // 13f3f20f
|
||||||
|
MOVHU X5, X6 // 1393020313530303
|
||||||
|
MOVWU X5, X6 // 1393020213530302
|
||||||
|
|
||||||
MOVF 4(X5), F0 // 07a04200
|
MOVF 4(X5), F0 // 07a04200
|
||||||
MOVF F0, 4(X5) // 27a20200
|
MOVF F0, 4(X5) // 27a20200
|
||||||
MOVF F0, F1 // d3000020
|
MOVF F0, F1 // d3000020
|
||||||
|
|
@ -318,7 +325,7 @@ start:
|
||||||
// These jumps can get printed as jumps to 2 because they go to the
|
// These jumps can get printed as jumps to 2 because they go to the
|
||||||
// second instruction in the function (the first instruction is an
|
// second instruction in the function (the first instruction is an
|
||||||
// invisible stack pointer adjustment).
|
// invisible stack pointer adjustment).
|
||||||
JMP start // JMP 2 // 6ff01fc5
|
JMP start // JMP 2 // 6ff09fc2
|
||||||
JMP (X5) // 67800200
|
JMP (X5) // 67800200
|
||||||
JMP 4(X5) // 67804200
|
JMP 4(X5) // 67804200
|
||||||
|
|
||||||
|
|
@ -331,16 +338,16 @@ start:
|
||||||
JMP asmtest(SB) // 970f0000
|
JMP asmtest(SB) // 970f0000
|
||||||
|
|
||||||
// Branch pseudo-instructions
|
// Branch pseudo-instructions
|
||||||
BEQZ X5, start // BEQZ X5, 2 // e38a02c2
|
BEQZ X5, start // BEQZ X5, 2 // e38602c0
|
||||||
BGEZ X5, start // BGEZ X5, 2 // e3d802c2
|
BGEZ X5, start // BGEZ X5, 2 // e3d402c0
|
||||||
BGT X5, X6, start // BGT X5, X6, 2 // e3c662c2
|
BGT X5, X6, start // BGT X5, X6, 2 // e3c262c0
|
||||||
BGTU X5, X6, start // BGTU X5, X6, 2 // e3e462c2
|
BGTU X5, X6, start // BGTU X5, X6, 2 // e3e062c0
|
||||||
BGTZ X5, start // BGTZ X5, 2 // e34250c2
|
BGTZ X5, start // BGTZ X5, 2 // e34e50be
|
||||||
BLE X5, X6, start // BLE X5, X6, 2 // e3d062c2
|
BLE X5, X6, start // BLE X5, X6, 2 // e3dc62be
|
||||||
BLEU X5, X6, start // BLEU X5, X6, 2 // e3fe62c0
|
BLEU X5, X6, start // BLEU X5, X6, 2 // e3fa62be
|
||||||
BLEZ X5, start // BLEZ X5, 2 // e35c50c0
|
BLEZ X5, start // BLEZ X5, 2 // e35850be
|
||||||
BLTZ X5, start // BLTZ X5, 2 // e3ca02c0
|
BLTZ X5, start // BLTZ X5, 2 // e3c602be
|
||||||
BNEZ X5, start // BNEZ X5, 2 // e39802c0
|
BNEZ X5, start // BNEZ X5, 2 // e39402be
|
||||||
|
|
||||||
// Set pseudo-instructions
|
// Set pseudo-instructions
|
||||||
SEQZ X15, X15 // 93b71700
|
SEQZ X15, X15 // 93b71700
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ var (
|
||||||
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
|
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
|
||||||
Importpath = flag.String("p", "", "set expected package import to path")
|
Importpath = flag.String("p", "", "set expected package import to path")
|
||||||
Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
|
Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
|
||||||
|
CompilingRuntime = flag.Bool("compiling-runtime", false, "source to be compiled is part of the Go runtime")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@ func main() {
|
||||||
case "all", "ret":
|
case "all", "ret":
|
||||||
ctxt.Retpoline = true
|
ctxt.Retpoline = true
|
||||||
}
|
}
|
||||||
compilingRuntime := objabi.IsRuntimePackagePath(*flags.Importpath)
|
|
||||||
|
|
||||||
ctxt.Bso = bufio.NewWriter(os.Stdout)
|
ctxt.Bso = bufio.NewWriter(os.Stdout)
|
||||||
defer ctxt.Bso.Flush()
|
defer ctxt.Bso.Flush()
|
||||||
|
|
@ -75,7 +74,8 @@ func main() {
|
||||||
var failedFile string
|
var failedFile string
|
||||||
for _, f := range flag.Args() {
|
for _, f := range flag.Args() {
|
||||||
lexer := lex.NewLexer(f)
|
lexer := lex.NewLexer(f)
|
||||||
parser := asm.NewParser(ctxt, architecture, lexer, compilingRuntime)
|
parser := asm.NewParser(ctxt, architecture, lexer,
|
||||||
|
*flags.CompilingRuntime)
|
||||||
ctxt.DiagFunc = func(format string, args ...interface{}) {
|
ctxt.DiagFunc = func(format string, args ...interface{}) {
|
||||||
diag = true
|
diag = true
|
||||||
log.Printf(format, args...)
|
log.Printf(format, args...)
|
||||||
|
|
|
||||||
|
|
@ -22,21 +22,6 @@ func usage() {
|
||||||
|
|
||||||
var wflag = flag.Bool("w", false, "write build ID")
|
var wflag = flag.Bool("w", false, "write build ID")
|
||||||
|
|
||||||
// taken from cmd/go/internal/work/buildid.go
|
|
||||||
func hashToString(h [32]byte) string {
|
|
||||||
const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
|
||||||
const chunks = 5
|
|
||||||
var dst [chunks * 4]byte
|
|
||||||
for i := 0; i < chunks; i++ {
|
|
||||||
v := uint32(h[3*i])<<16 | uint32(h[3*i+1])<<8 | uint32(h[3*i+2])
|
|
||||||
dst[4*i+0] = b64[(v>>18)&0x3F]
|
|
||||||
dst[4*i+1] = b64[(v>>12)&0x3F]
|
|
||||||
dst[4*i+2] = b64[(v>>6)&0x3F]
|
|
||||||
dst[4*i+3] = b64[v&0x3F]
|
|
||||||
}
|
|
||||||
return string(dst[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetPrefix("buildid: ")
|
log.SetPrefix("buildid: ")
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
|
|
@ -63,12 +48,12 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
matches, hash, err := buildid.FindAndHash(f, id, 0)
|
matches, hash, err := buildid.FindAndHash(f, id, 0)
|
||||||
|
f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
f.Close()
|
|
||||||
|
|
||||||
newID := id[:strings.LastIndex(id, "/")] + "/" + hashToString(hash)
|
newID := id[:strings.LastIndex(id, "/")] + "/" + buildid.HashToString(hash)
|
||||||
if len(newID) != len(id) {
|
if len(newID) != len(id) {
|
||||||
log.Fatalf("%s: build ID length mismatch %q vs %q", file, id, newID)
|
log.Fatalf("%s: build ID length mismatch %q vs %q", file, id, newID)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"go/scanner"
|
"go/scanner"
|
||||||
"go/token"
|
"go/token"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -44,14 +43,7 @@ func sourceLine(n ast.Node) int {
|
||||||
// attached to the import "C" comment, a list of references to C.xxx,
|
// attached to the import "C" comment, a list of references to C.xxx,
|
||||||
// a list of exported functions, and the actual AST, to be rewritten and
|
// a list of exported functions, and the actual AST, to be rewritten and
|
||||||
// printed.
|
// printed.
|
||||||
func (f *File) ParseGo(name string, src []byte) {
|
func (f *File) ParseGo(abspath string, src []byte) {
|
||||||
// Create absolute path for file, so that it will be used in error
|
|
||||||
// messages and recorded in debug line number information.
|
|
||||||
// This matches the rest of the toolchain. See golang.org/issue/5122.
|
|
||||||
if aname, err := filepath.Abs(name); err == nil {
|
|
||||||
name = aname
|
|
||||||
}
|
|
||||||
|
|
||||||
// Two different parses: once with comments, once without.
|
// Two different parses: once with comments, once without.
|
||||||
// The printer is not good enough at printing comments in the
|
// The printer is not good enough at printing comments in the
|
||||||
// right place when we start editing the AST behind its back,
|
// right place when we start editing the AST behind its back,
|
||||||
|
|
@ -60,8 +52,8 @@ func (f *File) ParseGo(name string, src []byte) {
|
||||||
// and reprinting.
|
// and reprinting.
|
||||||
// In cgo mode, we ignore ast2 and just apply edits directly
|
// In cgo mode, we ignore ast2 and just apply edits directly
|
||||||
// the text behind ast1. In godefs mode we modify and print ast2.
|
// the text behind ast1. In godefs mode we modify and print ast2.
|
||||||
ast1 := parse(name, src, parser.ParseComments)
|
ast1 := parse(abspath, src, parser.ParseComments)
|
||||||
ast2 := parse(name, src, 0)
|
ast2 := parse(abspath, src, 0)
|
||||||
|
|
||||||
f.Package = ast1.Name.Name
|
f.Package = ast1.Name.Name
|
||||||
f.Name = make(map[string]*Name)
|
f.Name = make(map[string]*Name)
|
||||||
|
|
@ -88,7 +80,7 @@ func (f *File) ParseGo(name string, src []byte) {
|
||||||
cg = d.Doc
|
cg = d.Doc
|
||||||
}
|
}
|
||||||
if cg != nil {
|
if cg != nil {
|
||||||
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
|
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), abspath)
|
||||||
f.Preamble += commentText(cg) + "\n"
|
f.Preamble += commentText(cg) + "\n"
|
||||||
f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
|
f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -721,7 +721,7 @@ linkage to the desired libraries. The main function is provided by
|
||||||
_cgo_main.c:
|
_cgo_main.c:
|
||||||
|
|
||||||
int main() { return 0; }
|
int main() { return 0; }
|
||||||
void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { }
|
void crosscall2(void(*fn)(void*), void *a, int c, uintptr_t ctxt) { }
|
||||||
uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
|
uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
|
||||||
void _cgo_release_context(uintptr_t ctxt) { }
|
void _cgo_release_context(uintptr_t ctxt) { }
|
||||||
char* _cgo_topofstack(void) { return (char*)0; }
|
char* _cgo_topofstack(void) { return (char*)0; }
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// godefs returns the output for -godefs mode.
|
// godefs returns the output for -godefs mode.
|
||||||
func (p *Package) godefs(f *File, srcfile string) string {
|
func (p *Package) godefs(f *File) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
||||||
fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
|
fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
|
||||||
|
|
|
||||||
|
|
@ -243,6 +243,8 @@ var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used wit
|
||||||
var gccgoMangler func(string) string
|
var gccgoMangler func(string) string
|
||||||
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
|
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
|
||||||
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
|
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
|
||||||
|
var trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
|
||||||
|
|
||||||
var goarch, goos string
|
var goarch, goos string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
@ -322,6 +324,13 @@ func main() {
|
||||||
input = filepath.Join(*srcDir, input)
|
input = filepath.Join(*srcDir, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create absolute path for file, so that it will be used in error
|
||||||
|
// messages and recorded in debug line number information.
|
||||||
|
// This matches the rest of the toolchain. See golang.org/issue/5122.
|
||||||
|
if aname, err := filepath.Abs(input); err == nil {
|
||||||
|
input = aname
|
||||||
|
}
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(input)
|
b, err := ioutil.ReadFile(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalf("%s", err)
|
fatalf("%s", err)
|
||||||
|
|
@ -330,6 +339,10 @@ func main() {
|
||||||
fatalf("%s", err)
|
fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply trimpath to the file path. The path won't be read from after this point.
|
||||||
|
input, _ = objabi.ApplyRewrites(input, *trimpath)
|
||||||
|
goFiles[i] = input
|
||||||
|
|
||||||
f := new(File)
|
f := new(File)
|
||||||
f.Edit = edit.NewBuffer(b)
|
f.Edit = edit.NewBuffer(b)
|
||||||
f.ParseGo(input, b)
|
f.ParseGo(input, b)
|
||||||
|
|
@ -367,7 +380,7 @@ func main() {
|
||||||
p.PackagePath = f.Package
|
p.PackagePath = f.Package
|
||||||
p.Record(f)
|
p.Record(f)
|
||||||
if *godefs {
|
if *godefs {
|
||||||
os.Stdout.WriteString(p.godefs(f, input))
|
os.Stdout.WriteString(p.godefs(f))
|
||||||
} else {
|
} else {
|
||||||
p.writeOutput(f, input)
|
p.writeOutput(f, input)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,14 +59,14 @@ func (p *Package) writeDefs() {
|
||||||
// Write C main file for using gcc to resolve imports.
|
// Write C main file for using gcc to resolve imports.
|
||||||
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
||||||
if *importRuntimeCgo {
|
if *importRuntimeCgo {
|
||||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
|
||||||
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n")
|
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n")
|
||||||
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
|
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
|
||||||
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
||||||
} else {
|
} else {
|
||||||
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
||||||
// which provides these functions. We just need a prototype.
|
// which provides these functions. We just need a prototype.
|
||||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
||||||
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
||||||
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
|
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
|
||||||
}
|
}
|
||||||
|
|
@ -852,7 +852,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
|
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
|
||||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
|
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
|
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, __SIZE_TYPE__);\n")
|
||||||
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
||||||
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
||||||
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
|
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
|
||||||
|
|
@ -862,59 +862,48 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
for _, exp := range p.ExpFunc {
|
for _, exp := range p.ExpFunc {
|
||||||
fn := exp.Func
|
fn := exp.Func
|
||||||
|
|
||||||
// Construct a gcc struct matching the gc argument and
|
// Construct a struct that will be used to communicate
|
||||||
// result frame. The gcc struct will be compiled with
|
// arguments from C to Go. The C and Go definitions
|
||||||
// __attribute__((packed)) so all padding must be accounted
|
// just have to agree. The gcc struct will be compiled
|
||||||
// for explicitly.
|
// with __attribute__((packed)) so all padding must be
|
||||||
|
// accounted for explicitly.
|
||||||
ctype := "struct {\n"
|
ctype := "struct {\n"
|
||||||
|
gotype := new(bytes.Buffer)
|
||||||
|
fmt.Fprintf(gotype, "struct {\n")
|
||||||
off := int64(0)
|
off := int64(0)
|
||||||
npad := 0
|
npad := 0
|
||||||
if fn.Recv != nil {
|
argField := func(typ ast.Expr, namePat string, args ...interface{}) {
|
||||||
t := p.cgoType(fn.Recv.List[0].Type)
|
name := fmt.Sprintf(namePat, args...)
|
||||||
ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
|
t := p.cgoType(typ)
|
||||||
|
if off%t.Align != 0 {
|
||||||
|
pad := t.Align - off%t.Align
|
||||||
|
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
||||||
|
off += pad
|
||||||
|
npad++
|
||||||
|
}
|
||||||
|
ctype += fmt.Sprintf("\t\t%s %s;\n", t.C, name)
|
||||||
|
fmt.Fprintf(gotype, "\t\t%s ", name)
|
||||||
|
noSourceConf.Fprint(gotype, fset, typ)
|
||||||
|
fmt.Fprintf(gotype, "\n")
|
||||||
off += t.Size
|
off += t.Size
|
||||||
}
|
}
|
||||||
|
if fn.Recv != nil {
|
||||||
|
argField(fn.Recv.List[0].Type, "recv")
|
||||||
|
}
|
||||||
fntype := fn.Type
|
fntype := fn.Type
|
||||||
forFieldList(fntype.Params,
|
forFieldList(fntype.Params,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
t := p.cgoType(atype)
|
argField(atype, "p%d", i)
|
||||||
if off%t.Align != 0 {
|
|
||||||
pad := t.Align - off%t.Align
|
|
||||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
|
||||||
off += pad
|
|
||||||
npad++
|
|
||||||
}
|
|
||||||
ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
|
|
||||||
off += t.Size
|
|
||||||
})
|
})
|
||||||
if off%p.PtrSize != 0 {
|
|
||||||
pad := p.PtrSize - off%p.PtrSize
|
|
||||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
|
||||||
off += pad
|
|
||||||
npad++
|
|
||||||
}
|
|
||||||
forFieldList(fntype.Results,
|
forFieldList(fntype.Results,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
t := p.cgoType(atype)
|
argField(atype, "r%d", i)
|
||||||
if off%t.Align != 0 {
|
|
||||||
pad := t.Align - off%t.Align
|
|
||||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
|
||||||
off += pad
|
|
||||||
npad++
|
|
||||||
}
|
|
||||||
ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
|
|
||||||
off += t.Size
|
|
||||||
})
|
})
|
||||||
if off%p.PtrSize != 0 {
|
|
||||||
pad := p.PtrSize - off%p.PtrSize
|
|
||||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
|
||||||
off += pad
|
|
||||||
npad++
|
|
||||||
}
|
|
||||||
if ctype == "struct {\n" {
|
if ctype == "struct {\n" {
|
||||||
ctype += "\t\tchar unused;\n" // avoid empty struct
|
ctype += "\t\tchar unused;\n" // avoid empty struct
|
||||||
}
|
}
|
||||||
ctype += "\t}"
|
ctype += "\t}"
|
||||||
|
fmt.Fprintf(gotype, "\t}")
|
||||||
|
|
||||||
// Get the return type of the wrapper function
|
// Get the return type of the wrapper function
|
||||||
// compiled by gcc.
|
// compiled by gcc.
|
||||||
|
|
@ -939,7 +928,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the wrapper function compiled by gcc.
|
// Build the wrapper function compiled by gcc.
|
||||||
s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
|
gccExport := ""
|
||||||
|
if goos == "windows" {
|
||||||
|
gccExport = "__declspec(dllexport)"
|
||||||
|
}
|
||||||
|
s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName)
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
||||||
s += " recv"
|
s += " recv"
|
||||||
|
|
@ -961,12 +954,15 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgcch, "extern %s;\n", s)
|
fmt.Fprintf(fgcch, "extern %s;\n", s)
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
||||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||||
fmt.Fprintf(fgcc, "{\n")
|
fmt.Fprintf(fgcc, "{\n")
|
||||||
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
||||||
fmt.Fprintf(fgcc, "\t%s %v _cgo_a;\n", ctype, p.packedAttribute())
|
// The results part of the argument structure must be
|
||||||
|
// initialized to 0 so the write barriers generated by
|
||||||
|
// the assignments to these fields in Go are safe.
|
||||||
|
fmt.Fprintf(fgcc, "\t%s %v _cgo_a = {0};\n", ctype, p.packedAttribute())
|
||||||
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
||||||
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
||||||
}
|
}
|
||||||
|
|
@ -995,82 +991,28 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
fmt.Fprintf(fgcc, "}\n")
|
fmt.Fprintf(fgcc, "}\n")
|
||||||
|
|
||||||
// Build the wrapper function compiled by cmd/compile.
|
// Build the wrapper function compiled by cmd/compile.
|
||||||
goname := "_cgoexpwrap" + cPrefix + "_"
|
// This unpacks the argument struct above and calls the Go function.
|
||||||
if fn.Recv != nil {
|
|
||||||
goname += fn.Recv.List[0].Names[0].Name + "_"
|
|
||||||
}
|
|
||||||
goname += exp.Func.Name.Name
|
|
||||||
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
|
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
|
||||||
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
|
|
||||||
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix, exp.ExpName)
|
|
||||||
fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
|
|
||||||
// The indirect here is converting from a Go function pointer to a C function pointer.
|
|
||||||
fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n")
|
|
||||||
fmt.Fprintf(fgo2, "}\n")
|
|
||||||
|
|
||||||
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
||||||
|
|
||||||
// This code uses printer.Fprint, not conf.Fprint,
|
|
||||||
// because we don't want //line comments in the middle
|
|
||||||
// of the function types.
|
|
||||||
fmt.Fprintf(fgo2, "\n")
|
|
||||||
fmt.Fprintf(fgo2, "func %s(", goname)
|
|
||||||
comma := false
|
|
||||||
if fn.Recv != nil {
|
|
||||||
fmt.Fprintf(fgo2, "recv ")
|
|
||||||
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
|
|
||||||
comma = true
|
|
||||||
}
|
|
||||||
forFieldList(fntype.Params,
|
|
||||||
func(i int, aname string, atype ast.Expr) {
|
|
||||||
if comma {
|
|
||||||
fmt.Fprintf(fgo2, ", ")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fgo2, "p%d ", i)
|
|
||||||
printer.Fprint(fgo2, fset, atype)
|
|
||||||
comma = true
|
|
||||||
})
|
|
||||||
fmt.Fprintf(fgo2, ")")
|
|
||||||
if gccResult != "void" {
|
if gccResult != "void" {
|
||||||
fmt.Fprint(fgo2, " (")
|
// Write results back to frame.
|
||||||
|
fmt.Fprintf(fgo2, "\t")
|
||||||
forFieldList(fntype.Results,
|
forFieldList(fntype.Results,
|
||||||
func(i int, aname string, atype ast.Expr) {
|
func(i int, aname string, atype ast.Expr) {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Fprint(fgo2, ", ")
|
fmt.Fprintf(fgo2, ", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "r%d ", i)
|
fmt.Fprintf(fgo2, "a.r%d", i)
|
||||||
printer.Fprint(fgo2, fset, atype)
|
|
||||||
})
|
})
|
||||||
fmt.Fprint(fgo2, ")")
|
fmt.Fprintf(fgo2, " = ")
|
||||||
}
|
|
||||||
fmt.Fprint(fgo2, " {\n")
|
|
||||||
if gccResult == "void" {
|
|
||||||
fmt.Fprint(fgo2, "\t")
|
|
||||||
} else {
|
|
||||||
// Verify that any results don't contain any
|
|
||||||
// Go pointers.
|
|
||||||
addedDefer := false
|
|
||||||
forFieldList(fntype.Results,
|
|
||||||
func(i int, aname string, atype ast.Expr) {
|
|
||||||
if !p.hasPointer(nil, atype, false) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !addedDefer {
|
|
||||||
fmt.Fprint(fgo2, "\tdefer func() {\n")
|
|
||||||
addedDefer = true
|
|
||||||
}
|
|
||||||
fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
|
|
||||||
})
|
|
||||||
if addedDefer {
|
|
||||||
fmt.Fprint(fgo2, "\t}()\n")
|
|
||||||
}
|
|
||||||
fmt.Fprint(fgo2, "\treturn ")
|
|
||||||
}
|
}
|
||||||
if fn.Recv != nil {
|
if fn.Recv != nil {
|
||||||
fmt.Fprintf(fgo2, "recv.")
|
fmt.Fprintf(fgo2, "a.recv.")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
||||||
forFieldList(fntype.Params,
|
forFieldList(fntype.Params,
|
||||||
|
|
@ -1078,9 +1020,20 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Fprint(fgo2, ", ")
|
fmt.Fprint(fgo2, ", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgo2, "p%d", i)
|
fmt.Fprintf(fgo2, "a.p%d", i)
|
||||||
})
|
})
|
||||||
fmt.Fprint(fgo2, ")\n")
|
fmt.Fprint(fgo2, ")\n")
|
||||||
|
if gccResult != "void" {
|
||||||
|
// Verify that any results don't contain any
|
||||||
|
// Go pointers.
|
||||||
|
forFieldList(fntype.Results,
|
||||||
|
func(i int, aname string, atype ast.Expr) {
|
||||||
|
if !p.hasPointer(nil, atype, false) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(fgo2, "\t_cgoCheckResult(a.r%d)\n", i)
|
||||||
|
})
|
||||||
|
}
|
||||||
fmt.Fprint(fgo2, "}\n")
|
fmt.Fprint(fgo2, "}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1578,9 +1531,6 @@ const goProlog = `
|
||||||
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
||||||
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
||||||
|
|
||||||
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
|
|
||||||
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
|
|
||||||
|
|
||||||
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
||||||
func _cgoCheckPointer(interface{}, interface{})
|
func _cgoCheckPointer(interface{}, interface{})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,8 @@ var knownFormats = map[string]string{
|
||||||
"cmd/compile/internal/ssa.GCNode %v": "",
|
"cmd/compile/internal/ssa.GCNode %v": "",
|
||||||
"cmd/compile/internal/ssa.ID %d": "",
|
"cmd/compile/internal/ssa.ID %d": "",
|
||||||
"cmd/compile/internal/ssa.ID %v": "",
|
"cmd/compile/internal/ssa.ID %v": "",
|
||||||
"cmd/compile/internal/ssa.LocPair %s": "",
|
|
||||||
"cmd/compile/internal/ssa.LocalSlot %s": "",
|
"cmd/compile/internal/ssa.LocalSlot %s": "",
|
||||||
"cmd/compile/internal/ssa.LocalSlot %v": "",
|
"cmd/compile/internal/ssa.LocalSlot %v": "",
|
||||||
"cmd/compile/internal/ssa.Location %T": "",
|
|
||||||
"cmd/compile/internal/ssa.Location %s": "",
|
"cmd/compile/internal/ssa.Location %s": "",
|
||||||
"cmd/compile/internal/ssa.Op %s": "",
|
"cmd/compile/internal/ssa.Op %s": "",
|
||||||
"cmd/compile/internal/ssa.Op %v": "",
|
"cmd/compile/internal/ssa.Op %v": "",
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,11 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
|
||||||
// loadByType returns the load instruction of the given type.
|
// loadByType returns the load instruction of the given type.
|
||||||
func loadByType(t *types.Type) obj.As {
|
func loadByType(t *types.Type) obj.As {
|
||||||
// Avoid partial register write
|
// Avoid partial register write
|
||||||
if !t.IsFloat() && t.Size() <= 2 {
|
if !t.IsFloat() {
|
||||||
if t.Size() == 1 {
|
switch t.Size() {
|
||||||
|
case 1:
|
||||||
return x86.AMOVBLZX
|
return x86.AMOVBLZX
|
||||||
} else {
|
case 2:
|
||||||
return x86.AMOVWLZX
|
return x86.AMOVWLZX
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1070,7 +1071,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p := s.Prog(v.Op.Asm())
|
p := s.Prog(v.Op.Asm())
|
||||||
val := v.AuxInt
|
val := v.AuxInt
|
||||||
// 0 means math.RoundToEven, 1 Floor, 2 Ceil, 3 Trunc
|
// 0 means math.RoundToEven, 1 Floor, 2 Ceil, 3 Trunc
|
||||||
if val != 0 && val != 1 && val != 2 && val != 3 {
|
if val < 0 || val > 3 {
|
||||||
v.Fatalf("Invalid rounding mode")
|
v.Fatalf("Invalid rounding mode")
|
||||||
}
|
}
|
||||||
p.From.Offset = val
|
p.From.Offset = val
|
||||||
|
|
@ -1210,7 +1211,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p = s.Prog(x86.ASETEQ)
|
p = s.Prog(x86.ASETEQ)
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = v.Reg0()
|
p.To.Reg = v.Reg0()
|
||||||
case ssa.OpAMD64ANDBlock, ssa.OpAMD64ORBlock:
|
case ssa.OpAMD64ANDBlock, ssa.OpAMD64ANDLlock, ssa.OpAMD64ORBlock, ssa.OpAMD64ORLlock:
|
||||||
s.Prog(x86.ALOCK)
|
s.Prog(x86.ALOCK)
|
||||||
p := s.Prog(v.Op.Asm())
|
p := s.Prog(v.Op.Asm())
|
||||||
p.From.Type = obj.TYPE_REG
|
p.From.Type = obj.TYPE_REG
|
||||||
|
|
|
||||||
|
|
@ -581,6 +581,24 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p2.From.Reg = arm64.REGTMP
|
p2.From.Reg = arm64.REGTMP
|
||||||
p2.To.Type = obj.TYPE_BRANCH
|
p2.To.Type = obj.TYPE_BRANCH
|
||||||
gc.Patch(p2, p)
|
gc.Patch(p2, p)
|
||||||
|
case ssa.OpARM64LoweredAtomicExchange64Variant,
|
||||||
|
ssa.OpARM64LoweredAtomicExchange32Variant:
|
||||||
|
swap := arm64.ASWPALD
|
||||||
|
if v.Op == ssa.OpARM64LoweredAtomicExchange32Variant {
|
||||||
|
swap = arm64.ASWPALW
|
||||||
|
}
|
||||||
|
r0 := v.Args[0].Reg()
|
||||||
|
r1 := v.Args[1].Reg()
|
||||||
|
out := v.Reg0()
|
||||||
|
|
||||||
|
// SWPALD Rarg1, (Rarg0), Rout
|
||||||
|
p := s.Prog(swap)
|
||||||
|
p.From.Type = obj.TYPE_REG
|
||||||
|
p.From.Reg = r1
|
||||||
|
p.To.Type = obj.TYPE_MEM
|
||||||
|
p.To.Reg = r0
|
||||||
|
p.RegTo2 = out
|
||||||
|
|
||||||
case ssa.OpARM64LoweredAtomicAdd64,
|
case ssa.OpARM64LoweredAtomicAdd64,
|
||||||
ssa.OpARM64LoweredAtomicAdd32:
|
ssa.OpARM64LoweredAtomicAdd32:
|
||||||
// LDAXR (Rarg0), Rout
|
// LDAXR (Rarg0), Rout
|
||||||
|
|
@ -687,16 +705,74 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p5.To.Type = obj.TYPE_REG
|
p5.To.Type = obj.TYPE_REG
|
||||||
p5.To.Reg = out
|
p5.To.Reg = out
|
||||||
gc.Patch(p2, p5)
|
gc.Patch(p2, p5)
|
||||||
|
case ssa.OpARM64LoweredAtomicCas64Variant,
|
||||||
|
ssa.OpARM64LoweredAtomicCas32Variant:
|
||||||
|
// Rarg0: ptr
|
||||||
|
// Rarg1: old
|
||||||
|
// Rarg2: new
|
||||||
|
// MOV Rarg1, Rtmp
|
||||||
|
// CASAL Rtmp, (Rarg0), Rarg2
|
||||||
|
// CMP Rarg1, Rtmp
|
||||||
|
// CSET EQ, Rout
|
||||||
|
cas := arm64.ACASALD
|
||||||
|
cmp := arm64.ACMP
|
||||||
|
mov := arm64.AMOVD
|
||||||
|
if v.Op == ssa.OpARM64LoweredAtomicCas32Variant {
|
||||||
|
cas = arm64.ACASALW
|
||||||
|
cmp = arm64.ACMPW
|
||||||
|
mov = arm64.AMOVW
|
||||||
|
}
|
||||||
|
r0 := v.Args[0].Reg()
|
||||||
|
r1 := v.Args[1].Reg()
|
||||||
|
r2 := v.Args[2].Reg()
|
||||||
|
out := v.Reg0()
|
||||||
|
|
||||||
|
// MOV Rarg1, Rtmp
|
||||||
|
p := s.Prog(mov)
|
||||||
|
p.From.Type = obj.TYPE_REG
|
||||||
|
p.From.Reg = r1
|
||||||
|
p.To.Type = obj.TYPE_REG
|
||||||
|
p.To.Reg = arm64.REGTMP
|
||||||
|
|
||||||
|
// CASAL Rtmp, (Rarg0), Rarg2
|
||||||
|
p1 := s.Prog(cas)
|
||||||
|
p1.From.Type = obj.TYPE_REG
|
||||||
|
p1.From.Reg = arm64.REGTMP
|
||||||
|
p1.To.Type = obj.TYPE_MEM
|
||||||
|
p1.To.Reg = r0
|
||||||
|
p1.RegTo2 = r2
|
||||||
|
|
||||||
|
// CMP Rarg1, Rtmp
|
||||||
|
p2 := s.Prog(cmp)
|
||||||
|
p2.From.Type = obj.TYPE_REG
|
||||||
|
p2.From.Reg = r1
|
||||||
|
p2.Reg = arm64.REGTMP
|
||||||
|
|
||||||
|
// CSET EQ, Rout
|
||||||
|
p3 := s.Prog(arm64.ACSET)
|
||||||
|
p3.From.Type = obj.TYPE_REG
|
||||||
|
p3.From.Reg = arm64.COND_EQ
|
||||||
|
p3.To.Type = obj.TYPE_REG
|
||||||
|
p3.To.Reg = out
|
||||||
|
|
||||||
case ssa.OpARM64LoweredAtomicAnd8,
|
case ssa.OpARM64LoweredAtomicAnd8,
|
||||||
ssa.OpARM64LoweredAtomicOr8:
|
ssa.OpARM64LoweredAtomicAnd32,
|
||||||
// LDAXRB (Rarg0), Rout
|
ssa.OpARM64LoweredAtomicOr8,
|
||||||
|
ssa.OpARM64LoweredAtomicOr32:
|
||||||
|
// LDAXRB/LDAXRW (Rarg0), Rout
|
||||||
// AND/OR Rarg1, Rout
|
// AND/OR Rarg1, Rout
|
||||||
// STLXRB Rout, (Rarg0), Rtmp
|
// STLXRB/STLXRB Rout, (Rarg0), Rtmp
|
||||||
// CBNZ Rtmp, -3(PC)
|
// CBNZ Rtmp, -3(PC)
|
||||||
|
ld := arm64.ALDAXRB
|
||||||
|
st := arm64.ASTLXRB
|
||||||
|
if v.Op == ssa.OpARM64LoweredAtomicAnd32 || v.Op == ssa.OpARM64LoweredAtomicOr32 {
|
||||||
|
ld = arm64.ALDAXRW
|
||||||
|
st = arm64.ASTLXRW
|
||||||
|
}
|
||||||
r0 := v.Args[0].Reg()
|
r0 := v.Args[0].Reg()
|
||||||
r1 := v.Args[1].Reg()
|
r1 := v.Args[1].Reg()
|
||||||
out := v.Reg0()
|
out := v.Reg0()
|
||||||
p := s.Prog(arm64.ALDAXRB)
|
p := s.Prog(ld)
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Reg = r0
|
p.From.Reg = r0
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
|
|
@ -706,7 +782,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p1.From.Reg = r1
|
p1.From.Reg = r1
|
||||||
p1.To.Type = obj.TYPE_REG
|
p1.To.Type = obj.TYPE_REG
|
||||||
p1.To.Reg = out
|
p1.To.Reg = out
|
||||||
p2 := s.Prog(arm64.ASTLXRB)
|
p2 := s.Prog(st)
|
||||||
p2.From.Type = obj.TYPE_REG
|
p2.From.Type = obj.TYPE_REG
|
||||||
p2.From.Reg = out
|
p2.From.Reg = out
|
||||||
p2.To.Type = obj.TYPE_MEM
|
p2.To.Type = obj.TYPE_MEM
|
||||||
|
|
@ -717,6 +793,63 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p3.From.Reg = arm64.REGTMP
|
p3.From.Reg = arm64.REGTMP
|
||||||
p3.To.Type = obj.TYPE_BRANCH
|
p3.To.Type = obj.TYPE_BRANCH
|
||||||
gc.Patch(p3, p)
|
gc.Patch(p3, p)
|
||||||
|
case ssa.OpARM64LoweredAtomicAnd8Variant,
|
||||||
|
ssa.OpARM64LoweredAtomicAnd32Variant:
|
||||||
|
atomic_clear := arm64.ALDCLRALW
|
||||||
|
if v.Op == ssa.OpARM64LoweredAtomicAnd8Variant {
|
||||||
|
atomic_clear = arm64.ALDCLRALB
|
||||||
|
}
|
||||||
|
r0 := v.Args[0].Reg()
|
||||||
|
r1 := v.Args[1].Reg()
|
||||||
|
out := v.Reg0()
|
||||||
|
|
||||||
|
// MNV Rarg1 Rtemp
|
||||||
|
p := s.Prog(arm64.AMVN)
|
||||||
|
p.From.Type = obj.TYPE_REG
|
||||||
|
p.From.Reg = r1
|
||||||
|
p.To.Type = obj.TYPE_REG
|
||||||
|
p.To.Reg = arm64.REGTMP
|
||||||
|
|
||||||
|
// LDCLRALW Rtemp, (Rarg0), Rout
|
||||||
|
p1 := s.Prog(atomic_clear)
|
||||||
|
p1.From.Type = obj.TYPE_REG
|
||||||
|
p1.From.Reg = arm64.REGTMP
|
||||||
|
p1.To.Type = obj.TYPE_MEM
|
||||||
|
p1.To.Reg = r0
|
||||||
|
p1.RegTo2 = out
|
||||||
|
|
||||||
|
// AND Rarg1, Rout
|
||||||
|
p2 := s.Prog(arm64.AAND)
|
||||||
|
p2.From.Type = obj.TYPE_REG
|
||||||
|
p2.From.Reg = r1
|
||||||
|
p2.To.Type = obj.TYPE_REG
|
||||||
|
p2.To.Reg = out
|
||||||
|
|
||||||
|
case ssa.OpARM64LoweredAtomicOr8Variant,
|
||||||
|
ssa.OpARM64LoweredAtomicOr32Variant:
|
||||||
|
atomic_or := arm64.ALDORALW
|
||||||
|
if v.Op == ssa.OpARM64LoweredAtomicOr8Variant {
|
||||||
|
atomic_or = arm64.ALDORALB
|
||||||
|
}
|
||||||
|
r0 := v.Args[0].Reg()
|
||||||
|
r1 := v.Args[1].Reg()
|
||||||
|
out := v.Reg0()
|
||||||
|
|
||||||
|
// LDORALW Rarg1, (Rarg0), Rout
|
||||||
|
p := s.Prog(atomic_or)
|
||||||
|
p.From.Type = obj.TYPE_REG
|
||||||
|
p.From.Reg = r1
|
||||||
|
p.To.Type = obj.TYPE_MEM
|
||||||
|
p.To.Reg = r0
|
||||||
|
p.RegTo2 = out
|
||||||
|
|
||||||
|
// ORR Rarg1, Rout
|
||||||
|
p2 := s.Prog(arm64.AORR)
|
||||||
|
p2.From.Type = obj.TYPE_REG
|
||||||
|
p2.From.Reg = r1
|
||||||
|
p2.To.Type = obj.TYPE_REG
|
||||||
|
p2.To.Reg = out
|
||||||
|
|
||||||
case ssa.OpARM64MOVBreg,
|
case ssa.OpARM64MOVBreg,
|
||||||
ssa.OpARM64MOVBUreg,
|
ssa.OpARM64MOVBUreg,
|
||||||
ssa.OpARM64MOVHreg,
|
ssa.OpARM64MOVHreg,
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,7 @@ func genhash(t *types.Type) *obj.LSym {
|
||||||
}
|
}
|
||||||
|
|
||||||
sym := typesymprefix(".hash", t)
|
sym := typesymprefix(".hash", t)
|
||||||
if Debug['r'] != 0 {
|
if Debug.r != 0 {
|
||||||
fmt.Printf("genhash %v %v %v\n", closure, sym, t)
|
fmt.Printf("genhash %v %v %v\n", closure, sym, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -374,7 +374,7 @@ func genhash(t *types.Type) *obj.LSym {
|
||||||
r.List.Append(nh)
|
r.List.Append(nh)
|
||||||
fn.Nbody.Append(r)
|
fn.Nbody.Append(r)
|
||||||
|
|
||||||
if Debug['r'] != 0 {
|
if Debug.r != 0 {
|
||||||
dumplist("genhash body", fn.Nbody)
|
dumplist("genhash body", fn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -509,7 +509,7 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
return closure
|
return closure
|
||||||
}
|
}
|
||||||
sym := typesymprefix(".eq", t)
|
sym := typesymprefix(".eq", t)
|
||||||
if Debug['r'] != 0 {
|
if Debug.r != 0 {
|
||||||
fmt.Printf("geneq %v\n", t)
|
fmt.Printf("geneq %v\n", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -529,6 +529,10 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
fn := dclfunc(sym, tfn)
|
fn := dclfunc(sym, tfn)
|
||||||
np := asNode(tfn.Type.Params().Field(0).Nname)
|
np := asNode(tfn.Type.Params().Field(0).Nname)
|
||||||
nq := asNode(tfn.Type.Params().Field(1).Nname)
|
nq := asNode(tfn.Type.Params().Field(1).Nname)
|
||||||
|
nr := asNode(tfn.Type.Results().Field(0).Nname)
|
||||||
|
|
||||||
|
// Label to jump to if an equality test fails.
|
||||||
|
neq := autolabel(".neq")
|
||||||
|
|
||||||
// We reach here only for types that have equality but
|
// We reach here only for types that have equality but
|
||||||
// cannot be handled by the standard algorithms,
|
// cannot be handled by the standard algorithms,
|
||||||
|
|
@ -555,13 +559,13 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
// for i := 0; i < nelem; i++ {
|
// for i := 0; i < nelem; i++ {
|
||||||
// if eq(p[i], q[i]) {
|
// if eq(p[i], q[i]) {
|
||||||
// } else {
|
// } else {
|
||||||
// return
|
// goto neq
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// TODO(josharian): consider doing some loop unrolling
|
// TODO(josharian): consider doing some loop unrolling
|
||||||
// for larger nelem as well, processing a few elements at a time in a loop.
|
// for larger nelem as well, processing a few elements at a time in a loop.
|
||||||
checkAll := func(unroll int64, eq func(pi, qi *Node) *Node) {
|
checkAll := func(unroll int64, last bool, eq func(pi, qi *Node) *Node) {
|
||||||
// checkIdx generates a node to check for equality at index i.
|
// checkIdx generates a node to check for equality at index i.
|
||||||
checkIdx := func(i *Node) *Node {
|
checkIdx := func(i *Node) *Node {
|
||||||
// pi := p[i]
|
// pi := p[i]
|
||||||
|
|
@ -576,23 +580,21 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
}
|
}
|
||||||
|
|
||||||
if nelem <= unroll {
|
if nelem <= unroll {
|
||||||
|
if last {
|
||||||
|
// Do last comparison in a different manner.
|
||||||
|
nelem--
|
||||||
|
}
|
||||||
// Generate a series of checks.
|
// Generate a series of checks.
|
||||||
var cond *Node
|
|
||||||
for i := int64(0); i < nelem; i++ {
|
for i := int64(0); i < nelem; i++ {
|
||||||
c := nodintconst(i)
|
// if check {} else { goto neq }
|
||||||
check := checkIdx(c)
|
nif := nod(OIF, checkIdx(nodintconst(i)), nil)
|
||||||
if cond == nil {
|
nif.Rlist.Append(nodSym(OGOTO, nil, neq))
|
||||||
cond = check
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cond = nod(OANDAND, cond, check)
|
|
||||||
}
|
|
||||||
nif := nod(OIF, cond, nil)
|
|
||||||
nif.Rlist.Append(nod(ORETURN, nil, nil))
|
|
||||||
fn.Nbody.Append(nif)
|
fn.Nbody.Append(nif)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
if last {
|
||||||
|
fn.Nbody.Append(nod(OAS, nr, checkIdx(nodintconst(nelem))))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// Generate a for loop.
|
// Generate a for loop.
|
||||||
// for i := 0; i < nelem; i++
|
// for i := 0; i < nelem; i++
|
||||||
i := temp(types.Types[TINT])
|
i := temp(types.Types[TINT])
|
||||||
|
|
@ -601,12 +603,15 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
post := nod(OAS, i, nod(OADD, i, nodintconst(1)))
|
post := nod(OAS, i, nod(OADD, i, nodintconst(1)))
|
||||||
loop := nod(OFOR, cond, post)
|
loop := nod(OFOR, cond, post)
|
||||||
loop.Ninit.Append(init)
|
loop.Ninit.Append(init)
|
||||||
// if eq(pi, qi) {} else { return }
|
// if eq(pi, qi) {} else { goto neq }
|
||||||
check := checkIdx(i)
|
nif := nod(OIF, checkIdx(i), nil)
|
||||||
nif := nod(OIF, check, nil)
|
nif.Rlist.Append(nodSym(OGOTO, nil, neq))
|
||||||
nif.Rlist.Append(nod(ORETURN, nil, nil))
|
|
||||||
loop.Nbody.Append(nif)
|
loop.Nbody.Append(nif)
|
||||||
fn.Nbody.Append(loop)
|
fn.Nbody.Append(loop)
|
||||||
|
if last {
|
||||||
|
fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t.Elem().Etype {
|
switch t.Elem().Etype {
|
||||||
|
|
@ -614,32 +619,28 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
// Do two loops. First, check that all the lengths match (cheap).
|
// Do two loops. First, check that all the lengths match (cheap).
|
||||||
// Second, check that all the contents match (expensive).
|
// Second, check that all the contents match (expensive).
|
||||||
// TODO: when the array size is small, unroll the length match checks.
|
// TODO: when the array size is small, unroll the length match checks.
|
||||||
checkAll(3, func(pi, qi *Node) *Node {
|
checkAll(3, false, func(pi, qi *Node) *Node {
|
||||||
// Compare lengths.
|
// Compare lengths.
|
||||||
eqlen, _ := eqstring(pi, qi)
|
eqlen, _ := eqstring(pi, qi)
|
||||||
return eqlen
|
return eqlen
|
||||||
})
|
})
|
||||||
checkAll(1, func(pi, qi *Node) *Node {
|
checkAll(1, true, func(pi, qi *Node) *Node {
|
||||||
// Compare contents.
|
// Compare contents.
|
||||||
_, eqmem := eqstring(pi, qi)
|
_, eqmem := eqstring(pi, qi)
|
||||||
return eqmem
|
return eqmem
|
||||||
})
|
})
|
||||||
case TFLOAT32, TFLOAT64:
|
case TFLOAT32, TFLOAT64:
|
||||||
checkAll(2, func(pi, qi *Node) *Node {
|
checkAll(2, true, func(pi, qi *Node) *Node {
|
||||||
// p[i] == q[i]
|
// p[i] == q[i]
|
||||||
return nod(OEQ, pi, qi)
|
return nod(OEQ, pi, qi)
|
||||||
})
|
})
|
||||||
// TODO: pick apart structs, do them piecemeal too
|
// TODO: pick apart structs, do them piecemeal too
|
||||||
default:
|
default:
|
||||||
checkAll(1, func(pi, qi *Node) *Node {
|
checkAll(1, true, func(pi, qi *Node) *Node {
|
||||||
// p[i] == q[i]
|
// p[i] == q[i]
|
||||||
return nod(OEQ, pi, qi)
|
return nod(OEQ, pi, qi)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// return true
|
|
||||||
ret := nod(ORETURN, nil, nil)
|
|
||||||
ret.List.Append(nodbool(true))
|
|
||||||
fn.Nbody.Append(ret)
|
|
||||||
|
|
||||||
case TSTRUCT:
|
case TSTRUCT:
|
||||||
// Build a list of conditions to satisfy.
|
// Build a list of conditions to satisfy.
|
||||||
|
|
@ -717,22 +718,42 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
flatConds = append(flatConds, c...)
|
flatConds = append(flatConds, c...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var cond *Node
|
|
||||||
if len(flatConds) == 0 {
|
if len(flatConds) == 0 {
|
||||||
cond = nodbool(true)
|
fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
|
||||||
} else {
|
} else {
|
||||||
cond = flatConds[0]
|
for _, c := range flatConds[:len(flatConds)-1] {
|
||||||
for _, c := range flatConds[1:] {
|
// if cond {} else { goto neq }
|
||||||
cond = nod(OANDAND, cond, c)
|
n := nod(OIF, c, nil)
|
||||||
|
n.Rlist.Append(nodSym(OGOTO, nil, neq))
|
||||||
|
fn.Nbody.Append(n)
|
||||||
|
}
|
||||||
|
fn.Nbody.Append(nod(OAS, nr, flatConds[len(flatConds)-1]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := nod(ORETURN, nil, nil)
|
// ret:
|
||||||
ret.List.Append(cond)
|
// return
|
||||||
fn.Nbody.Append(ret)
|
ret := autolabel(".ret")
|
||||||
}
|
fn.Nbody.Append(nodSym(OLABEL, nil, ret))
|
||||||
|
fn.Nbody.Append(nod(ORETURN, nil, nil))
|
||||||
|
|
||||||
if Debug['r'] != 0 {
|
// neq:
|
||||||
|
// r = false
|
||||||
|
// return (or goto ret)
|
||||||
|
fn.Nbody.Append(nodSym(OLABEL, nil, neq))
|
||||||
|
fn.Nbody.Append(nod(OAS, nr, nodbool(false)))
|
||||||
|
if EqCanPanic(t) || hasCall(fn) {
|
||||||
|
// Epilogue is large, so share it with the equal case.
|
||||||
|
fn.Nbody.Append(nodSym(OGOTO, nil, ret))
|
||||||
|
} else {
|
||||||
|
// Epilogue is small, so don't bother sharing.
|
||||||
|
fn.Nbody.Append(nod(ORETURN, nil, nil))
|
||||||
|
}
|
||||||
|
// TODO(khr): the epilogue size detection condition above isn't perfect.
|
||||||
|
// We should really do a generic CL that shares epilogues across
|
||||||
|
// the board. See #24936.
|
||||||
|
|
||||||
|
if Debug.r != 0 {
|
||||||
dumplist("geneq body", fn.Nbody)
|
dumplist("geneq body", fn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -762,6 +783,39 @@ func geneq(t *types.Type) *obj.LSym {
|
||||||
return closure
|
return closure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hasCall(n *Node) bool {
|
||||||
|
if n.Op == OCALL || n.Op == OCALLFUNC {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if n.Left != nil && hasCall(n.Left) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if n.Right != nil && hasCall(n.Right) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, x := range n.Ninit.Slice() {
|
||||||
|
if hasCall(x) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, x := range n.Nbody.Slice() {
|
||||||
|
if hasCall(x) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, x := range n.List.Slice() {
|
||||||
|
if hasCall(x) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, x := range n.Rlist.Slice() {
|
||||||
|
if hasCall(x) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// eqfield returns the node
|
// eqfield returns the node
|
||||||
// p.field == q.field
|
// p.field == q.field
|
||||||
func eqfield(p *Node, q *Node, field *types.Sym) *Node {
|
func eqfield(p *Node, q *Node, field *types.Sym) *Node {
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ func expandiface(t *types.Type) {
|
||||||
sort.Sort(methcmp(methods))
|
sort.Sort(methcmp(methods))
|
||||||
|
|
||||||
if int64(len(methods)) >= thearch.MAXWIDTH/int64(Widthptr) {
|
if int64(len(methods)) >= thearch.MAXWIDTH/int64(Widthptr) {
|
||||||
yyerror("interface too large")
|
yyerrorl(typePos(t), "interface too large")
|
||||||
}
|
}
|
||||||
for i, m := range methods {
|
for i, m := range methods {
|
||||||
m.Offset = int64(i) * int64(Widthptr)
|
m.Offset = int64(i) * int64(Widthptr)
|
||||||
|
|
@ -150,7 +150,7 @@ func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 {
|
||||||
maxwidth = 1<<31 - 1
|
maxwidth = 1<<31 - 1
|
||||||
}
|
}
|
||||||
if o >= maxwidth {
|
if o >= maxwidth {
|
||||||
yyerror("type %L too large", errtype)
|
yyerrorl(typePos(errtype), "type %L too large", errtype)
|
||||||
o = 8 // small but nonzero
|
o = 8 // small but nonzero
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +199,7 @@ func findTypeLoop(t *types.Type, path *[]*types.Type) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
*path = append(*path, t)
|
*path = append(*path, t)
|
||||||
if findTypeLoop(asNode(t.Nod).Name.Param.Ntype.Type, path) {
|
if p := asNode(t.Nod).Name.Param; p != nil && findTypeLoop(p.Ntype.Type, path) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
*path = (*path)[:len(*path)-1]
|
*path = (*path)[:len(*path)-1]
|
||||||
|
|
@ -381,7 +381,7 @@ func dowidth(t *types.Type) {
|
||||||
t1 := t.ChanArgs()
|
t1 := t.ChanArgs()
|
||||||
dowidth(t1) // just in case
|
dowidth(t1) // just in case
|
||||||
if t1.Elem().Width >= 1<<16 {
|
if t1.Elem().Width >= 1<<16 {
|
||||||
yyerror("channel element type too large (>64kB)")
|
yyerrorl(typePos(t1), "channel element type too large (>64kB)")
|
||||||
}
|
}
|
||||||
w = 1 // anything will do
|
w = 1 // anything will do
|
||||||
|
|
||||||
|
|
@ -414,7 +414,7 @@ func dowidth(t *types.Type) {
|
||||||
if t.Elem().Width != 0 {
|
if t.Elem().Width != 0 {
|
||||||
cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
|
cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
|
||||||
if uint64(t.NumElem()) > cap {
|
if uint64(t.NumElem()) > cap {
|
||||||
yyerror("type %L larger than address space", t)
|
yyerrorl(typePos(t), "type %L larger than address space", t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w = t.NumElem() * t.Elem().Width
|
w = t.NumElem() * t.Elem().Width
|
||||||
|
|
@ -456,7 +456,7 @@ func dowidth(t *types.Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if Widthptr == 4 && w != int64(int32(w)) {
|
if Widthptr == 4 && w != int64(int32(w)) {
|
||||||
yyerror("type %v too large", t)
|
yyerrorl(typePos(t), "type %v too large", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Width = w
|
t.Width = w
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ var runtimeDecls = [...]struct {
|
||||||
{"printcomplex", funcTag, 27},
|
{"printcomplex", funcTag, 27},
|
||||||
{"printstring", funcTag, 29},
|
{"printstring", funcTag, 29},
|
||||||
{"printpointer", funcTag, 30},
|
{"printpointer", funcTag, 30},
|
||||||
|
{"printuintptr", funcTag, 31},
|
||||||
{"printiface", funcTag, 30},
|
{"printiface", funcTag, 30},
|
||||||
{"printeface", funcTag, 30},
|
{"printeface", funcTag, 30},
|
||||||
{"printslice", funcTag, 30},
|
{"printslice", funcTag, 30},
|
||||||
|
|
@ -51,134 +52,134 @@ var runtimeDecls = [...]struct {
|
||||||
{"printsp", funcTag, 9},
|
{"printsp", funcTag, 9},
|
||||||
{"printlock", funcTag, 9},
|
{"printlock", funcTag, 9},
|
||||||
{"printunlock", funcTag, 9},
|
{"printunlock", funcTag, 9},
|
||||||
{"concatstring2", funcTag, 33},
|
{"concatstring2", funcTag, 34},
|
||||||
{"concatstring3", funcTag, 34},
|
{"concatstring3", funcTag, 35},
|
||||||
{"concatstring4", funcTag, 35},
|
{"concatstring4", funcTag, 36},
|
||||||
{"concatstring5", funcTag, 36},
|
{"concatstring5", funcTag, 37},
|
||||||
{"concatstrings", funcTag, 38},
|
{"concatstrings", funcTag, 39},
|
||||||
{"cmpstring", funcTag, 39},
|
{"cmpstring", funcTag, 40},
|
||||||
{"intstring", funcTag, 42},
|
{"intstring", funcTag, 43},
|
||||||
{"slicebytetostring", funcTag, 43},
|
{"slicebytetostring", funcTag, 44},
|
||||||
{"slicebytetostringtmp", funcTag, 44},
|
{"slicebytetostringtmp", funcTag, 45},
|
||||||
{"slicerunetostring", funcTag, 47},
|
{"slicerunetostring", funcTag, 48},
|
||||||
{"stringtoslicebyte", funcTag, 49},
|
{"stringtoslicebyte", funcTag, 50},
|
||||||
{"stringtoslicerune", funcTag, 52},
|
{"stringtoslicerune", funcTag, 53},
|
||||||
{"slicecopy", funcTag, 53},
|
{"slicecopy", funcTag, 54},
|
||||||
{"decoderune", funcTag, 54},
|
{"decoderune", funcTag, 55},
|
||||||
{"countrunes", funcTag, 55},
|
{"countrunes", funcTag, 56},
|
||||||
{"convI2I", funcTag, 56},
|
{"convI2I", funcTag, 57},
|
||||||
{"convT16", funcTag, 57},
|
{"convT16", funcTag, 58},
|
||||||
{"convT32", funcTag, 57},
|
{"convT32", funcTag, 58},
|
||||||
{"convT64", funcTag, 57},
|
{"convT64", funcTag, 58},
|
||||||
{"convTstring", funcTag, 57},
|
{"convTstring", funcTag, 58},
|
||||||
{"convTslice", funcTag, 57},
|
{"convTslice", funcTag, 58},
|
||||||
{"convT2E", funcTag, 58},
|
{"convT2E", funcTag, 59},
|
||||||
{"convT2Enoptr", funcTag, 58},
|
{"convT2Enoptr", funcTag, 59},
|
||||||
{"convT2I", funcTag, 58},
|
{"convT2I", funcTag, 59},
|
||||||
{"convT2Inoptr", funcTag, 58},
|
{"convT2Inoptr", funcTag, 59},
|
||||||
{"assertE2I", funcTag, 56},
|
{"assertE2I", funcTag, 57},
|
||||||
{"assertE2I2", funcTag, 59},
|
{"assertE2I2", funcTag, 60},
|
||||||
{"assertI2I", funcTag, 56},
|
{"assertI2I", funcTag, 57},
|
||||||
{"assertI2I2", funcTag, 59},
|
{"assertI2I2", funcTag, 60},
|
||||||
{"panicdottypeE", funcTag, 60},
|
{"panicdottypeE", funcTag, 61},
|
||||||
{"panicdottypeI", funcTag, 60},
|
{"panicdottypeI", funcTag, 61},
|
||||||
{"panicnildottype", funcTag, 61},
|
{"panicnildottype", funcTag, 62},
|
||||||
{"ifaceeq", funcTag, 63},
|
{"ifaceeq", funcTag, 64},
|
||||||
{"efaceeq", funcTag, 63},
|
{"efaceeq", funcTag, 64},
|
||||||
{"fastrand", funcTag, 65},
|
{"fastrand", funcTag, 66},
|
||||||
{"makemap64", funcTag, 67},
|
{"makemap64", funcTag, 68},
|
||||||
{"makemap", funcTag, 68},
|
{"makemap", funcTag, 69},
|
||||||
{"makemap_small", funcTag, 69},
|
{"makemap_small", funcTag, 70},
|
||||||
{"mapaccess1", funcTag, 70},
|
{"mapaccess1", funcTag, 71},
|
||||||
{"mapaccess1_fast32", funcTag, 71},
|
{"mapaccess1_fast32", funcTag, 72},
|
||||||
{"mapaccess1_fast64", funcTag, 71},
|
{"mapaccess1_fast64", funcTag, 72},
|
||||||
{"mapaccess1_faststr", funcTag, 71},
|
{"mapaccess1_faststr", funcTag, 72},
|
||||||
{"mapaccess1_fat", funcTag, 72},
|
{"mapaccess1_fat", funcTag, 73},
|
||||||
{"mapaccess2", funcTag, 73},
|
{"mapaccess2", funcTag, 74},
|
||||||
{"mapaccess2_fast32", funcTag, 74},
|
{"mapaccess2_fast32", funcTag, 75},
|
||||||
{"mapaccess2_fast64", funcTag, 74},
|
{"mapaccess2_fast64", funcTag, 75},
|
||||||
{"mapaccess2_faststr", funcTag, 74},
|
{"mapaccess2_faststr", funcTag, 75},
|
||||||
{"mapaccess2_fat", funcTag, 75},
|
{"mapaccess2_fat", funcTag, 76},
|
||||||
{"mapassign", funcTag, 70},
|
{"mapassign", funcTag, 71},
|
||||||
{"mapassign_fast32", funcTag, 71},
|
{"mapassign_fast32", funcTag, 72},
|
||||||
{"mapassign_fast32ptr", funcTag, 71},
|
{"mapassign_fast32ptr", funcTag, 72},
|
||||||
{"mapassign_fast64", funcTag, 71},
|
{"mapassign_fast64", funcTag, 72},
|
||||||
{"mapassign_fast64ptr", funcTag, 71},
|
{"mapassign_fast64ptr", funcTag, 72},
|
||||||
{"mapassign_faststr", funcTag, 71},
|
{"mapassign_faststr", funcTag, 72},
|
||||||
{"mapiterinit", funcTag, 76},
|
{"mapiterinit", funcTag, 77},
|
||||||
{"mapdelete", funcTag, 76},
|
{"mapdelete", funcTag, 77},
|
||||||
{"mapdelete_fast32", funcTag, 77},
|
{"mapdelete_fast32", funcTag, 78},
|
||||||
{"mapdelete_fast64", funcTag, 77},
|
{"mapdelete_fast64", funcTag, 78},
|
||||||
{"mapdelete_faststr", funcTag, 77},
|
{"mapdelete_faststr", funcTag, 78},
|
||||||
{"mapiternext", funcTag, 78},
|
{"mapiternext", funcTag, 79},
|
||||||
{"mapclear", funcTag, 79},
|
{"mapclear", funcTag, 80},
|
||||||
{"makechan64", funcTag, 81},
|
{"makechan64", funcTag, 82},
|
||||||
{"makechan", funcTag, 82},
|
{"makechan", funcTag, 83},
|
||||||
{"chanrecv1", funcTag, 84},
|
{"chanrecv1", funcTag, 85},
|
||||||
{"chanrecv2", funcTag, 85},
|
{"chanrecv2", funcTag, 86},
|
||||||
{"chansend1", funcTag, 87},
|
{"chansend1", funcTag, 88},
|
||||||
{"closechan", funcTag, 30},
|
{"closechan", funcTag, 30},
|
||||||
{"writeBarrier", varTag, 89},
|
{"writeBarrier", varTag, 90},
|
||||||
{"typedmemmove", funcTag, 90},
|
{"typedmemmove", funcTag, 91},
|
||||||
{"typedmemclr", funcTag, 91},
|
{"typedmemclr", funcTag, 92},
|
||||||
{"typedslicecopy", funcTag, 92},
|
{"typedslicecopy", funcTag, 93},
|
||||||
{"selectnbsend", funcTag, 93},
|
{"selectnbsend", funcTag, 94},
|
||||||
{"selectnbrecv", funcTag, 94},
|
{"selectnbrecv", funcTag, 95},
|
||||||
{"selectnbrecv2", funcTag, 96},
|
{"selectnbrecv2", funcTag, 97},
|
||||||
{"selectsetpc", funcTag, 97},
|
{"selectsetpc", funcTag, 98},
|
||||||
{"selectgo", funcTag, 98},
|
{"selectgo", funcTag, 99},
|
||||||
{"block", funcTag, 9},
|
{"block", funcTag, 9},
|
||||||
{"makeslice", funcTag, 99},
|
{"makeslice", funcTag, 100},
|
||||||
{"makeslice64", funcTag, 100},
|
{"makeslice64", funcTag, 101},
|
||||||
{"makeslicecopy", funcTag, 101},
|
{"makeslicecopy", funcTag, 102},
|
||||||
{"growslice", funcTag, 103},
|
{"growslice", funcTag, 104},
|
||||||
{"memmove", funcTag, 104},
|
{"memmove", funcTag, 105},
|
||||||
{"memclrNoHeapPointers", funcTag, 105},
|
{"memclrNoHeapPointers", funcTag, 106},
|
||||||
{"memclrHasPointers", funcTag, 105},
|
{"memclrHasPointers", funcTag, 106},
|
||||||
{"memequal", funcTag, 106},
|
{"memequal", funcTag, 107},
|
||||||
{"memequal0", funcTag, 107},
|
{"memequal0", funcTag, 108},
|
||||||
{"memequal8", funcTag, 107},
|
{"memequal8", funcTag, 108},
|
||||||
{"memequal16", funcTag, 107},
|
{"memequal16", funcTag, 108},
|
||||||
{"memequal32", funcTag, 107},
|
{"memequal32", funcTag, 108},
|
||||||
{"memequal64", funcTag, 107},
|
{"memequal64", funcTag, 108},
|
||||||
{"memequal128", funcTag, 107},
|
{"memequal128", funcTag, 108},
|
||||||
{"f32equal", funcTag, 108},
|
{"f32equal", funcTag, 109},
|
||||||
{"f64equal", funcTag, 108},
|
{"f64equal", funcTag, 109},
|
||||||
{"c64equal", funcTag, 108},
|
{"c64equal", funcTag, 109},
|
||||||
{"c128equal", funcTag, 108},
|
{"c128equal", funcTag, 109},
|
||||||
{"strequal", funcTag, 108},
|
{"strequal", funcTag, 109},
|
||||||
{"interequal", funcTag, 108},
|
{"interequal", funcTag, 109},
|
||||||
{"nilinterequal", funcTag, 108},
|
{"nilinterequal", funcTag, 109},
|
||||||
{"memhash", funcTag, 109},
|
{"memhash", funcTag, 110},
|
||||||
{"memhash0", funcTag, 110},
|
{"memhash0", funcTag, 111},
|
||||||
{"memhash8", funcTag, 110},
|
{"memhash8", funcTag, 111},
|
||||||
{"memhash16", funcTag, 110},
|
{"memhash16", funcTag, 111},
|
||||||
{"memhash32", funcTag, 110},
|
{"memhash32", funcTag, 111},
|
||||||
{"memhash64", funcTag, 110},
|
{"memhash64", funcTag, 111},
|
||||||
{"memhash128", funcTag, 110},
|
{"memhash128", funcTag, 111},
|
||||||
{"f32hash", funcTag, 110},
|
{"f32hash", funcTag, 111},
|
||||||
{"f64hash", funcTag, 110},
|
{"f64hash", funcTag, 111},
|
||||||
{"c64hash", funcTag, 110},
|
{"c64hash", funcTag, 111},
|
||||||
{"c128hash", funcTag, 110},
|
{"c128hash", funcTag, 111},
|
||||||
{"strhash", funcTag, 110},
|
{"strhash", funcTag, 111},
|
||||||
{"interhash", funcTag, 110},
|
{"interhash", funcTag, 111},
|
||||||
{"nilinterhash", funcTag, 110},
|
{"nilinterhash", funcTag, 111},
|
||||||
{"int64div", funcTag, 111},
|
{"int64div", funcTag, 112},
|
||||||
{"uint64div", funcTag, 112},
|
{"uint64div", funcTag, 113},
|
||||||
{"int64mod", funcTag, 111},
|
{"int64mod", funcTag, 112},
|
||||||
{"uint64mod", funcTag, 112},
|
{"uint64mod", funcTag, 113},
|
||||||
{"float64toint64", funcTag, 113},
|
{"float64toint64", funcTag, 114},
|
||||||
{"float64touint64", funcTag, 114},
|
{"float64touint64", funcTag, 115},
|
||||||
{"float64touint32", funcTag, 115},
|
{"float64touint32", funcTag, 116},
|
||||||
{"int64tofloat64", funcTag, 116},
|
{"int64tofloat64", funcTag, 117},
|
||||||
{"uint64tofloat64", funcTag, 117},
|
{"uint64tofloat64", funcTag, 118},
|
||||||
{"uint32tofloat64", funcTag, 118},
|
{"uint32tofloat64", funcTag, 119},
|
||||||
{"complex128div", funcTag, 119},
|
{"complex128div", funcTag, 120},
|
||||||
{"racefuncenter", funcTag, 120},
|
{"racefuncenter", funcTag, 31},
|
||||||
{"racefuncenterfp", funcTag, 9},
|
{"racefuncenterfp", funcTag, 9},
|
||||||
{"racefuncexit", funcTag, 9},
|
{"racefuncexit", funcTag, 9},
|
||||||
{"raceread", funcTag, 120},
|
{"raceread", funcTag, 31},
|
||||||
{"racewrite", funcTag, 120},
|
{"racewrite", funcTag, 31},
|
||||||
{"racereadrange", funcTag, 121},
|
{"racereadrange", funcTag, 121},
|
||||||
{"racewriterange", funcTag, 121},
|
{"racewriterange", funcTag, 121},
|
||||||
{"msanread", funcTag, 121},
|
{"msanread", funcTag, 121},
|
||||||
|
|
@ -233,96 +234,96 @@ func runtimeTypes() []*types.Type {
|
||||||
typs[28] = types.Types[TSTRING]
|
typs[28] = types.Types[TSTRING]
|
||||||
typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
|
typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
|
||||||
typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
|
typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
|
||||||
typs[31] = types.NewArray(typs[0], 32)
|
typs[31] = functype(nil, []*Node{anonfield(typs[5])}, nil)
|
||||||
typs[32] = types.NewPtr(typs[31])
|
typs[32] = types.NewArray(typs[0], 32)
|
||||||
typs[33] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
typs[33] = types.NewPtr(typs[32])
|
||||||
typs[34] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
typs[34] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||||
typs[35] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
typs[35] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||||
typs[36] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
typs[36] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||||
typs[37] = types.NewSlice(typs[28])
|
typs[37] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||||
typs[38] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[37])}, []*Node{anonfield(typs[28])})
|
typs[38] = types.NewSlice(typs[28])
|
||||||
typs[39] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
typs[39] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[38])}, []*Node{anonfield(typs[28])})
|
||||||
typs[40] = types.NewArray(typs[0], 4)
|
typs[40] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
||||||
typs[41] = types.NewPtr(typs[40])
|
typs[41] = types.NewArray(typs[0], 4)
|
||||||
typs[42] = functype(nil, []*Node{anonfield(typs[41]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
|
typs[42] = types.NewPtr(typs[41])
|
||||||
typs[43] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
typs[43] = functype(nil, []*Node{anonfield(typs[42]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
|
||||||
typs[44] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
typs[44] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
||||||
typs[45] = types.Runetype
|
typs[45] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
||||||
typs[46] = types.NewSlice(typs[45])
|
typs[46] = types.Runetype
|
||||||
typs[47] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[46])}, []*Node{anonfield(typs[28])})
|
typs[47] = types.NewSlice(typs[46])
|
||||||
typs[48] = types.NewSlice(typs[0])
|
typs[48] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[47])}, []*Node{anonfield(typs[28])})
|
||||||
typs[49] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28])}, []*Node{anonfield(typs[48])})
|
typs[49] = types.NewSlice(typs[0])
|
||||||
typs[50] = types.NewArray(typs[45], 32)
|
typs[50] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28])}, []*Node{anonfield(typs[49])})
|
||||||
typs[51] = types.NewPtr(typs[50])
|
typs[51] = types.NewArray(typs[46], 32)
|
||||||
typs[52] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[28])}, []*Node{anonfield(typs[46])})
|
typs[52] = types.NewPtr(typs[51])
|
||||||
typs[53] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
|
typs[53] = functype(nil, []*Node{anonfield(typs[52]), anonfield(typs[28])}, []*Node{anonfield(typs[47])})
|
||||||
typs[54] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[45]), anonfield(typs[15])})
|
typs[54] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
|
||||||
typs[55] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[46]), anonfield(typs[15])})
|
||||||
typs[56] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
|
typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
||||||
typs[57] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
|
typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
|
||||||
typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
|
typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
|
||||||
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
|
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
|
||||||
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
|
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
|
||||||
typs[61] = functype(nil, []*Node{anonfield(typs[1])}, nil)
|
typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
|
||||||
typs[62] = types.NewPtr(typs[5])
|
typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
|
||||||
typs[63] = functype(nil, []*Node{anonfield(typs[62]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
typs[63] = types.NewPtr(typs[5])
|
||||||
typs[64] = types.Types[TUINT32]
|
typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
||||||
typs[65] = functype(nil, nil, []*Node{anonfield(typs[64])})
|
typs[65] = types.Types[TUINT32]
|
||||||
typs[66] = types.NewMap(typs[2], typs[2])
|
typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
|
||||||
typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
|
typs[67] = types.NewMap(typs[2], typs[2])
|
||||||
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
|
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
|
||||||
typs[69] = functype(nil, nil, []*Node{anonfield(typs[66])})
|
typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
|
||||||
typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
|
typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
|
||||||
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
|
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
|
||||||
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
|
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
|
||||||
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
|
||||||
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||||
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||||
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, nil)
|
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||||
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, nil)
|
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
|
||||||
typs[78] = functype(nil, []*Node{anonfield(typs[3])}, nil)
|
typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
|
||||||
typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66])}, nil)
|
typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
|
||||||
typs[80] = types.NewChan(typs[2], types.Cboth)
|
typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
|
||||||
typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[80])})
|
typs[81] = types.NewChan(typs[2], types.Cboth)
|
||||||
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[80])})
|
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
|
||||||
typs[83] = types.NewChan(typs[2], types.Crecv)
|
typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
|
||||||
typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
|
typs[84] = types.NewChan(typs[2], types.Crecv)
|
||||||
typs[85] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
|
||||||
typs[86] = types.NewChan(typs[2], types.Csend)
|
typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||||
typs[87] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, nil)
|
typs[87] = types.NewChan(typs[2], types.Csend)
|
||||||
typs[88] = types.NewArray(typs[0], 3)
|
typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
|
||||||
typs[89] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[88]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
|
typs[89] = types.NewArray(typs[0], 3)
|
||||||
typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
|
typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
|
||||||
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
|
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
|
||||||
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
|
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
|
||||||
typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
|
||||||
typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[6])})
|
typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||||
typs[95] = types.NewPtr(typs[6])
|
typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
|
||||||
typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[95]), anonfield(typs[83])}, []*Node{anonfield(typs[6])})
|
typs[96] = types.NewPtr(typs[6])
|
||||||
typs[97] = functype(nil, []*Node{anonfield(typs[62])}, nil)
|
typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
|
||||||
typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
|
typs[98] = functype(nil, []*Node{anonfield(typs[63])}, nil)
|
||||||
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
|
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
|
||||||
typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
|
typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
|
||||||
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
|
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
|
||||||
typs[102] = types.NewSlice(typs[2])
|
typs[102] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
|
||||||
typs[103] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[102]), anonfield(typs[15])}, []*Node{anonfield(typs[102])})
|
typs[103] = types.NewSlice(typs[2])
|
||||||
typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
|
typs[104] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[103]), anonfield(typs[15])}, []*Node{anonfield(typs[103])})
|
||||||
typs[105] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
|
typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
|
||||||
typs[106] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
|
typs[106] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
|
||||||
typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
|
||||||
typs[108] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
typs[108] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||||
typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
||||||
typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
||||||
typs[111] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
|
typs[111] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
||||||
typs[112] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
|
typs[112] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
|
||||||
typs[113] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
|
typs[113] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
|
||||||
typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
|
typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
|
||||||
typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[64])})
|
typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
|
||||||
typs[116] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
|
typs[116] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
|
||||||
typs[117] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
|
typs[117] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
|
||||||
typs[118] = functype(nil, []*Node{anonfield(typs[64])}, []*Node{anonfield(typs[20])})
|
typs[118] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
|
||||||
typs[119] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
|
typs[119] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
|
||||||
typs[120] = functype(nil, []*Node{anonfield(typs[5])}, nil)
|
typs[120] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
|
||||||
typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
|
typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
|
||||||
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
|
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
|
||||||
typs[123] = types.NewSlice(typs[7])
|
typs[123] = types.NewSlice(typs[7])
|
||||||
|
|
@ -331,7 +332,7 @@ func runtimeTypes() []*types.Type {
|
||||||
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
|
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
|
||||||
typs[127] = types.Types[TUINT16]
|
typs[127] = types.Types[TUINT16]
|
||||||
typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
|
typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
|
||||||
typs[129] = functype(nil, []*Node{anonfield(typs[64]), anonfield(typs[64])}, nil)
|
typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
|
||||||
typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
|
typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
|
||||||
return typs[:]
|
return typs[:]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ func printuint(uint64)
|
||||||
func printcomplex(complex128)
|
func printcomplex(complex128)
|
||||||
func printstring(string)
|
func printstring(string)
|
||||||
func printpointer(any)
|
func printpointer(any)
|
||||||
|
func printuintptr(uintptr)
|
||||||
func printiface(any)
|
func printiface(any)
|
||||||
func printeface(any)
|
func printeface(any)
|
||||||
func printslice(any)
|
func printslice(any)
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ func capturevars(xfunc *Node) {
|
||||||
outer = nod(OADDR, outer, nil)
|
outer = nod(OADDR, outer, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug['m'] > 1 {
|
if Debug.m > 1 {
|
||||||
var name *types.Sym
|
var name *types.Sym
|
||||||
if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
|
if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
|
||||||
name = v.Name.Curfn.Func.Nname.Sym
|
name = v.Name.Curfn.Func.Nname.Sym
|
||||||
|
|
@ -434,6 +434,8 @@ func typecheckpartialcall(fn *Node, sym *types.Sym) {
|
||||||
fn.Type = xfunc.Type
|
fn.Type = xfunc.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
|
||||||
|
// for partial calls.
|
||||||
func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
||||||
rcvrtype := fn.Left.Type
|
rcvrtype := fn.Left.Type
|
||||||
sym := methodSymSuffix(rcvrtype, meth, "-fm")
|
sym := methodSymSuffix(rcvrtype, meth, "-fm")
|
||||||
|
|
@ -500,6 +502,10 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
||||||
funcbody()
|
funcbody()
|
||||||
|
|
||||||
xfunc = typecheck(xfunc, ctxStmt)
|
xfunc = typecheck(xfunc, ctxStmt)
|
||||||
|
// Need to typecheck the body of the just-generated wrapper.
|
||||||
|
// typecheckslice() requires that Curfn is set when processing an ORETURN.
|
||||||
|
Curfn = xfunc
|
||||||
|
typecheckslice(xfunc.Nbody.Slice(), ctxStmt)
|
||||||
sym.Def = asTypesNode(xfunc)
|
sym.Def = asTypesNode(xfunc)
|
||||||
xtop = append(xtop, xfunc)
|
xtop = append(xtop, xfunc)
|
||||||
Curfn = savecurfn
|
Curfn = savecurfn
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ func oldname(s *types.Sym) *Node {
|
||||||
c.Name.Defn = n
|
c.Name.Defn = n
|
||||||
|
|
||||||
// Link into list of active closure variables.
|
// Link into list of active closure variables.
|
||||||
// Popped from list in func closurebody.
|
// Popped from list in func funcLit.
|
||||||
c.Name.Param.Outer = n.Name.Param.Innermost
|
c.Name.Param.Outer = n.Name.Param.Innermost
|
||||||
n.Name.Param.Innermost = c
|
n.Name.Param.Innermost = c
|
||||||
|
|
||||||
|
|
|
||||||
273
src/cmd/compile/internal/gc/embed.go
Normal file
273
src/cmd/compile/internal/gc/embed.go
Normal file
|
|
@ -0,0 +1,273 @@
|
||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/compile/internal/syntax"
|
||||||
|
"cmd/compile/internal/types"
|
||||||
|
"cmd/internal/obj"
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var embedlist []*Node
|
||||||
|
|
||||||
|
var embedCfg struct {
|
||||||
|
Patterns map[string][]string
|
||||||
|
Files map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func readEmbedCfg(file string) {
|
||||||
|
data, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("-embedcfg: %v", err)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &embedCfg); err != nil {
|
||||||
|
log.Fatalf("%s: %v", file, err)
|
||||||
|
}
|
||||||
|
if embedCfg.Patterns == nil {
|
||||||
|
log.Fatalf("%s: invalid embedcfg: missing Patterns", file)
|
||||||
|
}
|
||||||
|
if embedCfg.Files == nil {
|
||||||
|
log.Fatalf("%s: invalid embedcfg: missing Files", file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
embedUnknown = iota
|
||||||
|
embedBytes
|
||||||
|
embedString
|
||||||
|
embedFiles
|
||||||
|
)
|
||||||
|
|
||||||
|
var numLocalEmbed int
|
||||||
|
|
||||||
|
func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []PragmaEmbed) (newExprs []*Node) {
|
||||||
|
haveEmbed := false
|
||||||
|
for _, decl := range p.file.DeclList {
|
||||||
|
imp, ok := decl.(*syntax.ImportDecl)
|
||||||
|
if !ok {
|
||||||
|
// imports always come first
|
||||||
|
break
|
||||||
|
}
|
||||||
|
path, _ := strconv.Unquote(imp.Path.Value)
|
||||||
|
if path == "embed" {
|
||||||
|
haveEmbed = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := embeds[0].Pos
|
||||||
|
if !haveEmbed {
|
||||||
|
p.yyerrorpos(pos, "invalid go:embed: missing import \"embed\"")
|
||||||
|
return exprs
|
||||||
|
}
|
||||||
|
if embedCfg.Patterns == nil {
|
||||||
|
p.yyerrorpos(pos, "invalid go:embed: build system did not supply embed configuration")
|
||||||
|
return exprs
|
||||||
|
}
|
||||||
|
if len(names) > 1 {
|
||||||
|
p.yyerrorpos(pos, "go:embed cannot apply to multiple vars")
|
||||||
|
return exprs
|
||||||
|
}
|
||||||
|
if len(exprs) > 0 {
|
||||||
|
p.yyerrorpos(pos, "go:embed cannot apply to var with initializer")
|
||||||
|
return exprs
|
||||||
|
}
|
||||||
|
if typ == nil {
|
||||||
|
// Should not happen, since len(exprs) == 0 now.
|
||||||
|
p.yyerrorpos(pos, "go:embed cannot apply to var without type")
|
||||||
|
return exprs
|
||||||
|
}
|
||||||
|
|
||||||
|
kind := embedKindApprox(typ)
|
||||||
|
if kind == embedUnknown {
|
||||||
|
p.yyerrorpos(pos, "go:embed cannot apply to var of type %v", typ)
|
||||||
|
return exprs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build list of files to store.
|
||||||
|
have := make(map[string]bool)
|
||||||
|
var list []string
|
||||||
|
for _, e := range embeds {
|
||||||
|
for _, pattern := range e.Patterns {
|
||||||
|
files, ok := embedCfg.Patterns[pattern]
|
||||||
|
if !ok {
|
||||||
|
p.yyerrorpos(e.Pos, "invalid go:embed: build system did not map pattern: %s", pattern)
|
||||||
|
}
|
||||||
|
for _, file := range files {
|
||||||
|
if embedCfg.Files[file] == "" {
|
||||||
|
p.yyerrorpos(e.Pos, "invalid go:embed: build system did not map file: %s", file)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !have[file] {
|
||||||
|
have[file] = true
|
||||||
|
list = append(list, file)
|
||||||
|
}
|
||||||
|
if kind == embedFiles {
|
||||||
|
for dir := path.Dir(file); dir != "." && !have[dir]; dir = path.Dir(dir) {
|
||||||
|
have[dir] = true
|
||||||
|
list = append(list, dir+"/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(list, func(i, j int) bool {
|
||||||
|
return embedFileLess(list[i], list[j])
|
||||||
|
})
|
||||||
|
|
||||||
|
if kind == embedString || kind == embedBytes {
|
||||||
|
if len(list) > 1 {
|
||||||
|
p.yyerrorpos(pos, "invalid go:embed: multiple files for type %v", typ)
|
||||||
|
return exprs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v := names[0]
|
||||||
|
if dclcontext != PEXTERN {
|
||||||
|
numLocalEmbed++
|
||||||
|
v = newnamel(v.Pos, lookupN("embed.", numLocalEmbed))
|
||||||
|
v.Sym.Def = asTypesNode(v)
|
||||||
|
v.Name.Param.Ntype = typ
|
||||||
|
v.SetClass(PEXTERN)
|
||||||
|
externdcl = append(externdcl, v)
|
||||||
|
exprs = []*Node{v}
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Name.Param.SetEmbedFiles(list)
|
||||||
|
embedlist = append(embedlist, v)
|
||||||
|
return exprs
|
||||||
|
}
|
||||||
|
|
||||||
|
// embedKindApprox determines the kind of embedding variable, approximately.
|
||||||
|
// The match is approximate because we haven't done scope resolution yet and
|
||||||
|
// can't tell whether "string" and "byte" really mean "string" and "byte".
|
||||||
|
// The result must be confirmed later, after type checking, using embedKind.
|
||||||
|
func embedKindApprox(typ *Node) int {
|
||||||
|
if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && myimportpath == "embed")) {
|
||||||
|
return embedFiles
|
||||||
|
}
|
||||||
|
// These are not guaranteed to match only string and []byte -
|
||||||
|
// maybe the local package has redefined one of those words.
|
||||||
|
// But it's the best we can do now during the noder.
|
||||||
|
// The stricter check happens later, in initEmbed calling embedKind.
|
||||||
|
if typ.Sym != nil && typ.Sym.Name == "string" && typ.Sym.Pkg == localpkg {
|
||||||
|
return embedString
|
||||||
|
}
|
||||||
|
if typ.Op == OTARRAY && typ.Left == nil && typ.Right.Sym != nil && typ.Right.Sym.Name == "byte" && typ.Right.Sym.Pkg == localpkg {
|
||||||
|
return embedBytes
|
||||||
|
}
|
||||||
|
return embedUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
// embedKind determines the kind of embedding variable.
|
||||||
|
func embedKind(typ *types.Type) int {
|
||||||
|
if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && myimportpath == "embed")) {
|
||||||
|
return embedFiles
|
||||||
|
}
|
||||||
|
if typ == types.Types[TSTRING] {
|
||||||
|
return embedString
|
||||||
|
}
|
||||||
|
if typ.Sym == nil && typ.IsSlice() && typ.Elem() == types.Bytetype {
|
||||||
|
return embedBytes
|
||||||
|
}
|
||||||
|
return embedUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
func embedFileNameSplit(name string) (dir, elem string, isDir bool) {
|
||||||
|
if name[len(name)-1] == '/' {
|
||||||
|
isDir = true
|
||||||
|
name = name[:len(name)-1]
|
||||||
|
}
|
||||||
|
i := len(name) - 1
|
||||||
|
for i >= 0 && name[i] != '/' {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
if i < 0 {
|
||||||
|
return ".", name, isDir
|
||||||
|
}
|
||||||
|
return name[:i], name[i+1:], isDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// embedFileLess implements the sort order for a list of embedded files.
|
||||||
|
// See the comment inside ../../../../embed/embed.go's Files struct for rationale.
|
||||||
|
func embedFileLess(x, y string) bool {
|
||||||
|
xdir, xelem, _ := embedFileNameSplit(x)
|
||||||
|
ydir, yelem, _ := embedFileNameSplit(y)
|
||||||
|
return xdir < ydir || xdir == ydir && xelem < yelem
|
||||||
|
}
|
||||||
|
|
||||||
|
func dumpembeds() {
|
||||||
|
for _, v := range embedlist {
|
||||||
|
initEmbed(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initEmbed emits the init data for a //go:embed variable,
|
||||||
|
// which is either a string, a []byte, or an embed.FS.
|
||||||
|
func initEmbed(v *Node) {
|
||||||
|
files := v.Name.Param.EmbedFiles()
|
||||||
|
switch kind := embedKind(v.Type); kind {
|
||||||
|
case embedUnknown:
|
||||||
|
yyerrorl(v.Pos, "go:embed cannot apply to var of type %v", v.Type)
|
||||||
|
|
||||||
|
case embedString, embedBytes:
|
||||||
|
file := files[0]
|
||||||
|
fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], kind == embedString, nil)
|
||||||
|
if err != nil {
|
||||||
|
yyerrorl(v.Pos, "embed %s: %v", file, err)
|
||||||
|
}
|
||||||
|
sym := v.Sym.Linksym()
|
||||||
|
off := 0
|
||||||
|
off = dsymptr(sym, off, fsym, 0) // data string
|
||||||
|
off = duintptr(sym, off, uint64(size)) // len
|
||||||
|
if kind == embedBytes {
|
||||||
|
duintptr(sym, off, uint64(size)) // cap for slice
|
||||||
|
}
|
||||||
|
|
||||||
|
case embedFiles:
|
||||||
|
slicedata := Ctxt.Lookup(`"".` + v.Sym.Name + `.files`)
|
||||||
|
off := 0
|
||||||
|
// []files pointed at by Files
|
||||||
|
off = dsymptr(slicedata, off, slicedata, 3*Widthptr) // []file, pointing just past slice
|
||||||
|
off = duintptr(slicedata, off, uint64(len(files)))
|
||||||
|
off = duintptr(slicedata, off, uint64(len(files)))
|
||||||
|
|
||||||
|
// embed/embed.go type file is:
|
||||||
|
// name string
|
||||||
|
// data string
|
||||||
|
// hash [16]byte
|
||||||
|
// Emit one of these per file in the set.
|
||||||
|
const hashSize = 16
|
||||||
|
hash := make([]byte, hashSize)
|
||||||
|
for _, file := range files {
|
||||||
|
off = dsymptr(slicedata, off, stringsym(v.Pos, file), 0) // file string
|
||||||
|
off = duintptr(slicedata, off, uint64(len(file)))
|
||||||
|
if strings.HasSuffix(file, "/") {
|
||||||
|
// entry for directory - no data
|
||||||
|
off = duintptr(slicedata, off, 0)
|
||||||
|
off = duintptr(slicedata, off, 0)
|
||||||
|
off += hashSize
|
||||||
|
} else {
|
||||||
|
fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], true, hash)
|
||||||
|
if err != nil {
|
||||||
|
yyerrorl(v.Pos, "embed %s: %v", file, err)
|
||||||
|
}
|
||||||
|
off = dsymptr(slicedata, off, fsym, 0) // data string
|
||||||
|
off = duintptr(slicedata, off, uint64(size))
|
||||||
|
off = int(slicedata.WriteBytes(Ctxt, int64(off), hash))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ggloblsym(slicedata, int32(off), obj.RODATA|obj.LOCAL)
|
||||||
|
sym := v.Sym.Linksym()
|
||||||
|
dsymptr(sym, 0, slicedata, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -282,7 +282,7 @@ func addrescapes(n *Node) {
|
||||||
|
|
||||||
// moveToHeap records the parameter or local variable n as moved to the heap.
|
// moveToHeap records the parameter or local variable n as moved to the heap.
|
||||||
func moveToHeap(n *Node) {
|
func moveToHeap(n *Node) {
|
||||||
if Debug['r'] != 0 {
|
if Debug.r != 0 {
|
||||||
Dump("MOVE", n)
|
Dump("MOVE", n)
|
||||||
}
|
}
|
||||||
if compiling_runtime {
|
if compiling_runtime {
|
||||||
|
|
@ -359,7 +359,7 @@ func moveToHeap(n *Node) {
|
||||||
n.Xoffset = 0
|
n.Xoffset = 0
|
||||||
n.Name.Param.Heapaddr = heapaddr
|
n.Name.Param.Heapaddr = heapaddr
|
||||||
n.Esc = EscHeap
|
n.Esc = EscHeap
|
||||||
if Debug['m'] != 0 {
|
if Debug.m != 0 {
|
||||||
Warnl(n.Pos, "moved to heap: %v", n)
|
Warnl(n.Pos, "moved to heap: %v", n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -389,7 +389,7 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||||
// but we are reusing the ability to annotate an individual function
|
// but we are reusing the ability to annotate an individual function
|
||||||
// argument and pass those annotations along to importing code.
|
// argument and pass those annotations along to importing code.
|
||||||
if f.Type.IsUintptr() {
|
if f.Type.IsUintptr() {
|
||||||
if Debug['m'] != 0 {
|
if Debug.m != 0 {
|
||||||
Warnl(f.Pos, "assuming %v is unsafe uintptr", name())
|
Warnl(f.Pos, "assuming %v is unsafe uintptr", name())
|
||||||
}
|
}
|
||||||
return unsafeUintptrTag
|
return unsafeUintptrTag
|
||||||
|
|
@ -404,11 +404,11 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||||
// External functions are assumed unsafe, unless
|
// External functions are assumed unsafe, unless
|
||||||
// //go:noescape is given before the declaration.
|
// //go:noescape is given before the declaration.
|
||||||
if fn.Func.Pragma&Noescape != 0 {
|
if fn.Func.Pragma&Noescape != 0 {
|
||||||
if Debug['m'] != 0 && f.Sym != nil {
|
if Debug.m != 0 && f.Sym != nil {
|
||||||
Warnl(f.Pos, "%v does not escape", name())
|
Warnl(f.Pos, "%v does not escape", name())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if Debug['m'] != 0 && f.Sym != nil {
|
if Debug.m != 0 && f.Sym != nil {
|
||||||
Warnl(f.Pos, "leaking param: %v", name())
|
Warnl(f.Pos, "leaking param: %v", name())
|
||||||
}
|
}
|
||||||
esc.AddHeap(0)
|
esc.AddHeap(0)
|
||||||
|
|
@ -419,14 +419,14 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||||
|
|
||||||
if fn.Func.Pragma&UintptrEscapes != 0 {
|
if fn.Func.Pragma&UintptrEscapes != 0 {
|
||||||
if f.Type.IsUintptr() {
|
if f.Type.IsUintptr() {
|
||||||
if Debug['m'] != 0 {
|
if Debug.m != 0 {
|
||||||
Warnl(f.Pos, "marking %v as escaping uintptr", name())
|
Warnl(f.Pos, "marking %v as escaping uintptr", name())
|
||||||
}
|
}
|
||||||
return uintptrEscapesTag
|
return uintptrEscapesTag
|
||||||
}
|
}
|
||||||
if f.IsDDD() && f.Type.Elem().IsUintptr() {
|
if f.IsDDD() && f.Type.Elem().IsUintptr() {
|
||||||
// final argument is ...uintptr.
|
// final argument is ...uintptr.
|
||||||
if Debug['m'] != 0 {
|
if Debug.m != 0 {
|
||||||
Warnl(f.Pos, "marking %v as escaping ...uintptr", name())
|
Warnl(f.Pos, "marking %v as escaping ...uintptr", name())
|
||||||
}
|
}
|
||||||
return uintptrEscapesTag
|
return uintptrEscapesTag
|
||||||
|
|
@ -448,7 +448,7 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||||
esc := loc.paramEsc
|
esc := loc.paramEsc
|
||||||
esc.Optimize()
|
esc.Optimize()
|
||||||
|
|
||||||
if Debug['m'] != 0 && !loc.escapes {
|
if Debug.m != 0 && !loc.escapes {
|
||||||
if esc.Empty() {
|
if esc.Empty() {
|
||||||
Warnl(f.Pos, "%v does not escape", name())
|
Warnl(f.Pos, "%v does not escape", name())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ func (e *Escape) initFunc(fn *Node) {
|
||||||
Fatalf("unexpected node: %v", fn)
|
Fatalf("unexpected node: %v", fn)
|
||||||
}
|
}
|
||||||
fn.Esc = EscFuncPlanned
|
fn.Esc = EscFuncPlanned
|
||||||
if Debug['m'] > 3 {
|
if Debug.m > 3 {
|
||||||
Dump("escAnalyze", fn)
|
Dump("escAnalyze", fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,7 +247,7 @@ func (e *Escape) stmt(n *Node) {
|
||||||
lineno = lno
|
lineno = lno
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if Debug['m'] > 2 {
|
if Debug.m > 2 {
|
||||||
fmt.Printf("%v:[%d] %v stmt: %v\n", linestr(lineno), e.loopDepth, funcSym(e.curfn), n)
|
fmt.Printf("%v:[%d] %v stmt: %v\n", linestr(lineno), e.loopDepth, funcSym(e.curfn), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,11 +275,11 @@ func (e *Escape) stmt(n *Node) {
|
||||||
case OLABEL:
|
case OLABEL:
|
||||||
switch asNode(n.Sym.Label) {
|
switch asNode(n.Sym.Label) {
|
||||||
case &nonlooping:
|
case &nonlooping:
|
||||||
if Debug['m'] > 2 {
|
if Debug.m > 2 {
|
||||||
fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n)
|
fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n)
|
||||||
}
|
}
|
||||||
case &looping:
|
case &looping:
|
||||||
if Debug['m'] > 2 {
|
if Debug.m > 2 {
|
||||||
fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
|
fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
|
||||||
}
|
}
|
||||||
e.loopDepth++
|
e.loopDepth++
|
||||||
|
|
@ -717,7 +717,7 @@ func (e *Escape) addrs(l Nodes) []EscHole {
|
||||||
func (e *Escape) assign(dst, src *Node, why string, where *Node) {
|
func (e *Escape) assign(dst, src *Node, why string, where *Node) {
|
||||||
// Filter out some no-op assignments for escape analysis.
|
// Filter out some no-op assignments for escape analysis.
|
||||||
ignore := dst != nil && src != nil && isSelfAssign(dst, src)
|
ignore := dst != nil && src != nil && isSelfAssign(dst, src)
|
||||||
if ignore && Debug['m'] != 0 {
|
if ignore && Debug.m != 0 {
|
||||||
Warnl(where.Pos, "%v ignoring self-assignment in %S", funcSym(e.curfn), where)
|
Warnl(where.Pos, "%v ignoring self-assignment in %S", funcSym(e.curfn), where)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -931,7 +931,7 @@ func (k EscHole) note(where *Node, why string) EscHole {
|
||||||
if where == nil || why == "" {
|
if where == nil || why == "" {
|
||||||
Fatalf("note: missing where/why")
|
Fatalf("note: missing where/why")
|
||||||
}
|
}
|
||||||
if Debug['m'] >= 2 || logopt.Enabled() {
|
if Debug.m >= 2 || logopt.Enabled() {
|
||||||
k.notes = &EscNote{
|
k.notes = &EscNote{
|
||||||
next: k.notes,
|
next: k.notes,
|
||||||
where: where,
|
where: where,
|
||||||
|
|
@ -1077,9 +1077,9 @@ func (e *Escape) flow(k EscHole, src *EscLocation) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if dst.escapes && k.derefs < 0 { // dst = &src
|
if dst.escapes && k.derefs < 0 { // dst = &src
|
||||||
if Debug['m'] >= 2 || logopt.Enabled() {
|
if Debug.m >= 2 || logopt.Enabled() {
|
||||||
pos := linestr(src.n.Pos)
|
pos := linestr(src.n.Pos)
|
||||||
if Debug['m'] >= 2 {
|
if Debug.m >= 2 {
|
||||||
fmt.Printf("%s: %v escapes to heap:\n", pos, src.n)
|
fmt.Printf("%s: %v escapes to heap:\n", pos, src.n)
|
||||||
}
|
}
|
||||||
explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{})
|
explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{})
|
||||||
|
|
@ -1179,8 +1179,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
|
||||||
// that value flow for tagging the function
|
// that value flow for tagging the function
|
||||||
// later.
|
// later.
|
||||||
if l.isName(PPARAM) {
|
if l.isName(PPARAM) {
|
||||||
if (logopt.Enabled() || Debug['m'] >= 2) && !l.escapes {
|
if (logopt.Enabled() || Debug.m >= 2) && !l.escapes {
|
||||||
if Debug['m'] >= 2 {
|
if Debug.m >= 2 {
|
||||||
fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", linestr(l.n.Pos), l.n, e.explainLoc(root), base)
|
fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", linestr(l.n.Pos), l.n, e.explainLoc(root), base)
|
||||||
}
|
}
|
||||||
explanation := e.explainPath(root, l)
|
explanation := e.explainPath(root, l)
|
||||||
|
|
@ -1196,8 +1196,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
|
||||||
// outlives it, then l needs to be heap
|
// outlives it, then l needs to be heap
|
||||||
// allocated.
|
// allocated.
|
||||||
if addressOf && !l.escapes {
|
if addressOf && !l.escapes {
|
||||||
if logopt.Enabled() || Debug['m'] >= 2 {
|
if logopt.Enabled() || Debug.m >= 2 {
|
||||||
if Debug['m'] >= 2 {
|
if Debug.m >= 2 {
|
||||||
fmt.Printf("%s: %v escapes to heap:\n", linestr(l.n.Pos), l.n)
|
fmt.Printf("%s: %v escapes to heap:\n", linestr(l.n.Pos), l.n)
|
||||||
}
|
}
|
||||||
explanation := e.explainPath(root, l)
|
explanation := e.explainPath(root, l)
|
||||||
|
|
@ -1235,7 +1235,7 @@ func (e *Escape) explainPath(root, src *EscLocation) []*logopt.LoggedOpt {
|
||||||
for {
|
for {
|
||||||
// Prevent infinite loop.
|
// Prevent infinite loop.
|
||||||
if visited[src] {
|
if visited[src] {
|
||||||
if Debug['m'] >= 2 {
|
if Debug.m >= 2 {
|
||||||
fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos)
|
fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
@ -1263,7 +1263,7 @@ func (e *Escape) explainFlow(pos string, dst, srcloc *EscLocation, derefs int, n
|
||||||
if derefs >= 0 {
|
if derefs >= 0 {
|
||||||
ops = strings.Repeat("*", derefs)
|
ops = strings.Repeat("*", derefs)
|
||||||
}
|
}
|
||||||
print := Debug['m'] >= 2
|
print := Debug.m >= 2
|
||||||
|
|
||||||
flow := fmt.Sprintf(" flow: %s = %s%v:", e.explainLoc(dst), ops, e.explainLoc(srcloc))
|
flow := fmt.Sprintf(" flow: %s = %s%v:", e.explainLoc(dst), ops, e.explainLoc(srcloc))
|
||||||
if print {
|
if print {
|
||||||
|
|
@ -1417,7 +1417,7 @@ func (e *Escape) finish(fns []*Node) {
|
||||||
|
|
||||||
if loc.escapes {
|
if loc.escapes {
|
||||||
if n.Op != ONAME {
|
if n.Op != ONAME {
|
||||||
if Debug['m'] != 0 {
|
if Debug.m != 0 {
|
||||||
Warnl(n.Pos, "%S escapes to heap", n)
|
Warnl(n.Pos, "%S escapes to heap", n)
|
||||||
}
|
}
|
||||||
if logopt.Enabled() {
|
if logopt.Enabled() {
|
||||||
|
|
@ -1427,7 +1427,7 @@ func (e *Escape) finish(fns []*Node) {
|
||||||
n.Esc = EscHeap
|
n.Esc = EscHeap
|
||||||
addrescapes(n)
|
addrescapes(n)
|
||||||
} else {
|
} else {
|
||||||
if Debug['m'] != 0 && n.Op != ONAME {
|
if Debug.m != 0 && n.Op != ONAME {
|
||||||
Warnl(n.Pos, "%S does not escape", n)
|
Warnl(n.Pos, "%S does not escape", n)
|
||||||
}
|
}
|
||||||
n.Esc = EscNone
|
n.Esc = EscNone
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ func exportsym(n *Node) {
|
||||||
}
|
}
|
||||||
n.Sym.SetOnExportList(true)
|
n.Sym.SetOnExportList(true)
|
||||||
|
|
||||||
if Debug['E'] != 0 {
|
if Debug.E != 0 {
|
||||||
fmt.Printf("export symbol %v\n", n.Sym)
|
fmt.Printf("export symbol %v\n", n.Sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val
|
||||||
|
|
||||||
n.SetVal(val)
|
n.SetVal(val)
|
||||||
|
|
||||||
if Debug['E'] != 0 {
|
if Debug.E != 0 {
|
||||||
fmt.Printf("import const %v %L = %v\n", s, t, val)
|
fmt.Printf("import const %v %L = %v\n", s, t, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +166,7 @@ func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
|
||||||
n.Func = new(Func)
|
n.Func = new(Func)
|
||||||
t.SetNname(asTypesNode(n))
|
t.SetNname(asTypesNode(n))
|
||||||
|
|
||||||
if Debug['E'] != 0 {
|
if Debug.E != 0 {
|
||||||
fmt.Printf("import func %v%S\n", s, t)
|
fmt.Printf("import func %v%S\n", s, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -179,7 +179,7 @@ func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug['E'] != 0 {
|
if Debug.E != 0 {
|
||||||
fmt.Printf("import var %v %L\n", s, t)
|
fmt.Printf("import var %v %L\n", s, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +192,7 @@ func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug['E'] != 0 {
|
if Debug.E != 0 {
|
||||||
fmt.Printf("import type %v = %L\n", s, t)
|
fmt.Printf("import type %v = %L\n", s, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -419,10 +419,17 @@ func (n *Node) format(s fmt.State, verb rune, mode fmtMode) {
|
||||||
func (n *Node) jconv(s fmt.State, flag FmtFlag) {
|
func (n *Node) jconv(s fmt.State, flag FmtFlag) {
|
||||||
c := flag & FmtShort
|
c := flag & FmtShort
|
||||||
|
|
||||||
|
// Useful to see which nodes in an AST printout are actually identical
|
||||||
|
fmt.Fprintf(s, " p(%p)", n)
|
||||||
if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
|
if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
|
||||||
fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
|
fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c == 0 && n.Name != nil && n.Name.Defn != nil {
|
||||||
|
// Useful to see where Defn is set and what node it points to
|
||||||
|
fmt.Fprintf(s, " defn(%p)", n.Name.Defn)
|
||||||
|
}
|
||||||
|
|
||||||
if n.Pos.IsKnown() {
|
if n.Pos.IsKnown() {
|
||||||
pfx := ""
|
pfx := ""
|
||||||
switch n.Pos.IsStmt() {
|
switch n.Pos.IsStmt() {
|
||||||
|
|
@ -492,6 +499,15 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) {
|
||||||
if n.Name.Assigned() {
|
if n.Name.Assigned() {
|
||||||
fmt.Fprint(s, " assigned")
|
fmt.Fprint(s, " assigned")
|
||||||
}
|
}
|
||||||
|
if n.Name.IsClosureVar() {
|
||||||
|
fmt.Fprint(s, " closurevar")
|
||||||
|
}
|
||||||
|
if n.Name.Captured() {
|
||||||
|
fmt.Fprint(s, " captured")
|
||||||
|
}
|
||||||
|
if n.Name.IsOutputParamHeapAddr() {
|
||||||
|
fmt.Fprint(s, " outputparamheapaddr")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if n.Bounded() {
|
if n.Bounded() {
|
||||||
fmt.Fprint(s, " bounded")
|
fmt.Fprint(s, " bounded")
|
||||||
|
|
@ -792,6 +808,13 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mode == FDbg {
|
||||||
|
b.WriteString(t.Etype.String())
|
||||||
|
b.WriteByte('-')
|
||||||
|
tconv2(b, t, flag, FErr, visited)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// At this point, we might call tconv2 recursively. Add the current type to the visited list so we don't
|
// At this point, we might call tconv2 recursively. Add the current type to the visited list so we don't
|
||||||
// try to print it recursively.
|
// try to print it recursively.
|
||||||
// We record the offset in the result buffer where the type's text starts. This offset serves as a reference
|
// We record the offset in the result buffer where the type's text starts. This offset serves as a reference
|
||||||
|
|
@ -805,12 +828,6 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
||||||
visited[t] = b.Len()
|
visited[t] = b.Len()
|
||||||
defer delete(visited, t)
|
defer delete(visited, t)
|
||||||
|
|
||||||
if mode == FDbg {
|
|
||||||
b.WriteString(t.Etype.String())
|
|
||||||
b.WriteByte('-')
|
|
||||||
tconv2(b, t, flag, FErr, visited)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch t.Etype {
|
switch t.Etype {
|
||||||
case TPTR:
|
case TPTR:
|
||||||
b.WriteByte('*')
|
b.WriteByte('*')
|
||||||
|
|
@ -1709,6 +1726,9 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.Op == OCLOSURE && n.Func.Closure != nil && n.Func.Closure.Func.Nname.Sym != nil {
|
||||||
|
mode.Fprintf(s, " fnName %v", n.Func.Closure.Func.Nname.Sym)
|
||||||
|
}
|
||||||
if n.Sym != nil && n.Op != ONAME {
|
if n.Sym != nil && n.Op != ONAME {
|
||||||
mode.Fprintf(s, " %v", n.Sym)
|
mode.Fprintf(s, " %v", n.Sym)
|
||||||
}
|
}
|
||||||
|
|
@ -1724,6 +1744,16 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
|
||||||
if n.Right != nil {
|
if n.Right != nil {
|
||||||
mode.Fprintf(s, "%v", n.Right)
|
mode.Fprintf(s, "%v", n.Right)
|
||||||
}
|
}
|
||||||
|
if n.Func != nil && n.Func.Closure != nil && n.Func.Closure.Nbody.Len() != 0 {
|
||||||
|
indent(s)
|
||||||
|
// The function associated with a closure
|
||||||
|
mode.Fprintf(s, "%v-clofunc%v", n.Op, n.Func.Closure)
|
||||||
|
}
|
||||||
|
if n.Func != nil && n.Func.Dcl != nil && len(n.Func.Dcl) != 0 {
|
||||||
|
indent(s)
|
||||||
|
// The dcls for a func or closure
|
||||||
|
mode.Fprintf(s, "%v-dcl%v", n.Op, asNodes(n.Func.Dcl))
|
||||||
|
}
|
||||||
if n.List.Len() != 0 {
|
if n.List.Len() != 0 {
|
||||||
indent(s)
|
indent(s)
|
||||||
mode.Fprintf(s, "%v-list%v", n.Op, n.List)
|
mode.Fprintf(s, "%v-list%v", n.Op, n.List)
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,12 @@ type Class uint8
|
||||||
//go:generate stringer -type=Class
|
//go:generate stringer -type=Class
|
||||||
const (
|
const (
|
||||||
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
|
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
|
||||||
PEXTERN // global variable
|
PEXTERN // global variables
|
||||||
PAUTO // local variables
|
PAUTO // local variables
|
||||||
PAUTOHEAP // local variable or parameter moved to heap
|
PAUTOHEAP // local variables or parameters moved to heap
|
||||||
PPARAM // input arguments
|
PPARAM // input arguments
|
||||||
PPARAMOUT // output results
|
PPARAMOUT // output results
|
||||||
PFUNC // global function
|
PFUNC // global functions
|
||||||
|
|
||||||
// Careful: Class is stored in three bits in Node.flags.
|
// Careful: Class is stored in three bits in Node.flags.
|
||||||
_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
|
_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
|
||||||
|
|
@ -116,7 +116,15 @@ var decldepth int32
|
||||||
|
|
||||||
var nolocalimports bool
|
var nolocalimports bool
|
||||||
|
|
||||||
var Debug [256]int
|
// gc debug flags
|
||||||
|
type DebugFlags struct {
|
||||||
|
P, B, C, E,
|
||||||
|
K, L, N, S,
|
||||||
|
W, e, h, j,
|
||||||
|
l, m, r, w int
|
||||||
|
}
|
||||||
|
|
||||||
|
var Debug DebugFlags
|
||||||
|
|
||||||
var debugstr string
|
var debugstr string
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,12 +70,8 @@ func newProgs(fn *Node, worker int) *Progs {
|
||||||
pp.pos = fn.Pos
|
pp.pos = fn.Pos
|
||||||
pp.settext(fn)
|
pp.settext(fn)
|
||||||
// PCDATA tables implicitly start with index -1.
|
// PCDATA tables implicitly start with index -1.
|
||||||
pp.prevLive = LivenessIndex{-1, -1, false}
|
pp.prevLive = LivenessIndex{-1, false}
|
||||||
if go115ReduceLiveness {
|
|
||||||
pp.nextLive = pp.prevLive
|
pp.nextLive = pp.prevLive
|
||||||
} else {
|
|
||||||
pp.nextLive = LivenessInvalid
|
|
||||||
}
|
|
||||||
return pp
|
return pp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,21 +116,6 @@ func (pp *Progs) Prog(as obj.As) *obj.Prog {
|
||||||
Addrconst(&p.From, objabi.PCDATA_StackMapIndex)
|
Addrconst(&p.From, objabi.PCDATA_StackMapIndex)
|
||||||
Addrconst(&p.To, int64(idx))
|
Addrconst(&p.To, int64(idx))
|
||||||
}
|
}
|
||||||
if !go115ReduceLiveness {
|
|
||||||
if pp.nextLive.isUnsafePoint {
|
|
||||||
// Unsafe points are encoded as a special value in the
|
|
||||||
// register map.
|
|
||||||
pp.nextLive.regMapIndex = objabi.PCDATA_RegMapUnsafe
|
|
||||||
}
|
|
||||||
if pp.nextLive.regMapIndex != pp.prevLive.regMapIndex {
|
|
||||||
// Emit register map index change.
|
|
||||||
idx := pp.nextLive.regMapIndex
|
|
||||||
pp.prevLive.regMapIndex = idx
|
|
||||||
p := pp.Prog(obj.APCDATA)
|
|
||||||
Addrconst(&p.From, objabi.PCDATA_RegMapIndex)
|
|
||||||
Addrconst(&p.To, int64(idx))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if pp.nextLive.isUnsafePoint != pp.prevLive.isUnsafePoint {
|
if pp.nextLive.isUnsafePoint != pp.prevLive.isUnsafePoint {
|
||||||
// Emit unsafe-point marker.
|
// Emit unsafe-point marker.
|
||||||
pp.prevLive.isUnsafePoint = pp.nextLive.isUnsafePoint
|
pp.prevLive.isUnsafePoint = pp.nextLive.isUnsafePoint
|
||||||
|
|
@ -146,14 +127,13 @@ func (pp *Progs) Prog(as obj.As) *obj.Prog {
|
||||||
Addrconst(&p.To, objabi.PCDATA_UnsafePointSafe)
|
Addrconst(&p.To, objabi.PCDATA_UnsafePointSafe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
p := pp.next
|
p := pp.next
|
||||||
pp.next = pp.NewProg()
|
pp.next = pp.NewProg()
|
||||||
pp.clearp(pp.next)
|
pp.clearp(pp.next)
|
||||||
p.Link = pp.next
|
p.Link = pp.next
|
||||||
|
|
||||||
if !pp.pos.IsKnown() && Debug['K'] != 0 {
|
if !pp.pos.IsKnown() && Debug.K != 0 {
|
||||||
Warn("prog: unknown position (line 0)")
|
Warn("prog: unknown position (line 0)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -322,6 +302,12 @@ func ggloblnod(nam *Node) {
|
||||||
if nam.Name.LibfuzzerExtraCounter() {
|
if nam.Name.LibfuzzerExtraCounter() {
|
||||||
s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
|
s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
|
||||||
}
|
}
|
||||||
|
if nam.Sym.Linkname != "" {
|
||||||
|
// Make sure linkname'd symbol is non-package. When a symbol is
|
||||||
|
// both imported and linkname'd, s.Pkg may not set to "_" in
|
||||||
|
// types.Sym.Linksym because LSym already exists. Set it here.
|
||||||
|
s.Pkg = "_"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ggloblsym(s *obj.LSym, width int32, flags int16) {
|
func ggloblsym(s *obj.LSym, width int32, flags int16) {
|
||||||
|
|
|
||||||
|
|
@ -1138,13 +1138,10 @@ func (w *exportWriter) stmt(n *Node) {
|
||||||
w.pos(n.Pos)
|
w.pos(n.Pos)
|
||||||
w.stmtList(n.Ninit)
|
w.stmtList(n.Ninit)
|
||||||
w.exprsOrNil(n.Left, nil)
|
w.exprsOrNil(n.Left, nil)
|
||||||
w.stmtList(n.List)
|
w.caseList(n)
|
||||||
|
|
||||||
case OCASE:
|
// case OCASE:
|
||||||
w.op(OCASE)
|
// handled by caseList
|
||||||
w.pos(n.Pos)
|
|
||||||
w.stmtList(n.List)
|
|
||||||
w.stmtList(n.Nbody)
|
|
||||||
|
|
||||||
case OFALL:
|
case OFALL:
|
||||||
w.op(OFALL)
|
w.op(OFALL)
|
||||||
|
|
@ -1168,6 +1165,24 @@ func (w *exportWriter) stmt(n *Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *exportWriter) caseList(sw *Node) {
|
||||||
|
namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil
|
||||||
|
|
||||||
|
cases := sw.List.Slice()
|
||||||
|
w.uint64(uint64(len(cases)))
|
||||||
|
for _, cas := range cases {
|
||||||
|
if cas.Op != OCASE {
|
||||||
|
Fatalf("expected OCASE, got %v", cas)
|
||||||
|
}
|
||||||
|
w.pos(cas.Pos)
|
||||||
|
w.stmtList(cas.List)
|
||||||
|
if namedTypeSwitch {
|
||||||
|
w.localName(cas.Rlist.First())
|
||||||
|
}
|
||||||
|
w.stmtList(cas.Nbody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (w *exportWriter) exprList(list Nodes) {
|
func (w *exportWriter) exprList(list Nodes) {
|
||||||
for _, n := range list.Slice() {
|
for _, n := range list.Slice() {
|
||||||
w.expr(n)
|
w.expr(n)
|
||||||
|
|
@ -1232,6 +1247,19 @@ func (w *exportWriter) expr(n *Node) {
|
||||||
w.op(OTYPE)
|
w.op(OTYPE)
|
||||||
w.typ(n.Type)
|
w.typ(n.Type)
|
||||||
|
|
||||||
|
case OTYPESW:
|
||||||
|
w.op(OTYPESW)
|
||||||
|
w.pos(n.Pos)
|
||||||
|
var s *types.Sym
|
||||||
|
if n.Left != nil {
|
||||||
|
if n.Left.Op != ONONAME {
|
||||||
|
Fatalf("expected ONONAME, got %v", n.Left)
|
||||||
|
}
|
||||||
|
s = n.Left.Sym
|
||||||
|
}
|
||||||
|
w.localIdent(s, 0) // declared pseudo-variable, if any
|
||||||
|
w.exprsOrNil(n.Right, nil)
|
||||||
|
|
||||||
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
||||||
// should have been resolved by typechecking - handled by default case
|
// should have been resolved by typechecking - handled by default case
|
||||||
|
|
||||||
|
|
@ -1266,8 +1294,13 @@ func (w *exportWriter) expr(n *Node) {
|
||||||
// case OSTRUCTKEY:
|
// case OSTRUCTKEY:
|
||||||
// unreachable - handled in case OSTRUCTLIT by elemList
|
// unreachable - handled in case OSTRUCTLIT by elemList
|
||||||
|
|
||||||
// case OCALLPART:
|
case OCALLPART:
|
||||||
// unimplemented - handled by default case
|
// An OCALLPART is an OXDOT before type checking.
|
||||||
|
w.op(OXDOT)
|
||||||
|
w.pos(n.Pos)
|
||||||
|
w.expr(n.Left)
|
||||||
|
// Right node should be ONAME
|
||||||
|
w.selector(n.Right.Sym)
|
||||||
|
|
||||||
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
||||||
w.op(OXDOT)
|
w.op(OXDOT)
|
||||||
|
|
|
||||||
|
|
@ -742,8 +742,8 @@ func (r *importReader) doInline(n *Node) {
|
||||||
|
|
||||||
importlist = append(importlist, n)
|
importlist = append(importlist, n)
|
||||||
|
|
||||||
if Debug['E'] > 0 && Debug['m'] > 2 {
|
if Debug.E > 0 && Debug.m > 2 {
|
||||||
if Debug['m'] > 3 {
|
if Debug.m > 3 {
|
||||||
fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body))
|
fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body))
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body))
|
fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body))
|
||||||
|
|
@ -784,6 +784,28 @@ func (r *importReader) stmtList() []*Node {
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *importReader) caseList(sw *Node) []*Node {
|
||||||
|
namedTypeSwitch := sw.Op == OSWITCH && sw.Left != nil && sw.Left.Op == OTYPESW && sw.Left.Left != nil
|
||||||
|
|
||||||
|
cases := make([]*Node, r.uint64())
|
||||||
|
for i := range cases {
|
||||||
|
cas := nodl(r.pos(), OCASE, nil, nil)
|
||||||
|
cas.List.Set(r.stmtList())
|
||||||
|
if namedTypeSwitch {
|
||||||
|
// Note: per-case variables will have distinct, dotted
|
||||||
|
// names after import. That's okay: swt.go only needs
|
||||||
|
// Sym for diagnostics anyway.
|
||||||
|
caseVar := newnamel(cas.Pos, r.ident())
|
||||||
|
declare(caseVar, dclcontext)
|
||||||
|
cas.Rlist.Set1(caseVar)
|
||||||
|
caseVar.Name.Defn = sw.Left
|
||||||
|
}
|
||||||
|
cas.Nbody.Set(r.stmtList())
|
||||||
|
cases[i] = cas
|
||||||
|
}
|
||||||
|
return cases
|
||||||
|
}
|
||||||
|
|
||||||
func (r *importReader) exprList() []*Node {
|
func (r *importReader) exprList() []*Node {
|
||||||
var list []*Node
|
var list []*Node
|
||||||
for {
|
for {
|
||||||
|
|
@ -831,6 +853,14 @@ func (r *importReader) node() *Node {
|
||||||
case OTYPE:
|
case OTYPE:
|
||||||
return typenod(r.typ())
|
return typenod(r.typ())
|
||||||
|
|
||||||
|
case OTYPESW:
|
||||||
|
n := nodl(r.pos(), OTYPESW, nil, nil)
|
||||||
|
if s := r.ident(); s != nil {
|
||||||
|
n.Left = npos(n.Pos, newnoname(s))
|
||||||
|
}
|
||||||
|
n.Right, _ = r.exprsOrNil()
|
||||||
|
return n
|
||||||
|
|
||||||
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
||||||
// unreachable - should have been resolved by typechecking
|
// unreachable - should have been resolved by typechecking
|
||||||
|
|
||||||
|
|
@ -866,7 +896,7 @@ func (r *importReader) node() *Node {
|
||||||
// unreachable - handled in case OSTRUCTLIT by elemList
|
// unreachable - handled in case OSTRUCTLIT by elemList
|
||||||
|
|
||||||
// case OCALLPART:
|
// case OCALLPART:
|
||||||
// unimplemented
|
// unreachable - mapped to case OXDOT below by exporter
|
||||||
|
|
||||||
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
||||||
// unreachable - mapped to case OXDOT below by exporter
|
// unreachable - mapped to case OXDOT below by exporter
|
||||||
|
|
@ -1025,16 +1055,11 @@ func (r *importReader) node() *Node {
|
||||||
n := nodl(r.pos(), op, nil, nil)
|
n := nodl(r.pos(), op, nil, nil)
|
||||||
n.Ninit.Set(r.stmtList())
|
n.Ninit.Set(r.stmtList())
|
||||||
n.Left, _ = r.exprsOrNil()
|
n.Left, _ = r.exprsOrNil()
|
||||||
n.List.Set(r.stmtList())
|
n.List.Set(r.caseList(n))
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OCASE:
|
// case OCASE:
|
||||||
n := nodl(r.pos(), OCASE, nil, nil)
|
// handled by caseList
|
||||||
n.List.Set(r.exprList())
|
|
||||||
// TODO(gri) eventually we must declare variables for type switch
|
|
||||||
// statements (type switch statements are not yet exported)
|
|
||||||
n.Nbody.Set(r.stmtList())
|
|
||||||
return n
|
|
||||||
|
|
||||||
case OFALL:
|
case OFALL:
|
||||||
n := nodl(r.pos(), OFALL, nil, nil)
|
n := nodl(r.pos(), OFALL, nil, nil)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
// saves a copy of the body. Then inlcalls walks each function body to
|
// saves a copy of the body. Then inlcalls walks each function body to
|
||||||
// expand calls to inlinable functions.
|
// expand calls to inlinable functions.
|
||||||
//
|
//
|
||||||
// The debug['l'] flag controls the aggressiveness. Note that main() swaps level 0 and 1,
|
// The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
|
||||||
// making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
|
// making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
|
||||||
// are not supported.
|
// are not supported.
|
||||||
// 0: disabled
|
// 0: disabled
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
// The -d typcheckinl flag enables early typechecking of all imported bodies,
|
// The -d typcheckinl flag enables early typechecking of all imported bodies,
|
||||||
// which is useful to flush out bugs.
|
// which is useful to flush out bugs.
|
||||||
//
|
//
|
||||||
// The debug['m'] flag enables diagnostic output. a single -m is useful for verifying
|
// The Debug.m flag enables diagnostic output. a single -m is useful for verifying
|
||||||
// which calls get inlined or not, more is for debugging, and may go away at any point.
|
// which calls get inlined or not, more is for debugging, and may go away at any point.
|
||||||
|
|
||||||
package gc
|
package gc
|
||||||
|
|
@ -85,7 +85,7 @@ func typecheckinl(fn *Node) {
|
||||||
return // typecheckinl on local function
|
return // typecheckinl on local function
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug['m'] > 2 || Debug_export != 0 {
|
if Debug.m > 2 || Debug_export != 0 {
|
||||||
fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
|
fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,10 +116,10 @@ func caninl(fn *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var reason string // reason, if any, that the function was not inlined
|
var reason string // reason, if any, that the function was not inlined
|
||||||
if Debug['m'] > 1 || logopt.Enabled() {
|
if Debug.m > 1 || logopt.Enabled() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if reason != "" {
|
if reason != "" {
|
||||||
if Debug['m'] > 1 {
|
if Debug.m > 1 {
|
||||||
fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
|
fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
|
||||||
}
|
}
|
||||||
if logopt.Enabled() {
|
if logopt.Enabled() {
|
||||||
|
|
@ -187,7 +187,7 @@ func caninl(fn *Node) {
|
||||||
defer n.Func.SetInlinabilityChecked(true)
|
defer n.Func.SetInlinabilityChecked(true)
|
||||||
|
|
||||||
cc := int32(inlineExtraCallCost)
|
cc := int32(inlineExtraCallCost)
|
||||||
if Debug['l'] == 4 {
|
if Debug.l == 4 {
|
||||||
cc = 1 // this appears to yield better performance than 0.
|
cc = 1 // this appears to yield better performance than 0.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,9 +224,9 @@ func caninl(fn *Node) {
|
||||||
// this is so export can find the body of a method
|
// this is so export can find the body of a method
|
||||||
fn.Type.FuncType().Nname = asTypesNode(n)
|
fn.Type.FuncType().Nname = asTypesNode(n)
|
||||||
|
|
||||||
if Debug['m'] > 1 {
|
if Debug.m > 1 {
|
||||||
fmt.Printf("%v: can inline %#v with cost %d as: %#v { %#v }\n", fn.Line(), n, inlineMaxBudget-visitor.budget, fn.Type, asNodes(n.Func.Inl.Body))
|
fmt.Printf("%v: can inline %#v with cost %d as: %#v { %#v }\n", fn.Line(), n, inlineMaxBudget-visitor.budget, fn.Type, asNodes(n.Func.Inl.Body))
|
||||||
} else if Debug['m'] != 0 {
|
} else if Debug.m != 0 {
|
||||||
fmt.Printf("%v: can inline %v\n", fn.Line(), n)
|
fmt.Printf("%v: can inline %v\n", fn.Line(), n)
|
||||||
}
|
}
|
||||||
if logopt.Enabled() {
|
if logopt.Enabled() {
|
||||||
|
|
@ -257,21 +257,39 @@ func inlFlood(n *Node) {
|
||||||
|
|
||||||
typecheckinl(n)
|
typecheckinl(n)
|
||||||
|
|
||||||
|
// Recursively identify all referenced functions for
|
||||||
|
// reexport. We want to include even non-called functions,
|
||||||
|
// because after inlining they might be callable.
|
||||||
inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
|
inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
// Mark any referenced global variables or
|
switch n.Class() {
|
||||||
// functions for reexport. Skip methods,
|
case PFUNC:
|
||||||
// because they're reexported alongside their
|
if n.isMethodExpression() {
|
||||||
// receiver type.
|
inlFlood(asNode(n.Type.Nname()))
|
||||||
if n.Class() == PEXTERN || n.Class() == PFUNC && !n.isMethodExpression() {
|
} else {
|
||||||
|
inlFlood(n)
|
||||||
|
exportsym(n)
|
||||||
|
}
|
||||||
|
case PEXTERN:
|
||||||
exportsym(n)
|
exportsym(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
case OCALLFUNC, OCALLMETH:
|
case ODOTMETH:
|
||||||
// Recursively flood any functions called by
|
fn := asNode(n.Type.Nname())
|
||||||
// this one.
|
inlFlood(fn)
|
||||||
inlFlood(asNode(n.Left.Type.Nname()))
|
|
||||||
|
case OCALLPART:
|
||||||
|
// Okay, because we don't yet inline indirect
|
||||||
|
// calls to method values.
|
||||||
|
case OCLOSURE:
|
||||||
|
// If the closure is inlinable, we'll need to
|
||||||
|
// flood it too. But today we don't support
|
||||||
|
// inlining functions that contain closures.
|
||||||
|
//
|
||||||
|
// When we do, we'll probably want:
|
||||||
|
// inlFlood(n.Func.Closure.Func.Nname)
|
||||||
|
Fatalf("unexpected closure in inlinable function")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
@ -375,10 +393,8 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case OCLOSURE,
|
case OCLOSURE,
|
||||||
OCALLPART,
|
|
||||||
ORANGE,
|
ORANGE,
|
||||||
OSELECT,
|
OSELECT,
|
||||||
OTYPESW,
|
|
||||||
OGO,
|
OGO,
|
||||||
ODEFER,
|
ODEFER,
|
||||||
ODCLTYPE, // can't print yet
|
ODCLTYPE, // can't print yet
|
||||||
|
|
@ -423,7 +439,7 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
||||||
v.budget--
|
v.budget--
|
||||||
|
|
||||||
// When debugging, don't stop early, to get full cost of inlining this function
|
// When debugging, don't stop early, to get full cost of inlining this function
|
||||||
if v.budget < 0 && Debug['m'] < 2 && !logopt.Enabled() {
|
if v.budget < 0 && Debug.m < 2 && !logopt.Enabled() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,7 +470,7 @@ func inlcopy(n *Node) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
m := n.copy()
|
m := n.copy()
|
||||||
if m.Func != nil {
|
if n.Op != OCALLPART && m.Func != nil {
|
||||||
Fatalf("unexpected Func: %v", m)
|
Fatalf("unexpected Func: %v", m)
|
||||||
}
|
}
|
||||||
m.Left = inlcopy(n.Left)
|
m.Left = inlcopy(n.Left)
|
||||||
|
|
@ -572,13 +588,11 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
// inhibit inlining of their argument
|
|
||||||
case ODEFER, OGO:
|
case ODEFER, OGO:
|
||||||
switch n.Left.Op {
|
switch n.Left.Op {
|
||||||
case OCALLFUNC, OCALLMETH:
|
case OCALLFUNC, OCALLMETH:
|
||||||
n.Left.SetNoInline(true)
|
n.Left.SetNoInline(true)
|
||||||
}
|
}
|
||||||
return n
|
|
||||||
|
|
||||||
// TODO do them here (or earlier),
|
// TODO do them here (or earlier),
|
||||||
// so escape analysis can avoid more heapmoves.
|
// so escape analysis can avoid more heapmoves.
|
||||||
|
|
@ -668,7 +682,7 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
|
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case OCALLFUNC:
|
case OCALLFUNC:
|
||||||
if Debug['m'] > 3 {
|
if Debug.m > 3 {
|
||||||
fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
|
fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
|
||||||
}
|
}
|
||||||
if isIntrinsicCall(n) {
|
if isIntrinsicCall(n) {
|
||||||
|
|
@ -679,7 +693,7 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
case OCALLMETH:
|
case OCALLMETH:
|
||||||
if Debug['m'] > 3 {
|
if Debug.m > 3 {
|
||||||
fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
|
fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -706,7 +720,14 @@ func inlCallee(fn *Node) *Node {
|
||||||
switch {
|
switch {
|
||||||
case fn.Op == ONAME && fn.Class() == PFUNC:
|
case fn.Op == ONAME && fn.Class() == PFUNC:
|
||||||
if fn.isMethodExpression() {
|
if fn.isMethodExpression() {
|
||||||
return asNode(fn.Sym.Def)
|
n := asNode(fn.Type.Nname())
|
||||||
|
// Check that receiver type matches fn.Left.
|
||||||
|
// TODO(mdempsky): Handle implicit dereference
|
||||||
|
// of pointer receiver argument?
|
||||||
|
if n == nil || !types.Identical(n.Type.Recv().Type, fn.Left.Type) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
return fn
|
return fn
|
||||||
case fn.Op == OCLOSURE:
|
case fn.Op == OCLOSURE:
|
||||||
|
|
@ -719,6 +740,11 @@ func inlCallee(fn *Node) *Node {
|
||||||
|
|
||||||
func staticValue(n *Node) *Node {
|
func staticValue(n *Node) *Node {
|
||||||
for {
|
for {
|
||||||
|
if n.Op == OCONVNOP {
|
||||||
|
n = n.Left
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
n1 := staticValue1(n)
|
n1 := staticValue1(n)
|
||||||
if n1 == nil {
|
if n1 == nil {
|
||||||
return n
|
return n
|
||||||
|
|
@ -809,14 +835,12 @@ func (v *reassignVisitor) visit(n *Node) *Node {
|
||||||
if n.Left == v.name && n != v.name.Name.Defn {
|
if n.Left == v.name && n != v.name.Name.Defn {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE:
|
case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE:
|
||||||
for _, p := range n.List.Slice() {
|
for _, p := range n.List.Slice() {
|
||||||
if p == v.name && n != v.name.Name.Defn {
|
if p == v.name && n != v.name.Name.Defn {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
if a := v.visit(n.Left); a != nil {
|
if a := v.visit(n.Left); a != nil {
|
||||||
return a
|
return a
|
||||||
|
|
@ -909,7 +933,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
if inlMap[fn] {
|
if inlMap[fn] {
|
||||||
if Debug['m'] > 1 {
|
if Debug.m > 1 {
|
||||||
fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", n.Line(), fn, Curfn.funcname())
|
fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", n.Line(), fn, Curfn.funcname())
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
|
@ -923,12 +947,12 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have a function node, and it has an inlineable body.
|
// We have a function node, and it has an inlineable body.
|
||||||
if Debug['m'] > 1 {
|
if Debug.m > 1 {
|
||||||
fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
|
fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
|
||||||
} else if Debug['m'] != 0 {
|
} else if Debug.m != 0 {
|
||||||
fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
|
fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
|
||||||
}
|
}
|
||||||
if Debug['m'] > 2 {
|
if Debug.m > 2 {
|
||||||
fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
|
fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1009,15 +1033,28 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nreturns := 0
|
||||||
|
inspectList(asNodes(fn.Func.Inl.Body), func(n *Node) bool {
|
||||||
|
if n != nil && n.Op == ORETURN {
|
||||||
|
nreturns++
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
// We can delay declaring+initializing result parameters if:
|
||||||
|
// (1) there's only one "return" statement in the inlined
|
||||||
|
// function, and (2) the result parameters aren't named.
|
||||||
|
delayretvars := nreturns == 1
|
||||||
|
|
||||||
// temporaries for return values.
|
// temporaries for return values.
|
||||||
var retvars []*Node
|
var retvars []*Node
|
||||||
for i, t := range fn.Type.Results().Fields().Slice() {
|
for i, t := range fn.Type.Results().Fields().Slice() {
|
||||||
var m *Node
|
var m *Node
|
||||||
mpos := t.Pos
|
if n := asNode(t.Nname); n != nil && !n.isBlank() && !strings.HasPrefix(n.Sym.Name, "~r") {
|
||||||
if n := asNode(t.Nname); n != nil && !n.isBlank() {
|
|
||||||
m = inlvar(n)
|
m = inlvar(n)
|
||||||
m = typecheck(m, ctxExpr)
|
m = typecheck(m, ctxExpr)
|
||||||
inlvars[n] = m
|
inlvars[n] = m
|
||||||
|
delayretvars = false // found a named result parameter
|
||||||
} else {
|
} else {
|
||||||
// anonymous return values, synthesize names for use in assignment that replaces return
|
// anonymous return values, synthesize names for use in assignment that replaces return
|
||||||
m = retvar(t, i)
|
m = retvar(t, i)
|
||||||
|
|
@ -1029,12 +1066,11 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
// were not part of the original callee.
|
// were not part of the original callee.
|
||||||
if !strings.HasPrefix(m.Sym.Name, "~R") {
|
if !strings.HasPrefix(m.Sym.Name, "~R") {
|
||||||
m.Name.SetInlFormal(true)
|
m.Name.SetInlFormal(true)
|
||||||
m.Pos = mpos
|
m.Pos = t.Pos
|
||||||
inlfvars = append(inlfvars, m)
|
inlfvars = append(inlfvars, m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ninit.Append(nod(ODCL, m, nil))
|
|
||||||
retvars = append(retvars, m)
|
retvars = append(retvars, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1095,12 +1131,15 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
ninit.Append(vas)
|
ninit.Append(vas)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !delayretvars {
|
||||||
// Zero the return parameters.
|
// Zero the return parameters.
|
||||||
for _, n := range retvars {
|
for _, n := range retvars {
|
||||||
|
ninit.Append(nod(ODCL, n, nil))
|
||||||
ras := nod(OAS, n, nil)
|
ras := nod(OAS, n, nil)
|
||||||
ras = typecheck(ras, ctxStmt)
|
ras = typecheck(ras, ctxStmt)
|
||||||
ninit.Append(ras)
|
ninit.Append(ras)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
retlabel := autolabel(".i")
|
retlabel := autolabel(".i")
|
||||||
|
|
||||||
|
|
@ -1132,6 +1171,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
subst := inlsubst{
|
subst := inlsubst{
|
||||||
retlabel: retlabel,
|
retlabel: retlabel,
|
||||||
retvars: retvars,
|
retvars: retvars,
|
||||||
|
delayretvars: delayretvars,
|
||||||
inlvars: inlvars,
|
inlvars: inlvars,
|
||||||
bases: make(map[*src.PosBase]*src.PosBase),
|
bases: make(map[*src.PosBase]*src.PosBase),
|
||||||
newInlIndex: newIndex,
|
newInlIndex: newIndex,
|
||||||
|
|
@ -1172,7 +1212,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug['m'] > 2 {
|
if Debug.m > 2 {
|
||||||
fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
|
fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1183,7 +1223,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||||
// PAUTO's in the calling functions, and link them off of the
|
// PAUTO's in the calling functions, and link them off of the
|
||||||
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
|
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
|
||||||
func inlvar(var_ *Node) *Node {
|
func inlvar(var_ *Node) *Node {
|
||||||
if Debug['m'] > 3 {
|
if Debug.m > 3 {
|
||||||
fmt.Printf("inlvar %+v\n", var_)
|
fmt.Printf("inlvar %+v\n", var_)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1230,6 +1270,10 @@ type inlsubst struct {
|
||||||
// Temporary result variables.
|
// Temporary result variables.
|
||||||
retvars []*Node
|
retvars []*Node
|
||||||
|
|
||||||
|
// Whether result variables should be initialized at the
|
||||||
|
// "return" statement.
|
||||||
|
delayretvars bool
|
||||||
|
|
||||||
inlvars map[*Node]*Node
|
inlvars map[*Node]*Node
|
||||||
|
|
||||||
// bases maps from original PosBase to PosBase with an extra
|
// bases maps from original PosBase to PosBase with an extra
|
||||||
|
|
@ -1262,13 +1306,13 @@ func (subst *inlsubst) node(n *Node) *Node {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
|
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
|
||||||
if Debug['m'] > 2 {
|
if Debug.m > 2 {
|
||||||
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
|
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
|
||||||
}
|
}
|
||||||
return inlvar
|
return inlvar
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug['m'] > 2 {
|
if Debug.m > 2 {
|
||||||
fmt.Printf("not substituting name %+v\n", n)
|
fmt.Printf("not substituting name %+v\n", n)
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
|
@ -1298,6 +1342,14 @@ func (subst *inlsubst) node(n *Node) *Node {
|
||||||
as.List.Append(n)
|
as.List.Append(n)
|
||||||
}
|
}
|
||||||
as.Rlist.Set(subst.list(n.List))
|
as.Rlist.Set(subst.list(n.List))
|
||||||
|
|
||||||
|
if subst.delayretvars {
|
||||||
|
for _, n := range as.List.Slice() {
|
||||||
|
as.Ninit.Append(nod(ODCL, n, nil))
|
||||||
|
n.Name.Defn = as
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
as = typecheck(as, ctxStmt)
|
as = typecheck(as, ctxStmt)
|
||||||
m.Ninit.Append(as)
|
m.Ninit.Append(as)
|
||||||
}
|
}
|
||||||
|
|
@ -1360,3 +1412,68 @@ func pruneUnusedAutos(ll []*Node, vis *hairyVisitor) []*Node {
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// devirtualize replaces interface method calls within fn with direct
|
||||||
|
// concrete-type method calls where applicable.
|
||||||
|
func devirtualize(fn *Node) {
|
||||||
|
Curfn = fn
|
||||||
|
inspectList(fn.Nbody, func(n *Node) bool {
|
||||||
|
if n.Op == OCALLINTER {
|
||||||
|
devirtualizeCall(n)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func devirtualizeCall(call *Node) {
|
||||||
|
recv := staticValue(call.Left.Left)
|
||||||
|
if recv.Op != OCONVIFACE {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := recv.Left.Type
|
||||||
|
if typ.IsInterface() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
x := nodl(call.Left.Pos, ODOTTYPE, call.Left.Left, nil)
|
||||||
|
x.Type = typ
|
||||||
|
x = nodlSym(call.Left.Pos, OXDOT, x, call.Left.Sym)
|
||||||
|
x = typecheck(x, ctxExpr|ctxCallee)
|
||||||
|
switch x.Op {
|
||||||
|
case ODOTMETH:
|
||||||
|
if Debug.m != 0 {
|
||||||
|
Warnl(call.Pos, "devirtualizing %v to %v", call.Left, typ)
|
||||||
|
}
|
||||||
|
call.Op = OCALLMETH
|
||||||
|
call.Left = x
|
||||||
|
case ODOTINTER:
|
||||||
|
// Promoted method from embedded interface-typed field (#42279).
|
||||||
|
if Debug.m != 0 {
|
||||||
|
Warnl(call.Pos, "partially devirtualizing %v to %v", call.Left, typ)
|
||||||
|
}
|
||||||
|
call.Op = OCALLINTER
|
||||||
|
call.Left = x
|
||||||
|
default:
|
||||||
|
// TODO(mdempsky): Turn back into Fatalf after more testing.
|
||||||
|
if Debug.m != 0 {
|
||||||
|
Warnl(call.Pos, "failed to devirtualize %v (%v)", x, x.Op)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicated logic from typecheck for function call return
|
||||||
|
// value types.
|
||||||
|
//
|
||||||
|
// Receiver parameter size may have changed; need to update
|
||||||
|
// call.Type to get correct stack offsets for result
|
||||||
|
// parameters.
|
||||||
|
checkwidth(x.Type)
|
||||||
|
switch ft := x.Type; ft.NumResults() {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
call.Type = ft.Results().Field(0).Type
|
||||||
|
default:
|
||||||
|
call.Type = ft.Results()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ func TestIntendedInlining(t *testing.T) {
|
||||||
"funcPC",
|
"funcPC",
|
||||||
"getArgInfoFast",
|
"getArgInfoFast",
|
||||||
"getm",
|
"getm",
|
||||||
|
"getMCache",
|
||||||
"isDirectIface",
|
"isDirectIface",
|
||||||
"itabHashFunc",
|
"itabHashFunc",
|
||||||
"noescape",
|
"noescape",
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var imported_unsafe bool
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
buildid string
|
buildid string
|
||||||
spectre string
|
spectre string
|
||||||
|
|
@ -132,7 +130,7 @@ func hidePanic() {
|
||||||
// supportsDynlink reports whether or not the code generator for the given
|
// supportsDynlink reports whether or not the code generator for the given
|
||||||
// architecture supports the -shared and -dynlink flags.
|
// architecture supports the -shared and -dynlink flags.
|
||||||
func supportsDynlink(arch *sys.Arch) bool {
|
func supportsDynlink(arch *sys.Arch) bool {
|
||||||
return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
|
return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||||
}
|
}
|
||||||
|
|
||||||
// timing data for compiler phases
|
// timing data for compiler phases
|
||||||
|
|
@ -211,18 +209,27 @@ func Main(archInit func(*Arch)) {
|
||||||
|
|
||||||
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
|
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
|
||||||
flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
|
flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
|
||||||
objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
|
|
||||||
objabi.Flagcount("B", "disable bounds checking", &Debug['B'])
|
|
||||||
objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C']) // TODO(gri) remove eventually
|
|
||||||
flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
|
flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
|
||||||
objabi.Flagcount("E", "debug symbol export", &Debug['E'])
|
|
||||||
|
objabi.Flagcount("%", "debug non-static initializers", &Debug.P)
|
||||||
|
objabi.Flagcount("B", "disable bounds checking", &Debug.B)
|
||||||
|
objabi.Flagcount("C", "disable printing of columns in error messages", &Debug.C)
|
||||||
|
objabi.Flagcount("E", "debug symbol export", &Debug.E)
|
||||||
|
objabi.Flagcount("K", "debug missing line numbers", &Debug.K)
|
||||||
|
objabi.Flagcount("L", "show full file names in error messages", &Debug.L)
|
||||||
|
objabi.Flagcount("N", "disable optimizations", &Debug.N)
|
||||||
|
objabi.Flagcount("S", "print assembly listing", &Debug.S)
|
||||||
|
objabi.Flagcount("W", "debug parse tree after type checking", &Debug.W)
|
||||||
|
objabi.Flagcount("e", "no limit on number of errors reported", &Debug.e)
|
||||||
|
objabi.Flagcount("h", "halt on error", &Debug.h)
|
||||||
|
objabi.Flagcount("j", "debug runtime-initialized variables", &Debug.j)
|
||||||
|
objabi.Flagcount("l", "disable inlining", &Debug.l)
|
||||||
|
objabi.Flagcount("m", "print optimization decisions", &Debug.m)
|
||||||
|
objabi.Flagcount("r", "debug generated wrappers", &Debug.r)
|
||||||
|
objabi.Flagcount("w", "debug type checking", &Debug.w)
|
||||||
|
|
||||||
objabi.Flagfn1("I", "add `directory` to import search path", addidir)
|
objabi.Flagfn1("I", "add `directory` to import search path", addidir)
|
||||||
objabi.Flagcount("K", "debug missing line numbers", &Debug['K'])
|
|
||||||
objabi.Flagcount("L", "show full file names in error messages", &Debug['L'])
|
|
||||||
objabi.Flagcount("N", "disable optimizations", &Debug['N'])
|
|
||||||
objabi.Flagcount("S", "print assembly listing", &Debug['S'])
|
|
||||||
objabi.AddVersionFlag() // -V
|
objabi.AddVersionFlag() // -V
|
||||||
objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
|
|
||||||
flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
|
flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
|
||||||
flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
|
flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
|
||||||
flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
|
flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
|
||||||
|
|
@ -231,17 +238,13 @@ func Main(archInit func(*Arch)) {
|
||||||
flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
|
flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
|
||||||
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
|
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
|
||||||
flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
|
flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
|
||||||
objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
|
objabi.Flagfn1("embedcfg", "read go:embed configuration from `file`", readEmbedCfg)
|
||||||
objabi.Flagcount("h", "halt on error", &Debug['h'])
|
|
||||||
objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
|
objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
|
||||||
objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
|
objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
|
||||||
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
|
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
|
||||||
objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
|
|
||||||
objabi.Flagcount("l", "disable inlining", &Debug['l'])
|
|
||||||
flag.StringVar(&flag_lang, "lang", "", "release to compile for")
|
flag.StringVar(&flag_lang, "lang", "", "release to compile for")
|
||||||
flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
|
flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
|
||||||
objabi.Flagcount("live", "debug liveness analysis", &debuglive)
|
objabi.Flagcount("live", "debug liveness analysis", &debuglive)
|
||||||
objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
|
|
||||||
if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
|
if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
|
||||||
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
|
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
|
||||||
}
|
}
|
||||||
|
|
@ -249,7 +252,6 @@ func Main(archInit func(*Arch)) {
|
||||||
flag.StringVar(&outfile, "o", "", "write output to `file`")
|
flag.StringVar(&outfile, "o", "", "write output to `file`")
|
||||||
flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
|
flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
|
||||||
flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o")
|
flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o")
|
||||||
objabi.Flagcount("r", "debug generated wrappers", &Debug['r'])
|
|
||||||
if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
|
if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
|
||||||
flag.BoolVar(&flag_race, "race", false, "enable race detector")
|
flag.BoolVar(&flag_race, "race", false, "enable race detector")
|
||||||
}
|
}
|
||||||
|
|
@ -259,7 +261,6 @@ func Main(archInit func(*Arch)) {
|
||||||
}
|
}
|
||||||
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
|
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
|
||||||
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
|
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
|
||||||
objabi.Flagcount("w", "debug type checking", &Debug['w'])
|
|
||||||
flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
|
flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
|
||||||
var flag_shared bool
|
var flag_shared bool
|
||||||
var flag_dynlink bool
|
var flag_dynlink bool
|
||||||
|
|
@ -325,9 +326,9 @@ func Main(archInit func(*Arch)) {
|
||||||
|
|
||||||
Ctxt.Flag_shared = flag_dynlink || flag_shared
|
Ctxt.Flag_shared = flag_dynlink || flag_shared
|
||||||
Ctxt.Flag_dynlink = flag_dynlink
|
Ctxt.Flag_dynlink = flag_dynlink
|
||||||
Ctxt.Flag_optimize = Debug['N'] == 0
|
Ctxt.Flag_optimize = Debug.N == 0
|
||||||
|
|
||||||
Ctxt.Debugasm = Debug['S']
|
Ctxt.Debugasm = Debug.S
|
||||||
Ctxt.Debugvlog = Debug_vlog
|
Ctxt.Debugvlog = Debug_vlog
|
||||||
if flagDWARF {
|
if flagDWARF {
|
||||||
Ctxt.DebugInfo = debuginfo
|
Ctxt.DebugInfo = debuginfo
|
||||||
|
|
@ -399,7 +400,7 @@ func Main(archInit func(*Arch)) {
|
||||||
instrumenting = true
|
instrumenting = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if compiling_runtime && Debug['N'] != 0 {
|
if compiling_runtime && Debug.N != 0 {
|
||||||
log.Fatal("cannot disable optimizations while compiling runtime")
|
log.Fatal("cannot disable optimizations while compiling runtime")
|
||||||
}
|
}
|
||||||
if nBackendWorkers < 1 {
|
if nBackendWorkers < 1 {
|
||||||
|
|
@ -504,11 +505,11 @@ func Main(archInit func(*Arch)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable inlining. for now:
|
// enable inlining. for now:
|
||||||
// default: inlining on. (debug['l'] == 1)
|
// default: inlining on. (Debug.l == 1)
|
||||||
// -l: inlining off (debug['l'] == 0)
|
// -l: inlining off (Debug.l == 0)
|
||||||
// -l=2, -l=3: inlining on again, with extra debugging (debug['l'] > 1)
|
// -l=2, -l=3: inlining on again, with extra debugging (Debug.l > 1)
|
||||||
if Debug['l'] <= 1 {
|
if Debug.l <= 1 {
|
||||||
Debug['l'] = 1 - Debug['l']
|
Debug.l = 1 - Debug.l
|
||||||
}
|
}
|
||||||
|
|
||||||
if jsonLogOpt != "" { // parse version,destination from json logging optimization.
|
if jsonLogOpt != "" { // parse version,destination from json logging optimization.
|
||||||
|
|
@ -595,7 +596,7 @@ func Main(archInit func(*Arch)) {
|
||||||
timings.Start("fe", "typecheck", "top1")
|
timings.Start("fe", "typecheck", "top1")
|
||||||
for i := 0; i < len(xtop); i++ {
|
for i := 0; i < len(xtop); i++ {
|
||||||
n := xtop[i]
|
n := xtop[i]
|
||||||
if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
|
if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias()) {
|
||||||
xtop[i] = typecheck(n, ctxStmt)
|
xtop[i] = typecheck(n, ctxStmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -607,7 +608,7 @@ func Main(archInit func(*Arch)) {
|
||||||
timings.Start("fe", "typecheck", "top2")
|
timings.Start("fe", "typecheck", "top2")
|
||||||
for i := 0; i < len(xtop); i++ {
|
for i := 0; i < len(xtop); i++ {
|
||||||
n := xtop[i]
|
n := xtop[i]
|
||||||
if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
|
if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias() {
|
||||||
xtop[i] = typecheck(n, ctxStmt)
|
xtop[i] = typecheck(n, ctxStmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -666,7 +667,7 @@ func Main(archInit func(*Arch)) {
|
||||||
// Phase 5: Inlining
|
// Phase 5: Inlining
|
||||||
timings.Start("fe", "inlining")
|
timings.Start("fe", "inlining")
|
||||||
if Debug_typecheckinl != 0 {
|
if Debug_typecheckinl != 0 {
|
||||||
// Typecheck imported function bodies if debug['l'] > 1,
|
// Typecheck imported function bodies if Debug.l > 1,
|
||||||
// otherwise lazily when used or re-exported.
|
// otherwise lazily when used or re-exported.
|
||||||
for _, n := range importlist {
|
for _, n := range importlist {
|
||||||
if n.Func.Inl != nil {
|
if n.Func.Inl != nil {
|
||||||
|
|
@ -680,7 +681,7 @@ func Main(archInit func(*Arch)) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if Debug['l'] != 0 {
|
if Debug.l != 0 {
|
||||||
// Find functions that can be inlined and clone them before walk expands them.
|
// Find functions that can be inlined and clone them before walk expands them.
|
||||||
visitBottomUp(xtop, func(list []*Node, recursive bool) {
|
visitBottomUp(xtop, func(list []*Node, recursive bool) {
|
||||||
numfns := numNonClosures(list)
|
numfns := numNonClosures(list)
|
||||||
|
|
@ -691,7 +692,7 @@ func Main(archInit func(*Arch)) {
|
||||||
// across more than one function.
|
// across more than one function.
|
||||||
caninl(n)
|
caninl(n)
|
||||||
} else {
|
} else {
|
||||||
if Debug['m'] > 1 {
|
if Debug.m > 1 {
|
||||||
fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
|
fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -700,6 +701,13 @@ func Main(archInit func(*Arch)) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, n := range xtop {
|
||||||
|
if n.Op == ODCLFUNC {
|
||||||
|
devirtualize(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Curfn = nil
|
||||||
|
|
||||||
// Phase 6: Escape analysis.
|
// Phase 6: Escape analysis.
|
||||||
// Required for moving heap allocations onto stack,
|
// Required for moving heap allocations onto stack,
|
||||||
// which in turn is required by the closure implementation,
|
// which in turn is required by the closure implementation,
|
||||||
|
|
@ -1175,7 +1183,6 @@ func importfile(f *Val) *types.Pkg {
|
||||||
}
|
}
|
||||||
|
|
||||||
if path_ == "unsafe" {
|
if path_ == "unsafe" {
|
||||||
imported_unsafe = true
|
|
||||||
return unsafepkg
|
return unsafepkg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1408,29 +1415,34 @@ func IsAlias(sym *types.Sym) bool {
|
||||||
return sym.Def != nil && asNode(sym.Def).Sym != sym
|
return sym.Def != nil && asNode(sym.Def).Sym != sym
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, assume any debug flags are incompatible with concurrent compilation.
|
// By default, assume any debug flags are incompatible with concurrent
|
||||||
// A few are safe and potentially in common use for normal compiles, though; mark them as such here.
|
// compilation. A few are safe and potentially in common use for
|
||||||
var concurrentFlagOK = [256]bool{
|
// normal compiles, though; return true for those.
|
||||||
'B': true, // disabled bounds checking
|
func concurrentFlagOk() bool {
|
||||||
'C': true, // disable printing of columns in error messages
|
// Report whether any debug flag that would prevent concurrent
|
||||||
'e': true, // no limit on errors; errors all come from non-concurrent code
|
// compilation is set, by zeroing out the allowed ones and then
|
||||||
'I': true, // add `directory` to import search path
|
// checking if the resulting struct is zero.
|
||||||
'N': true, // disable optimizations
|
d := Debug
|
||||||
'l': true, // disable inlining
|
d.B = 0 // disable bounds checking
|
||||||
'w': true, // all printing happens before compilation
|
d.C = 0 // disable printing of columns in error messages
|
||||||
'W': true, // all printing happens before compilation
|
d.e = 0 // no limit on errors; errors all come from non-concurrent code
|
||||||
'S': true, // printing disassembly happens at the end (but see concurrentBackendAllowed below)
|
d.N = 0 // disable optimizations
|
||||||
|
d.l = 0 // disable inlining
|
||||||
|
d.w = 0 // all printing happens before compilation
|
||||||
|
d.W = 0 // all printing happens before compilation
|
||||||
|
d.S = 0 // printing disassembly happens at the end (but see concurrentBackendAllowed below)
|
||||||
|
|
||||||
|
return d == DebugFlags{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func concurrentBackendAllowed() bool {
|
func concurrentBackendAllowed() bool {
|
||||||
for i, x := range &Debug {
|
if !concurrentFlagOk() {
|
||||||
if x != 0 && !concurrentFlagOK[i] {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Debug['S'] by itself is ok, because all printing occurs
|
// Debug.S by itself is ok, because all printing occurs
|
||||||
// while writing the object file, and that is non-concurrent.
|
// while writing the object file, and that is non-concurrent.
|
||||||
// Adding Debug_vlog, however, causes Debug['S'] to also print
|
// Adding Debug_vlog, however, causes Debug.S to also print
|
||||||
// while flushing the plist, which happens concurrently.
|
// while flushing the plist, which happens concurrently.
|
||||||
if Debug_vlog || debugstr != "" || debuglive > 0 {
|
if Debug_vlog || debugstr != "" || debuglive > 0 {
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"cmd/compile/internal/syntax"
|
"cmd/compile/internal/syntax"
|
||||||
|
|
@ -90,7 +91,11 @@ func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
|
||||||
} else {
|
} else {
|
||||||
// line directive base
|
// line directive base
|
||||||
p0 := b0.Pos()
|
p0 := b0.Pos()
|
||||||
p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line(), p0.Col())
|
p0b := p0.Base()
|
||||||
|
if p0b == b0 {
|
||||||
|
panic("infinite recursion in makeSrcPosBase")
|
||||||
|
}
|
||||||
|
p1 := src.MakePos(p.makeSrcPosBase(p0b), p0.Line(), p0.Col())
|
||||||
b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
|
b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
|
||||||
}
|
}
|
||||||
p.basemap[b0] = b1
|
p.basemap[b0] = b1
|
||||||
|
|
@ -135,6 +140,8 @@ type noder struct {
|
||||||
pragcgobuf [][]string
|
pragcgobuf [][]string
|
||||||
err chan syntax.Error
|
err chan syntax.Error
|
||||||
scope ScopeID
|
scope ScopeID
|
||||||
|
importedUnsafe bool
|
||||||
|
importedEmbed bool
|
||||||
|
|
||||||
// scopeVars is a stack tracking the number of variables declared in the
|
// scopeVars is a stack tracking the number of variables declared in the
|
||||||
// current function at the moment each open scope was opened.
|
// current function at the moment each open scope was opened.
|
||||||
|
|
@ -236,7 +243,8 @@ type linkname struct {
|
||||||
|
|
||||||
func (p *noder) node() {
|
func (p *noder) node() {
|
||||||
types.Block = 1
|
types.Block = 1
|
||||||
imported_unsafe = false
|
p.importedUnsafe = false
|
||||||
|
p.importedEmbed = false
|
||||||
|
|
||||||
p.setlineno(p.file.PkgName)
|
p.setlineno(p.file.PkgName)
|
||||||
mkpackage(p.file.PkgName.Value)
|
mkpackage(p.file.PkgName.Value)
|
||||||
|
|
@ -249,7 +257,7 @@ func (p *noder) node() {
|
||||||
xtop = append(xtop, p.decls(p.file.DeclList)...)
|
xtop = append(xtop, p.decls(p.file.DeclList)...)
|
||||||
|
|
||||||
for _, n := range p.linknames {
|
for _, n := range p.linknames {
|
||||||
if !imported_unsafe {
|
if !p.importedUnsafe {
|
||||||
p.yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
|
p.yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -324,7 +332,6 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
|
||||||
|
|
||||||
val := p.basicLit(imp.Path)
|
val := p.basicLit(imp.Path)
|
||||||
ipkg := importfile(&val)
|
ipkg := importfile(&val)
|
||||||
|
|
||||||
if ipkg == nil {
|
if ipkg == nil {
|
||||||
if nerrors == 0 {
|
if nerrors == 0 {
|
||||||
Fatalf("phase error in import")
|
Fatalf("phase error in import")
|
||||||
|
|
@ -332,6 +339,13 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ipkg == unsafepkg {
|
||||||
|
p.importedUnsafe = true
|
||||||
|
}
|
||||||
|
if ipkg.Path == "embed" {
|
||||||
|
p.importedEmbed = true
|
||||||
|
}
|
||||||
|
|
||||||
ipkg.Direct = true
|
ipkg.Direct = true
|
||||||
|
|
||||||
var my *types.Sym
|
var my *types.Sym
|
||||||
|
|
@ -373,6 +387,20 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
if pragma, ok := decl.Pragma.(*Pragma); ok {
|
if pragma, ok := decl.Pragma.(*Pragma); ok {
|
||||||
|
if len(pragma.Embeds) > 0 {
|
||||||
|
if !p.importedEmbed {
|
||||||
|
// This check can't be done when building the list pragma.Embeds
|
||||||
|
// because that list is created before the noder starts walking over the file,
|
||||||
|
// so at that point it hasn't seen the imports.
|
||||||
|
// We're left to check now, just before applying the //go:embed lines.
|
||||||
|
for _, e := range pragma.Embeds {
|
||||||
|
p.yyerrorpos(e.Pos, "//go:embed only allowed in Go files that import \"embed\"")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
exprs = varEmbed(p, names, typ, exprs, pragma.Embeds)
|
||||||
|
}
|
||||||
|
pragma.Embeds = nil
|
||||||
|
}
|
||||||
p.checkUnused(pragma)
|
p.checkUnused(pragma)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -455,17 +483,17 @@ func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
|
||||||
|
|
||||||
param := n.Name.Param
|
param := n.Name.Param
|
||||||
param.Ntype = typ
|
param.Ntype = typ
|
||||||
param.Alias = decl.Alias
|
param.SetAlias(decl.Alias)
|
||||||
if pragma, ok := decl.Pragma.(*Pragma); ok {
|
if pragma, ok := decl.Pragma.(*Pragma); ok {
|
||||||
if !decl.Alias {
|
if !decl.Alias {
|
||||||
param.Pragma = pragma.Flag & TypePragmas
|
param.SetPragma(pragma.Flag & TypePragmas)
|
||||||
pragma.Flag &^= TypePragmas
|
pragma.Flag &^= TypePragmas
|
||||||
}
|
}
|
||||||
p.checkUnused(pragma)
|
p.checkUnused(pragma)
|
||||||
}
|
}
|
||||||
|
|
||||||
nod := p.nod(decl, ODCLTYPE, n, nil)
|
nod := p.nod(decl, ODCLTYPE, n, nil)
|
||||||
if param.Alias && !langSupported(1, 9, localpkg) {
|
if param.Alias() && !langSupported(1, 9, localpkg) {
|
||||||
yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9")
|
yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9")
|
||||||
}
|
}
|
||||||
return nod
|
return nod
|
||||||
|
|
@ -1438,11 +1466,6 @@ func (p *noder) mkname(name *syntax.Name) *Node {
|
||||||
return mkname(p.name(name))
|
return mkname(p.name(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *noder) newname(name *syntax.Name) *Node {
|
|
||||||
// TODO(mdempsky): Set line number?
|
|
||||||
return newname(p.name(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *noder) wrapname(n syntax.Node, x *Node) *Node {
|
func (p *noder) wrapname(n syntax.Node, x *Node) *Node {
|
||||||
// These nodes do not carry line numbers.
|
// These nodes do not carry line numbers.
|
||||||
// Introduce a wrapper node to give them the correct line.
|
// Introduce a wrapper node to give them the correct line.
|
||||||
|
|
@ -1498,6 +1521,7 @@ var allowedStdPragmas = map[string]bool{
|
||||||
"go:cgo_import_dynamic": true,
|
"go:cgo_import_dynamic": true,
|
||||||
"go:cgo_ldflag": true,
|
"go:cgo_ldflag": true,
|
||||||
"go:cgo_dynamic_linker": true,
|
"go:cgo_dynamic_linker": true,
|
||||||
|
"go:embed": true,
|
||||||
"go:generate": true,
|
"go:generate": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1505,6 +1529,7 @@ var allowedStdPragmas = map[string]bool{
|
||||||
type Pragma struct {
|
type Pragma struct {
|
||||||
Flag PragmaFlag // collected bits
|
Flag PragmaFlag // collected bits
|
||||||
Pos []PragmaPos // position of each individual flag
|
Pos []PragmaPos // position of each individual flag
|
||||||
|
Embeds []PragmaEmbed
|
||||||
}
|
}
|
||||||
|
|
||||||
type PragmaPos struct {
|
type PragmaPos struct {
|
||||||
|
|
@ -1512,12 +1537,22 @@ type PragmaPos struct {
|
||||||
Pos syntax.Pos
|
Pos syntax.Pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PragmaEmbed struct {
|
||||||
|
Pos syntax.Pos
|
||||||
|
Patterns []string
|
||||||
|
}
|
||||||
|
|
||||||
func (p *noder) checkUnused(pragma *Pragma) {
|
func (p *noder) checkUnused(pragma *Pragma) {
|
||||||
for _, pos := range pragma.Pos {
|
for _, pos := range pragma.Pos {
|
||||||
if pos.Flag&pragma.Flag != 0 {
|
if pos.Flag&pragma.Flag != 0 {
|
||||||
p.yyerrorpos(pos.Pos, "misplaced compiler directive")
|
p.yyerrorpos(pos.Pos, "misplaced compiler directive")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(pragma.Embeds) > 0 {
|
||||||
|
for _, e := range pragma.Embeds {
|
||||||
|
p.yyerrorpos(e.Pos, "misplaced go:embed directive")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
|
func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
|
||||||
|
|
@ -1526,6 +1561,11 @@ func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
|
||||||
p.error(syntax.Error{Pos: pos.Pos, Msg: "misplaced compiler directive"})
|
p.error(syntax.Error{Pos: pos.Pos, Msg: "misplaced compiler directive"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(pragma.Embeds) > 0 {
|
||||||
|
for _, e := range pragma.Embeds {
|
||||||
|
p.error(syntax.Error{Pos: e.Pos, Msg: "misplaced go:embed directive"})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pragma is called concurrently if files are parsed concurrently.
|
// pragma is called concurrently if files are parsed concurrently.
|
||||||
|
|
@ -1570,6 +1610,17 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P
|
||||||
}
|
}
|
||||||
p.linknames = append(p.linknames, linkname{pos, f[1], target})
|
p.linknames = append(p.linknames, linkname{pos, f[1], target})
|
||||||
|
|
||||||
|
case text == "go:embed", strings.HasPrefix(text, "go:embed "):
|
||||||
|
args, err := parseGoEmbed(text[len("go:embed"):])
|
||||||
|
if err != nil {
|
||||||
|
p.error(syntax.Error{Pos: pos, Msg: err.Error()})
|
||||||
|
}
|
||||||
|
if len(args) == 0 {
|
||||||
|
p.error(syntax.Error{Pos: pos, Msg: "usage: //go:embed pattern..."})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pragma.Embeds = append(pragma.Embeds, PragmaEmbed{pos, args})
|
||||||
|
|
||||||
case strings.HasPrefix(text, "go:cgo_import_dynamic "):
|
case strings.HasPrefix(text, "go:cgo_import_dynamic "):
|
||||||
// This is permitted for general use because Solaris
|
// This is permitted for general use because Solaris
|
||||||
// code relies on it in golang.org/x/sys/unix and others.
|
// code relies on it in golang.org/x/sys/unix and others.
|
||||||
|
|
@ -1642,3 +1693,64 @@ func mkname(sym *types.Sym) *Node {
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
|
||||||
|
// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
|
||||||
|
// go/build/read.go also processes these strings and contains similar logic.
|
||||||
|
func parseGoEmbed(args string) ([]string, error) {
|
||||||
|
var list []string
|
||||||
|
for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) {
|
||||||
|
var path string
|
||||||
|
Switch:
|
||||||
|
switch args[0] {
|
||||||
|
default:
|
||||||
|
i := len(args)
|
||||||
|
for j, c := range args {
|
||||||
|
if unicode.IsSpace(c) {
|
||||||
|
i = j
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path = args[:i]
|
||||||
|
args = args[i:]
|
||||||
|
|
||||||
|
case '`':
|
||||||
|
i := strings.Index(args[1:], "`")
|
||||||
|
if i < 0 {
|
||||||
|
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
||||||
|
}
|
||||||
|
path = args[1 : 1+i]
|
||||||
|
args = args[1+i+1:]
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
i := 1
|
||||||
|
for ; i < len(args); i++ {
|
||||||
|
if args[i] == '\\' {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if args[i] == '"' {
|
||||||
|
q, err := strconv.Unquote(args[:i+1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
|
||||||
|
}
|
||||||
|
path = q
|
||||||
|
args = args[i+1:]
|
||||||
|
break Switch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i >= len(args) {
|
||||||
|
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if args != "" {
|
||||||
|
r, _ := utf8.DecodeRuneInString(args)
|
||||||
|
if !unicode.IsSpace(r) {
|
||||||
|
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list = append(list, path)
|
||||||
|
}
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
@ -125,6 +127,7 @@ func dumpdata() {
|
||||||
itabsLen := len(itabs)
|
itabsLen := len(itabs)
|
||||||
dumpimportstrings()
|
dumpimportstrings()
|
||||||
dumpbasictypes()
|
dumpbasictypes()
|
||||||
|
dumpembeds()
|
||||||
|
|
||||||
// Calls to dumpsignats can generate functions,
|
// Calls to dumpsignats can generate functions,
|
||||||
// like method wrappers and hash and equality routines.
|
// like method wrappers and hash and equality routines.
|
||||||
|
|
@ -309,7 +312,7 @@ func addGCLocals() {
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals, fn.GCRegs} {
|
for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals} {
|
||||||
if gcsym != nil && !gcsym.OnList() {
|
if gcsym != nil && !gcsym.OnList() {
|
||||||
ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
|
ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
|
||||||
}
|
}
|
||||||
|
|
@ -358,28 +361,31 @@ func dbvec(s *obj.LSym, off int, bv bvec) int {
|
||||||
return off
|
return off
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
stringSymPrefix = "go.string."
|
||||||
|
stringSymPattern = ".gostring.%d.%x"
|
||||||
|
)
|
||||||
|
|
||||||
|
// stringsym returns a symbol containing the string s.
|
||||||
|
// The symbol contains the string data, not a string header.
|
||||||
func stringsym(pos src.XPos, s string) (data *obj.LSym) {
|
func stringsym(pos src.XPos, s string) (data *obj.LSym) {
|
||||||
var symname string
|
var symname string
|
||||||
if len(s) > 100 {
|
if len(s) > 100 {
|
||||||
// Huge strings are hashed to avoid long names in object files.
|
// Huge strings are hashed to avoid long names in object files.
|
||||||
// Indulge in some paranoia by writing the length of s, too,
|
// Indulge in some paranoia by writing the length of s, too,
|
||||||
// as protection against length extension attacks.
|
// as protection against length extension attacks.
|
||||||
|
// Same pattern is known to fileStringSym below.
|
||||||
h := sha256.New()
|
h := sha256.New()
|
||||||
io.WriteString(h, s)
|
io.WriteString(h, s)
|
||||||
symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil))
|
symname = fmt.Sprintf(stringSymPattern, len(s), h.Sum(nil))
|
||||||
} else {
|
} else {
|
||||||
// Small strings get named directly by their contents.
|
// Small strings get named directly by their contents.
|
||||||
symname = strconv.Quote(s)
|
symname = strconv.Quote(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
const prefix = "go.string."
|
symdata := Ctxt.Lookup(stringSymPrefix + symname)
|
||||||
symdataname := prefix + symname
|
|
||||||
|
|
||||||
symdata := Ctxt.Lookup(symdataname)
|
|
||||||
|
|
||||||
if !symdata.OnList() {
|
if !symdata.OnList() {
|
||||||
// string data
|
off := dstringdata(symdata, 0, s, pos, "string")
|
||||||
off := dsname(symdata, 0, s, pos, "string")
|
|
||||||
ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
||||||
symdata.Set(obj.AttrContentAddressable, true)
|
symdata.Set(obj.AttrContentAddressable, true)
|
||||||
}
|
}
|
||||||
|
|
@ -387,26 +393,122 @@ func stringsym(pos src.XPos, s string) (data *obj.LSym) {
|
||||||
return symdata
|
return symdata
|
||||||
}
|
}
|
||||||
|
|
||||||
var slicebytes_gen int
|
// fileStringSym returns a symbol for the contents and the size of file.
|
||||||
|
// If readonly is true, the symbol shares storage with any literal string
|
||||||
|
// or other file with the same content and is placed in a read-only section.
|
||||||
|
// If readonly is false, the symbol is a read-write copy separate from any other,
|
||||||
|
// for use as the backing store of a []byte.
|
||||||
|
// The content hash of file is copied into hash. (If hash is nil, nothing is copied.)
|
||||||
|
// The returned symbol contains the data itself, not a string header.
|
||||||
|
func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.LSym, int64, error) {
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
info, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if !info.Mode().IsRegular() {
|
||||||
|
return nil, 0, fmt.Errorf("not a regular file")
|
||||||
|
}
|
||||||
|
size := info.Size()
|
||||||
|
if size <= 1*1024 {
|
||||||
|
data, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if int64(len(data)) != size {
|
||||||
|
return nil, 0, fmt.Errorf("file changed between reads")
|
||||||
|
}
|
||||||
|
var sym *obj.LSym
|
||||||
|
if readonly {
|
||||||
|
sym = stringsym(pos, string(data))
|
||||||
|
} else {
|
||||||
|
sym = slicedata(pos, string(data)).Sym.Linksym()
|
||||||
|
}
|
||||||
|
if len(hash) > 0 {
|
||||||
|
sum := sha256.Sum256(data)
|
||||||
|
copy(hash, sum[:])
|
||||||
|
}
|
||||||
|
return sym, size, nil
|
||||||
|
}
|
||||||
|
if size > 2e9 {
|
||||||
|
// ggloblsym takes an int32,
|
||||||
|
// and probably the rest of the toolchain
|
||||||
|
// can't handle such big symbols either.
|
||||||
|
// See golang.org/issue/9862.
|
||||||
|
return nil, 0, fmt.Errorf("file too large")
|
||||||
|
}
|
||||||
|
|
||||||
func slicebytes(nam *Node, s string) {
|
// File is too big to read and keep in memory.
|
||||||
slicebytes_gen++
|
// Compute hash if needed for read-only content hashing or if the caller wants it.
|
||||||
symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
|
var sum []byte
|
||||||
|
if readonly || len(hash) > 0 {
|
||||||
|
h := sha256.New()
|
||||||
|
n, err := io.Copy(h, f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if n != size {
|
||||||
|
return nil, 0, fmt.Errorf("file changed between reads")
|
||||||
|
}
|
||||||
|
sum = h.Sum(nil)
|
||||||
|
copy(hash, sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
var symdata *obj.LSym
|
||||||
|
if readonly {
|
||||||
|
symname := fmt.Sprintf(stringSymPattern, size, sum)
|
||||||
|
symdata = Ctxt.Lookup(stringSymPrefix + symname)
|
||||||
|
if !symdata.OnList() {
|
||||||
|
info := symdata.NewFileInfo()
|
||||||
|
info.Name = file
|
||||||
|
info.Size = size
|
||||||
|
ggloblsym(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
||||||
|
// Note: AttrContentAddressable cannot be set here,
|
||||||
|
// because the content-addressable-handling code
|
||||||
|
// does not know about file symbols.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Emit a zero-length data symbol
|
||||||
|
// and then fix up length and content to use file.
|
||||||
|
symdata = slicedata(pos, "").Sym.Linksym()
|
||||||
|
symdata.Size = size
|
||||||
|
symdata.Type = objabi.SNOPTRDATA
|
||||||
|
info := symdata.NewFileInfo()
|
||||||
|
info.Name = file
|
||||||
|
info.Size = size
|
||||||
|
}
|
||||||
|
|
||||||
|
return symdata, size, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var slicedataGen int
|
||||||
|
|
||||||
|
func slicedata(pos src.XPos, s string) *Node {
|
||||||
|
slicedataGen++
|
||||||
|
symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
|
||||||
sym := localpkg.Lookup(symname)
|
sym := localpkg.Lookup(symname)
|
||||||
symnode := newname(sym)
|
symnode := newname(sym)
|
||||||
sym.Def = asTypesNode(symnode)
|
sym.Def = asTypesNode(symnode)
|
||||||
|
|
||||||
lsym := sym.Linksym()
|
lsym := sym.Linksym()
|
||||||
off := dsname(lsym, 0, s, nam.Pos, "slice")
|
off := dstringdata(lsym, 0, s, pos, "slice")
|
||||||
ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL)
|
ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL)
|
||||||
|
|
||||||
|
return symnode
|
||||||
|
}
|
||||||
|
|
||||||
|
func slicebytes(nam *Node, s string) {
|
||||||
if nam.Op != ONAME {
|
if nam.Op != ONAME {
|
||||||
Fatalf("slicebytes %v", nam)
|
Fatalf("slicebytes %v", nam)
|
||||||
}
|
}
|
||||||
slicesym(nam, symnode, int64(len(s)))
|
slicesym(nam, slicedata(nam.Pos, s), int64(len(s)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func dsname(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
|
func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
|
||||||
// Objects that are too large will cause the data section to overflow right away,
|
// Objects that are too large will cause the data section to overflow right away,
|
||||||
// causing a cryptic error message by the linker. Check for oversize objects here
|
// causing a cryptic error message by the linker. Check for oversize objects here
|
||||||
// and provide a useful error message instead.
|
// and provide a useful error message instead.
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ type Order struct {
|
||||||
// Order rewrites fn.Nbody to apply the ordering constraints
|
// Order rewrites fn.Nbody to apply the ordering constraints
|
||||||
// described in the comment at the top of the file.
|
// described in the comment at the top of the file.
|
||||||
func order(fn *Node) {
|
func order(fn *Node) {
|
||||||
if Debug['W'] > 1 {
|
if Debug.W > 1 {
|
||||||
s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
|
s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
|
||||||
dumplist(s, fn.Nbody)
|
dumplist(s, fn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
@ -323,12 +323,7 @@ func (o *Order) stmtList(l Nodes) {
|
||||||
// and rewrites it to:
|
// and rewrites it to:
|
||||||
// m = OMAKESLICECOPY([]T, x, s); nil
|
// m = OMAKESLICECOPY([]T, x, s); nil
|
||||||
func orderMakeSliceCopy(s []*Node) {
|
func orderMakeSliceCopy(s []*Node) {
|
||||||
const go115makeslicecopy = true
|
if Debug.N != 0 || instrumenting {
|
||||||
if !go115makeslicecopy {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if Debug['N'] != 0 || instrumenting {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,16 +24,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// go115ReduceLiveness disables register maps and only produces stack
|
|
||||||
// maps at call sites.
|
|
||||||
//
|
|
||||||
// In Go 1.15, we changed debug call injection to use conservative
|
|
||||||
// scanning instead of precise pointer maps, so these are no longer
|
|
||||||
// necessary.
|
|
||||||
//
|
|
||||||
// Keep in sync with runtime/preempt.go:go115ReduceLiveness.
|
|
||||||
const go115ReduceLiveness = true
|
|
||||||
|
|
||||||
// OpVarDef is an annotation for the liveness analysis, marking a place
|
// OpVarDef is an annotation for the liveness analysis, marking a place
|
||||||
// where a complete initialization (definition) of a variable begins.
|
// where a complete initialization (definition) of a variable begins.
|
||||||
// Since the liveness analysis can see initialization of single-word
|
// Since the liveness analysis can see initialization of single-word
|
||||||
|
|
@ -96,15 +86,15 @@ type BlockEffects struct {
|
||||||
//
|
//
|
||||||
// uevar: upward exposed variables (used before set in block)
|
// uevar: upward exposed variables (used before set in block)
|
||||||
// varkill: killed variables (set in block)
|
// varkill: killed variables (set in block)
|
||||||
uevar varRegVec
|
uevar bvec
|
||||||
varkill varRegVec
|
varkill bvec
|
||||||
|
|
||||||
// Computed during Liveness.solve using control flow information:
|
// Computed during Liveness.solve using control flow information:
|
||||||
//
|
//
|
||||||
// livein: variables live at block entry
|
// livein: variables live at block entry
|
||||||
// liveout: variables live at block exit
|
// liveout: variables live at block exit
|
||||||
livein varRegVec
|
livein bvec
|
||||||
liveout varRegVec
|
liveout bvec
|
||||||
}
|
}
|
||||||
|
|
||||||
// A collection of global state used by liveness analysis.
|
// A collection of global state used by liveness analysis.
|
||||||
|
|
@ -128,16 +118,14 @@ type Liveness struct {
|
||||||
// current Block during Liveness.epilogue. Indexed in Value
|
// current Block during Liveness.epilogue. Indexed in Value
|
||||||
// order for that block. Additionally, for the entry block
|
// order for that block. Additionally, for the entry block
|
||||||
// livevars[0] is the entry bitmap. Liveness.compact moves
|
// livevars[0] is the entry bitmap. Liveness.compact moves
|
||||||
// these to stackMaps and regMaps.
|
// these to stackMaps.
|
||||||
livevars []varRegVec
|
livevars []bvec
|
||||||
|
|
||||||
// livenessMap maps from safe points (i.e., CALLs) to their
|
// livenessMap maps from safe points (i.e., CALLs) to their
|
||||||
// liveness map indexes.
|
// liveness map indexes.
|
||||||
livenessMap LivenessMap
|
livenessMap LivenessMap
|
||||||
stackMapSet bvecSet
|
stackMapSet bvecSet
|
||||||
stackMaps []bvec
|
stackMaps []bvec
|
||||||
regMapSet map[liveRegMask]int
|
|
||||||
regMaps []liveRegMask
|
|
||||||
|
|
||||||
cache progeffectscache
|
cache progeffectscache
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +146,7 @@ func (m *LivenessMap) reset() {
|
||||||
delete(m.vals, k)
|
delete(m.vals, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m.deferreturn = LivenessInvalid
|
m.deferreturn = LivenessDontCare
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *LivenessMap) set(v *ssa.Value, i LivenessIndex) {
|
func (m *LivenessMap) set(v *ssa.Value, i LivenessIndex) {
|
||||||
|
|
@ -166,27 +154,17 @@ func (m *LivenessMap) set(v *ssa.Value, i LivenessIndex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m LivenessMap) Get(v *ssa.Value) LivenessIndex {
|
func (m LivenessMap) Get(v *ssa.Value) LivenessIndex {
|
||||||
if !go115ReduceLiveness {
|
|
||||||
// All safe-points are in the map, so if v isn't in
|
|
||||||
// the map, it's an unsafe-point.
|
|
||||||
if idx, ok := m.vals[v.ID]; ok {
|
|
||||||
return idx
|
|
||||||
}
|
|
||||||
return LivenessInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
// If v isn't in the map, then it's a "don't care" and not an
|
// If v isn't in the map, then it's a "don't care" and not an
|
||||||
// unsafe-point.
|
// unsafe-point.
|
||||||
if idx, ok := m.vals[v.ID]; ok {
|
if idx, ok := m.vals[v.ID]; ok {
|
||||||
return idx
|
return idx
|
||||||
}
|
}
|
||||||
return LivenessIndex{StackMapDontCare, StackMapDontCare, false}
|
return LivenessIndex{StackMapDontCare, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LivenessIndex stores the liveness map information for a Value.
|
// LivenessIndex stores the liveness map information for a Value.
|
||||||
type LivenessIndex struct {
|
type LivenessIndex struct {
|
||||||
stackMapIndex int
|
stackMapIndex int
|
||||||
regMapIndex int // only for !go115ReduceLiveness
|
|
||||||
|
|
||||||
// isUnsafePoint indicates that this is an unsafe-point.
|
// isUnsafePoint indicates that this is an unsafe-point.
|
||||||
//
|
//
|
||||||
|
|
@ -197,8 +175,10 @@ type LivenessIndex struct {
|
||||||
isUnsafePoint bool
|
isUnsafePoint bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// LivenessInvalid indicates an unsafe point with no stack map.
|
// LivenessDontCare indicates that the liveness information doesn't
|
||||||
var LivenessInvalid = LivenessIndex{StackMapDontCare, StackMapDontCare, true} // only for !go115ReduceLiveness
|
// matter. Currently it is used in deferreturn liveness when we don't
|
||||||
|
// actually need it. It should never be emitted to the PCDATA stream.
|
||||||
|
var LivenessDontCare = LivenessIndex{StackMapDontCare, true}
|
||||||
|
|
||||||
// StackMapDontCare indicates that the stack map index at a Value
|
// StackMapDontCare indicates that the stack map index at a Value
|
||||||
// doesn't matter.
|
// doesn't matter.
|
||||||
|
|
@ -212,46 +192,12 @@ func (idx LivenessIndex) StackMapValid() bool {
|
||||||
return idx.stackMapIndex != StackMapDontCare
|
return idx.stackMapIndex != StackMapDontCare
|
||||||
}
|
}
|
||||||
|
|
||||||
func (idx LivenessIndex) RegMapValid() bool {
|
|
||||||
return idx.regMapIndex != StackMapDontCare
|
|
||||||
}
|
|
||||||
|
|
||||||
type progeffectscache struct {
|
type progeffectscache struct {
|
||||||
retuevar []int32
|
retuevar []int32
|
||||||
tailuevar []int32
|
tailuevar []int32
|
||||||
initialized bool
|
initialized bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// varRegVec contains liveness bitmaps for variables and registers.
|
|
||||||
type varRegVec struct {
|
|
||||||
vars bvec
|
|
||||||
regs liveRegMask
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *varRegVec) Eq(v2 varRegVec) bool {
|
|
||||||
return v.vars.Eq(v2.vars) && v.regs == v2.regs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *varRegVec) Copy(v2 varRegVec) {
|
|
||||||
v.vars.Copy(v2.vars)
|
|
||||||
v.regs = v2.regs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *varRegVec) Clear() {
|
|
||||||
v.vars.Clear()
|
|
||||||
v.regs = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *varRegVec) Or(v1, v2 varRegVec) {
|
|
||||||
v.vars.Or(v1.vars, v2.vars)
|
|
||||||
v.regs = v1.regs | v2.regs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *varRegVec) AndNot(v1, v2 varRegVec) {
|
|
||||||
v.vars.AndNot(v1.vars, v2.vars)
|
|
||||||
v.regs = v1.regs &^ v2.regs
|
|
||||||
}
|
|
||||||
|
|
||||||
// livenessShouldTrack reports whether the liveness analysis
|
// livenessShouldTrack reports whether the liveness analysis
|
||||||
// should track the variable n.
|
// should track the variable n.
|
||||||
// We don't care about variables that have no pointers,
|
// We don't care about variables that have no pointers,
|
||||||
|
|
@ -400,110 +346,6 @@ func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// regEffects returns the registers affected by v.
|
|
||||||
func (lv *Liveness) regEffects(v *ssa.Value) (uevar, kill liveRegMask) {
|
|
||||||
if go115ReduceLiveness {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
if v.Op == ssa.OpPhi {
|
|
||||||
// All phi node arguments must come from the same
|
|
||||||
// register and the result must also go to that
|
|
||||||
// register, so there's no overall effect.
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
addLocs := func(mask liveRegMask, v *ssa.Value, ptrOnly bool) liveRegMask {
|
|
||||||
if int(v.ID) >= len(lv.f.RegAlloc) {
|
|
||||||
// v has no allocated registers.
|
|
||||||
return mask
|
|
||||||
}
|
|
||||||
loc := lv.f.RegAlloc[v.ID]
|
|
||||||
if loc == nil {
|
|
||||||
// v has no allocated registers.
|
|
||||||
return mask
|
|
||||||
}
|
|
||||||
if v.Op == ssa.OpGetG {
|
|
||||||
// GetG represents the G register, which is a
|
|
||||||
// pointer, but not a valid GC register. The
|
|
||||||
// current G is always reachable, so it's okay
|
|
||||||
// to ignore this register.
|
|
||||||
return mask
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect registers and types from v's location.
|
|
||||||
var regs [2]*ssa.Register
|
|
||||||
nreg := 0
|
|
||||||
switch loc := loc.(type) {
|
|
||||||
case ssa.LocalSlot:
|
|
||||||
return mask
|
|
||||||
case *ssa.Register:
|
|
||||||
if ptrOnly && !v.Type.HasPointers() {
|
|
||||||
return mask
|
|
||||||
}
|
|
||||||
regs[0] = loc
|
|
||||||
nreg = 1
|
|
||||||
case ssa.LocPair:
|
|
||||||
// The value will have TTUPLE type, and the
|
|
||||||
// children are nil or *ssa.Register.
|
|
||||||
if v.Type.Etype != types.TTUPLE {
|
|
||||||
v.Fatalf("location pair %s has non-tuple type %v", loc, v.Type)
|
|
||||||
}
|
|
||||||
for i, loc1 := range &loc {
|
|
||||||
if loc1 == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ptrOnly && !v.Type.FieldType(i).HasPointers() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
regs[nreg] = loc1.(*ssa.Register)
|
|
||||||
nreg++
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
v.Fatalf("weird RegAlloc location: %s (%T)", loc, loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add register locations to vars.
|
|
||||||
for _, reg := range regs[:nreg] {
|
|
||||||
if reg.GCNum() == -1 {
|
|
||||||
if ptrOnly {
|
|
||||||
v.Fatalf("pointer in non-pointer register %v", reg)
|
|
||||||
} else {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mask |= 1 << uint(reg.GCNum())
|
|
||||||
}
|
|
||||||
return mask
|
|
||||||
}
|
|
||||||
|
|
||||||
// v clobbers all registers it writes to (whether or not the
|
|
||||||
// write is pointer-typed).
|
|
||||||
kill = addLocs(0, v, false)
|
|
||||||
for _, arg := range v.Args {
|
|
||||||
// v uses all registers is reads from, but we only
|
|
||||||
// care about marking those containing pointers.
|
|
||||||
uevar = addLocs(uevar, arg, true)
|
|
||||||
}
|
|
||||||
return uevar, kill
|
|
||||||
}
|
|
||||||
|
|
||||||
type liveRegMask uint32 // only if !go115ReduceLiveness
|
|
||||||
|
|
||||||
func (m liveRegMask) niceString(config *ssa.Config) string {
|
|
||||||
if m == 0 {
|
|
||||||
return "<none>"
|
|
||||||
}
|
|
||||||
str := ""
|
|
||||||
for i, reg := range config.GCRegMap {
|
|
||||||
if m&(1<<uint(i)) != 0 {
|
|
||||||
if str != "" {
|
|
||||||
str += ","
|
|
||||||
}
|
|
||||||
str += reg.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
type livenessFuncCache struct {
|
type livenessFuncCache struct {
|
||||||
be []BlockEffects
|
be []BlockEffects
|
||||||
livenessMap LivenessMap
|
livenessMap LivenessMap
|
||||||
|
|
@ -519,8 +361,6 @@ func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkpt
|
||||||
vars: vars,
|
vars: vars,
|
||||||
idx: idx,
|
idx: idx,
|
||||||
stkptrsize: stkptrsize,
|
stkptrsize: stkptrsize,
|
||||||
|
|
||||||
regMapSet: make(map[liveRegMask]int),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Significant sources of allocation are kept in the ssa.Cache
|
// Significant sources of allocation are kept in the ssa.Cache
|
||||||
|
|
@ -533,7 +373,7 @@ func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkpt
|
||||||
if cap(lc.be) >= f.NumBlocks() {
|
if cap(lc.be) >= f.NumBlocks() {
|
||||||
lv.be = lc.be[:f.NumBlocks()]
|
lv.be = lc.be[:f.NumBlocks()]
|
||||||
}
|
}
|
||||||
lv.livenessMap = LivenessMap{vals: lc.livenessMap.vals, deferreturn: LivenessInvalid}
|
lv.livenessMap = LivenessMap{vals: lc.livenessMap.vals, deferreturn: LivenessDontCare}
|
||||||
lc.livenessMap.vals = nil
|
lc.livenessMap.vals = nil
|
||||||
}
|
}
|
||||||
if lv.be == nil {
|
if lv.be == nil {
|
||||||
|
|
@ -546,10 +386,10 @@ func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkpt
|
||||||
for _, b := range f.Blocks {
|
for _, b := range f.Blocks {
|
||||||
be := lv.blockEffects(b)
|
be := lv.blockEffects(b)
|
||||||
|
|
||||||
be.uevar = varRegVec{vars: bulk.next()}
|
be.uevar = bulk.next()
|
||||||
be.varkill = varRegVec{vars: bulk.next()}
|
be.varkill = bulk.next()
|
||||||
be.livein = varRegVec{vars: bulk.next()}
|
be.livein = bulk.next()
|
||||||
be.liveout = varRegVec{vars: bulk.next()}
|
be.liveout = bulk.next()
|
||||||
}
|
}
|
||||||
lv.livenessMap.reset()
|
lv.livenessMap.reset()
|
||||||
|
|
||||||
|
|
@ -637,20 +477,6 @@ func onebitwalktype1(t *types.Type, off int64, bv bvec) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// usedRegs returns the maximum width of the live register map.
|
|
||||||
func (lv *Liveness) usedRegs() int32 {
|
|
||||||
var any liveRegMask
|
|
||||||
for _, live := range lv.regMaps {
|
|
||||||
any |= live
|
|
||||||
}
|
|
||||||
i := int32(0)
|
|
||||||
for any != 0 {
|
|
||||||
any >>= 1
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates live pointer value maps for arguments and local variables. The
|
// Generates live pointer value maps for arguments and local variables. The
|
||||||
// this argument and the in arguments are always assumed live. The vars
|
// this argument and the in arguments are always assumed live. The vars
|
||||||
// argument is a slice of *Nodes.
|
// argument is a slice of *Nodes.
|
||||||
|
|
@ -851,10 +677,6 @@ func (lv *Liveness) markUnsafePoints() {
|
||||||
// particular, call Values can have a stack map in case the callee
|
// particular, call Values can have a stack map in case the callee
|
||||||
// grows the stack, but not themselves be a safe-point.
|
// grows the stack, but not themselves be a safe-point.
|
||||||
func (lv *Liveness) hasStackMap(v *ssa.Value) bool {
|
func (lv *Liveness) hasStackMap(v *ssa.Value) bool {
|
||||||
// The runtime only has safe-points in function prologues, so
|
|
||||||
// we only need stack maps at call sites. go:nosplit functions
|
|
||||||
// are similar.
|
|
||||||
if go115ReduceLiveness || compiling_runtime || lv.f.NoSplit {
|
|
||||||
if !v.Op.IsCall() {
|
if !v.Op.IsCall() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -865,17 +687,6 @@ func (lv *Liveness) hasStackMap(v *ssa.Value) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
|
||||||
|
|
||||||
switch v.Op {
|
|
||||||
case ssa.OpInitMem, ssa.OpArg, ssa.OpSP, ssa.OpSB,
|
|
||||||
ssa.OpSelect0, ssa.OpSelect1, ssa.OpGetG,
|
|
||||||
ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive,
|
|
||||||
ssa.OpPhi:
|
|
||||||
// These don't produce code (see genssa).
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return !lv.unsafePoints.Get(int32(v.ID))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the sets for solving the live variables. Visits all the
|
// Initializes the sets for solving the live variables. Visits all the
|
||||||
|
|
@ -891,17 +702,13 @@ func (lv *Liveness) prologue() {
|
||||||
// effects with the each prog effects.
|
// effects with the each prog effects.
|
||||||
for j := len(b.Values) - 1; j >= 0; j-- {
|
for j := len(b.Values) - 1; j >= 0; j-- {
|
||||||
pos, e := lv.valueEffects(b.Values[j])
|
pos, e := lv.valueEffects(b.Values[j])
|
||||||
regUevar, regKill := lv.regEffects(b.Values[j])
|
|
||||||
if e&varkill != 0 {
|
if e&varkill != 0 {
|
||||||
be.varkill.vars.Set(pos)
|
be.varkill.Set(pos)
|
||||||
be.uevar.vars.Unset(pos)
|
be.uevar.Unset(pos)
|
||||||
}
|
}
|
||||||
be.varkill.regs |= regKill
|
|
||||||
be.uevar.regs &^= regKill
|
|
||||||
if e&uevar != 0 {
|
if e&uevar != 0 {
|
||||||
be.uevar.vars.Set(pos)
|
be.uevar.Set(pos)
|
||||||
}
|
}
|
||||||
be.uevar.regs |= regUevar
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -911,8 +718,8 @@ func (lv *Liveness) solve() {
|
||||||
// These temporary bitvectors exist to avoid successive allocations and
|
// These temporary bitvectors exist to avoid successive allocations and
|
||||||
// frees within the loop.
|
// frees within the loop.
|
||||||
nvars := int32(len(lv.vars))
|
nvars := int32(len(lv.vars))
|
||||||
newlivein := varRegVec{vars: bvalloc(nvars)}
|
newlivein := bvalloc(nvars)
|
||||||
newliveout := varRegVec{vars: bvalloc(nvars)}
|
newliveout := bvalloc(nvars)
|
||||||
|
|
||||||
// Walk blocks in postorder ordering. This improves convergence.
|
// Walk blocks in postorder ordering. This improves convergence.
|
||||||
po := lv.f.Postorder()
|
po := lv.f.Postorder()
|
||||||
|
|
@ -930,11 +737,11 @@ func (lv *Liveness) solve() {
|
||||||
switch b.Kind {
|
switch b.Kind {
|
||||||
case ssa.BlockRet:
|
case ssa.BlockRet:
|
||||||
for _, pos := range lv.cache.retuevar {
|
for _, pos := range lv.cache.retuevar {
|
||||||
newliveout.vars.Set(pos)
|
newliveout.Set(pos)
|
||||||
}
|
}
|
||||||
case ssa.BlockRetJmp:
|
case ssa.BlockRetJmp:
|
||||||
for _, pos := range lv.cache.tailuevar {
|
for _, pos := range lv.cache.tailuevar {
|
||||||
newliveout.vars.Set(pos)
|
newliveout.Set(pos)
|
||||||
}
|
}
|
||||||
case ssa.BlockExit:
|
case ssa.BlockExit:
|
||||||
// panic exit - nothing to do
|
// panic exit - nothing to do
|
||||||
|
|
@ -969,7 +776,7 @@ func (lv *Liveness) solve() {
|
||||||
// variables at each safe point locations.
|
// variables at each safe point locations.
|
||||||
func (lv *Liveness) epilogue() {
|
func (lv *Liveness) epilogue() {
|
||||||
nvars := int32(len(lv.vars))
|
nvars := int32(len(lv.vars))
|
||||||
liveout := varRegVec{vars: bvalloc(nvars)}
|
liveout := bvalloc(nvars)
|
||||||
livedefer := bvalloc(nvars) // always-live variables
|
livedefer := bvalloc(nvars) // always-live variables
|
||||||
|
|
||||||
// If there is a defer (that could recover), then all output
|
// If there is a defer (that could recover), then all output
|
||||||
|
|
@ -1025,12 +832,11 @@ func (lv *Liveness) epilogue() {
|
||||||
{
|
{
|
||||||
// Reserve an entry for function entry.
|
// Reserve an entry for function entry.
|
||||||
live := bvalloc(nvars)
|
live := bvalloc(nvars)
|
||||||
lv.livevars = append(lv.livevars, varRegVec{vars: live})
|
lv.livevars = append(lv.livevars, live)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, b := range lv.f.Blocks {
|
for _, b := range lv.f.Blocks {
|
||||||
be := lv.blockEffects(b)
|
be := lv.blockEffects(b)
|
||||||
firstBitmapIndex := len(lv.livevars)
|
|
||||||
|
|
||||||
// Walk forward through the basic block instructions and
|
// Walk forward through the basic block instructions and
|
||||||
// allocate liveness maps for those instructions that need them.
|
// allocate liveness maps for those instructions that need them.
|
||||||
|
|
@ -1040,7 +846,7 @@ func (lv *Liveness) epilogue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
live := bvalloc(nvars)
|
live := bvalloc(nvars)
|
||||||
lv.livevars = append(lv.livevars, varRegVec{vars: live})
|
lv.livevars = append(lv.livevars, live)
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk backward, construct maps at each safe point
|
// walk backward, construct maps at each safe point
|
||||||
|
|
@ -1056,21 +862,18 @@ func (lv *Liveness) epilogue() {
|
||||||
|
|
||||||
live := &lv.livevars[index]
|
live := &lv.livevars[index]
|
||||||
live.Or(*live, liveout)
|
live.Or(*live, liveout)
|
||||||
live.vars.Or(live.vars, livedefer) // only for non-entry safe points
|
live.Or(*live, livedefer) // only for non-entry safe points
|
||||||
index--
|
index--
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update liveness information.
|
// Update liveness information.
|
||||||
pos, e := lv.valueEffects(v)
|
pos, e := lv.valueEffects(v)
|
||||||
regUevar, regKill := lv.regEffects(v)
|
|
||||||
if e&varkill != 0 {
|
if e&varkill != 0 {
|
||||||
liveout.vars.Unset(pos)
|
liveout.Unset(pos)
|
||||||
}
|
}
|
||||||
liveout.regs &^= regKill
|
|
||||||
if e&uevar != 0 {
|
if e&uevar != 0 {
|
||||||
liveout.vars.Set(pos)
|
liveout.Set(pos)
|
||||||
}
|
}
|
||||||
liveout.regs |= regUevar
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if b == lv.f.Entry {
|
if b == lv.f.Entry {
|
||||||
|
|
@ -1080,7 +883,7 @@ func (lv *Liveness) epilogue() {
|
||||||
|
|
||||||
// Check to make sure only input variables are live.
|
// Check to make sure only input variables are live.
|
||||||
for i, n := range lv.vars {
|
for i, n := range lv.vars {
|
||||||
if !liveout.vars.Get(int32(i)) {
|
if !liveout.Get(int32(i)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.Class() == PPARAM {
|
if n.Class() == PPARAM {
|
||||||
|
|
@ -1094,32 +897,16 @@ func (lv *Liveness) epilogue() {
|
||||||
live.Or(*live, liveout)
|
live.Or(*live, liveout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that no registers are live across calls.
|
|
||||||
// For closure calls, the CALLclosure is the last use
|
|
||||||
// of the context register, so it's dead after the call.
|
|
||||||
index = int32(firstBitmapIndex)
|
|
||||||
for _, v := range b.Values {
|
|
||||||
if lv.hasStackMap(v) {
|
|
||||||
live := lv.livevars[index]
|
|
||||||
if v.Op.IsCall() && live.regs != 0 {
|
|
||||||
lv.printDebug()
|
|
||||||
v.Fatalf("%v register %s recorded as live at call", lv.fn.Func.Nname, live.regs.niceString(lv.f.Config))
|
|
||||||
}
|
|
||||||
index++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The liveness maps for this block are now complete. Compact them.
|
// The liveness maps for this block are now complete. Compact them.
|
||||||
lv.compact(b)
|
lv.compact(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have an open-coded deferreturn call, make a liveness map for it.
|
// If we have an open-coded deferreturn call, make a liveness map for it.
|
||||||
if lv.fn.Func.OpenCodedDeferDisallowed() {
|
if lv.fn.Func.OpenCodedDeferDisallowed() {
|
||||||
lv.livenessMap.deferreturn = LivenessInvalid
|
lv.livenessMap.deferreturn = LivenessDontCare
|
||||||
} else {
|
} else {
|
||||||
lv.livenessMap.deferreturn = LivenessIndex{
|
lv.livenessMap.deferreturn = LivenessIndex{
|
||||||
stackMapIndex: lv.stackMapSet.add(livedefer),
|
stackMapIndex: lv.stackMapSet.add(livedefer),
|
||||||
regMapIndex: 0, // entry regMap, containing no live registers
|
|
||||||
isUnsafePoint: false,
|
isUnsafePoint: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1136,20 +923,10 @@ func (lv *Liveness) epilogue() {
|
||||||
lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Func.Nname, n)
|
lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Func.Nname, n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !go115ReduceLiveness {
|
|
||||||
// Check that no registers are live at function entry.
|
|
||||||
// The context register, if any, comes from a
|
|
||||||
// LoweredGetClosurePtr operation first thing in the function,
|
|
||||||
// so it doesn't appear live at entry.
|
|
||||||
if regs := lv.regMaps[0]; regs != 0 {
|
|
||||||
lv.printDebug()
|
|
||||||
lv.f.Fatalf("%v register %s recorded as live on entry", lv.fn.Func.Nname, regs.niceString(lv.f.Config))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compact coalesces identical bitmaps from lv.livevars into the sets
|
// Compact coalesces identical bitmaps from lv.livevars into the sets
|
||||||
// lv.stackMapSet and lv.regMaps.
|
// lv.stackMapSet.
|
||||||
//
|
//
|
||||||
// Compact clears lv.livevars.
|
// Compact clears lv.livevars.
|
||||||
//
|
//
|
||||||
|
|
@ -1165,45 +942,23 @@ func (lv *Liveness) epilogue() {
|
||||||
// PCDATA tables cost about 100k. So for now we keep using a single index for
|
// PCDATA tables cost about 100k. So for now we keep using a single index for
|
||||||
// both bitmap lists.
|
// both bitmap lists.
|
||||||
func (lv *Liveness) compact(b *ssa.Block) {
|
func (lv *Liveness) compact(b *ssa.Block) {
|
||||||
add := func(live varRegVec, isUnsafePoint bool) LivenessIndex { // only if !go115ReduceLiveness
|
|
||||||
// Deduplicate the stack map.
|
|
||||||
stackIndex := lv.stackMapSet.add(live.vars)
|
|
||||||
// Deduplicate the register map.
|
|
||||||
regIndex, ok := lv.regMapSet[live.regs]
|
|
||||||
if !ok {
|
|
||||||
regIndex = len(lv.regMapSet)
|
|
||||||
lv.regMapSet[live.regs] = regIndex
|
|
||||||
lv.regMaps = append(lv.regMaps, live.regs)
|
|
||||||
}
|
|
||||||
return LivenessIndex{stackIndex, regIndex, isUnsafePoint}
|
|
||||||
}
|
|
||||||
pos := 0
|
pos := 0
|
||||||
if b == lv.f.Entry {
|
if b == lv.f.Entry {
|
||||||
// Handle entry stack map.
|
// Handle entry stack map.
|
||||||
if !go115ReduceLiveness {
|
lv.stackMapSet.add(lv.livevars[0])
|
||||||
add(lv.livevars[0], false)
|
|
||||||
} else {
|
|
||||||
lv.stackMapSet.add(lv.livevars[0].vars)
|
|
||||||
}
|
|
||||||
pos++
|
pos++
|
||||||
}
|
}
|
||||||
for _, v := range b.Values {
|
for _, v := range b.Values {
|
||||||
if go115ReduceLiveness {
|
|
||||||
hasStackMap := lv.hasStackMap(v)
|
hasStackMap := lv.hasStackMap(v)
|
||||||
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
|
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
|
||||||
idx := LivenessIndex{StackMapDontCare, StackMapDontCare, isUnsafePoint}
|
idx := LivenessIndex{StackMapDontCare, isUnsafePoint}
|
||||||
if hasStackMap {
|
if hasStackMap {
|
||||||
idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos].vars)
|
idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos])
|
||||||
pos++
|
pos++
|
||||||
}
|
}
|
||||||
if hasStackMap || isUnsafePoint {
|
if hasStackMap || isUnsafePoint {
|
||||||
lv.livenessMap.set(v, idx)
|
lv.livenessMap.set(v, idx)
|
||||||
}
|
}
|
||||||
} else if lv.hasStackMap(v) {
|
|
||||||
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
|
|
||||||
lv.livenessMap.set(v, add(lv.livevars[pos], isUnsafePoint))
|
|
||||||
pos++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset livevars.
|
// Reset livevars.
|
||||||
|
|
@ -1250,8 +1005,8 @@ func (lv *Liveness) showlive(v *ssa.Value, live bvec) {
|
||||||
Warnl(pos, s)
|
Warnl(pos, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lv *Liveness) printbvec(printed bool, name string, live varRegVec) bool {
|
func (lv *Liveness) printbvec(printed bool, name string, live bvec) bool {
|
||||||
if live.vars.IsEmpty() && live.regs == 0 {
|
if live.IsEmpty() {
|
||||||
return printed
|
return printed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1264,19 +1019,18 @@ func (lv *Liveness) printbvec(printed bool, name string, live varRegVec) bool {
|
||||||
|
|
||||||
comma := ""
|
comma := ""
|
||||||
for i, n := range lv.vars {
|
for i, n := range lv.vars {
|
||||||
if !live.vars.Get(int32(i)) {
|
if !live.Get(int32(i)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("%s%s", comma, n.Sym.Name)
|
fmt.Printf("%s%s", comma, n.Sym.Name)
|
||||||
comma = ","
|
comma = ","
|
||||||
}
|
}
|
||||||
fmt.Printf("%s%s", comma, live.regs.niceString(lv.f.Config))
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// printeffect is like printbvec, but for valueEffects and regEffects.
|
// printeffect is like printbvec, but for valueEffects.
|
||||||
func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool, regMask liveRegMask) bool {
|
func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool) bool {
|
||||||
if !x && regMask == 0 {
|
if !x {
|
||||||
return printed
|
return printed
|
||||||
}
|
}
|
||||||
if !printed {
|
if !printed {
|
||||||
|
|
@ -1288,15 +1042,7 @@ func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool, re
|
||||||
if x {
|
if x {
|
||||||
fmt.Printf("%s", lv.vars[pos].Sym.Name)
|
fmt.Printf("%s", lv.vars[pos].Sym.Name)
|
||||||
}
|
}
|
||||||
for j, reg := range lv.f.Config.GCRegMap {
|
|
||||||
if regMask&(1<<uint(j)) != 0 {
|
|
||||||
if x {
|
|
||||||
fmt.Printf(",")
|
|
||||||
}
|
|
||||||
x = true
|
|
||||||
fmt.Printf("%v", reg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1364,15 +1110,14 @@ func (lv *Liveness) printDebug() {
|
||||||
pcdata := lv.livenessMap.Get(v)
|
pcdata := lv.livenessMap.Get(v)
|
||||||
|
|
||||||
pos, effect := lv.valueEffects(v)
|
pos, effect := lv.valueEffects(v)
|
||||||
regUevar, regKill := lv.regEffects(v)
|
|
||||||
printed = false
|
printed = false
|
||||||
printed = lv.printeffect(printed, "uevar", pos, effect&uevar != 0, regUevar)
|
printed = lv.printeffect(printed, "uevar", pos, effect&uevar != 0)
|
||||||
printed = lv.printeffect(printed, "varkill", pos, effect&varkill != 0, regKill)
|
printed = lv.printeffect(printed, "varkill", pos, effect&varkill != 0)
|
||||||
if printed {
|
if printed {
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if pcdata.StackMapValid() || pcdata.RegMapValid() {
|
if pcdata.StackMapValid() {
|
||||||
fmt.Printf("\tlive=")
|
fmt.Printf("\tlive=")
|
||||||
printed = false
|
printed = false
|
||||||
if pcdata.StackMapValid() {
|
if pcdata.StackMapValid() {
|
||||||
|
|
@ -1388,16 +1133,6 @@ func (lv *Liveness) printDebug() {
|
||||||
printed = true
|
printed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pcdata.RegMapValid() { // only if !go115ReduceLiveness
|
|
||||||
regLive := lv.regMaps[pcdata.regMapIndex]
|
|
||||||
if regLive != 0 {
|
|
||||||
if printed {
|
|
||||||
fmt.Printf(",")
|
|
||||||
}
|
|
||||||
fmt.Printf("%s", regLive.niceString(lv.f.Config))
|
|
||||||
printed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Printf("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1423,7 +1158,7 @@ func (lv *Liveness) printDebug() {
|
||||||
// first word dumped is the total number of bitmaps. The second word is the
|
// first word dumped is the total number of bitmaps. The second word is the
|
||||||
// length of the bitmaps. All bitmaps are assumed to be of equal length. The
|
// length of the bitmaps. All bitmaps are assumed to be of equal length. The
|
||||||
// remaining bytes are the raw bitmaps.
|
// remaining bytes are the raw bitmaps.
|
||||||
func (lv *Liveness) emit() (argsSym, liveSym, regsSym *obj.LSym) {
|
func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) {
|
||||||
// Size args bitmaps to be just large enough to hold the largest pointer.
|
// Size args bitmaps to be just large enough to hold the largest pointer.
|
||||||
// First, find the largest Xoffset node we care about.
|
// First, find the largest Xoffset node we care about.
|
||||||
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
|
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
|
||||||
|
|
@ -1452,7 +1187,7 @@ func (lv *Liveness) emit() (argsSym, liveSym, regsSym *obj.LSym) {
|
||||||
maxLocals := lv.stkptrsize
|
maxLocals := lv.stkptrsize
|
||||||
|
|
||||||
// Temporary symbols for encoding bitmaps.
|
// Temporary symbols for encoding bitmaps.
|
||||||
var argsSymTmp, liveSymTmp, regsSymTmp obj.LSym
|
var argsSymTmp, liveSymTmp obj.LSym
|
||||||
|
|
||||||
args := bvalloc(int32(maxArgs / int64(Widthptr)))
|
args := bvalloc(int32(maxArgs / int64(Widthptr)))
|
||||||
aoff := duint32(&argsSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
|
aoff := duint32(&argsSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
|
||||||
|
|
@ -1472,24 +1207,6 @@ func (lv *Liveness) emit() (argsSym, liveSym, regsSym *obj.LSym) {
|
||||||
loff = dbvec(&liveSymTmp, loff, locals)
|
loff = dbvec(&liveSymTmp, loff, locals)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !go115ReduceLiveness {
|
|
||||||
regs := bvalloc(lv.usedRegs())
|
|
||||||
roff := duint32(®sSymTmp, 0, uint32(len(lv.regMaps))) // number of bitmaps
|
|
||||||
roff = duint32(®sSymTmp, roff, uint32(regs.n)) // number of bits in each bitmap
|
|
||||||
if regs.n > 32 {
|
|
||||||
// Our uint32 conversion below won't work.
|
|
||||||
Fatalf("GP registers overflow uint32")
|
|
||||||
}
|
|
||||||
|
|
||||||
if regs.n > 0 {
|
|
||||||
for _, live := range lv.regMaps {
|
|
||||||
regs.Clear()
|
|
||||||
regs.b[0] = uint32(live)
|
|
||||||
roff = dbvec(®sSymTmp, roff, regs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Give these LSyms content-addressable names,
|
// Give these LSyms content-addressable names,
|
||||||
// so that they can be de-duplicated.
|
// so that they can be de-duplicated.
|
||||||
// This provides significant binary size savings.
|
// This provides significant binary size savings.
|
||||||
|
|
@ -1502,11 +1219,7 @@ func (lv *Liveness) emit() (argsSym, liveSym, regsSym *obj.LSym) {
|
||||||
lsym.Set(obj.AttrContentAddressable, true)
|
lsym.Set(obj.AttrContentAddressable, true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if !go115ReduceLiveness {
|
return makeSym(&argsSymTmp), makeSym(&liveSymTmp)
|
||||||
return makeSym(&argsSymTmp), makeSym(&liveSymTmp), makeSym(®sSymTmp)
|
|
||||||
}
|
|
||||||
// TODO(go115ReduceLiveness): Remove regsSym result
|
|
||||||
return makeSym(&argsSymTmp), makeSym(&liveSymTmp), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entry pointer for liveness analysis. Solves for the liveness of
|
// Entry pointer for liveness analysis. Solves for the liveness of
|
||||||
|
|
@ -1553,7 +1266,7 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
|
||||||
// Emit the live pointer map data structures
|
// Emit the live pointer map data structures
|
||||||
ls := e.curfn.Func.lsym
|
ls := e.curfn.Func.lsym
|
||||||
fninfo := ls.Func()
|
fninfo := ls.Func()
|
||||||
fninfo.GCArgs, fninfo.GCLocals, fninfo.GCRegs = lv.emit()
|
fninfo.GCArgs, fninfo.GCLocals = lv.emit()
|
||||||
|
|
||||||
p := pp.Prog(obj.AFUNCDATA)
|
p := pp.Prog(obj.AFUNCDATA)
|
||||||
Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
|
Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
|
||||||
|
|
@ -1567,14 +1280,6 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
|
||||||
p.To.Name = obj.NAME_EXTERN
|
p.To.Name = obj.NAME_EXTERN
|
||||||
p.To.Sym = fninfo.GCLocals
|
p.To.Sym = fninfo.GCLocals
|
||||||
|
|
||||||
if !go115ReduceLiveness {
|
|
||||||
p = pp.Prog(obj.AFUNCDATA)
|
|
||||||
Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
|
|
||||||
p.To.Type = obj.TYPE_MEM
|
|
||||||
p.To.Name = obj.NAME_EXTERN
|
|
||||||
p.To.Sym = fninfo.GCRegs
|
|
||||||
}
|
|
||||||
|
|
||||||
return lv.livenessMap
|
return lv.livenessMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -466,7 +466,7 @@ func walkrange(n *Node) *Node {
|
||||||
//
|
//
|
||||||
// where == for keys of map m is reflexive.
|
// where == for keys of map m is reflexive.
|
||||||
func isMapClear(n *Node) bool {
|
func isMapClear(n *Node) bool {
|
||||||
if Debug['N'] != 0 || instrumenting {
|
if Debug.N != 0 || instrumenting {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -533,7 +533,7 @@ func mapClear(m *Node) *Node {
|
||||||
//
|
//
|
||||||
// Parameters are as in walkrange: "for v1, v2 = range a".
|
// Parameters are as in walkrange: "for v1, v2 = range a".
|
||||||
func arrayClear(n, v1, v2, a *Node) bool {
|
func arrayClear(n, v1, v2, a *Node) bool {
|
||||||
if Debug['N'] != 0 || instrumenting {
|
if Debug.N != 0 || instrumenting {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1275,9 +1275,8 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||||
}
|
}
|
||||||
ot = dgopkgpath(lsym, ot, tpkg)
|
ot = dgopkgpath(lsym, ot, tpkg)
|
||||||
|
|
||||||
xcount := sort.Search(n, func(i int) bool { return !types.IsExported(m[i].name.Name) })
|
|
||||||
ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
|
ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
|
||||||
ot = duintptr(lsym, ot, uint64(xcount))
|
ot = duintptr(lsym, ot, uint64(n))
|
||||||
ot = duintptr(lsym, ot, uint64(n))
|
ot = duintptr(lsym, ot, uint64(n))
|
||||||
dataAdd := imethodSize() * n
|
dataAdd := imethodSize() * n
|
||||||
ot = dextratype(lsym, ot, t, dataAdd)
|
ot = dextratype(lsym, ot, t, dataAdd)
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,19 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
|
||||||
|
|
||||||
inspectList(n.Nbody, func(n *Node) bool {
|
inspectList(n.Nbody, func(n *Node) bool {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case OCALLFUNC, OCALLMETH:
|
case ONAME:
|
||||||
fn := asNode(n.Left.Type.Nname())
|
if n.Class() == PFUNC {
|
||||||
|
if n.isMethodExpression() {
|
||||||
|
n = asNode(n.Type.Nname())
|
||||||
|
}
|
||||||
|
if n != nil && n.Name.Defn != nil {
|
||||||
|
if m := v.visit(n.Name.Defn); m < min {
|
||||||
|
min = m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ODOTMETH:
|
||||||
|
fn := asNode(n.Type.Nname())
|
||||||
if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
|
if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
|
||||||
if m := v.visit(fn.Name.Defn); m < min {
|
if m := v.visit(fn.Name.Defn); m < min {
|
||||||
min = m
|
min = m
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func (s *InitSchedule) append(n *Node) {
|
||||||
// staticInit adds an initialization statement n to the schedule.
|
// staticInit adds an initialization statement n to the schedule.
|
||||||
func (s *InitSchedule) staticInit(n *Node) {
|
func (s *InitSchedule) staticInit(n *Node) {
|
||||||
if !s.tryStaticInit(n) {
|
if !s.tryStaticInit(n) {
|
||||||
if Debug['%'] != 0 {
|
if Debug.P != 0 {
|
||||||
Dump("nonstatic", n)
|
Dump("nonstatic", n)
|
||||||
}
|
}
|
||||||
s.append(n)
|
s.append(n)
|
||||||
|
|
@ -375,11 +375,6 @@ func readonlystaticname(t *types.Type) *Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func isLiteral(n *Node) bool {
|
|
||||||
// Treat nils as zeros rather than literals.
|
|
||||||
return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Node) isSimpleName() bool {
|
func (n *Node) isSimpleName() bool {
|
||||||
return n.Op == ONAME && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
|
return n.Op == ONAME && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
|
||||||
}
|
}
|
||||||
|
|
@ -404,7 +399,7 @@ const (
|
||||||
func getdyn(n *Node, top bool) initGenType {
|
func getdyn(n *Node, top bool) initGenType {
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
default:
|
default:
|
||||||
if isLiteral(n) {
|
if n.isGoConst() {
|
||||||
return initConst
|
return initConst
|
||||||
}
|
}
|
||||||
return initDynamic
|
return initDynamic
|
||||||
|
|
@ -559,7 +554,7 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
islit := isLiteral(value)
|
islit := value.isGoConst()
|
||||||
if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
|
if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -732,7 +727,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if vstat != nil && isLiteral(value) { // already set by copy from static value
|
if vstat != nil && value.isGoConst() { // already set by copy from static value
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func initssaconfig() {
|
||||||
_ = types.NewPtr(types.Types[TINT64]) // *int64
|
_ = types.NewPtr(types.Types[TINT64]) // *int64
|
||||||
_ = types.NewPtr(types.Errortype) // *error
|
_ = types.NewPtr(types.Errortype) // *error
|
||||||
types.NewPtrCacheEnabled = false
|
types.NewPtrCacheEnabled = false
|
||||||
ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug['N'] == 0)
|
ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug.N == 0)
|
||||||
ssaConfig.SoftFloat = thearch.SoftFloat
|
ssaConfig.SoftFloat = thearch.SoftFloat
|
||||||
ssaConfig.Race = flag_race
|
ssaConfig.Race = flag_race
|
||||||
ssaCaches = make([]ssa.Cache, nBackendWorkers)
|
ssaCaches = make([]ssa.Cache, nBackendWorkers)
|
||||||
|
|
@ -72,9 +72,9 @@ func initssaconfig() {
|
||||||
deferproc = sysfunc("deferproc")
|
deferproc = sysfunc("deferproc")
|
||||||
deferprocStack = sysfunc("deferprocStack")
|
deferprocStack = sysfunc("deferprocStack")
|
||||||
Deferreturn = sysfunc("deferreturn")
|
Deferreturn = sysfunc("deferreturn")
|
||||||
Duffcopy = sysvar("duffcopy") // asm func with special ABI
|
Duffcopy = sysfunc("duffcopy")
|
||||||
Duffzero = sysvar("duffzero") // asm func with special ABI
|
Duffzero = sysfunc("duffzero")
|
||||||
gcWriteBarrier = sysvar("gcWriteBarrier") // asm func with special ABI
|
gcWriteBarrier = sysfunc("gcWriteBarrier")
|
||||||
goschedguarded = sysfunc("goschedguarded")
|
goschedguarded = sysfunc("goschedguarded")
|
||||||
growslice = sysfunc("growslice")
|
growslice = sysfunc("growslice")
|
||||||
msanread = sysfunc("msanread")
|
msanread = sysfunc("msanread")
|
||||||
|
|
@ -105,51 +105,51 @@ func initssaconfig() {
|
||||||
// asm funcs with special ABI
|
// asm funcs with special ABI
|
||||||
if thearch.LinkArch.Name == "amd64" {
|
if thearch.LinkArch.Name == "amd64" {
|
||||||
GCWriteBarrierReg = map[int16]*obj.LSym{
|
GCWriteBarrierReg = map[int16]*obj.LSym{
|
||||||
x86.REG_AX: sysvar("gcWriteBarrier"),
|
x86.REG_AX: sysfunc("gcWriteBarrier"),
|
||||||
x86.REG_CX: sysvar("gcWriteBarrierCX"),
|
x86.REG_CX: sysfunc("gcWriteBarrierCX"),
|
||||||
x86.REG_DX: sysvar("gcWriteBarrierDX"),
|
x86.REG_DX: sysfunc("gcWriteBarrierDX"),
|
||||||
x86.REG_BX: sysvar("gcWriteBarrierBX"),
|
x86.REG_BX: sysfunc("gcWriteBarrierBX"),
|
||||||
x86.REG_BP: sysvar("gcWriteBarrierBP"),
|
x86.REG_BP: sysfunc("gcWriteBarrierBP"),
|
||||||
x86.REG_SI: sysvar("gcWriteBarrierSI"),
|
x86.REG_SI: sysfunc("gcWriteBarrierSI"),
|
||||||
x86.REG_R8: sysvar("gcWriteBarrierR8"),
|
x86.REG_R8: sysfunc("gcWriteBarrierR8"),
|
||||||
x86.REG_R9: sysvar("gcWriteBarrierR9"),
|
x86.REG_R9: sysfunc("gcWriteBarrierR9"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if thearch.LinkArch.Family == sys.Wasm {
|
if thearch.LinkArch.Family == sys.Wasm {
|
||||||
BoundsCheckFunc[ssa.BoundsIndex] = sysvar("goPanicIndex")
|
BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("goPanicIndex")
|
||||||
BoundsCheckFunc[ssa.BoundsIndexU] = sysvar("goPanicIndexU")
|
BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("goPanicIndexU")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceAlen] = sysvar("goPanicSliceAlen")
|
BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("goPanicSliceAlen")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysvar("goPanicSliceAlenU")
|
BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("goPanicSliceAlenU")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceAcap] = sysvar("goPanicSliceAcap")
|
BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("goPanicSliceAcap")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysvar("goPanicSliceAcapU")
|
BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("goPanicSliceAcapU")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceB] = sysvar("goPanicSliceB")
|
BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("goPanicSliceB")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceBU] = sysvar("goPanicSliceBU")
|
BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("goPanicSliceBU")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysvar("goPanicSlice3Alen")
|
BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("goPanicSlice3Alen")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysvar("goPanicSlice3AlenU")
|
BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("goPanicSlice3AlenU")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysvar("goPanicSlice3Acap")
|
BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("goPanicSlice3Acap")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysvar("goPanicSlice3AcapU")
|
BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("goPanicSlice3AcapU")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3B] = sysvar("goPanicSlice3B")
|
BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("goPanicSlice3B")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3BU] = sysvar("goPanicSlice3BU")
|
BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("goPanicSlice3BU")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3C] = sysvar("goPanicSlice3C")
|
BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("goPanicSlice3C")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3CU] = sysvar("goPanicSlice3CU")
|
BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("goPanicSlice3CU")
|
||||||
} else {
|
} else {
|
||||||
BoundsCheckFunc[ssa.BoundsIndex] = sysvar("panicIndex")
|
BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("panicIndex")
|
||||||
BoundsCheckFunc[ssa.BoundsIndexU] = sysvar("panicIndexU")
|
BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("panicIndexU")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceAlen] = sysvar("panicSliceAlen")
|
BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("panicSliceAlen")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysvar("panicSliceAlenU")
|
BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("panicSliceAlenU")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceAcap] = sysvar("panicSliceAcap")
|
BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("panicSliceAcap")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysvar("panicSliceAcapU")
|
BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("panicSliceAcapU")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceB] = sysvar("panicSliceB")
|
BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("panicSliceB")
|
||||||
BoundsCheckFunc[ssa.BoundsSliceBU] = sysvar("panicSliceBU")
|
BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("panicSliceBU")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysvar("panicSlice3Alen")
|
BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("panicSlice3Alen")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysvar("panicSlice3AlenU")
|
BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("panicSlice3AlenU")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysvar("panicSlice3Acap")
|
BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("panicSlice3Acap")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysvar("panicSlice3AcapU")
|
BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("panicSlice3AcapU")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3B] = sysvar("panicSlice3B")
|
BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("panicSlice3B")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3BU] = sysvar("panicSlice3BU")
|
BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("panicSlice3BU")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3C] = sysvar("panicSlice3C")
|
BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("panicSlice3C")
|
||||||
BoundsCheckFunc[ssa.BoundsSlice3CU] = sysvar("panicSlice3CU")
|
BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("panicSlice3CU")
|
||||||
}
|
}
|
||||||
if thearch.LinkArch.PtrSize == 4 {
|
if thearch.LinkArch.PtrSize == 4 {
|
||||||
ExtendCheckFunc[ssa.BoundsIndex] = sysvar("panicExtendIndex")
|
ExtendCheckFunc[ssa.BoundsIndex] = sysvar("panicExtendIndex")
|
||||||
|
|
@ -357,7 +357,7 @@ func buildssa(fn *Node, worker int) *ssa.Func {
|
||||||
s.fwdVars = map[*Node]*ssa.Value{}
|
s.fwdVars = map[*Node]*ssa.Value{}
|
||||||
s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
|
s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
|
||||||
|
|
||||||
s.hasOpenDefers = Debug['N'] == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
|
s.hasOpenDefers = Debug.N == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
|
||||||
switch {
|
switch {
|
||||||
case s.hasOpenDefers && (Ctxt.Flag_shared || Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386":
|
case s.hasOpenDefers && (Ctxt.Flag_shared || Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386":
|
||||||
// Don't support open-coded defers for 386 ONLY when using shared
|
// Don't support open-coded defers for 386 ONLY when using shared
|
||||||
|
|
@ -409,11 +409,17 @@ func buildssa(fn *Node, worker int) *ssa.Func {
|
||||||
|
|
||||||
// Generate addresses of local declarations
|
// Generate addresses of local declarations
|
||||||
s.decladdrs = map[*Node]*ssa.Value{}
|
s.decladdrs = map[*Node]*ssa.Value{}
|
||||||
|
var args []ssa.Param
|
||||||
|
var results []ssa.Param
|
||||||
for _, n := range fn.Func.Dcl {
|
for _, n := range fn.Func.Dcl {
|
||||||
switch n.Class() {
|
switch n.Class() {
|
||||||
case PPARAM, PPARAMOUT:
|
case PPARAM:
|
||||||
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
|
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
|
||||||
if n.Class() == PPARAMOUT && s.canSSA(n) {
|
args = append(args, ssa.Param{Type: n.Type, Offset: int32(n.Xoffset)})
|
||||||
|
case PPARAMOUT:
|
||||||
|
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
|
||||||
|
results = append(results, ssa.Param{Type: n.Type, Offset: int32(n.Xoffset)})
|
||||||
|
if s.canSSA(n) {
|
||||||
// Save ssa-able PPARAMOUT variables so we can
|
// Save ssa-able PPARAMOUT variables so we can
|
||||||
// store them back to the stack at the end of
|
// store them back to the stack at the end of
|
||||||
// the function.
|
// the function.
|
||||||
|
|
@ -741,7 +747,7 @@ func (s *state) pushLine(line src.XPos) {
|
||||||
// the frontend may emit node with line number missing,
|
// the frontend may emit node with line number missing,
|
||||||
// use the parent line number in this case.
|
// use the parent line number in this case.
|
||||||
line = s.peekPos()
|
line = s.peekPos()
|
||||||
if Debug['K'] != 0 {
|
if Debug.K != 0 {
|
||||||
Warn("buildssa: unknown position (line 0)")
|
Warn("buildssa: unknown position (line 0)")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1214,7 +1220,7 @@ func (s *state) stmt(n *Node) {
|
||||||
// Check whether we're writing the result of an append back to the same slice.
|
// Check whether we're writing the result of an append back to the same slice.
|
||||||
// If so, we handle it specially to avoid write barriers on the fast
|
// If so, we handle it specially to avoid write barriers on the fast
|
||||||
// (non-growth) path.
|
// (non-growth) path.
|
||||||
if !samesafeexpr(n.Left, rhs.List.First()) || Debug['N'] != 0 {
|
if !samesafeexpr(n.Left, rhs.List.First()) || Debug.N != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// If the slice can be SSA'd, it'll be on the stack,
|
// If the slice can be SSA'd, it'll be on the stack,
|
||||||
|
|
@ -2472,6 +2478,11 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||||
a := s.expr(n.Left)
|
a := s.expr(n.Left)
|
||||||
b := s.expr(n.Right)
|
b := s.expr(n.Right)
|
||||||
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
|
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
|
||||||
|
case OANDNOT:
|
||||||
|
a := s.expr(n.Left)
|
||||||
|
b := s.expr(n.Right)
|
||||||
|
b = s.newValue1(s.ssaOp(OBITNOT, b.Type), b.Type, b)
|
||||||
|
return s.newValue2(s.ssaOp(OAND, n.Type), a.Type, a, b)
|
||||||
case OLSH, ORSH:
|
case OLSH, ORSH:
|
||||||
a := s.expr(n.Left)
|
a := s.expr(n.Left)
|
||||||
b := s.expr(n.Right)
|
b := s.expr(n.Right)
|
||||||
|
|
@ -3389,6 +3400,13 @@ func init() {
|
||||||
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
|
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
|
||||||
},
|
},
|
||||||
sys.PPC64, sys.S390X)
|
sys.PPC64, sys.S390X)
|
||||||
|
addF("runtime/internal/atomic", "LoadAcq64",
|
||||||
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
|
v := s.newValue2(ssa.OpAtomicLoadAcq64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
|
||||||
|
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||||
|
return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
|
||||||
|
},
|
||||||
|
sys.PPC64)
|
||||||
addF("runtime/internal/atomic", "Loadp",
|
addF("runtime/internal/atomic", "Loadp",
|
||||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
|
v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
|
||||||
|
|
@ -3427,6 +3445,12 @@ func init() {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
sys.PPC64, sys.S390X)
|
sys.PPC64, sys.S390X)
|
||||||
|
addF("runtime/internal/atomic", "StoreRel64",
|
||||||
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
|
s.vars[&memVar] = s.newValue3(ssa.OpAtomicStoreRel64, types.TypeMem, args[0], args[1], s.mem())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
sys.PPC64)
|
||||||
|
|
||||||
addF("runtime/internal/atomic", "Xchg",
|
addF("runtime/internal/atomic", "Xchg",
|
||||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
|
|
@ -3434,14 +3458,64 @@ func init() {
|
||||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||||
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
|
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
|
||||||
},
|
},
|
||||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||||
addF("runtime/internal/atomic", "Xchg64",
|
addF("runtime/internal/atomic", "Xchg64",
|
||||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
v := s.newValue3(ssa.OpAtomicExchange64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
|
v := s.newValue3(ssa.OpAtomicExchange64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
|
||||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||||
return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
|
return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
|
||||||
},
|
},
|
||||||
sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||||
|
|
||||||
|
type atomicOpEmitter func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType)
|
||||||
|
|
||||||
|
makeAtomicGuardedIntrinsicARM64 := func(op0, op1 ssa.Op, typ, rtyp types.EType, emit atomicOpEmitter) intrinsicBuilder {
|
||||||
|
|
||||||
|
return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
|
// Target Atomic feature is identified by dynamic detection
|
||||||
|
addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), arm64HasATOMICS, s.sb)
|
||||||
|
v := s.load(types.Types[TBOOL], addr)
|
||||||
|
b := s.endBlock()
|
||||||
|
b.Kind = ssa.BlockIf
|
||||||
|
b.SetControl(v)
|
||||||
|
bTrue := s.f.NewBlock(ssa.BlockPlain)
|
||||||
|
bFalse := s.f.NewBlock(ssa.BlockPlain)
|
||||||
|
bEnd := s.f.NewBlock(ssa.BlockPlain)
|
||||||
|
b.AddEdgeTo(bTrue)
|
||||||
|
b.AddEdgeTo(bFalse)
|
||||||
|
b.Likely = ssa.BranchLikely
|
||||||
|
|
||||||
|
// We have atomic instructions - use it directly.
|
||||||
|
s.startBlock(bTrue)
|
||||||
|
emit(s, n, args, op1, typ)
|
||||||
|
s.endBlock().AddEdgeTo(bEnd)
|
||||||
|
|
||||||
|
// Use original instruction sequence.
|
||||||
|
s.startBlock(bFalse)
|
||||||
|
emit(s, n, args, op0, typ)
|
||||||
|
s.endBlock().AddEdgeTo(bEnd)
|
||||||
|
|
||||||
|
// Merge results.
|
||||||
|
s.startBlock(bEnd)
|
||||||
|
if rtyp == TNIL {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return s.variable(n, types.Types[rtyp])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
atomicXchgXaddEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
|
||||||
|
v := s.newValue3(op, types.NewTuple(types.Types[typ], types.TypeMem), args[0], args[1], s.mem())
|
||||||
|
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||||
|
s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[typ], v)
|
||||||
|
}
|
||||||
|
addF("runtime/internal/atomic", "Xchg",
|
||||||
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicExchange32, ssa.OpAtomicExchange32Variant, TUINT32, TUINT32, atomicXchgXaddEmitterARM64),
|
||||||
|
sys.ARM64)
|
||||||
|
addF("runtime/internal/atomic", "Xchg64",
|
||||||
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicExchange64, ssa.OpAtomicExchange64Variant, TUINT64, TUINT64, atomicXchgXaddEmitterARM64),
|
||||||
|
sys.ARM64)
|
||||||
|
|
||||||
addF("runtime/internal/atomic", "Xadd",
|
addF("runtime/internal/atomic", "Xadd",
|
||||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
|
|
@ -3458,46 +3532,11 @@ func init() {
|
||||||
},
|
},
|
||||||
sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||||
|
|
||||||
makeXaddARM64 := func(op0 ssa.Op, op1 ssa.Op, ty types.EType) func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
|
||||||
return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
|
||||||
// Target Atomic feature is identified by dynamic detection
|
|
||||||
addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), arm64HasATOMICS, s.sb)
|
|
||||||
v := s.load(types.Types[TBOOL], addr)
|
|
||||||
b := s.endBlock()
|
|
||||||
b.Kind = ssa.BlockIf
|
|
||||||
b.SetControl(v)
|
|
||||||
bTrue := s.f.NewBlock(ssa.BlockPlain)
|
|
||||||
bFalse := s.f.NewBlock(ssa.BlockPlain)
|
|
||||||
bEnd := s.f.NewBlock(ssa.BlockPlain)
|
|
||||||
b.AddEdgeTo(bTrue)
|
|
||||||
b.AddEdgeTo(bFalse)
|
|
||||||
b.Likely = ssa.BranchUnlikely // most machines don't have Atomics nowadays
|
|
||||||
|
|
||||||
// We have atomic instructions - use it directly.
|
|
||||||
s.startBlock(bTrue)
|
|
||||||
v0 := s.newValue3(op1, types.NewTuple(types.Types[ty], types.TypeMem), args[0], args[1], s.mem())
|
|
||||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v0)
|
|
||||||
s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[ty], v0)
|
|
||||||
s.endBlock().AddEdgeTo(bEnd)
|
|
||||||
|
|
||||||
// Use original instruction sequence.
|
|
||||||
s.startBlock(bFalse)
|
|
||||||
v1 := s.newValue3(op0, types.NewTuple(types.Types[ty], types.TypeMem), args[0], args[1], s.mem())
|
|
||||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v1)
|
|
||||||
s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[ty], v1)
|
|
||||||
s.endBlock().AddEdgeTo(bEnd)
|
|
||||||
|
|
||||||
// Merge results.
|
|
||||||
s.startBlock(bEnd)
|
|
||||||
return s.variable(n, types.Types[ty])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addF("runtime/internal/atomic", "Xadd",
|
addF("runtime/internal/atomic", "Xadd",
|
||||||
makeXaddARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, TUINT32),
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, TUINT32, TUINT32, atomicXchgXaddEmitterARM64),
|
||||||
sys.ARM64)
|
sys.ARM64)
|
||||||
addF("runtime/internal/atomic", "Xadd64",
|
addF("runtime/internal/atomic", "Xadd64",
|
||||||
makeXaddARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, TUINT64),
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, TUINT64, TUINT64, atomicXchgXaddEmitterARM64),
|
||||||
sys.ARM64)
|
sys.ARM64)
|
||||||
|
|
||||||
addF("runtime/internal/atomic", "Cas",
|
addF("runtime/internal/atomic", "Cas",
|
||||||
|
|
@ -3506,14 +3545,14 @@ func init() {
|
||||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||||
return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
|
return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
|
||||||
},
|
},
|
||||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||||
addF("runtime/internal/atomic", "Cas64",
|
addF("runtime/internal/atomic", "Cas64",
|
||||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
v := s.newValue4(ssa.OpAtomicCompareAndSwap64, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
|
v := s.newValue4(ssa.OpAtomicCompareAndSwap64, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
|
||||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||||
return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
|
return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
|
||||||
},
|
},
|
||||||
sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||||
addF("runtime/internal/atomic", "CasRel",
|
addF("runtime/internal/atomic", "CasRel",
|
||||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
|
v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
|
||||||
|
|
@ -3522,18 +3561,60 @@ func init() {
|
||||||
},
|
},
|
||||||
sys.PPC64)
|
sys.PPC64)
|
||||||
|
|
||||||
|
atomicCasEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
|
||||||
|
v := s.newValue4(op, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem())
|
||||||
|
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||||
|
s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[typ], v)
|
||||||
|
}
|
||||||
|
|
||||||
|
addF("runtime/internal/atomic", "Cas",
|
||||||
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicCompareAndSwap32, ssa.OpAtomicCompareAndSwap32Variant, TUINT32, TBOOL, atomicCasEmitterARM64),
|
||||||
|
sys.ARM64)
|
||||||
|
addF("runtime/internal/atomic", "Cas64",
|
||||||
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicCompareAndSwap64, ssa.OpAtomicCompareAndSwap64Variant, TUINT64, TBOOL, atomicCasEmitterARM64),
|
||||||
|
sys.ARM64)
|
||||||
|
|
||||||
addF("runtime/internal/atomic", "And8",
|
addF("runtime/internal/atomic", "And8",
|
||||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd8, types.TypeMem, args[0], args[1], s.mem())
|
s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd8, types.TypeMem, args[0], args[1], s.mem())
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||||
|
addF("runtime/internal/atomic", "And",
|
||||||
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
|
s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd32, types.TypeMem, args[0], args[1], s.mem())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||||
addF("runtime/internal/atomic", "Or8",
|
addF("runtime/internal/atomic", "Or8",
|
||||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem())
|
s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem())
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||||
|
addF("runtime/internal/atomic", "Or",
|
||||||
|
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||||
|
s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr32, types.TypeMem, args[0], args[1], s.mem())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||||
|
|
||||||
|
atomicAndOrEmitterARM64 := func(s *state, n *Node, args []*ssa.Value, op ssa.Op, typ types.EType) {
|
||||||
|
s.vars[&memVar] = s.newValue3(op, types.TypeMem, args[0], args[1], s.mem())
|
||||||
|
}
|
||||||
|
|
||||||
|
addF("runtime/internal/atomic", "And8",
|
||||||
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAnd8, ssa.OpAtomicAnd8Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
|
||||||
|
sys.ARM64)
|
||||||
|
addF("runtime/internal/atomic", "And",
|
||||||
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAnd32, ssa.OpAtomicAnd32Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
|
||||||
|
sys.ARM64)
|
||||||
|
addF("runtime/internal/atomic", "Or8",
|
||||||
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicOr8, ssa.OpAtomicOr8Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
|
||||||
|
sys.ARM64)
|
||||||
|
addF("runtime/internal/atomic", "Or",
|
||||||
|
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicOr32, ssa.OpAtomicOr32Variant, TNIL, TNIL, atomicAndOrEmitterARM64),
|
||||||
|
sys.ARM64)
|
||||||
|
|
||||||
alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...)
|
alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...)
|
||||||
alias("runtime/internal/atomic", "Xaddint64", "runtime/internal/atomic", "Xadd64", all...)
|
alias("runtime/internal/atomic", "Xaddint64", "runtime/internal/atomic", "Xadd64", all...)
|
||||||
|
|
@ -3542,9 +3623,19 @@ func init() {
|
||||||
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...)
|
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...)
|
||||||
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...)
|
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...)
|
||||||
alias("runtime/internal/atomic", "LoadAcq", "runtime/internal/atomic", "Load", lwatomics...)
|
alias("runtime/internal/atomic", "LoadAcq", "runtime/internal/atomic", "Load", lwatomics...)
|
||||||
|
alias("runtime/internal/atomic", "LoadAcq64", "runtime/internal/atomic", "Load64", lwatomics...)
|
||||||
|
alias("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq", p4...)
|
||||||
|
alias("sync", "runtime_LoadAcquintptr", "runtime/internal/atomic", "LoadAcq", p4...) // linknamed
|
||||||
|
alias("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...)
|
||||||
|
alias("sync", "runtime_LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...) // linknamed
|
||||||
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...)
|
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...)
|
||||||
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...)
|
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...)
|
||||||
alias("runtime/internal/atomic", "StoreRel", "runtime/internal/atomic", "Store", lwatomics...)
|
alias("runtime/internal/atomic", "StoreRel", "runtime/internal/atomic", "Store", lwatomics...)
|
||||||
|
alias("runtime/internal/atomic", "StoreRel64", "runtime/internal/atomic", "Store64", lwatomics...)
|
||||||
|
alias("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel", p4...)
|
||||||
|
alias("sync", "runtime_StoreReluintptr", "runtime/internal/atomic", "StoreRel", p4...) // linknamed
|
||||||
|
alias("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...)
|
||||||
|
alias("sync", "runtime_StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...) // linknamed
|
||||||
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...)
|
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...)
|
||||||
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...)
|
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...)
|
||||||
alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...)
|
alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...)
|
||||||
|
|
@ -4709,7 +4800,7 @@ func (s *state) getClosureAndRcvr(fn *Node) (*ssa.Value, *ssa.Value) {
|
||||||
s.nilCheck(itab)
|
s.nilCheck(itab)
|
||||||
itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab
|
itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab
|
||||||
closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
|
closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
|
||||||
rcvr := s.newValue1(ssa.OpIData, types.Types[TUINTPTR], i)
|
rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
|
||||||
return closure, rcvr
|
return closure, rcvr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4830,7 +4921,7 @@ func (s *state) addr(n *Node) *ssa.Value {
|
||||||
// canSSA reports whether n is SSA-able.
|
// canSSA reports whether n is SSA-able.
|
||||||
// n must be an ONAME (or an ODOT sequence with an ONAME base).
|
// n must be an ONAME (or an ODOT sequence with an ONAME base).
|
||||||
func (s *state) canSSA(n *Node) bool {
|
func (s *state) canSSA(n *Node) bool {
|
||||||
if Debug['N'] != 0 {
|
if Debug.N != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) {
|
for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) {
|
||||||
|
|
@ -4869,7 +4960,7 @@ func (s *state) canSSA(n *Node) bool {
|
||||||
if n.Class() == PPARAM && n.Sym != nil && n.Sym.Name == ".this" {
|
if n.Class() == PPARAM && n.Sym != nil && n.Sym.Name == ".this" {
|
||||||
// wrappers generated by genwrapper need to update
|
// wrappers generated by genwrapper need to update
|
||||||
// the .this pointer in place.
|
// the .this pointer in place.
|
||||||
// TODO: treat as a PPARMOUT?
|
// TODO: treat as a PPARAMOUT?
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return canSSAType(n.Type)
|
return canSSAType(n.Type)
|
||||||
|
|
@ -4941,7 +5032,7 @@ func (s *state) nilCheck(ptr *ssa.Value) {
|
||||||
func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
|
func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
|
||||||
idx = s.extendIndex(idx, len, kind, bounded)
|
idx = s.extendIndex(idx, len, kind, bounded)
|
||||||
|
|
||||||
if bounded || Debug['B'] != 0 {
|
if bounded || Debug.B != 0 {
|
||||||
// If bounded or bounds checking is flag-disabled, then no check necessary,
|
// If bounded or bounds checking is flag-disabled, then no check necessary,
|
||||||
// just return the extended index.
|
// just return the extended index.
|
||||||
//
|
//
|
||||||
|
|
@ -5182,7 +5273,10 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski
|
||||||
case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
|
case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
|
||||||
s.store(t, left, right)
|
s.store(t, left, right)
|
||||||
case t.IsPtrShaped():
|
case t.IsPtrShaped():
|
||||||
// no scalar fields.
|
if t.IsPtr() && t.Elem().NotInHeap() {
|
||||||
|
s.store(t, left, right) // see issue 42032
|
||||||
|
}
|
||||||
|
// otherwise, no scalar fields.
|
||||||
case t.IsString():
|
case t.IsString():
|
||||||
if skip&skipLen != 0 {
|
if skip&skipLen != 0 {
|
||||||
return
|
return
|
||||||
|
|
@ -5226,6 +5320,9 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski
|
||||||
func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
|
func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
|
||||||
switch {
|
switch {
|
||||||
case t.IsPtrShaped():
|
case t.IsPtrShaped():
|
||||||
|
if t.IsPtr() && t.Elem().NotInHeap() {
|
||||||
|
break // see issue 42032
|
||||||
|
}
|
||||||
s.store(t, left, right)
|
s.store(t, left, right)
|
||||||
case t.IsString():
|
case t.IsString():
|
||||||
ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
|
ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
|
||||||
|
|
@ -6213,7 +6310,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||||
// instruction. We won't use the actual liveness map on a
|
// instruction. We won't use the actual liveness map on a
|
||||||
// control instruction. Just mark it something that is
|
// control instruction. Just mark it something that is
|
||||||
// preemptible, unless this function is "all unsafe".
|
// preemptible, unless this function is "all unsafe".
|
||||||
s.pp.nextLive = LivenessIndex{-1, -1, allUnsafe(f)}
|
s.pp.nextLive = LivenessIndex{-1, allUnsafe(f)}
|
||||||
|
|
||||||
// Emit values in block
|
// Emit values in block
|
||||||
thearch.SSAMarkMoves(&s, b)
|
thearch.SSAMarkMoves(&s, b)
|
||||||
|
|
@ -6291,7 +6388,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||||
}
|
}
|
||||||
// Emit control flow instructions for block
|
// Emit control flow instructions for block
|
||||||
var next *ssa.Block
|
var next *ssa.Block
|
||||||
if i < len(f.Blocks)-1 && Debug['N'] == 0 {
|
if i < len(f.Blocks)-1 && Debug.N == 0 {
|
||||||
// If -N, leave next==nil so every block with successors
|
// If -N, leave next==nil so every block with successors
|
||||||
// ends in a JMP (except call blocks - plive doesn't like
|
// ends in a JMP (except call blocks - plive doesn't like
|
||||||
// select{send,recv} followed by a JMP call). Helps keep
|
// select{send,recv} followed by a JMP call). Helps keep
|
||||||
|
|
@ -6599,7 +6696,7 @@ func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bo
|
||||||
} else {
|
} else {
|
||||||
lo = s.newValue1(ssa.OpInt64Lo, types.Types[TUINT], idx)
|
lo = s.newValue1(ssa.OpInt64Lo, types.Types[TUINT], idx)
|
||||||
}
|
}
|
||||||
if bounded || Debug['B'] != 0 {
|
if bounded || Debug.B != 0 {
|
||||||
return lo
|
return lo
|
||||||
}
|
}
|
||||||
bNext := s.f.NewBlock(ssa.BlockPlain)
|
bNext := s.f.NewBlock(ssa.BlockPlain)
|
||||||
|
|
@ -6873,56 +6970,38 @@ func (e *ssafn) Auto(pos src.XPos, t *types.Type) ssa.GCNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||||
n := name.N.(*Node)
|
|
||||||
ptrType := types.NewPtr(types.Types[TUINT8])
|
ptrType := types.NewPtr(types.Types[TUINT8])
|
||||||
lenType := types.Types[TINT]
|
lenType := types.Types[TINT]
|
||||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
|
||||||
// Split this string up into two separate variables.
|
// Split this string up into two separate variables.
|
||||||
p := e.splitSlot(&name, ".ptr", 0, ptrType)
|
p := e.SplitSlot(&name, ".ptr", 0, ptrType)
|
||||||
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
|
l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
|
||||||
return p, l
|
return p, l
|
||||||
}
|
|
||||||
// Return the two parts of the larger variable.
|
|
||||||
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||||
n := name.N.(*Node)
|
n := name.N.(*Node)
|
||||||
u := types.Types[TUINTPTR]
|
u := types.Types[TUINTPTR]
|
||||||
t := types.NewPtr(types.Types[TUINT8])
|
t := types.NewPtr(types.Types[TUINT8])
|
||||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
|
||||||
// Split this interface up into two separate variables.
|
// Split this interface up into two separate variables.
|
||||||
f := ".itab"
|
f := ".itab"
|
||||||
if n.Type.IsEmptyInterface() {
|
if n.Type.IsEmptyInterface() {
|
||||||
f = ".type"
|
f = ".type"
|
||||||
}
|
}
|
||||||
c := e.splitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
|
c := e.SplitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
|
||||||
d := e.splitSlot(&name, ".data", u.Size(), t)
|
d := e.SplitSlot(&name, ".data", u.Size(), t)
|
||||||
return c, d
|
return c, d
|
||||||
}
|
|
||||||
// Return the two parts of the larger variable.
|
|
||||||
return ssa.LocalSlot{N: n, Type: u, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
|
func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
|
||||||
n := name.N.(*Node)
|
|
||||||
ptrType := types.NewPtr(name.Type.Elem())
|
ptrType := types.NewPtr(name.Type.Elem())
|
||||||
lenType := types.Types[TINT]
|
lenType := types.Types[TINT]
|
||||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
p := e.SplitSlot(&name, ".ptr", 0, ptrType)
|
||||||
// Split this slice up into three separate variables.
|
l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
|
||||||
p := e.splitSlot(&name, ".ptr", 0, ptrType)
|
c := e.SplitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
|
||||||
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
|
|
||||||
c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
|
|
||||||
return p, l, c
|
return p, l, c
|
||||||
}
|
|
||||||
// Return the three parts of the larger variable.
|
|
||||||
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
|
|
||||||
ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)},
|
|
||||||
ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(2*Widthptr)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||||
n := name.N.(*Node)
|
|
||||||
s := name.Type.Size() / 2
|
s := name.Type.Size() / 2
|
||||||
var t *types.Type
|
var t *types.Type
|
||||||
if s == 8 {
|
if s == 8 {
|
||||||
|
|
@ -6930,53 +7009,30 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot)
|
||||||
} else {
|
} else {
|
||||||
t = types.Types[TFLOAT32]
|
t = types.Types[TFLOAT32]
|
||||||
}
|
}
|
||||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
r := e.SplitSlot(&name, ".real", 0, t)
|
||||||
// Split this complex up into two separate variables.
|
i := e.SplitSlot(&name, ".imag", t.Size(), t)
|
||||||
r := e.splitSlot(&name, ".real", 0, t)
|
|
||||||
i := e.splitSlot(&name, ".imag", t.Size(), t)
|
|
||||||
return r, i
|
return r, i
|
||||||
}
|
|
||||||
// Return the two parts of the larger variable.
|
|
||||||
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||||
n := name.N.(*Node)
|
|
||||||
var t *types.Type
|
var t *types.Type
|
||||||
if name.Type.IsSigned() {
|
if name.Type.IsSigned() {
|
||||||
t = types.Types[TINT32]
|
t = types.Types[TINT32]
|
||||||
} else {
|
} else {
|
||||||
t = types.Types[TUINT32]
|
t = types.Types[TUINT32]
|
||||||
}
|
}
|
||||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
|
||||||
// Split this int64 up into two separate variables.
|
|
||||||
if thearch.LinkArch.ByteOrder == binary.BigEndian {
|
if thearch.LinkArch.ByteOrder == binary.BigEndian {
|
||||||
return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
|
return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
|
||||||
}
|
}
|
||||||
return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32])
|
return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[TUINT32])
|
||||||
}
|
|
||||||
// Return the two parts of the larger variable.
|
|
||||||
if thearch.LinkArch.ByteOrder == binary.BigEndian {
|
|
||||||
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off + 4}
|
|
||||||
}
|
|
||||||
return ssa.LocalSlot{N: n, Type: t, Off: name.Off + 4}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
|
func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
|
||||||
n := name.N.(*Node)
|
|
||||||
st := name.Type
|
st := name.Type
|
||||||
ft := st.FieldType(i)
|
|
||||||
var offset int64
|
|
||||||
for f := 0; f < i; f++ {
|
|
||||||
offset += st.FieldType(f).Size()
|
|
||||||
}
|
|
||||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
|
||||||
// Note: the _ field may appear several times. But
|
// Note: the _ field may appear several times. But
|
||||||
// have no fear, identically-named but distinct Autos are
|
// have no fear, identically-named but distinct Autos are
|
||||||
// ok, albeit maybe confusing for a debugger.
|
// ok, albeit maybe confusing for a debugger.
|
||||||
return e.splitSlot(&name, "."+st.FieldName(i), offset, ft)
|
return e.SplitSlot(&name, "."+st.FieldName(i), st.FieldOff(i), st.FieldType(i))
|
||||||
}
|
|
||||||
return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
|
func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
|
||||||
|
|
@ -6986,19 +7042,23 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
|
||||||
e.Fatalf(n.Pos, "bad array size")
|
e.Fatalf(n.Pos, "bad array size")
|
||||||
}
|
}
|
||||||
et := at.Elem()
|
et := at.Elem()
|
||||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
return e.SplitSlot(&name, "[0]", 0, et)
|
||||||
return e.splitSlot(&name, "[0]", 0, et)
|
|
||||||
}
|
|
||||||
return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
|
func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
|
||||||
return itabsym(it, offset)
|
return itabsym(it, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitSlot returns a slot representing the data of parent starting at offset.
|
// SplitSlot returns a slot representing the data of parent starting at offset.
|
||||||
func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
|
func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
|
||||||
s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg}
|
node := parent.N.(*Node)
|
||||||
|
|
||||||
|
if node.Class() != PAUTO || node.Name.Addrtaken() {
|
||||||
|
// addressed things and non-autos retain their parents (i.e., cannot truly be split)
|
||||||
|
return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &types.Sym{Name: node.Sym.Name + suffix, Pkg: localpkg}
|
||||||
|
|
||||||
n := &Node{
|
n := &Node{
|
||||||
Name: new(Name),
|
Name: new(Name),
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ func flusherrors() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func hcrash() {
|
func hcrash() {
|
||||||
if Debug['h'] != 0 {
|
if Debug.h != 0 {
|
||||||
flusherrors()
|
flusherrors()
|
||||||
if outfile != "" {
|
if outfile != "" {
|
||||||
os.Remove(outfile)
|
os.Remove(outfile)
|
||||||
|
|
@ -107,7 +107,7 @@ func hcrash() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func linestr(pos src.XPos) string {
|
func linestr(pos src.XPos) string {
|
||||||
return Ctxt.OutermostPos(pos).Format(Debug['C'] == 0, Debug['L'] == 1)
|
return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// lasterror keeps track of the most recently issued error.
|
// lasterror keeps track of the most recently issued error.
|
||||||
|
|
@ -153,7 +153,7 @@ func yyerrorl(pos src.XPos, format string, args ...interface{}) {
|
||||||
|
|
||||||
hcrash()
|
hcrash()
|
||||||
nerrors++
|
nerrors++
|
||||||
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
|
if nsavederrors+nerrors >= 10 && Debug.e == 0 {
|
||||||
flusherrors()
|
flusherrors()
|
||||||
fmt.Printf("%v: too many errors\n", linestr(pos))
|
fmt.Printf("%v: too many errors\n", linestr(pos))
|
||||||
errorexit()
|
errorexit()
|
||||||
|
|
@ -175,7 +175,7 @@ func Warn(fmt_ string, args ...interface{}) {
|
||||||
|
|
||||||
func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
|
func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
|
||||||
adderr(line, fmt_, args...)
|
adderr(line, fmt_, args...)
|
||||||
if Debug['m'] != 0 {
|
if Debug.m != 0 {
|
||||||
flusherrors()
|
flusherrors()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -222,7 +222,7 @@ func hasUniquePos(n *Node) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !n.Pos.IsKnown() {
|
if !n.Pos.IsKnown() {
|
||||||
if Debug['K'] != 0 {
|
if Debug.K != 0 {
|
||||||
Warn("setlineno: unknown position (line 0)")
|
Warn("setlineno: unknown position (line 0)")
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
@ -348,7 +348,7 @@ func newname(s *types.Sym) *Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// newname returns a new ONAME Node associated with symbol s at position pos.
|
// newnamel returns a new ONAME Node associated with symbol s at position pos.
|
||||||
// The caller is responsible for setting n.Name.Curfn.
|
// The caller is responsible for setting n.Name.Curfn.
|
||||||
func newnamel(pos src.XPos, s *types.Sym) *Node {
|
func newnamel(pos src.XPos, s *types.Sym) *Node {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
|
|
@ -1506,7 +1506,7 @@ func structargs(tl *types.Type, mustname bool) []*Node {
|
||||||
// method - M func (t T)(), a TFIELD type struct
|
// method - M func (t T)(), a TFIELD type struct
|
||||||
// newnam - the eventual mangled name of this function
|
// newnam - the eventual mangled name of this function
|
||||||
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
||||||
if false && Debug['r'] != 0 {
|
if false && Debug.r != 0 {
|
||||||
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
|
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1579,7 +1579,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
||||||
fn.Nbody.Append(call)
|
fn.Nbody.Append(call)
|
||||||
}
|
}
|
||||||
|
|
||||||
if false && Debug['r'] != 0 {
|
if false && Debug.r != 0 {
|
||||||
dumplist("genwrapper body", fn.Nbody)
|
dumplist("genwrapper body", fn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1720,7 +1720,7 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
|
||||||
// the method does not exist for value types.
|
// the method does not exist for value types.
|
||||||
rcvr := tm.Type.Recv().Type
|
rcvr := tm.Type.Recv().Type
|
||||||
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
|
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
|
||||||
if false && Debug['r'] != 0 {
|
if false && Debug.r != 0 {
|
||||||
yyerror("interface pointer mismatch")
|
yyerror("interface pointer mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1854,8 +1854,10 @@ func isdirectiface(t *types.Type) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t.Etype {
|
switch t.Etype {
|
||||||
case TPTR,
|
case TPTR:
|
||||||
TCHAN,
|
// Pointers to notinheap types must be stored indirectly. See issue 42076.
|
||||||
|
return !t.Elem().NotInHeap()
|
||||||
|
case TCHAN,
|
||||||
TMAP,
|
TMAP,
|
||||||
TFUNC,
|
TFUNC,
|
||||||
TUNSAFEPTR:
|
TUNSAFEPTR:
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ const (
|
||||||
_, _ // second nodeInitorder bit
|
_, _ // second nodeInitorder bit
|
||||||
_, nodeHasBreak
|
_, nodeHasBreak
|
||||||
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
|
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
|
||||||
_, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
|
_, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP
|
||||||
_, nodeIsDDD // is the argument variadic
|
_, nodeIsDDD // is the argument variadic
|
||||||
_, nodeDiag // already printed error about this
|
_, nodeDiag // already printed error about this
|
||||||
_, nodeColas // OAS resulting from :=
|
_, nodeColas // OAS resulting from :=
|
||||||
|
|
@ -247,7 +247,7 @@ func (n *Node) Val() Val {
|
||||||
// SetVal sets the Val for the node, which must not have been used with SetOpt.
|
// SetVal sets the Val for the node, which must not have been used with SetOpt.
|
||||||
func (n *Node) SetVal(v Val) {
|
func (n *Node) SetVal(v Val) {
|
||||||
if n.HasOpt() {
|
if n.HasOpt() {
|
||||||
Debug['h'] = 1
|
Debug.h = 1
|
||||||
Dump("have Opt", n)
|
Dump("have Opt", n)
|
||||||
Fatalf("have Opt")
|
Fatalf("have Opt")
|
||||||
}
|
}
|
||||||
|
|
@ -270,7 +270,7 @@ func (n *Node) SetOpt(x interface{}) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if n.HasVal() {
|
if n.HasVal() {
|
||||||
Debug['h'] = 1
|
Debug.h = 1
|
||||||
Dump("have Val", n)
|
Dump("have Val", n)
|
||||||
Fatalf("have Val")
|
Fatalf("have Val")
|
||||||
}
|
}
|
||||||
|
|
@ -460,14 +460,14 @@ type Param struct {
|
||||||
// x1 := xN.Defn
|
// x1 := xN.Defn
|
||||||
// x1.Innermost = xN.Outer
|
// x1.Innermost = xN.Outer
|
||||||
//
|
//
|
||||||
// We leave xN.Innermost set so that we can still get to the original
|
// We leave x1.Innermost set so that we can still get to the original
|
||||||
// variable quickly. Not shown here, but once we're
|
// variable quickly. Not shown here, but once we're
|
||||||
// done parsing a function and no longer need xN.Outer for the
|
// done parsing a function and no longer need xN.Outer for the
|
||||||
// lexical x reference links as described above, closurebody
|
// lexical x reference links as described above, funcLit
|
||||||
// recomputes xN.Outer as the semantic x reference link tree,
|
// recomputes xN.Outer as the semantic x reference link tree,
|
||||||
// even filling in x in intermediate closures that might not
|
// even filling in x in intermediate closures that might not
|
||||||
// have mentioned it along the way to inner closures that did.
|
// have mentioned it along the way to inner closures that did.
|
||||||
// See closurebody for details.
|
// See funcLit for details.
|
||||||
//
|
//
|
||||||
// During the eventual compilation, then, for closure variables we have:
|
// During the eventual compilation, then, for closure variables we have:
|
||||||
//
|
//
|
||||||
|
|
@ -480,11 +480,87 @@ type Param struct {
|
||||||
Innermost *Node
|
Innermost *Node
|
||||||
Outer *Node
|
Outer *Node
|
||||||
|
|
||||||
// OTYPE
|
// OTYPE & ONAME //go:embed info,
|
||||||
//
|
// sharing storage to reduce gc.Param size.
|
||||||
// TODO: Should Func pragmas also be stored on the Name?
|
// Extra is nil, or else *Extra is a *paramType or an *embedFileList.
|
||||||
Pragma PragmaFlag
|
Extra *interface{}
|
||||||
Alias bool // node is alias for Ntype (only used when type-checking ODCLTYPE)
|
}
|
||||||
|
|
||||||
|
type paramType struct {
|
||||||
|
flag PragmaFlag
|
||||||
|
alias bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type embedFileList []string
|
||||||
|
|
||||||
|
// Pragma returns the PragmaFlag for p, which must be for an OTYPE.
|
||||||
|
func (p *Param) Pragma() PragmaFlag {
|
||||||
|
if p.Extra == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (*p.Extra).(*paramType).flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPragma sets the PragmaFlag for p, which must be for an OTYPE.
|
||||||
|
func (p *Param) SetPragma(flag PragmaFlag) {
|
||||||
|
if p.Extra == nil {
|
||||||
|
if flag == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Extra = new(interface{})
|
||||||
|
*p.Extra = ¶mType{flag: flag}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
(*p.Extra).(*paramType).flag = flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alias reports whether p, which must be for an OTYPE, is a type alias.
|
||||||
|
func (p *Param) Alias() bool {
|
||||||
|
if p.Extra == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
t, ok := (*p.Extra).(*paramType)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return t.alias
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAlias sets whether p, which must be for an OTYPE, is a type alias.
|
||||||
|
func (p *Param) SetAlias(alias bool) {
|
||||||
|
if p.Extra == nil {
|
||||||
|
if !alias {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Extra = new(interface{})
|
||||||
|
*p.Extra = ¶mType{alias: alias}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
(*p.Extra).(*paramType).alias = alias
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmbedFiles returns the list of embedded files for p,
|
||||||
|
// which must be for an ONAME var.
|
||||||
|
func (p *Param) EmbedFiles() []string {
|
||||||
|
if p.Extra == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return *(*p.Extra).(*embedFileList)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEmbedFiles sets the list of embedded files for p,
|
||||||
|
// which must be for an ONAME var.
|
||||||
|
func (p *Param) SetEmbedFiles(list []string) {
|
||||||
|
if p.Extra == nil {
|
||||||
|
if len(list) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f := embedFileList(list)
|
||||||
|
p.Extra = new(interface{})
|
||||||
|
*p.Extra = &f
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*(*p.Extra).(*embedFileList) = list
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
@ -555,7 +631,7 @@ type Func struct {
|
||||||
Ntype *Node // signature
|
Ntype *Node // signature
|
||||||
Top int // top context (ctxCallee, etc)
|
Top int // top context (ctxCallee, etc)
|
||||||
Closure *Node // OCLOSURE <-> ODCLFUNC
|
Closure *Node // OCLOSURE <-> ODCLFUNC
|
||||||
Nname *Node
|
Nname *Node // The ONAME node associated with an ODCLFUNC (both have same Type)
|
||||||
lsym *obj.LSym
|
lsym *obj.LSym
|
||||||
|
|
||||||
Inl *Inline
|
Inl *Inline
|
||||||
|
|
@ -697,7 +773,7 @@ const (
|
||||||
OCALLPART // Left.Right (method expression x.Method, not called)
|
OCALLPART // Left.Right (method expression x.Method, not called)
|
||||||
OCAP // cap(Left)
|
OCAP // cap(Left)
|
||||||
OCLOSE // close(Left)
|
OCLOSE // close(Left)
|
||||||
OCLOSURE // func Type { Body } (func literal)
|
OCLOSURE // func Type { Func.Closure.Nbody } (func literal)
|
||||||
OCOMPLIT // Right{List} (composite literal, not yet lowered to specific form)
|
OCOMPLIT // Right{List} (composite literal, not yet lowered to specific form)
|
||||||
OMAPLIT // Type{List} (composite literal, Type is map)
|
OMAPLIT // Type{List} (composite literal, Type is map)
|
||||||
OSTRUCTLIT // Type{List} (composite literal, Type is struct)
|
OSTRUCTLIT // Type{List} (composite literal, Type is struct)
|
||||||
|
|
@ -789,7 +865,12 @@ const (
|
||||||
// statements
|
// statements
|
||||||
OBLOCK // { List } (block of code)
|
OBLOCK // { List } (block of code)
|
||||||
OBREAK // break [Sym]
|
OBREAK // break [Sym]
|
||||||
OCASE // case List: Nbody (List==nil means default)
|
// OCASE: case List: Nbody (List==nil means default)
|
||||||
|
// For OTYPESW, List is a OTYPE node for the specified type (or OLITERAL
|
||||||
|
// for nil), and, if a type-switch variable is specified, Rlist is an
|
||||||
|
// ONAME for the version of the type-switch variable with the specified
|
||||||
|
// type.
|
||||||
|
OCASE
|
||||||
OCONTINUE // continue [Sym]
|
OCONTINUE // continue [Sym]
|
||||||
ODEFER // defer Left (Left must be call)
|
ODEFER // defer Left (Left must be call)
|
||||||
OEMPTY // no-op (empty statement)
|
OEMPTY // no-op (empty statement)
|
||||||
|
|
@ -813,14 +894,18 @@ const (
|
||||||
ORETURN // return List
|
ORETURN // return List
|
||||||
OSELECT // select { List } (List is list of OCASE)
|
OSELECT // select { List } (List is list of OCASE)
|
||||||
OSWITCH // switch Ninit; Left { List } (List is a list of OCASE)
|
OSWITCH // switch Ninit; Left { List } (List is a list of OCASE)
|
||||||
OTYPESW // Left = Right.(type) (appears as .Left of OSWITCH)
|
// OTYPESW: Left := Right.(type) (appears as .Left of OSWITCH)
|
||||||
|
// Left is nil if there is no type-switch variable
|
||||||
|
OTYPESW
|
||||||
|
|
||||||
// types
|
// types
|
||||||
OTCHAN // chan int
|
OTCHAN // chan int
|
||||||
OTMAP // map[string]int
|
OTMAP // map[string]int
|
||||||
OTSTRUCT // struct{}
|
OTSTRUCT // struct{}
|
||||||
OTINTER // interface{}
|
OTINTER // interface{}
|
||||||
OTFUNC // func()
|
// OTFUNC: func() - Left is receiver field, List is list of param fields, Rlist is
|
||||||
|
// list of result fields.
|
||||||
|
OTFUNC
|
||||||
OTARRAY // []int, [8]int, [N]int or [...]int
|
OTARRAY // []int, [8]int, [N]int or [...]int
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
|
|
|
||||||
|
|
@ -257,12 +257,12 @@ func typecheck(n *Node, top int) (res *Node) {
|
||||||
// are substituted.
|
// are substituted.
|
||||||
cycle := cycleFor(n)
|
cycle := cycleFor(n)
|
||||||
for _, n1 := range cycle {
|
for _, n1 := range cycle {
|
||||||
if n1.Name != nil && !n1.Name.Param.Alias {
|
if n1.Name != nil && !n1.Name.Param.Alias() {
|
||||||
// Cycle is ok. But if n is an alias type and doesn't
|
// Cycle is ok. But if n is an alias type and doesn't
|
||||||
// have a type yet, we have a recursive type declaration
|
// have a type yet, we have a recursive type declaration
|
||||||
// with aliases that we can't handle properly yet.
|
// with aliases that we can't handle properly yet.
|
||||||
// Report an error rather than crashing later.
|
// Report an error rather than crashing later.
|
||||||
if n.Name != nil && n.Name.Param.Alias && n.Type == nil {
|
if n.Name != nil && n.Name.Param.Alias() && n.Type == nil {
|
||||||
lineno = n.Pos
|
lineno = n.Pos
|
||||||
Fatalf("cannot handle alias type declaration (issue #25838): %v", n)
|
Fatalf("cannot handle alias type declaration (issue #25838): %v", n)
|
||||||
}
|
}
|
||||||
|
|
@ -2065,11 +2065,6 @@ func typecheck1(n *Node, top int) (res *Node) {
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case OCASE:
|
|
||||||
ok |= ctxStmt
|
|
||||||
typecheckslice(n.List.Slice(), ctxExpr)
|
|
||||||
typecheckslice(n.Nbody.Slice(), ctxStmt)
|
|
||||||
|
|
||||||
case ODCLFUNC:
|
case ODCLFUNC:
|
||||||
ok |= ctxStmt
|
ok |= ctxStmt
|
||||||
typecheckfunc(n)
|
typecheckfunc(n)
|
||||||
|
|
@ -2516,7 +2511,7 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
|
||||||
n.Left = nod(OADDR, n.Left, nil)
|
n.Left = nod(OADDR, n.Left, nil)
|
||||||
n.Left.SetImplicit(true)
|
n.Left.SetImplicit(true)
|
||||||
n.Left = typecheck(n.Left, ctxType|ctxExpr)
|
n.Left = typecheck(n.Left, ctxType|ctxExpr)
|
||||||
} else if tt.IsPtr() && !rcvr.IsPtr() && types.Identical(tt.Elem(), rcvr) {
|
} else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
|
||||||
n.Left = nod(ODEREF, n.Left, nil)
|
n.Left = nod(ODEREF, n.Left, nil)
|
||||||
n.Left.SetImplicit(true)
|
n.Left.SetImplicit(true)
|
||||||
n.Left = typecheck(n.Left, ctxType|ctxExpr)
|
n.Left = typecheck(n.Left, ctxType|ctxExpr)
|
||||||
|
|
@ -3504,7 +3499,7 @@ func setUnderlying(t, underlying *types.Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propagate go:notinheap pragma from the Name to the Type.
|
// Propagate go:notinheap pragma from the Name to the Type.
|
||||||
if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma&NotInHeap != 0 {
|
if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma()&NotInHeap != 0 {
|
||||||
t.SetNotInHeap(true)
|
t.SetNotInHeap(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3676,7 +3671,7 @@ func typecheckdef(n *Node) {
|
||||||
n.Name.Defn = typecheck(n.Name.Defn, ctxStmt) // fills in n.Type
|
n.Name.Defn = typecheck(n.Name.Defn, ctxStmt) // fills in n.Type
|
||||||
|
|
||||||
case OTYPE:
|
case OTYPE:
|
||||||
if p := n.Name.Param; p.Alias {
|
if p := n.Name.Param; p.Alias() {
|
||||||
// Type alias declaration: Simply use the rhs type - no need
|
// Type alias declaration: Simply use the rhs type - no need
|
||||||
// to create a new type.
|
// to create a new type.
|
||||||
// If we have a syntax error, p.Ntype may be nil.
|
// If we have a syntax error, p.Ntype may be nil.
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
|
||||||
func walk(fn *Node) {
|
func walk(fn *Node) {
|
||||||
Curfn = fn
|
Curfn = fn
|
||||||
|
|
||||||
if Debug['W'] != 0 {
|
if Debug.W != 0 {
|
||||||
s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym)
|
s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym)
|
||||||
dumplist(s, Curfn.Nbody)
|
dumplist(s, Curfn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
@ -63,14 +63,14 @@ func walk(fn *Node) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
walkstmtlist(Curfn.Nbody.Slice())
|
walkstmtlist(Curfn.Nbody.Slice())
|
||||||
if Debug['W'] != 0 {
|
if Debug.W != 0 {
|
||||||
s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
|
s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
|
||||||
dumplist(s, Curfn.Nbody)
|
dumplist(s, Curfn.Nbody)
|
||||||
}
|
}
|
||||||
|
|
||||||
zeroResults()
|
zeroResults()
|
||||||
heapmoves()
|
heapmoves()
|
||||||
if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 {
|
if Debug.W != 0 && Curfn.Func.Enter.Len() > 0 {
|
||||||
s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
|
s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
|
||||||
dumplist(s, Curfn.Func.Enter)
|
dumplist(s, Curfn.Func.Enter)
|
||||||
}
|
}
|
||||||
|
|
@ -436,7 +436,7 @@ func walkexpr(n *Node, init *Nodes) *Node {
|
||||||
|
|
||||||
lno := setlineno(n)
|
lno := setlineno(n)
|
||||||
|
|
||||||
if Debug['w'] > 1 {
|
if Debug.w > 1 {
|
||||||
Dump("before walk expr", n)
|
Dump("before walk expr", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,7 +474,7 @@ opswitch:
|
||||||
ODEREF, OSPTR, OITAB, OIDATA, OADDR:
|
ODEREF, OSPTR, OITAB, OIDATA, OADDR:
|
||||||
n.Left = walkexpr(n.Left, init)
|
n.Left = walkexpr(n.Left, init)
|
||||||
|
|
||||||
case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH:
|
case OEFACE, OAND, OANDNOT, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH:
|
||||||
n.Left = walkexpr(n.Left, init)
|
n.Left = walkexpr(n.Left, init)
|
||||||
n.Right = walkexpr(n.Right, init)
|
n.Right = walkexpr(n.Right, init)
|
||||||
|
|
||||||
|
|
@ -965,14 +965,6 @@ opswitch:
|
||||||
fn := basicnames[param] + "to" + basicnames[result]
|
fn := basicnames[param] + "to" + basicnames[result]
|
||||||
n = conv(mkcall(fn, types.Types[result], init, conv(n.Left, types.Types[param])), n.Type)
|
n = conv(mkcall(fn, types.Types[result], init, conv(n.Left, types.Types[param])), n.Type)
|
||||||
|
|
||||||
case OANDNOT:
|
|
||||||
n.Left = walkexpr(n.Left, init)
|
|
||||||
n.Op = OAND
|
|
||||||
n.SetImplicit(true) // for walkCheckPtrArithmetic
|
|
||||||
n.Right = nod(OBITNOT, n.Right, nil)
|
|
||||||
n.Right = typecheck(n.Right, ctxExpr)
|
|
||||||
n.Right = walkexpr(n.Right, init)
|
|
||||||
|
|
||||||
case ODIV, OMOD:
|
case ODIV, OMOD:
|
||||||
n.Left = walkexpr(n.Left, init)
|
n.Left = walkexpr(n.Left, init)
|
||||||
n.Right = walkexpr(n.Right, init)
|
n.Right = walkexpr(n.Right, init)
|
||||||
|
|
@ -997,7 +989,7 @@ opswitch:
|
||||||
// runtime calls late in SSA processing.
|
// runtime calls late in SSA processing.
|
||||||
if Widthreg < 8 && (et == TINT64 || et == TUINT64) {
|
if Widthreg < 8 && (et == TINT64 || et == TUINT64) {
|
||||||
if n.Right.Op == OLITERAL {
|
if n.Right.Op == OLITERAL {
|
||||||
// Leave div/mod by constant powers of 2.
|
// Leave div/mod by constant powers of 2 or small 16-bit constants.
|
||||||
// The SSA backend will handle those.
|
// The SSA backend will handle those.
|
||||||
switch et {
|
switch et {
|
||||||
case TINT64:
|
case TINT64:
|
||||||
|
|
@ -1010,6 +1002,9 @@ opswitch:
|
||||||
}
|
}
|
||||||
case TUINT64:
|
case TUINT64:
|
||||||
c := uint64(n.Right.Int64Val())
|
c := uint64(n.Right.Int64Val())
|
||||||
|
if c < 1<<16 {
|
||||||
|
break opswitch
|
||||||
|
}
|
||||||
if c != 0 && c&(c-1) == 0 {
|
if c != 0 && c&(c-1) == 0 {
|
||||||
break opswitch
|
break opswitch
|
||||||
}
|
}
|
||||||
|
|
@ -1049,7 +1044,7 @@ opswitch:
|
||||||
}
|
}
|
||||||
if t.IsArray() {
|
if t.IsArray() {
|
||||||
n.SetBounded(bounded(r, t.NumElem()))
|
n.SetBounded(bounded(r, t.NumElem()))
|
||||||
if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
|
if Debug.m != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
|
||||||
Warn("index bounds check elided")
|
Warn("index bounds check elided")
|
||||||
}
|
}
|
||||||
if smallintconst(n.Right) && !n.Bounded() {
|
if smallintconst(n.Right) && !n.Bounded() {
|
||||||
|
|
@ -1057,7 +1052,7 @@ opswitch:
|
||||||
}
|
}
|
||||||
} else if Isconst(n.Left, CTSTR) {
|
} else if Isconst(n.Left, CTSTR) {
|
||||||
n.SetBounded(bounded(r, int64(len(n.Left.StringVal()))))
|
n.SetBounded(bounded(r, int64(len(n.Left.StringVal()))))
|
||||||
if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
|
if Debug.m != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
|
||||||
Warn("index bounds check elided")
|
Warn("index bounds check elided")
|
||||||
}
|
}
|
||||||
if smallintconst(n.Right) && !n.Bounded() {
|
if smallintconst(n.Right) && !n.Bounded() {
|
||||||
|
|
@ -1599,7 +1594,7 @@ opswitch:
|
||||||
|
|
||||||
updateHasCall(n)
|
updateHasCall(n)
|
||||||
|
|
||||||
if Debug['w'] != 0 && n != nil {
|
if Debug.w != 0 && n != nil {
|
||||||
Dump("after walk expr", n)
|
Dump("after walk expr", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1965,7 +1960,17 @@ func walkprint(nn *Node, init *Nodes) *Node {
|
||||||
on = syslook("printiface")
|
on = syslook("printiface")
|
||||||
}
|
}
|
||||||
on = substArgTypes(on, n.Type) // any-1
|
on = substArgTypes(on, n.Type) // any-1
|
||||||
case TPTR, TCHAN, TMAP, TFUNC, TUNSAFEPTR:
|
case TPTR:
|
||||||
|
if n.Type.Elem().NotInHeap() {
|
||||||
|
on = syslook("printuintptr")
|
||||||
|
n = nod(OCONV, n, nil)
|
||||||
|
n.Type = types.Types[TUNSAFEPTR]
|
||||||
|
n = nod(OCONV, n, nil)
|
||||||
|
n.Type = types.Types[TUINTPTR]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case TCHAN, TMAP, TFUNC, TUNSAFEPTR:
|
||||||
on = syslook("printpointer")
|
on = syslook("printpointer")
|
||||||
on = substArgTypes(on, n.Type) // any-1
|
on = substArgTypes(on, n.Type) // any-1
|
||||||
case TSLICE:
|
case TSLICE:
|
||||||
|
|
@ -2819,7 +2824,7 @@ func appendslice(n *Node, init *Nodes) *Node {
|
||||||
// isAppendOfMake reports whether n is of the form append(x , make([]T, y)...).
|
// isAppendOfMake reports whether n is of the form append(x , make([]T, y)...).
|
||||||
// isAppendOfMake assumes n has already been typechecked.
|
// isAppendOfMake assumes n has already been typechecked.
|
||||||
func isAppendOfMake(n *Node) bool {
|
func isAppendOfMake(n *Node) bool {
|
||||||
if Debug['N'] != 0 || instrumenting {
|
if Debug.N != 0 || instrumenting {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3609,14 +3614,20 @@ func bounded(n *Node, max int64) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case OAND:
|
case OAND, OANDNOT:
|
||||||
v := int64(-1)
|
v := int64(-1)
|
||||||
if smallintconst(n.Left) {
|
switch {
|
||||||
|
case smallintconst(n.Left):
|
||||||
v = n.Left.Int64Val()
|
v = n.Left.Int64Val()
|
||||||
} else if smallintconst(n.Right) {
|
case smallintconst(n.Right):
|
||||||
v = n.Right.Int64Val()
|
v = n.Right.Int64Val()
|
||||||
|
if n.Op == OANDNOT {
|
||||||
|
v = ^v
|
||||||
|
if !sign {
|
||||||
|
v &= 1<<uint(bits) - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if 0 <= v && v < max {
|
if 0 <= v && v < max {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -3976,7 +3987,7 @@ func canMergeLoads() bool {
|
||||||
// isRuneCount reports whether n is of the form len([]rune(string)).
|
// isRuneCount reports whether n is of the form len([]rune(string)).
|
||||||
// These are optimized into a call to runtime.countrunes.
|
// These are optimized into a call to runtime.countrunes.
|
||||||
func isRuneCount(n *Node) bool {
|
func isRuneCount(n *Node) bool {
|
||||||
return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES
|
return Debug.N == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES
|
||||||
}
|
}
|
||||||
|
|
||||||
func walkCheckPtrAlignment(n *Node, init *Nodes, count *Node) *Node {
|
func walkCheckPtrAlignment(n *Node, init *Nodes, count *Node) *Node {
|
||||||
|
|
@ -4045,12 +4056,8 @@ func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
|
||||||
case OADD:
|
case OADD:
|
||||||
walk(n.Left)
|
walk(n.Left)
|
||||||
walk(n.Right)
|
walk(n.Right)
|
||||||
case OSUB:
|
case OSUB, OANDNOT:
|
||||||
walk(n.Left)
|
walk(n.Left)
|
||||||
case OAND:
|
|
||||||
if n.Implicit() { // was OANDNOT
|
|
||||||
walk(n.Left)
|
|
||||||
}
|
|
||||||
case OCONVNOP:
|
case OCONVNOP:
|
||||||
if n.Left.Type.IsUnsafePtr() {
|
if n.Left.Type.IsUnsafePtr() {
|
||||||
n.Left = cheapexpr(n.Left, init)
|
n.Left = cheapexpr(n.Left, init)
|
||||||
|
|
|
||||||
|
|
@ -213,15 +213,15 @@ func s15a8(x *[15]int64) [15]int64 {
|
||||||
`"relatedInformation":[`+
|
`"relatedInformation":[`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r1 = y:"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~R0 = y:"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from \u0026y.b (address-of)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":9},"end":{"line":4,"character":9}}},"message":"inlineLoc"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~r1 = \u003cN\u003e (assign-pair)"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from ~R0 = \u003cN\u003e (assign-pair)"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r2 = ~r1:"},`+
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: flow: ~r2 = ~R0:"},`+
|
||||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~r1) (return)"}]}`)
|
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~R0) (return)"}]}`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,34 +166,46 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p2.To.Reg = v.Reg1()
|
p2.To.Reg = v.Reg1()
|
||||||
|
|
||||||
case ssa.OpPPC64LoweredAtomicAnd8,
|
case ssa.OpPPC64LoweredAtomicAnd8,
|
||||||
ssa.OpPPC64LoweredAtomicOr8:
|
ssa.OpPPC64LoweredAtomicAnd32,
|
||||||
|
ssa.OpPPC64LoweredAtomicOr8,
|
||||||
|
ssa.OpPPC64LoweredAtomicOr32:
|
||||||
// LWSYNC
|
// LWSYNC
|
||||||
// LBAR (Rarg0), Rtmp
|
// LBAR/LWAR (Rarg0), Rtmp
|
||||||
// AND/OR Rarg1, Rtmp
|
// AND/OR Rarg1, Rtmp
|
||||||
// STBCCC Rtmp, (Rarg0)
|
// STBCCC/STWCCC Rtmp, (Rarg0)
|
||||||
// BNE -3(PC)
|
// BNE -3(PC)
|
||||||
|
ld := ppc64.ALBAR
|
||||||
|
st := ppc64.ASTBCCC
|
||||||
|
if v.Op == ssa.OpPPC64LoweredAtomicAnd32 || v.Op == ssa.OpPPC64LoweredAtomicOr32 {
|
||||||
|
ld = ppc64.ALWAR
|
||||||
|
st = ppc64.ASTWCCC
|
||||||
|
}
|
||||||
r0 := v.Args[0].Reg()
|
r0 := v.Args[0].Reg()
|
||||||
r1 := v.Args[1].Reg()
|
r1 := v.Args[1].Reg()
|
||||||
// LWSYNC - Assuming shared data not write-through-required nor
|
// LWSYNC - Assuming shared data not write-through-required nor
|
||||||
// caching-inhibited. See Appendix B.2.2.2 in the ISA 2.07b.
|
// caching-inhibited. See Appendix B.2.2.2 in the ISA 2.07b.
|
||||||
plwsync := s.Prog(ppc64.ALWSYNC)
|
plwsync := s.Prog(ppc64.ALWSYNC)
|
||||||
plwsync.To.Type = obj.TYPE_NONE
|
plwsync.To.Type = obj.TYPE_NONE
|
||||||
p := s.Prog(ppc64.ALBAR)
|
// LBAR or LWAR
|
||||||
|
p := s.Prog(ld)
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Reg = r0
|
p.From.Reg = r0
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = ppc64.REGTMP
|
p.To.Reg = ppc64.REGTMP
|
||||||
|
// AND/OR reg1,out
|
||||||
p1 := s.Prog(v.Op.Asm())
|
p1 := s.Prog(v.Op.Asm())
|
||||||
p1.From.Type = obj.TYPE_REG
|
p1.From.Type = obj.TYPE_REG
|
||||||
p1.From.Reg = r1
|
p1.From.Reg = r1
|
||||||
p1.To.Type = obj.TYPE_REG
|
p1.To.Type = obj.TYPE_REG
|
||||||
p1.To.Reg = ppc64.REGTMP
|
p1.To.Reg = ppc64.REGTMP
|
||||||
p2 := s.Prog(ppc64.ASTBCCC)
|
// STBCCC or STWCCC
|
||||||
|
p2 := s.Prog(st)
|
||||||
p2.From.Type = obj.TYPE_REG
|
p2.From.Type = obj.TYPE_REG
|
||||||
p2.From.Reg = ppc64.REGTMP
|
p2.From.Reg = ppc64.REGTMP
|
||||||
p2.To.Type = obj.TYPE_MEM
|
p2.To.Type = obj.TYPE_MEM
|
||||||
p2.To.Reg = r0
|
p2.To.Reg = r0
|
||||||
p2.RegTo2 = ppc64.REGTMP
|
p2.RegTo2 = ppc64.REGTMP
|
||||||
|
// BNE retry
|
||||||
p3 := s.Prog(ppc64.ABNE)
|
p3 := s.Prog(ppc64.ABNE)
|
||||||
p3.To.Type = obj.TYPE_BRANCH
|
p3.To.Type = obj.TYPE_BRANCH
|
||||||
gc.Patch(p3, p)
|
gc.Patch(p3, p)
|
||||||
|
|
@ -637,6 +649,24 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = v.Reg()
|
p.To.Reg = v.Reg()
|
||||||
|
|
||||||
|
// Auxint holds encoded rotate + mask
|
||||||
|
case ssa.OpPPC64RLWINM, ssa.OpPPC64RLWMI:
|
||||||
|
rot, _, _, mask := ssa.DecodePPC64RotateMask(v.AuxInt)
|
||||||
|
p := s.Prog(v.Op.Asm())
|
||||||
|
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()}
|
||||||
|
p.Reg = v.Args[0].Reg()
|
||||||
|
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(rot)}
|
||||||
|
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(mask)})
|
||||||
|
|
||||||
|
// Auxint holds mask
|
||||||
|
case ssa.OpPPC64RLWNM:
|
||||||
|
_, _, _, mask := ssa.DecodePPC64RotateMask(v.AuxInt)
|
||||||
|
p := s.Prog(v.Op.Asm())
|
||||||
|
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()}
|
||||||
|
p.Reg = v.Args[0].Reg()
|
||||||
|
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[1].Reg()}
|
||||||
|
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(mask)})
|
||||||
|
|
||||||
case ssa.OpPPC64MADDLD:
|
case ssa.OpPPC64MADDLD:
|
||||||
r := v.Reg()
|
r := v.Reg()
|
||||||
r1 := v.Args[0].Reg()
|
r1 := v.Args[0].Reg()
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,15 @@ func zeroRange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jsing): Add a duff zero implementation for medium sized ranges.
|
if cnt <= int64(128*gc.Widthptr) {
|
||||||
|
p = pp.Appendpp(p, riscv.AADDI, obj.TYPE_CONST, 0, off, obj.TYPE_REG, riscv.REG_A0, 0)
|
||||||
|
p.Reg = riscv.REG_SP
|
||||||
|
p = pp.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
|
||||||
|
p.To.Name = obj.NAME_EXTERN
|
||||||
|
p.To.Sym = gc.Duffzero
|
||||||
|
p.To.Offset = 8 * (128 - cnt/int64(gc.Widthptr))
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
// Loop, zeroing pointer width bytes at a time.
|
// Loop, zeroing pointer width bytes at a time.
|
||||||
// ADD $(off), SP, T0
|
// ADD $(off), SP, T0
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
// input args need no code
|
// input args need no code
|
||||||
case ssa.OpPhi:
|
case ssa.OpPhi:
|
||||||
gc.CheckLoweredPhi(v)
|
gc.CheckLoweredPhi(v)
|
||||||
case ssa.OpCopy, ssa.OpRISCV64MOVconvert:
|
case ssa.OpCopy, ssa.OpRISCV64MOVconvert, ssa.OpRISCV64MOVDreg:
|
||||||
if v.Type.IsMemory() {
|
if v.Type.IsMemory() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -208,6 +208,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p.From.Reg = rs
|
p.From.Reg = rs
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = rd
|
p.To.Reg = rd
|
||||||
|
case ssa.OpRISCV64MOVDnop:
|
||||||
|
if v.Reg() != v.Args[0].Reg() {
|
||||||
|
v.Fatalf("input[0] and output not in same register %s", v.LongString())
|
||||||
|
}
|
||||||
|
// nothing to do
|
||||||
case ssa.OpLoadReg:
|
case ssa.OpLoadReg:
|
||||||
if v.Type.IsFlags() {
|
if v.Type.IsFlags() {
|
||||||
v.Fatalf("load flags not implemented: %v", v.LongString())
|
v.Fatalf("load flags not implemented: %v", v.LongString())
|
||||||
|
|
@ -228,6 +233,37 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
gc.AddrAuto(&p.To, v)
|
gc.AddrAuto(&p.To, v)
|
||||||
case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
|
case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
|
case ssa.OpRISCV64MOVBreg, ssa.OpRISCV64MOVHreg, ssa.OpRISCV64MOVWreg,
|
||||||
|
ssa.OpRISCV64MOVBUreg, ssa.OpRISCV64MOVHUreg, ssa.OpRISCV64MOVWUreg:
|
||||||
|
a := v.Args[0]
|
||||||
|
for a.Op == ssa.OpCopy || a.Op == ssa.OpRISCV64MOVDreg {
|
||||||
|
a = a.Args[0]
|
||||||
|
}
|
||||||
|
as := v.Op.Asm()
|
||||||
|
rs := v.Args[0].Reg()
|
||||||
|
rd := v.Reg()
|
||||||
|
if a.Op == ssa.OpLoadReg {
|
||||||
|
t := a.Type
|
||||||
|
switch {
|
||||||
|
case v.Op == ssa.OpRISCV64MOVBreg && t.Size() == 1 && t.IsSigned(),
|
||||||
|
v.Op == ssa.OpRISCV64MOVHreg && t.Size() == 2 && t.IsSigned(),
|
||||||
|
v.Op == ssa.OpRISCV64MOVWreg && t.Size() == 4 && t.IsSigned(),
|
||||||
|
v.Op == ssa.OpRISCV64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
|
||||||
|
v.Op == ssa.OpRISCV64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
|
||||||
|
v.Op == ssa.OpRISCV64MOVWUreg && t.Size() == 4 && !t.IsSigned():
|
||||||
|
// arg is a proper-typed load and already sign/zero-extended
|
||||||
|
if rs == rd {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
as = riscv.AMOV
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p := s.Prog(as)
|
||||||
|
p.From.Type = obj.TYPE_REG
|
||||||
|
p.From.Reg = rs
|
||||||
|
p.To.Type = obj.TYPE_REG
|
||||||
|
p.To.Reg = rd
|
||||||
case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND,
|
case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND,
|
||||||
ssa.OpRISCV64SLL, ssa.OpRISCV64SRA, ssa.OpRISCV64SRL,
|
ssa.OpRISCV64SLL, ssa.OpRISCV64SRA, ssa.OpRISCV64SRL,
|
||||||
ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH,
|
ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH,
|
||||||
|
|
@ -572,6 +608,20 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = v.Reg()
|
p.To.Reg = v.Reg()
|
||||||
|
|
||||||
|
case ssa.OpRISCV64DUFFZERO:
|
||||||
|
p := s.Prog(obj.ADUFFZERO)
|
||||||
|
p.To.Type = obj.TYPE_MEM
|
||||||
|
p.To.Name = obj.NAME_EXTERN
|
||||||
|
p.To.Sym = gc.Duffzero
|
||||||
|
p.To.Offset = v.AuxInt
|
||||||
|
|
||||||
|
case ssa.OpRISCV64DUFFCOPY:
|
||||||
|
p := s.Prog(obj.ADUFFCOPY)
|
||||||
|
p.To.Type = obj.TYPE_MEM
|
||||||
|
p.To.Name = obj.NAME_EXTERN
|
||||||
|
p.To.Sym = gc.Duffcopy
|
||||||
|
p.To.Offset = v.AuxInt
|
||||||
|
|
||||||
default:
|
default:
|
||||||
v.Fatalf("Unhandled op %v", v.Op)
|
v.Fatalf("Unhandled op %v", v.Op)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -182,11 +182,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
i := v.Aux.(s390x.RotateParams)
|
i := v.Aux.(s390x.RotateParams)
|
||||||
p := s.Prog(v.Op.Asm())
|
p := s.Prog(v.Op.Asm())
|
||||||
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(i.Start)}
|
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(i.Start)}
|
||||||
p.RestArgs = []obj.Addr{
|
p.SetRestArgs([]obj.Addr{
|
||||||
{Type: obj.TYPE_CONST, Offset: int64(i.End)},
|
{Type: obj.TYPE_CONST, Offset: int64(i.End)},
|
||||||
{Type: obj.TYPE_CONST, Offset: int64(i.Amount)},
|
{Type: obj.TYPE_CONST, Offset: int64(i.Amount)},
|
||||||
{Type: obj.TYPE_REG, Reg: r2},
|
{Type: obj.TYPE_REG, Reg: r2},
|
||||||
}
|
})
|
||||||
|
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: r1}
|
||||||
|
case ssa.OpS390XRISBGZ:
|
||||||
|
r1 := v.Reg()
|
||||||
|
r2 := v.Args[0].Reg()
|
||||||
|
i := v.Aux.(s390x.RotateParams)
|
||||||
|
p := s.Prog(v.Op.Asm())
|
||||||
|
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(i.Start)}
|
||||||
|
p.SetRestArgs([]obj.Addr{
|
||||||
|
{Type: obj.TYPE_CONST, Offset: int64(i.End)},
|
||||||
|
{Type: obj.TYPE_CONST, Offset: int64(i.Amount)},
|
||||||
|
{Type: obj.TYPE_REG, Reg: r2},
|
||||||
|
})
|
||||||
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: r1}
|
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: r1}
|
||||||
case ssa.OpS390XADD, ssa.OpS390XADDW,
|
case ssa.OpS390XADD, ssa.OpS390XADDW,
|
||||||
ssa.OpS390XSUB, ssa.OpS390XSUBW,
|
ssa.OpS390XSUB, ssa.OpS390XSUBW,
|
||||||
|
|
@ -360,7 +372,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst,
|
case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst,
|
||||||
ssa.OpS390XSRDconst, ssa.OpS390XSRWconst,
|
ssa.OpS390XSRDconst, ssa.OpS390XSRWconst,
|
||||||
ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst,
|
ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst,
|
||||||
ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst:
|
ssa.OpS390XRLLconst:
|
||||||
p := s.Prog(v.Op.Asm())
|
p := s.Prog(v.Op.Asm())
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = v.AuxInt
|
p.From.Offset = v.AuxInt
|
||||||
|
|
@ -761,6 +773,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
p.To.Type = obj.TYPE_MEM
|
p.To.Type = obj.TYPE_MEM
|
||||||
p.To.Reg = v.Args[0].Reg()
|
p.To.Reg = v.Args[0].Reg()
|
||||||
gc.AddAux(&p.To, v)
|
gc.AddAux(&p.To, v)
|
||||||
|
case ssa.OpS390XLAN, ssa.OpS390XLAO:
|
||||||
|
// LA(N|O) Ry, TMP, 0(Rx)
|
||||||
|
op := s.Prog(v.Op.Asm())
|
||||||
|
op.From.Type = obj.TYPE_REG
|
||||||
|
op.From.Reg = v.Args[1].Reg()
|
||||||
|
op.Reg = s390x.REGTMP
|
||||||
|
op.To.Type = obj.TYPE_MEM
|
||||||
|
op.To.Reg = v.Args[0].Reg()
|
||||||
case ssa.OpS390XLANfloor, ssa.OpS390XLAOfloor:
|
case ssa.OpS390XLANfloor, ssa.OpS390XLAOfloor:
|
||||||
r := v.Args[0].Reg() // clobbered, assumed R1 in comments
|
r := v.Args[0].Reg() // clobbered, assumed R1 in comments
|
||||||
|
|
||||||
|
|
@ -905,7 +925,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = int64(s390x.NotEqual & s390x.NotUnordered) // unordered is not possible
|
p.From.Offset = int64(s390x.NotEqual & s390x.NotUnordered) // unordered is not possible
|
||||||
p.Reg = s390x.REG_R3
|
p.Reg = s390x.REG_R3
|
||||||
p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: 0}}
|
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: 0})
|
||||||
if b.Succs[0].Block() != next {
|
if b.Succs[0].Block() != next {
|
||||||
s.Br(s390x.ABR, b.Succs[0].Block())
|
s.Br(s390x.ABR, b.Succs[0].Block())
|
||||||
}
|
}
|
||||||
|
|
@ -948,17 +968,17 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
||||||
p.Reg = b.Controls[0].Reg()
|
p.Reg = b.Controls[0].Reg()
|
||||||
p.RestArgs = []obj.Addr{{Type: obj.TYPE_REG, Reg: b.Controls[1].Reg()}}
|
p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: b.Controls[1].Reg()})
|
||||||
case ssa.BlockS390XCGIJ, ssa.BlockS390XCIJ:
|
case ssa.BlockS390XCGIJ, ssa.BlockS390XCIJ:
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
||||||
p.Reg = b.Controls[0].Reg()
|
p.Reg = b.Controls[0].Reg()
|
||||||
p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: int64(int8(b.AuxInt))}}
|
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(int8(b.AuxInt))})
|
||||||
case ssa.BlockS390XCLGIJ, ssa.BlockS390XCLIJ:
|
case ssa.BlockS390XCLGIJ, ssa.BlockS390XCLIJ:
|
||||||
p.From.Type = obj.TYPE_CONST
|
p.From.Type = obj.TYPE_CONST
|
||||||
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
||||||
p.Reg = b.Controls[0].Reg()
|
p.Reg = b.Controls[0].Reg()
|
||||||
p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: int64(uint8(b.AuxInt))}}
|
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(uint8(b.AuxInt))})
|
||||||
default:
|
default:
|
||||||
b.Fatalf("branch not implemented: %s", b.LongString())
|
b.Fatalf("branch not implemented: %s", b.LongString())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,22 +59,22 @@ func addressingModes(f *Func) {
|
||||||
v.AuxInt += p.AuxInt
|
v.AuxInt += p.AuxInt
|
||||||
case [2]auxType{auxSymValAndOff, auxInt32}:
|
case [2]auxType{auxSymValAndOff, auxInt32}:
|
||||||
vo := ValAndOff(v.AuxInt)
|
vo := ValAndOff(v.AuxInt)
|
||||||
if !vo.canAdd(p.AuxInt) {
|
if !vo.canAdd64(p.AuxInt) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
v.AuxInt = vo.add(p.AuxInt)
|
v.AuxInt = int64(vo.addOffset64(p.AuxInt))
|
||||||
case [2]auxType{auxSymValAndOff, auxSymOff}:
|
case [2]auxType{auxSymValAndOff, auxSymOff}:
|
||||||
vo := ValAndOff(v.AuxInt)
|
vo := ValAndOff(v.AuxInt)
|
||||||
if v.Aux != nil && p.Aux != nil {
|
if v.Aux != nil && p.Aux != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !vo.canAdd(p.AuxInt) {
|
if !vo.canAdd64(p.AuxInt) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p.Aux != nil {
|
if p.Aux != nil {
|
||||||
v.Aux = p.Aux
|
v.Aux = p.Aux
|
||||||
}
|
}
|
||||||
v.AuxInt = vo.add(p.AuxInt)
|
v.AuxInt = int64(vo.addOffset64(p.AuxInt))
|
||||||
case [2]auxType{auxSymOff, auxNone}:
|
case [2]auxType{auxSymOff, auxNone}:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
case [2]auxType{auxSymValAndOff, auxNone}:
|
case [2]auxType{auxSymValAndOff, auxNone}:
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func branchelim(f *Func) {
|
||||||
for _, b := range f.Blocks {
|
for _, b := range f.Blocks {
|
||||||
for _, v := range b.Values {
|
for _, v := range b.Values {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpLoad, OpAtomicLoad8, OpAtomicLoad32, OpAtomicLoad64, OpAtomicLoadPtr, OpAtomicLoadAcq32:
|
case OpLoad, OpAtomicLoad8, OpAtomicLoad32, OpAtomicLoad64, OpAtomicLoadPtr, OpAtomicLoadAcq32, OpAtomicLoadAcq64:
|
||||||
loadAddr.add(v.Args[0].ID)
|
loadAddr.add(v.Args[0].ID)
|
||||||
case OpMove:
|
case OpMove:
|
||||||
loadAddr.add(v.Args[1].ID)
|
loadAddr.add(v.Args[1].ID)
|
||||||
|
|
|
||||||
|
|
@ -304,37 +304,39 @@ commas. For example:
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
if phase == "check" && flag == "on" {
|
if phase == "check" {
|
||||||
|
switch flag {
|
||||||
|
case "on":
|
||||||
checkEnabled = val != 0
|
checkEnabled = val != 0
|
||||||
debugPoset = checkEnabled // also turn on advanced self-checking in prove's datastructure
|
debugPoset = checkEnabled // also turn on advanced self-checking in prove's datastructure
|
||||||
return ""
|
return ""
|
||||||
}
|
case "off":
|
||||||
if phase == "check" && flag == "off" {
|
|
||||||
checkEnabled = val == 0
|
checkEnabled = val == 0
|
||||||
debugPoset = checkEnabled
|
debugPoset = checkEnabled
|
||||||
return ""
|
return ""
|
||||||
}
|
case "seed":
|
||||||
if phase == "check" && flag == "seed" {
|
|
||||||
checkEnabled = true
|
checkEnabled = true
|
||||||
checkRandSeed = val
|
checkRandSeed = val
|
||||||
debugPoset = checkEnabled
|
debugPoset = checkEnabled
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
alltime := false
|
alltime := false
|
||||||
allmem := false
|
allmem := false
|
||||||
alldump := false
|
alldump := false
|
||||||
if phase == "all" {
|
if phase == "all" {
|
||||||
if flag == "time" {
|
switch flag {
|
||||||
|
case "time":
|
||||||
alltime = val != 0
|
alltime = val != 0
|
||||||
} else if flag == "mem" {
|
case "mem":
|
||||||
allmem = val != 0
|
allmem = val != 0
|
||||||
} else if flag == "dump" {
|
case "dump":
|
||||||
alldump = val != 0
|
alldump = val != 0
|
||||||
if alldump {
|
if alldump {
|
||||||
BuildDump = valString
|
BuildDump = valString
|
||||||
}
|
}
|
||||||
} else {
|
default:
|
||||||
return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
|
return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -429,7 +431,7 @@ var passes = [...]pass{
|
||||||
{name: "early copyelim", fn: copyelim},
|
{name: "early copyelim", fn: copyelim},
|
||||||
{name: "early deadcode", fn: deadcode}, // remove generated dead code to avoid doing pointless work during opt
|
{name: "early deadcode", fn: deadcode}, // remove generated dead code to avoid doing pointless work during opt
|
||||||
{name: "short circuit", fn: shortcircuit},
|
{name: "short circuit", fn: shortcircuit},
|
||||||
{name: "decompose args", fn: decomposeArgs, required: true},
|
{name: "decompose args", fn: decomposeArgs, required: !go116lateCallExpansion, disabled: go116lateCallExpansion}, // handled by late call lowering
|
||||||
{name: "decompose user", fn: decomposeUser, required: true},
|
{name: "decompose user", fn: decomposeUser, required: true},
|
||||||
{name: "pre-opt deadcode", fn: deadcode},
|
{name: "pre-opt deadcode", fn: deadcode},
|
||||||
{name: "opt", fn: opt, required: true}, // NB: some generic rules know the name of the opt pass. TODO: split required rules and optimizing rules
|
{name: "opt", fn: opt, required: true}, // NB: some generic rules know the name of the opt pass. TODO: split required rules and optimizing rules
|
||||||
|
|
@ -441,8 +443,8 @@ var passes = [...]pass{
|
||||||
{name: "nilcheckelim", fn: nilcheckelim},
|
{name: "nilcheckelim", fn: nilcheckelim},
|
||||||
{name: "prove", fn: prove},
|
{name: "prove", fn: prove},
|
||||||
{name: "early fuse", fn: fuseEarly},
|
{name: "early fuse", fn: fuseEarly},
|
||||||
{name: "expand calls", fn: expandCalls, required: true},
|
|
||||||
{name: "decompose builtin", fn: decomposeBuiltIn, required: true},
|
{name: "decompose builtin", fn: decomposeBuiltIn, required: true},
|
||||||
|
{name: "expand calls", fn: expandCalls, required: true},
|
||||||
{name: "softfloat", fn: softfloat, required: true},
|
{name: "softfloat", fn: softfloat, required: true},
|
||||||
{name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
|
{name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
|
||||||
{name: "dead auto elim", fn: elimDeadAutosGeneric},
|
{name: "dead auto elim", fn: elimDeadAutosGeneric},
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,7 @@ type Frontend interface {
|
||||||
SplitStruct(LocalSlot, int) LocalSlot
|
SplitStruct(LocalSlot, int) LocalSlot
|
||||||
SplitArray(LocalSlot) LocalSlot // array must be length 1
|
SplitArray(LocalSlot) LocalSlot // array must be length 1
|
||||||
SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
|
SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
|
||||||
|
SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot
|
||||||
|
|
||||||
// DerefItab dereferences an itab function
|
// DerefItab dereferences an itab function
|
||||||
// entry, given the symbol of the itab and
|
// entry, given the symbol of the itab and
|
||||||
|
|
@ -198,9 +199,9 @@ const (
|
||||||
const go116lateCallExpansion = true
|
const go116lateCallExpansion = true
|
||||||
|
|
||||||
// LateCallExpansionEnabledWithin returns true if late call expansion should be tested
|
// LateCallExpansionEnabledWithin returns true if late call expansion should be tested
|
||||||
// within compilation of a function/method triggered by GOSSAHASH (defaults to "yes").
|
// within compilation of a function/method.
|
||||||
func LateCallExpansionEnabledWithin(f *Func) bool {
|
func LateCallExpansionEnabledWithin(f *Func) bool {
|
||||||
return go116lateCallExpansion && f.DebugTest // Currently set up for GOSSAHASH bug searches
|
return go116lateCallExpansion
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfig returns a new configuration object for the given architecture.
|
// NewConfig returns a new configuration object for the given architecture.
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// decompose converts phi ops on compound builtin types into phi
|
// decompose converts phi ops on compound builtin types into phi
|
||||||
|
|
@ -31,77 +32,79 @@ func decomposeBuiltIn(f *Func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split up named values into their components.
|
// Split up named values into their components.
|
||||||
|
// accumulate old names for aggregates (that are decomposed) in toDelete for efficient bulk deletion,
|
||||||
|
// accumulate new LocalSlots in newNames for addition after the iteration. This decomposition is for
|
||||||
|
// builtin types with leaf components, and thus there is no need to reprocess the newly create LocalSlots.
|
||||||
|
var toDelete []namedVal
|
||||||
var newNames []LocalSlot
|
var newNames []LocalSlot
|
||||||
for _, name := range f.Names {
|
for i, name := range f.Names {
|
||||||
t := name.Type
|
t := name.Type
|
||||||
switch {
|
switch {
|
||||||
case t.IsInteger() && t.Size() > f.Config.RegSize:
|
case t.IsInteger() && t.Size() > f.Config.RegSize:
|
||||||
hiName, loName := f.fe.SplitInt64(name)
|
hiName, loName := f.fe.SplitInt64(name)
|
||||||
newNames = append(newNames, hiName, loName)
|
newNames = append(newNames, hiName, loName)
|
||||||
for _, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[name] {
|
||||||
if v.Op != OpInt64Make {
|
if v.Op != OpInt64Make {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[hiName] = append(f.NamedValues[hiName], v.Args[0])
|
f.NamedValues[hiName] = append(f.NamedValues[hiName], v.Args[0])
|
||||||
f.NamedValues[loName] = append(f.NamedValues[loName], v.Args[1])
|
f.NamedValues[loName] = append(f.NamedValues[loName], v.Args[1])
|
||||||
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
delete(f.NamedValues, name)
|
|
||||||
case t.IsComplex():
|
case t.IsComplex():
|
||||||
rName, iName := f.fe.SplitComplex(name)
|
rName, iName := f.fe.SplitComplex(name)
|
||||||
newNames = append(newNames, rName, iName)
|
newNames = append(newNames, rName, iName)
|
||||||
for _, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[name] {
|
||||||
if v.Op != OpComplexMake {
|
if v.Op != OpComplexMake {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[rName] = append(f.NamedValues[rName], v.Args[0])
|
f.NamedValues[rName] = append(f.NamedValues[rName], v.Args[0])
|
||||||
f.NamedValues[iName] = append(f.NamedValues[iName], v.Args[1])
|
f.NamedValues[iName] = append(f.NamedValues[iName], v.Args[1])
|
||||||
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
delete(f.NamedValues, name)
|
|
||||||
case t.IsString():
|
case t.IsString():
|
||||||
ptrName, lenName := f.fe.SplitString(name)
|
ptrName, lenName := f.fe.SplitString(name)
|
||||||
newNames = append(newNames, ptrName, lenName)
|
newNames = append(newNames, ptrName, lenName)
|
||||||
for _, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[name] {
|
||||||
if v.Op != OpStringMake {
|
if v.Op != OpStringMake {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
|
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
|
||||||
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
|
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
|
||||||
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
delete(f.NamedValues, name)
|
|
||||||
case t.IsSlice():
|
case t.IsSlice():
|
||||||
ptrName, lenName, capName := f.fe.SplitSlice(name)
|
ptrName, lenName, capName := f.fe.SplitSlice(name)
|
||||||
newNames = append(newNames, ptrName, lenName, capName)
|
newNames = append(newNames, ptrName, lenName, capName)
|
||||||
for _, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[name] {
|
||||||
if v.Op != OpSliceMake {
|
if v.Op != OpSliceMake {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
|
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
|
||||||
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
|
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
|
||||||
f.NamedValues[capName] = append(f.NamedValues[capName], v.Args[2])
|
f.NamedValues[capName] = append(f.NamedValues[capName], v.Args[2])
|
||||||
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
delete(f.NamedValues, name)
|
|
||||||
case t.IsInterface():
|
case t.IsInterface():
|
||||||
typeName, dataName := f.fe.SplitInterface(name)
|
typeName, dataName := f.fe.SplitInterface(name)
|
||||||
newNames = append(newNames, typeName, dataName)
|
newNames = append(newNames, typeName, dataName)
|
||||||
for _, v := range f.NamedValues[name] {
|
for j, v := range f.NamedValues[name] {
|
||||||
if v.Op != OpIMake {
|
if v.Op != OpIMake {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[typeName] = append(f.NamedValues[typeName], v.Args[0])
|
f.NamedValues[typeName] = append(f.NamedValues[typeName], v.Args[0])
|
||||||
f.NamedValues[dataName] = append(f.NamedValues[dataName], v.Args[1])
|
f.NamedValues[dataName] = append(f.NamedValues[dataName], v.Args[1])
|
||||||
|
toDelete = append(toDelete, namedVal{i, j})
|
||||||
}
|
}
|
||||||
delete(f.NamedValues, name)
|
|
||||||
case t.IsFloat():
|
case t.IsFloat():
|
||||||
// floats are never decomposed, even ones bigger than RegSize
|
// floats are never decomposed, even ones bigger than RegSize
|
||||||
newNames = append(newNames, name)
|
|
||||||
case t.Size() > f.Config.RegSize:
|
case t.Size() > f.Config.RegSize:
|
||||||
f.Fatalf("undecomposed named type %s %v", name, t)
|
f.Fatalf("undecomposed named type %s %v", name, t)
|
||||||
default:
|
|
||||||
newNames = append(newNames, name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.Names = newNames
|
|
||||||
|
deleteNamedVals(f, toDelete)
|
||||||
|
f.Names = append(f.Names, newNames...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func decomposeBuiltInPhi(v *Value) {
|
func decomposeBuiltInPhi(v *Value) {
|
||||||
|
|
@ -263,14 +266,20 @@ func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalS
|
||||||
f.Fatalf("array not of size 1")
|
f.Fatalf("array not of size 1")
|
||||||
}
|
}
|
||||||
elemName := f.fe.SplitArray(name)
|
elemName := f.fe.SplitArray(name)
|
||||||
|
var keep []*Value
|
||||||
for _, v := range f.NamedValues[name] {
|
for _, v := range f.NamedValues[name] {
|
||||||
if v.Op != OpArrayMake1 {
|
if v.Op != OpArrayMake1 {
|
||||||
|
keep = append(keep, v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.NamedValues[elemName] = append(f.NamedValues[elemName], v.Args[0])
|
f.NamedValues[elemName] = append(f.NamedValues[elemName], v.Args[0])
|
||||||
}
|
}
|
||||||
|
if len(keep) == 0 {
|
||||||
// delete the name for the array as a whole
|
// delete the name for the array as a whole
|
||||||
delete(f.NamedValues, name)
|
delete(f.NamedValues, name)
|
||||||
|
} else {
|
||||||
|
f.NamedValues[name] = keep
|
||||||
|
}
|
||||||
|
|
||||||
if t.Elem().IsArray() {
|
if t.Elem().IsArray() {
|
||||||
return decomposeUserArrayInto(f, elemName, slots)
|
return decomposeUserArrayInto(f, elemName, slots)
|
||||||
|
|
@ -300,17 +309,23 @@ func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []Local
|
||||||
}
|
}
|
||||||
|
|
||||||
makeOp := StructMakeOp(n)
|
makeOp := StructMakeOp(n)
|
||||||
|
var keep []*Value
|
||||||
// create named values for each struct field
|
// create named values for each struct field
|
||||||
for _, v := range f.NamedValues[name] {
|
for _, v := range f.NamedValues[name] {
|
||||||
if v.Op != makeOp {
|
if v.Op != makeOp {
|
||||||
|
keep = append(keep, v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for i := 0; i < len(fnames); i++ {
|
for i := 0; i < len(fnames); i++ {
|
||||||
f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], v.Args[i])
|
f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], v.Args[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// remove the name of the struct as a whole
|
if len(keep) == 0 {
|
||||||
|
// delete the name for the struct as a whole
|
||||||
delete(f.NamedValues, name)
|
delete(f.NamedValues, name)
|
||||||
|
} else {
|
||||||
|
f.NamedValues[name] = keep
|
||||||
|
}
|
||||||
|
|
||||||
// now that this f.NamedValues contains values for the struct
|
// now that this f.NamedValues contains values for the struct
|
||||||
// fields, recurse into nested structs
|
// fields, recurse into nested structs
|
||||||
|
|
@ -400,3 +415,35 @@ func StructMakeOp(nf int) Op {
|
||||||
}
|
}
|
||||||
panic("too many fields in an SSAable struct")
|
panic("too many fields in an SSAable struct")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type namedVal struct {
|
||||||
|
locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key
|
||||||
|
}
|
||||||
|
|
||||||
|
// deleteNamedVals removes particular values with debugger names from f's naming data structures
|
||||||
|
func deleteNamedVals(f *Func, toDelete []namedVal) {
|
||||||
|
// Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalid pending indices.
|
||||||
|
sort.Slice(toDelete, func(i, j int) bool {
|
||||||
|
if toDelete[i].locIndex != toDelete[j].locIndex {
|
||||||
|
return toDelete[i].locIndex > toDelete[j].locIndex
|
||||||
|
}
|
||||||
|
return toDelete[i].valIndex > toDelete[j].valIndex
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get rid of obsolete names
|
||||||
|
for _, d := range toDelete {
|
||||||
|
loc := f.Names[d.locIndex]
|
||||||
|
vals := f.NamedValues[loc]
|
||||||
|
l := len(vals) - 1
|
||||||
|
if l > 0 {
|
||||||
|
vals[d.valIndex] = vals[l]
|
||||||
|
f.NamedValues[loc] = vals[:l]
|
||||||
|
} else {
|
||||||
|
delete(f.NamedValues, loc)
|
||||||
|
l = len(f.Names) - 1
|
||||||
|
f.Names[d.locIndex] = f.Names[l]
|
||||||
|
f.Names = f.Names[:l]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -125,6 +125,10 @@ func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
|
||||||
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
|
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
|
||||||
return LocalSlot{N: s.N, Type: s.Type.Elem(), Off: s.Off}
|
return LocalSlot{N: s.N, Type: s.Type.Elem(), Off: s.Off}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d DummyFrontend) SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot {
|
||||||
|
return LocalSlot{N: parent.N, Type: t, Off: offset}
|
||||||
|
}
|
||||||
func (DummyFrontend) Line(_ src.XPos) string {
|
func (DummyFrontend) Line(_ src.XPos) string {
|
||||||
return "unknown.go:0"
|
return "unknown.go:0"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,11 +191,6 @@ func flagalloc(f *Func) {
|
||||||
b.FlagsLiveAtEnd = end[b.ID] != nil
|
b.FlagsLiveAtEnd = end[b.ID] != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const go115flagallocdeadcode = true
|
|
||||||
if !go115flagallocdeadcode {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove any now-dead values.
|
// Remove any now-dead values.
|
||||||
// The number of values to remove is likely small,
|
// The number of values to remove is likely small,
|
||||||
// and removing them requires processing all values in a block,
|
// and removing them requires processing all values in a block,
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@
|
||||||
(Const32 ...) => (MOVLconst ...)
|
(Const32 ...) => (MOVLconst ...)
|
||||||
(Const(32|64)F ...) => (MOVS(S|D)const ...)
|
(Const(32|64)F ...) => (MOVS(S|D)const ...)
|
||||||
(ConstNil) => (MOVLconst [0])
|
(ConstNil) => (MOVLconst [0])
|
||||||
(ConstBool [c]) => (MOVLconst [int32(b2i(c))])
|
(ConstBool [c]) => (MOVLconst [b2i32(c)])
|
||||||
|
|
||||||
// Lowering calls
|
// Lowering calls
|
||||||
(StaticCall ...) => (CALLstatic ...)
|
(StaticCall ...) => (CALLstatic ...)
|
||||||
|
|
@ -640,31 +640,31 @@
|
||||||
// it compiles to a thunk call).
|
// it compiles to a thunk call).
|
||||||
(MOV(L|W|B|SS|SD|BLSX|WLSX)load [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)
|
(MOV(L|W|B|SS|SD|BLSX|WLSX)load [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)
|
||||||
&& (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOV(L|W|B|SS|SD|BLSX|WLSX)load [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
(MOV(L|W|B|SS|SD|BLSX|WLSX)load [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||||
|
|
||||||
(MOV(L|W|B|SS|SD)store [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)
|
(MOV(L|W|B|SS|SD)store [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2)
|
||||||
&& (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOV(L|W|B|SS|SD)store [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
(MOV(L|W|B|SS|SD)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
|
|
||||||
(MOV(L|W|B)storeconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off)
|
(MOV(L|W|B)storeconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off)
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOV(L|W|B)storeconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
(MOV(L|W|B)storeconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||||
|
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
((ADD|SUB|MUL|DIV)SDload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
((ADD|SUB|MUL|DIV)SDload [off1] {sym1} val (LEAL [off2] {sym2} base) mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
|
((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem)
|
((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem)
|
||||||
&& valoff1.canAdd32(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& valoff1.canAdd32(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
((ADD|AND|OR|XOR)Lconstmodify [valoff1.addOffset32(off2)] {mergeSymTyped(sym1,sym2)} base mem)
|
((ADD|AND|OR|XOR)Lconstmodify [valoff1.addOffset32(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||||
|
|
||||||
// Merge load/store to op
|
// Merge load/store to op
|
||||||
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem)
|
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem)
|
||||||
|
|
@ -679,37 +679,37 @@
|
||||||
|
|
||||||
// fold LEALs together
|
// fold LEALs together
|
||||||
(LEAL [off1] {sym1} (LEAL [off2] {sym2} x)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAL [off1] {sym1} (LEAL [off2] {sym2} x)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAL [off1+off2] {mergeSymTyped(sym1,sym2)} x)
|
(LEAL [off1+off2] {mergeSym(sym1,sym2)} x)
|
||||||
|
|
||||||
// LEAL into LEAL1
|
// LEAL into LEAL1
|
||||||
(LEAL1 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
(LEAL1 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||||
(LEAL1 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
// LEAL1 into LEAL
|
// LEAL1 into LEAL
|
||||||
(LEAL [off1] {sym1} (LEAL1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAL [off1] {sym1} (LEAL1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAL1 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
// LEAL into LEAL[248]
|
// LEAL into LEAL[248]
|
||||||
(LEAL2 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
(LEAL2 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||||
(LEAL2 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAL2 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
(LEAL4 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
(LEAL4 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||||
(LEAL4 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAL4 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
(LEAL8 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
(LEAL8 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||||
(LEAL8 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
// LEAL[248] into LEAL
|
// LEAL[248] into LEAL
|
||||||
(LEAL [off1] {sym1} (LEAL2 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAL [off1] {sym1} (LEAL2 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAL2 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAL2 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
(LEAL [off1] {sym1} (LEAL4 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAL [off1] {sym1} (LEAL4 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAL4 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAL4 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
(LEAL [off1] {sym1} (LEAL8 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAL [off1] {sym1} (LEAL8 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAL8 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
// LEAL[1248] into LEAL[1248]. Only some such merges are possible.
|
// LEAL[1248] into LEAL[1248]. Only some such merges are possible.
|
||||||
(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} y y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} y y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAL2 [off1+off2] {mergeSymTyped(sym1, sym2)} x y)
|
(LEAL2 [off1+off2] {mergeSym(sym1, sym2)} x y)
|
||||||
(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAL2 [off1+off2] {mergeSymTyped(sym1, sym2)} y x)
|
(LEAL2 [off1+off2] {mergeSym(sym1, sym2)} y x)
|
||||||
(LEAL2 [off1] {sym} x (LEAL1 [off2] {nil} y y)) && is32Bit(int64(off1)+2*int64(off2)) =>
|
(LEAL2 [off1] {sym} x (LEAL1 [off2] {nil} y y)) && is32Bit(int64(off1)+2*int64(off2)) =>
|
||||||
(LEAL4 [off1+2*off2] {sym} x y)
|
(LEAL4 [off1+2*off2] {sym} x y)
|
||||||
(LEAL4 [off1] {sym} x (LEAL1 [off2] {nil} y y)) && is32Bit(int64(off1)+4*int64(off2)) =>
|
(LEAL4 [off1] {sym} x (LEAL1 [off2] {nil} y y)) && is32Bit(int64(off1)+4*int64(off2)) =>
|
||||||
|
|
@ -993,49 +993,49 @@
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& a.Off() + 1 == c.Off()
|
&& a.Off() + 1 == c.Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), int32(a.Off()))] {s} p mem)
|
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p mem)
|
||||||
(MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem))
|
(MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& a.Off() + 1 == c.Off()
|
&& a.Off() + 1 == c.Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), int32(a.Off()))] {s} p mem)
|
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p mem)
|
||||||
|
|
||||||
(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem))
|
(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& a.Off() == c.Off()
|
&& a.Off() == c.Off()
|
||||||
&& sequentialAddresses(p0, p1, 1)
|
&& sequentialAddresses(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), int32(a.Off()))] {s} p0 mem)
|
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p0 mem)
|
||||||
(MOVBstoreconst [a] {s} p0 x:(MOVBstoreconst [c] {s} p1 mem))
|
(MOVBstoreconst [a] {s} p0 x:(MOVBstoreconst [c] {s} p1 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& a.Off() == c.Off()
|
&& a.Off() == c.Off()
|
||||||
&& sequentialAddresses(p0, p1, 1)
|
&& sequentialAddresses(p0, p1, 1)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), int32(a.Off()))] {s} p0 mem)
|
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p0 mem)
|
||||||
|
|
||||||
(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
|
(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& a.Off() + 2 == c.Off()
|
&& a.Off() + 2 == c.Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), int32(a.Off()))] {s} p mem)
|
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p mem)
|
||||||
(MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem))
|
(MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), int32(a.Off()))] {s} p mem)
|
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p mem)
|
||||||
|
|
||||||
(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem))
|
(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& a.Off() == c.Off()
|
&& a.Off() == c.Off()
|
||||||
&& sequentialAddresses(p0, p1, 2)
|
&& sequentialAddresses(p0, p1, 2)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), int32(a.Off()))] {s} p0 mem)
|
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p0 mem)
|
||||||
(MOVWstoreconst [a] {s} p0 x:(MOVWstoreconst [c] {s} p1 mem))
|
(MOVWstoreconst [a] {s} p0 x:(MOVWstoreconst [c] {s} p1 mem))
|
||||||
&& x.Uses == 1
|
&& x.Uses == 1
|
||||||
&& a.Off() == c.Off()
|
&& a.Off() == c.Off()
|
||||||
&& sequentialAddresses(p0, p1, 2)
|
&& sequentialAddresses(p0, p1, 2)
|
||||||
&& clobber(x)
|
&& clobber(x)
|
||||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), int32(a.Off()))] {s} p0 mem)
|
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p0 mem)
|
||||||
|
|
||||||
// Combine stores into larger (unaligned) stores.
|
// Combine stores into larger (unaligned) stores.
|
||||||
(MOVBstore [i] {s} p (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p w mem))
|
(MOVBstore [i] {s} p (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p w mem))
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,7 @@
|
||||||
(Const32F ...) => (MOVSSconst ...)
|
(Const32F ...) => (MOVSSconst ...)
|
||||||
(Const64F ...) => (MOVSDconst ...)
|
(Const64F ...) => (MOVSDconst ...)
|
||||||
(ConstNil ) => (MOVQconst [0])
|
(ConstNil ) => (MOVQconst [0])
|
||||||
(ConstBool [c]) => (MOVLconst [int32(b2i(c))])
|
(ConstBool [c]) => (MOVLconst [b2i32(c)])
|
||||||
|
|
||||||
// Lowering calls
|
// Lowering calls
|
||||||
(StaticCall ...) => (CALLstatic ...)
|
(StaticCall ...) => (CALLstatic ...)
|
||||||
|
|
@ -531,7 +531,9 @@
|
||||||
|
|
||||||
// Atomic memory updates.
|
// Atomic memory updates.
|
||||||
(AtomicAnd8 ptr val mem) => (ANDBlock ptr val mem)
|
(AtomicAnd8 ptr val mem) => (ANDBlock ptr val mem)
|
||||||
|
(AtomicAnd32 ptr val mem) => (ANDLlock ptr val mem)
|
||||||
(AtomicOr8 ptr val mem) => (ORBlock ptr val mem)
|
(AtomicOr8 ptr val mem) => (ORBlock ptr val mem)
|
||||||
|
(AtomicOr32 ptr val mem) => (ORLlock ptr val mem)
|
||||||
|
|
||||||
// Write barrier.
|
// Write barrier.
|
||||||
(WB ...) => (LoweredWB ...)
|
(WB ...) => (LoweredWB ...)
|
||||||
|
|
@ -581,7 +583,7 @@
|
||||||
((NE|EQ) (TESTQconst [c] x)) && isUint64PowerOfTwo(int64(c))
|
((NE|EQ) (TESTQconst [c] x)) && isUint64PowerOfTwo(int64(c))
|
||||||
=> ((ULT|UGE) (BTQconst [int8(log32(c))] x))
|
=> ((ULT|UGE) (BTQconst [int8(log32(c))] x))
|
||||||
((NE|EQ) (TESTQ (MOVQconst [c]) x)) && isUint64PowerOfTwo(c)
|
((NE|EQ) (TESTQ (MOVQconst [c]) x)) && isUint64PowerOfTwo(c)
|
||||||
=> ((ULT|UGE) (BTQconst [int8(log2(c))] x))
|
=> ((ULT|UGE) (BTQconst [int8(log64(c))] x))
|
||||||
(SET(NE|EQ) (TESTL (SHLL (MOVLconst [1]) x) y)) => (SET(B|AE) (BTL x y))
|
(SET(NE|EQ) (TESTL (SHLL (MOVLconst [1]) x) y)) => (SET(B|AE) (BTL x y))
|
||||||
(SET(NE|EQ) (TESTQ (SHLQ (MOVQconst [1]) x) y)) => (SET(B|AE) (BTQ x y))
|
(SET(NE|EQ) (TESTQ (SHLQ (MOVQconst [1]) x) y)) => (SET(B|AE) (BTQ x y))
|
||||||
(SET(NE|EQ) (TESTLconst [c] x)) && isUint32PowerOfTwo(int64(c))
|
(SET(NE|EQ) (TESTLconst [c] x)) && isUint32PowerOfTwo(int64(c))
|
||||||
|
|
@ -589,7 +591,7 @@
|
||||||
(SET(NE|EQ) (TESTQconst [c] x)) && isUint64PowerOfTwo(int64(c))
|
(SET(NE|EQ) (TESTQconst [c] x)) && isUint64PowerOfTwo(int64(c))
|
||||||
=> (SET(B|AE) (BTQconst [int8(log32(c))] x))
|
=> (SET(B|AE) (BTQconst [int8(log32(c))] x))
|
||||||
(SET(NE|EQ) (TESTQ (MOVQconst [c]) x)) && isUint64PowerOfTwo(c)
|
(SET(NE|EQ) (TESTQ (MOVQconst [c]) x)) && isUint64PowerOfTwo(c)
|
||||||
=> (SET(B|AE) (BTQconst [int8(log2(c))] x))
|
=> (SET(B|AE) (BTQconst [int8(log64(c))] x))
|
||||||
// SET..store variant
|
// SET..store variant
|
||||||
(SET(NE|EQ)store [off] {sym} ptr (TESTL (SHLL (MOVLconst [1]) x) y) mem)
|
(SET(NE|EQ)store [off] {sym} ptr (TESTL (SHLL (MOVLconst [1]) x) y) mem)
|
||||||
=> (SET(B|AE)store [off] {sym} ptr (BTL x y) mem)
|
=> (SET(B|AE)store [off] {sym} ptr (BTL x y) mem)
|
||||||
|
|
@ -600,7 +602,7 @@
|
||||||
(SET(NE|EQ)store [off] {sym} ptr (TESTQconst [c] x) mem) && isUint64PowerOfTwo(int64(c))
|
(SET(NE|EQ)store [off] {sym} ptr (TESTQconst [c] x) mem) && isUint64PowerOfTwo(int64(c))
|
||||||
=> (SET(B|AE)store [off] {sym} ptr (BTQconst [int8(log32(c))] x) mem)
|
=> (SET(B|AE)store [off] {sym} ptr (BTQconst [int8(log32(c))] x) mem)
|
||||||
(SET(NE|EQ)store [off] {sym} ptr (TESTQ (MOVQconst [c]) x) mem) && isUint64PowerOfTwo(c)
|
(SET(NE|EQ)store [off] {sym} ptr (TESTQ (MOVQconst [c]) x) mem) && isUint64PowerOfTwo(c)
|
||||||
=> (SET(B|AE)store [off] {sym} ptr (BTQconst [int8(log2(c))] x) mem)
|
=> (SET(B|AE)store [off] {sym} ptr (BTQconst [int8(log64(c))] x) mem)
|
||||||
|
|
||||||
// Handle bit-testing in the form (a>>b)&1 != 0 by building the above rules
|
// Handle bit-testing in the form (a>>b)&1 != 0 by building the above rules
|
||||||
// and further combining shifts.
|
// and further combining shifts.
|
||||||
|
|
@ -629,7 +631,7 @@
|
||||||
((ORL|XORL)const [c] x) && isUint32PowerOfTwo(int64(c)) && uint64(c) >= 128
|
((ORL|XORL)const [c] x) && isUint32PowerOfTwo(int64(c)) && uint64(c) >= 128
|
||||||
=> (BT(S|C)Lconst [int8(log32(c))] x)
|
=> (BT(S|C)Lconst [int8(log32(c))] x)
|
||||||
((ORQ|XORQ) (MOVQconst [c]) x) && isUint64PowerOfTwo(c) && uint64(c) >= 128
|
((ORQ|XORQ) (MOVQconst [c]) x) && isUint64PowerOfTwo(c) && uint64(c) >= 128
|
||||||
=> (BT(S|C)Qconst [int8(log2(c))] x)
|
=> (BT(S|C)Qconst [int8(log64(c))] x)
|
||||||
((ORL|XORL) (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(c)) && uint64(c) >= 128
|
((ORL|XORL) (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(c)) && uint64(c) >= 128
|
||||||
=> (BT(S|C)Lconst [int8(log32(c))] x)
|
=> (BT(S|C)Lconst [int8(log32(c))] x)
|
||||||
|
|
||||||
|
|
@ -640,7 +642,7 @@
|
||||||
(ANDLconst [c] x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
|
(ANDLconst [c] x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
|
||||||
=> (BTRLconst [int8(log32(^c))] x)
|
=> (BTRLconst [int8(log32(^c))] x)
|
||||||
(ANDQ (MOVQconst [c]) x) && isUint64PowerOfTwo(^c) && uint64(^c) >= 128
|
(ANDQ (MOVQconst [c]) x) && isUint64PowerOfTwo(^c) && uint64(^c) >= 128
|
||||||
=> (BTRQconst [int8(log2(^c))] x)
|
=> (BTRQconst [int8(log64(^c))] x)
|
||||||
(ANDL (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
|
(ANDL (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
|
||||||
=> (BTRLconst [int8(log32(^c))] x)
|
=> (BTRLconst [int8(log32(^c))] x)
|
||||||
|
|
||||||
|
|
@ -957,7 +959,7 @@
|
||||||
(MUL(Q|L)const [73] x) => (LEA(Q|L)8 x (LEA(Q|L)8 <v.Type> x x))
|
(MUL(Q|L)const [73] x) => (LEA(Q|L)8 x (LEA(Q|L)8 <v.Type> x x))
|
||||||
(MUL(Q|L)const [81] x) => (LEA(Q|L)8 (LEA(Q|L)8 <v.Type> x x) (LEA(Q|L)8 <v.Type> x x))
|
(MUL(Q|L)const [81] x) => (LEA(Q|L)8 (LEA(Q|L)8 <v.Type> x x) (LEA(Q|L)8 <v.Type> x x))
|
||||||
|
|
||||||
(MUL(Q|L)const [c] x) && isPowerOfTwo(int64(c)+1) && c >= 15 => (SUB(Q|L) (SHL(Q|L)const <v.Type> [int8(log2(int64(c)+1))] x) x)
|
(MUL(Q|L)const [c] x) && isPowerOfTwo64(int64(c)+1) && c >= 15 => (SUB(Q|L) (SHL(Q|L)const <v.Type> [int8(log64(int64(c)+1))] x) x)
|
||||||
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-1) && c >= 17 => (LEA(Q|L)1 (SHL(Q|L)const <v.Type> [int8(log32(c-1))] x) x)
|
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-1) && c >= 17 => (LEA(Q|L)1 (SHL(Q|L)const <v.Type> [int8(log32(c-1))] x) x)
|
||||||
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-2) && c >= 34 => (LEA(Q|L)2 (SHL(Q|L)const <v.Type> [int8(log32(c-2))] x) x)
|
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-2) && c >= 34 => (LEA(Q|L)2 (SHL(Q|L)const <v.Type> [int8(log32(c-2))] x) x)
|
||||||
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-4) && c >= 68 => (LEA(Q|L)4 (SHL(Q|L)const <v.Type> [int8(log32(c-4))] x) x)
|
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-4) && c >= 68 => (LEA(Q|L)4 (SHL(Q|L)const <v.Type> [int8(log32(c-4))] x) x)
|
||||||
|
|
@ -1135,80 +1137,80 @@
|
||||||
// what variables are being read/written by the ops.
|
// what variables are being read/written by the ops.
|
||||||
(MOV(Q|L|W|B|SS|SD|O|BQSX|WQSX|LQSX)load [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
(MOV(Q|L|W|B|SS|SD|O|BQSX|WQSX|LQSX)load [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(MOV(Q|L|W|B|SS|SD|O|BQSX|WQSX|LQSX)load [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
(MOV(Q|L|W|B|SS|SD|O|BQSX|WQSX|LQSX)load [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||||
(MOV(Q|L|W|B|SS|SD|O)store [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
(MOV(Q|L|W|B|SS|SD|O)store [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(MOV(Q|L|W|B|SS|SD|O)store [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
(MOV(Q|L|W|B|SS|SD|O)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
(MOV(Q|L|W|B)storeconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd32(off) =>
|
(MOV(Q|L|W|B)storeconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd32(off) =>
|
||||||
(MOV(Q|L|W|B)storeconst [ValAndOff(sc).addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
(MOV(Q|L|W|B)storeconst [ValAndOff(sc).addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||||
(SET(L|G|B|A|LE|GE|BE|AE|EQ|NE)store [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
(SET(L|G|B|A|LE|GE|BE|AE|EQ|NE)store [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(SET(L|G|B|A|LE|GE|BE|AE|EQ|NE)store [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
(SET(L|G|B|A|LE|GE|BE|AE|EQ|NE)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
((ADD|SUB|AND|OR|XOR)Qload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
((ADD|SUB|AND|OR|XOR)Qload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
((ADD|SUB|AND|OR|XOR)Qload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
((ADD|SUB|AND|OR|XOR)Qload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
((ADD|SUB|AND|OR|XOR)Lload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
((ADD|SUB|AND|OR|XOR)Lload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
((ADD|SUB|AND|OR|XOR)Lload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
((ADD|SUB|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
(CMP(Q|L|W|B)load [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
(CMP(Q|L|W|B)load [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(CMP(Q|L|W|B)load [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
(CMP(Q|L|W|B)load [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
(CMP(Q|L|W|B)constload [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
(CMP(Q|L|W|B)constload [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||||
&& ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) =>
|
&& ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) =>
|
||||||
(CMP(Q|L|W|B)constload [ValAndOff(valoff1).addOffset32(off2)] {mergeSymTyped(sym1,sym2)} base mem)
|
(CMP(Q|L|W|B)constload [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||||
|
|
||||||
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
((ADD|SUB|MUL|DIV)SDload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
((ADD|SUB|MUL|DIV)SDload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||||
&& ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) =>
|
&& ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) =>
|
||||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSymTyped(sym1,sym2)} base mem)
|
((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||||
&& ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) =>
|
&& ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) =>
|
||||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSymTyped(sym1,sym2)} base mem)
|
((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Qmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Qmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Qmodify [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Qmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
||||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
|
|
||||||
// fold LEAQs together
|
// fold LEAQs together
|
||||||
(LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAQ [off1+off2] {mergeSymTyped(sym1,sym2)} x)
|
(LEAQ [off1+off2] {mergeSym(sym1,sym2)} x)
|
||||||
|
|
||||||
// LEAQ into LEAQ1
|
// LEAQ into LEAQ1
|
||||||
(LEAQ1 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
(LEAQ1 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||||
(LEAQ1 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
// LEAQ1 into LEAQ
|
// LEAQ1 into LEAQ
|
||||||
(LEAQ [off1] {sym1} (LEAQ1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAQ [off1] {sym1} (LEAQ1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAQ1 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
// LEAQ into LEAQ[248]
|
// LEAQ into LEAQ[248]
|
||||||
(LEAQ2 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
(LEAQ2 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||||
(LEAQ2 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
(LEAQ4 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
(LEAQ4 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||||
(LEAQ4 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
(LEAQ8 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
(LEAQ8 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||||
(LEAQ8 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
// LEAQ[248] into LEAQ
|
// LEAQ[248] into LEAQ
|
||||||
(LEAQ [off1] {sym1} (LEAQ2 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAQ [off1] {sym1} (LEAQ2 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAQ2 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
(LEAQ [off1] {sym1} (LEAQ4 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAQ [off1] {sym1} (LEAQ4 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAQ4 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
(LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAQ8 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
(LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||||
|
|
||||||
// LEAQ[1248] into LEAQ[1248]. Only some such merges are possible.
|
// LEAQ[1248] into LEAQ[1248]. Only some such merges are possible.
|
||||||
(LEAQ1 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAQ1 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAQ2 [off1+off2] {mergeSymTyped(sym1, sym2)} x y)
|
(LEAQ2 [off1+off2] {mergeSym(sym1, sym2)} x y)
|
||||||
(LEAQ1 [off1] {sym1} x (LEAQ1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(LEAQ1 [off1] {sym1} x (LEAQ1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(LEAQ2 [off1+off2] {mergeSymTyped(sym1, sym2)} y x)
|
(LEAQ2 [off1+off2] {mergeSym(sym1, sym2)} y x)
|
||||||
(LEAQ2 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(int64(off1)+2*int64(off2)) && sym2 == nil =>
|
(LEAQ2 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(int64(off1)+2*int64(off2)) && sym2 == nil =>
|
||||||
(LEAQ4 [off1+2*off2] {sym1} x y)
|
(LEAQ4 [off1+2*off2] {sym1} x y)
|
||||||
(LEAQ4 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(int64(off1)+4*int64(off2)) && sym2 == nil =>
|
(LEAQ4 [off1] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(int64(off1)+4*int64(off2)) && sym2 == nil =>
|
||||||
|
|
@ -1998,31 +2000,31 @@
|
||||||
=> (MOVQstore [i-4] {s} p (MOVQload [j-4] {s2} p2 mem) mem)
|
=> (MOVQstore [i-4] {s} p (MOVQload [j-4] {s2} p2 mem) mem)
|
||||||
|
|
||||||
(MOVQload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOVQload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOVQload [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
(MOVQload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||||
(MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOVLload [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
(MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||||
(MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOVWload [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||||
(MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOVBload [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||||
|
|
||||||
(MOVQstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOVQstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOVQstore [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
(MOVQstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
(MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOVLstore [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
(MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
(MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOVWstore [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
(MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOVBstore [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||||
|
|
||||||
(MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
(MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
||||||
(MOVQstoreconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
(MOVQstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||||
(MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
(MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
||||||
(MOVLstoreconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
(MOVLstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||||
(MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
(MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
||||||
(MOVWstoreconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
(MOVWstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||||
(MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
(MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
||||||
(MOVBstoreconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
(MOVBstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||||
|
|
||||||
(MOVQload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) => (MOVQload [off1+off2] {sym} ptr mem)
|
(MOVQload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) => (MOVQload [off1+off2] {sym} ptr mem)
|
||||||
(MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) => (MOVLload [off1+off2] {sym} ptr mem)
|
(MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) => (MOVLload [off1+off2] {sym} ptr mem)
|
||||||
|
|
@ -2058,17 +2060,17 @@
|
||||||
(MOV(Q|L|B)atomicload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
(MOV(Q|L|B)atomicload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(MOV(Q|L|B)atomicload [off1+off2] {sym} ptr mem)
|
(MOV(Q|L|B)atomicload [off1+off2] {sym} ptr mem)
|
||||||
(MOV(Q|L|B)atomicload [off1] {sym1} (LEAQ [off2] {sym2} ptr) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
(MOV(Q|L|B)atomicload [off1] {sym1} (LEAQ [off2] {sym2} ptr) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||||
(MOV(Q|L|B)atomicload [off1+off2] {mergeSymTyped(sym1, sym2)} ptr mem)
|
(MOV(Q|L|B)atomicload [off1+off2] {mergeSym(sym1, sym2)} ptr mem)
|
||||||
|
|
||||||
// Merge ADDQconst and LEAQ into atomic stores.
|
// Merge ADDQconst and LEAQ into atomic stores.
|
||||||
(XCHGQ [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
(XCHGQ [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(XCHGQ [off1+off2] {sym} val ptr mem)
|
(XCHGQ [off1+off2] {sym} val ptr mem)
|
||||||
(XCHGQ [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && ptr.Op != OpSB =>
|
(XCHGQ [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && ptr.Op != OpSB =>
|
||||||
(XCHGQ [off1+off2] {mergeSymTyped(sym1,sym2)} val ptr mem)
|
(XCHGQ [off1+off2] {mergeSym(sym1,sym2)} val ptr mem)
|
||||||
(XCHGL [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
(XCHGL [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
||||||
(XCHGL [off1+off2] {sym} val ptr mem)
|
(XCHGL [off1+off2] {sym} val ptr mem)
|
||||||
(XCHGL [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && ptr.Op != OpSB =>
|
(XCHGL [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && ptr.Op != OpSB =>
|
||||||
(XCHGL [off1+off2] {mergeSymTyped(sym1,sym2)} val ptr mem)
|
(XCHGL [off1+off2] {mergeSym(sym1,sym2)} val ptr mem)
|
||||||
|
|
||||||
// Merge ADDQconst into atomic adds.
|
// Merge ADDQconst into atomic adds.
|
||||||
// TODO: merging LEAQ doesn't work, assembler doesn't like the resulting instructions.
|
// TODO: merging LEAQ doesn't work, assembler doesn't like the resulting instructions.
|
||||||
|
|
|
||||||
|
|
@ -902,7 +902,9 @@ func init() {
|
||||||
|
|
||||||
// Atomic memory updates.
|
// Atomic memory updates.
|
||||||
{name: "ANDBlock", argLength: 3, reg: gpstore, asm: "ANDB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) &= arg1
|
{name: "ANDBlock", argLength: 3, reg: gpstore, asm: "ANDB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) &= arg1
|
||||||
|
{name: "ANDLlock", argLength: 3, reg: gpstore, asm: "ANDL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) &= arg1
|
||||||
{name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) |= arg1
|
{name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) |= arg1
|
||||||
|
{name: "ORLlock", argLength: 3, reg: gpstore, asm: "ORL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) |= arg1
|
||||||
}
|
}
|
||||||
|
|
||||||
var AMD64blocks = []blockData{
|
var AMD64blocks = []blockData{
|
||||||
|
|
|
||||||
|
|
@ -169,10 +169,10 @@
|
||||||
(Rsh8x64 x (Const64 [c])) && uint64(c) >= 8 => (SRAconst (SLLconst <typ.UInt32> x [24]) [31])
|
(Rsh8x64 x (Const64 [c])) && uint64(c) >= 8 => (SRAconst (SLLconst <typ.UInt32> x [24]) [31])
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
(Const(8|16|32) ...) -> (MOVWconst ...)
|
(Const(8|16|32) [val]) => (MOVWconst [int32(val)])
|
||||||
(Const(32F|64F) ...) -> (MOV(F|D)const ...)
|
(Const(32|64)F [val]) => (MOV(F|D)const [float64(val)])
|
||||||
(ConstNil) => (MOVWconst [0])
|
(ConstNil) => (MOVWconst [0])
|
||||||
(ConstBool ...) -> (MOVWconst ...)
|
(ConstBool [b]) => (MOVWconst [b2i32(b)])
|
||||||
|
|
||||||
// truncations
|
// truncations
|
||||||
// Because we ignore high parts of registers, truncates are just copies.
|
// Because we ignore high parts of registers, truncates are just copies.
|
||||||
|
|
@ -243,10 +243,10 @@
|
||||||
(Leq16U x y) => (LessEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
|
(Leq16U x y) => (LessEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
|
||||||
(Leq32U x y) => (LessEqualU (CMP x y))
|
(Leq32U x y) => (LessEqualU (CMP x y))
|
||||||
|
|
||||||
(OffPtr [off] ptr:(SP)) -> (MOVWaddr [off] ptr)
|
(OffPtr [off] ptr:(SP)) => (MOVWaddr [int32(off)] ptr)
|
||||||
(OffPtr [off] ptr) -> (ADDconst [off] ptr)
|
(OffPtr [off] ptr) => (ADDconst [int32(off)] ptr)
|
||||||
|
|
||||||
(Addr ...) -> (MOVWaddr ...)
|
(Addr {sym} base) => (MOVWaddr {sym} base)
|
||||||
(LocalAddr {sym} base _) => (MOVWaddr {sym} base)
|
(LocalAddr {sym} base _) => (MOVWaddr {sym} base)
|
||||||
|
|
||||||
// loads
|
// loads
|
||||||
|
|
@ -433,30 +433,30 @@
|
||||||
(MOVDstore [off1] {sym} (SUBconst [off2] ptr) val mem) => (MOVDstore [off1-off2] {sym} ptr val mem)
|
(MOVDstore [off1] {sym} (SUBconst [off2] ptr) val mem) => (MOVDstore [off1-off2] {sym} ptr val mem)
|
||||||
|
|
||||||
(MOVBload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
(MOVBload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVBload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVBUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
(MOVBUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVBUload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVHload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
(MOVHload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVHload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVHUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
(MOVHUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVHUload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVWload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
(MOVWload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVWload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVFload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
(MOVFload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVFload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVDload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
(MOVDload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVDload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
|
|
||||||
(MOVBstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
(MOVBstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVBstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(MOVHstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
(MOVHstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVHstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(MOVWstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
(MOVWstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVWstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(MOVFstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
(MOVFstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVFstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
(MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||||
(MOVDstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
|
|
||||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) => (MOVBreg x)
|
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) => (MOVBreg x)
|
||||||
|
|
@ -1052,8 +1052,8 @@
|
||||||
(BICshiftRL x (MOVWconst [c]) [d]) => (BICconst x [int32(uint32(c)>>uint64(d))])
|
(BICshiftRL x (MOVWconst [c]) [d]) => (BICconst x [int32(uint32(c)>>uint64(d))])
|
||||||
(BICshiftRA x (MOVWconst [c]) [d]) => (BICconst x [c>>uint64(d)])
|
(BICshiftRA x (MOVWconst [c]) [d]) => (BICconst x [c>>uint64(d)])
|
||||||
(MVNshiftLL (MOVWconst [c]) [d]) => (MOVWconst [^(c<<uint64(d))])
|
(MVNshiftLL (MOVWconst [c]) [d]) => (MOVWconst [^(c<<uint64(d))])
|
||||||
(MVNshiftRL (MOVWconst [c]) [d]) -> (MOVWconst [^int64(uint32(c)>>uint64(d))])
|
(MVNshiftRL (MOVWconst [c]) [d]) => (MOVWconst [^int32(uint32(c)>>uint64(d))])
|
||||||
(MVNshiftRA (MOVWconst [c]) [d]) -> (MOVWconst [^int64(int32(c)>>uint64(d))])
|
(MVNshiftRA (MOVWconst [c]) [d]) => (MOVWconst [int32(c)>>uint64(d)])
|
||||||
(CMPshiftLL x (MOVWconst [c]) [d]) => (CMPconst x [c<<uint64(d)])
|
(CMPshiftLL x (MOVWconst [c]) [d]) => (CMPconst x [c<<uint64(d)])
|
||||||
(CMPshiftRL x (MOVWconst [c]) [d]) => (CMPconst x [int32(uint32(c)>>uint64(d))])
|
(CMPshiftRL x (MOVWconst [c]) [d]) => (CMPconst x [int32(uint32(c)>>uint64(d))])
|
||||||
(CMPshiftRA x (MOVWconst [c]) [d]) => (CMPconst x [c>>uint64(d)])
|
(CMPshiftRA x (MOVWconst [c]) [d]) => (CMPconst x [c>>uint64(d)])
|
||||||
|
|
@ -1190,12 +1190,12 @@
|
||||||
(MOVWstoreidx ptr (SRAconst idx [c]) val mem) => (MOVWstoreshiftRA ptr idx [c] val mem)
|
(MOVWstoreidx ptr (SRAconst idx [c]) val mem) => (MOVWstoreshiftRA ptr idx [c] val mem)
|
||||||
(MOVWstoreidx (SRAconst idx [c]) ptr val mem) => (MOVWstoreshiftRA ptr idx [c] val mem)
|
(MOVWstoreidx (SRAconst idx [c]) ptr val mem) => (MOVWstoreshiftRA ptr idx [c] val mem)
|
||||||
|
|
||||||
(MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem)
|
(MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) => (MOVWload [int32(uint32(c)<<uint64(d))] ptr mem)
|
||||||
(MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem)
|
(MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) => (MOVWload [int32(uint32(c)>>uint64(d))] ptr mem)
|
||||||
(MOVWloadshiftRA ptr (MOVWconst [c]) [d] mem) => (MOVWload [c>>uint64(d)] ptr mem)
|
(MOVWloadshiftRA ptr (MOVWconst [c]) [d] mem) => (MOVWload [c>>uint64(d)] ptr mem)
|
||||||
|
|
||||||
(MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem)
|
(MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [int32(uint32(c)<<uint64(d))] ptr val mem)
|
||||||
(MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem)
|
(MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [int32(uint32(c)>>uint64(d))] ptr val mem)
|
||||||
(MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [c>>uint64(d)] ptr val mem)
|
(MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [c>>uint64(d)] ptr val mem)
|
||||||
|
|
||||||
// generic simplifications
|
// generic simplifications
|
||||||
|
|
@ -1470,6 +1470,6 @@
|
||||||
(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRLreg x y z) yes no)
|
(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRLreg x y z) yes no)
|
||||||
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRAreg x y z) yes no)
|
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRAreg x y z) yes no)
|
||||||
|
|
||||||
(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(read8(sym, off))])
|
(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read8(sym, int64(off)))])
|
||||||
(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(read16(sym, off, config.ctxt.Arch.ByteOrder))])
|
(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])
|
||||||
(MOVWload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(int32(read32(sym, off, config.ctxt.Arch.ByteOrder)))])
|
(MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))])
|
||||||
|
|
|
||||||
|
|
@ -547,11 +547,20 @@
|
||||||
(AtomicAdd(32|64) ...) => (LoweredAtomicAdd(32|64) ...)
|
(AtomicAdd(32|64) ...) => (LoweredAtomicAdd(32|64) ...)
|
||||||
(AtomicCompareAndSwap(32|64) ...) => (LoweredAtomicCas(32|64) ...)
|
(AtomicCompareAndSwap(32|64) ...) => (LoweredAtomicCas(32|64) ...)
|
||||||
|
|
||||||
|
(AtomicAdd(32|64)Variant ...) => (LoweredAtomicAdd(32|64)Variant ...)
|
||||||
|
(AtomicExchange(32|64)Variant ...) => (LoweredAtomicExchange(32|64)Variant ...)
|
||||||
|
(AtomicCompareAndSwap(32|64)Variant ...) => (LoweredAtomicCas(32|64)Variant ...)
|
||||||
|
|
||||||
// Currently the updated value is not used, but we need a register to temporarily hold it.
|
// Currently the updated value is not used, but we need a register to temporarily hold it.
|
||||||
(AtomicAnd8 ptr val mem) => (Select1 (LoweredAtomicAnd8 ptr val mem))
|
(AtomicAnd8 ptr val mem) => (Select1 (LoweredAtomicAnd8 ptr val mem))
|
||||||
|
(AtomicAnd32 ptr val mem) => (Select1 (LoweredAtomicAnd32 ptr val mem))
|
||||||
(AtomicOr8 ptr val mem) => (Select1 (LoweredAtomicOr8 ptr val mem))
|
(AtomicOr8 ptr val mem) => (Select1 (LoweredAtomicOr8 ptr val mem))
|
||||||
|
(AtomicOr32 ptr val mem) => (Select1 (LoweredAtomicOr32 ptr val mem))
|
||||||
|
|
||||||
(AtomicAdd(32|64)Variant ...) => (LoweredAtomicAdd(32|64)Variant ...)
|
(AtomicAnd8Variant ptr val mem) => (Select1 (LoweredAtomicAnd8Variant ptr val mem))
|
||||||
|
(AtomicAnd32Variant ptr val mem) => (Select1 (LoweredAtomicAnd32Variant ptr val mem))
|
||||||
|
(AtomicOr8Variant ptr val mem) => (Select1 (LoweredAtomicOr8Variant ptr val mem))
|
||||||
|
(AtomicOr32Variant ptr val mem) => (Select1 (LoweredAtomicOr32Variant ptr val mem))
|
||||||
|
|
||||||
// Write barrier.
|
// Write barrier.
|
||||||
(WB ...) => (LoweredWB ...)
|
(WB ...) => (LoweredWB ...)
|
||||||
|
|
@ -859,88 +868,88 @@
|
||||||
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVBload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVBUload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVHload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVHUload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVWload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVWUload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVDload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(FMOVSload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(FMOVDload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
|
|
||||||
(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVBstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVHstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVWstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVDstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(STP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val1 val2 mem)
|
(STP [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val1 val2 mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(STP [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val1 val2 mem)
|
(STP [off1+off2] {mergeSym(sym1,sym2)} ptr val1 val2 mem)
|
||||||
(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(FMOVSstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(FMOVDstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||||
(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVBstorezero [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVHstorezero [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVWstorezero [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVDstorezero [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
(MOVQstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
(MOVQstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
|
||||||
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
&& canMergeSym(sym1,sym2) && is32Bit(int64(off1)+int64(off2))
|
||||||
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
&& (ptr.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||||
(MOVQstorezero [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
(MOVQstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||||
|
|
||||||
// store zero
|
// store zero
|
||||||
(MOVBstore [off] {sym} ptr (MOVDconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
|
(MOVBstore [off] {sym} ptr (MOVDconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
|
||||||
|
|
@ -1171,145 +1180,147 @@
|
||||||
(MUL x (MOVDconst [-1])) => (NEG x)
|
(MUL x (MOVDconst [-1])) => (NEG x)
|
||||||
(MUL _ (MOVDconst [0])) => (MOVDconst [0])
|
(MUL _ (MOVDconst [0])) => (MOVDconst [0])
|
||||||
(MUL x (MOVDconst [1])) => x
|
(MUL x (MOVDconst [1])) => x
|
||||||
(MUL x (MOVDconst [c])) && isPowerOfTwo(c) => (SLLconst [log2(c)] x)
|
(MUL x (MOVDconst [c])) && isPowerOfTwo64(c) => (SLLconst [log64(c)] x)
|
||||||
(MUL x (MOVDconst [c])) && isPowerOfTwo(c-1) && c >= 3 => (ADDshiftLL x x [log2(c-1)])
|
(MUL x (MOVDconst [c])) && isPowerOfTwo64(c-1) && c >= 3 => (ADDshiftLL x x [log64(c-1)])
|
||||||
(MUL x (MOVDconst [c])) && isPowerOfTwo(c+1) && c >= 7 => (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
|
(MUL x (MOVDconst [c])) && isPowerOfTwo64(c+1) && c >= 7 => (ADDshiftLL (NEG <x.Type> x) x [log64(c+1)])
|
||||||
(MUL x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) => (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
|
(MUL x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) => (SLLconst [log64(c/3)] (ADDshiftLL <x.Type> x x [1]))
|
||||||
(MUL x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) => (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
|
(MUL x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) => (SLLconst [log64(c/5)] (ADDshiftLL <x.Type> x x [2]))
|
||||||
(MUL x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) => (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
|
(MUL x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) => (SLLconst [log64(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
|
||||||
(MUL x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) => (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
|
(MUL x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) => (SLLconst [log64(c/9)] (ADDshiftLL <x.Type> x x [3]))
|
||||||
|
|
||||||
(MULW x (MOVDconst [c])) && int32(c)==-1 => (NEG x)
|
(MULW x (MOVDconst [c])) && int32(c)==-1 => (NEG x)
|
||||||
(MULW _ (MOVDconst [c])) && int32(c)==0 => (MOVDconst [0])
|
(MULW _ (MOVDconst [c])) && int32(c)==0 => (MOVDconst [0])
|
||||||
(MULW x (MOVDconst [c])) && int32(c)==1 => x
|
(MULW x (MOVDconst [c])) && int32(c)==1 => x
|
||||||
(MULW x (MOVDconst [c])) && isPowerOfTwo(c) => (SLLconst [log2(c)] x)
|
(MULW x (MOVDconst [c])) && isPowerOfTwo64(c) => (SLLconst [log64(c)] x)
|
||||||
(MULW x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c) >= 3 => (ADDshiftLL x x [log2(c-1)])
|
(MULW x (MOVDconst [c])) && isPowerOfTwo64(c-1) && int32(c) >= 3 => (ADDshiftLL x x [log64(c-1)])
|
||||||
(MULW x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c) >= 7 => (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
|
(MULW x (MOVDconst [c])) && isPowerOfTwo64(c+1) && int32(c) >= 7 => (ADDshiftLL (NEG <x.Type> x) x [log64(c+1)])
|
||||||
(MULW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
|
(MULW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (SLLconst [log64(c/3)] (ADDshiftLL <x.Type> x x [1]))
|
||||||
(MULW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
|
(MULW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (SLLconst [log64(c/5)] (ADDshiftLL <x.Type> x x [2]))
|
||||||
(MULW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
|
(MULW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (SLLconst [log64(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
|
||||||
(MULW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
|
(MULW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (SLLconst [log64(c/9)] (ADDshiftLL <x.Type> x x [3]))
|
||||||
|
|
||||||
// mneg by constant
|
// mneg by constant
|
||||||
(MNEG x (MOVDconst [-1])) => x
|
(MNEG x (MOVDconst [-1])) => x
|
||||||
(MNEG _ (MOVDconst [0])) => (MOVDconst [0])
|
(MNEG _ (MOVDconst [0])) => (MOVDconst [0])
|
||||||
(MNEG x (MOVDconst [1])) => (NEG x)
|
(MNEG x (MOVDconst [1])) => (NEG x)
|
||||||
(MNEG x (MOVDconst [c])) && isPowerOfTwo(c) => (NEG (SLLconst <x.Type> [log2(c)] x))
|
(MNEG x (MOVDconst [c])) && isPowerOfTwo64(c) => (NEG (SLLconst <x.Type> [log64(c)] x))
|
||||||
(MNEG x (MOVDconst [c])) && isPowerOfTwo(c-1) && c >= 3 => (NEG (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MNEG x (MOVDconst [c])) && isPowerOfTwo64(c-1) && c >= 3 => (NEG (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MNEG x (MOVDconst [c])) && isPowerOfTwo(c+1) && c >= 7 => (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log2(c+1)]))
|
(MNEG x (MOVDconst [c])) && isPowerOfTwo64(c+1) && c >= 7 => (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log64(c+1)]))
|
||||||
(MNEG x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) => (SLLconst <x.Type> [log2(c/3)] (SUBshiftLL <x.Type> x x [2]))
|
(MNEG x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) => (SLLconst <x.Type> [log64(c/3)] (SUBshiftLL <x.Type> x x [2]))
|
||||||
(MNEG x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) => (NEG (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])))
|
(MNEG x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) => (NEG (SLLconst <x.Type> [log64(c/5)] (ADDshiftLL <x.Type> x x [2])))
|
||||||
(MNEG x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) => (SLLconst <x.Type> [log2(c/7)] (SUBshiftLL <x.Type> x x [3]))
|
(MNEG x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) => (SLLconst <x.Type> [log64(c/7)] (SUBshiftLL <x.Type> x x [3]))
|
||||||
(MNEG x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) => (NEG (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])))
|
(MNEG x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) => (NEG (SLLconst <x.Type> [log64(c/9)] (ADDshiftLL <x.Type> x x [3])))
|
||||||
|
|
||||||
|
|
||||||
(MNEGW x (MOVDconst [c])) && int32(c)==-1 => x
|
(MNEGW x (MOVDconst [c])) && int32(c)==-1 => x
|
||||||
(MNEGW _ (MOVDconst [c])) && int32(c)==0 => (MOVDconst [0])
|
(MNEGW _ (MOVDconst [c])) && int32(c)==0 => (MOVDconst [0])
|
||||||
(MNEGW x (MOVDconst [c])) && int32(c)==1 => (NEG x)
|
(MNEGW x (MOVDconst [c])) && int32(c)==1 => (NEG x)
|
||||||
(MNEGW x (MOVDconst [c])) && isPowerOfTwo(c) => (NEG (SLLconst <x.Type> [log2(c)] x))
|
(MNEGW x (MOVDconst [c])) && isPowerOfTwo64(c) => (NEG (SLLconst <x.Type> [log64(c)] x))
|
||||||
(MNEGW x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c) >= 3 => (NEG (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MNEGW x (MOVDconst [c])) && isPowerOfTwo64(c-1) && int32(c) >= 3 => (NEG (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MNEGW x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c) >= 7 => (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log2(c+1)]))
|
(MNEGW x (MOVDconst [c])) && isPowerOfTwo64(c+1) && int32(c) >= 7 => (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log64(c+1)]))
|
||||||
(MNEGW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (SLLconst <x.Type> [log2(c/3)] (SUBshiftLL <x.Type> x x [2]))
|
(MNEGW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (SLLconst <x.Type> [log64(c/3)] (SUBshiftLL <x.Type> x x [2]))
|
||||||
(MNEGW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (NEG (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])))
|
(MNEGW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (NEG (SLLconst <x.Type> [log64(c/5)] (ADDshiftLL <x.Type> x x [2])))
|
||||||
(MNEGW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (SLLconst <x.Type> [log2(c/7)] (SUBshiftLL <x.Type> x x [3]))
|
(MNEGW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (SLLconst <x.Type> [log64(c/7)] (SUBshiftLL <x.Type> x x [3]))
|
||||||
(MNEGW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (NEG (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])))
|
(MNEGW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (NEG (SLLconst <x.Type> [log64(c/9)] (ADDshiftLL <x.Type> x x [3])))
|
||||||
|
|
||||||
|
|
||||||
(MADD a x (MOVDconst [-1])) => (SUB a x)
|
(MADD a x (MOVDconst [-1])) => (SUB a x)
|
||||||
(MADD a _ (MOVDconst [0])) => a
|
(MADD a _ (MOVDconst [0])) => a
|
||||||
(MADD a x (MOVDconst [1])) => (ADD a x)
|
(MADD a x (MOVDconst [1])) => (ADD a x)
|
||||||
(MADD a x (MOVDconst [c])) && isPowerOfTwo(c) => (ADDshiftLL a x [log2(c)])
|
(MADD a x (MOVDconst [c])) && isPowerOfTwo64(c) => (ADDshiftLL a x [log64(c)])
|
||||||
(MADD a x (MOVDconst [c])) && isPowerOfTwo(c-1) && c>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MADD a x (MOVDconst [c])) && isPowerOfTwo64(c-1) && c>=3 => (ADD a (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MADD a x (MOVDconst [c])) && isPowerOfTwo(c+1) && c>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
|
(MADD a x (MOVDconst [c])) && isPowerOfTwo64(c+1) && c>=7 => (SUB a (SUBshiftLL <x.Type> x x [log64(c+1)]))
|
||||||
(MADD a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
|
(MADD a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log64(c/3)])
|
||||||
(MADD a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
|
(MADD a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log64(c/5)])
|
||||||
(MADD a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
|
(MADD a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log64(c/7)])
|
||||||
(MADD a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
|
(MADD a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log64(c/9)])
|
||||||
|
|
||||||
(MADD a (MOVDconst [-1]) x) => (SUB a x)
|
(MADD a (MOVDconst [-1]) x) => (SUB a x)
|
||||||
(MADD a (MOVDconst [0]) _) => a
|
(MADD a (MOVDconst [0]) _) => a
|
||||||
(MADD a (MOVDconst [1]) x) => (ADD a x)
|
(MADD a (MOVDconst [1]) x) => (ADD a x)
|
||||||
(MADD a (MOVDconst [c]) x) && isPowerOfTwo(c) => (ADDshiftLL a x [log2(c)])
|
(MADD a (MOVDconst [c]) x) && isPowerOfTwo64(c) => (ADDshiftLL a x [log64(c)])
|
||||||
(MADD a (MOVDconst [c]) x) && isPowerOfTwo(c-1) && c>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MADD a (MOVDconst [c]) x) && isPowerOfTwo64(c-1) && c>=3 => (ADD a (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MADD a (MOVDconst [c]) x) && isPowerOfTwo(c+1) && c>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
|
(MADD a (MOVDconst [c]) x) && isPowerOfTwo64(c+1) && c>=7 => (SUB a (SUBshiftLL <x.Type> x x [log64(c+1)]))
|
||||||
(MADD a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
|
(MADD a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo64(c/3) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log64(c/3)])
|
||||||
(MADD a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
|
(MADD a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo64(c/5) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log64(c/5)])
|
||||||
(MADD a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
|
(MADD a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo64(c/7) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log64(c/7)])
|
||||||
(MADD a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
|
(MADD a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo64(c/9) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log64(c/9)])
|
||||||
|
|
||||||
(MADDW a x (MOVDconst [c])) && int32(c)==-1 => (SUB a x)
|
(MADDW a x (MOVDconst [c])) && int32(c)==-1 => (SUB a x)
|
||||||
(MADDW a _ (MOVDconst [c])) && int32(c)==0 => a
|
(MADDW a _ (MOVDconst [c])) && int32(c)==0 => a
|
||||||
(MADDW a x (MOVDconst [c])) && int32(c)==1 => (ADD a x)
|
(MADDW a x (MOVDconst [c])) && int32(c)==1 => (ADD a x)
|
||||||
(MADDW a x (MOVDconst [c])) && isPowerOfTwo(c) => (ADDshiftLL a x [log2(c)])
|
(MADDW a x (MOVDconst [c])) && isPowerOfTwo64(c) => (ADDshiftLL a x [log64(c)])
|
||||||
(MADDW a x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c)>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MADDW a x (MOVDconst [c])) && isPowerOfTwo64(c-1) && int32(c)>=3 => (ADD a (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MADDW a x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c)>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
|
(MADDW a x (MOVDconst [c])) && isPowerOfTwo64(c+1) && int32(c)>=7 => (SUB a (SUBshiftLL <x.Type> x x [log64(c+1)]))
|
||||||
(MADDW a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
|
(MADDW a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log64(c/3)])
|
||||||
(MADDW a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
|
(MADDW a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log64(c/5)])
|
||||||
(MADDW a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
|
(MADDW a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log64(c/7)])
|
||||||
(MADDW a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
|
(MADDW a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log64(c/9)])
|
||||||
|
|
||||||
(MADDW a (MOVDconst [c]) x) && int32(c)==-1 => (SUB a x)
|
(MADDW a (MOVDconst [c]) x) && int32(c)==-1 => (SUB a x)
|
||||||
(MADDW a (MOVDconst [c]) _) && int32(c)==0 => a
|
(MADDW a (MOVDconst [c]) _) && int32(c)==0 => a
|
||||||
(MADDW a (MOVDconst [c]) x) && int32(c)==1 => (ADD a x)
|
(MADDW a (MOVDconst [c]) x) && int32(c)==1 => (ADD a x)
|
||||||
(MADDW a (MOVDconst [c]) x) && isPowerOfTwo(c) => (ADDshiftLL a x [log2(c)])
|
(MADDW a (MOVDconst [c]) x) && isPowerOfTwo64(c) => (ADDshiftLL a x [log64(c)])
|
||||||
(MADDW a (MOVDconst [c]) x) && isPowerOfTwo(c-1) && int32(c)>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MADDW a (MOVDconst [c]) x) && isPowerOfTwo64(c-1) && int32(c)>=3 => (ADD a (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MADDW a (MOVDconst [c]) x) && isPowerOfTwo(c+1) && int32(c)>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
|
(MADDW a (MOVDconst [c]) x) && isPowerOfTwo64(c+1) && int32(c)>=7 => (SUB a (SUBshiftLL <x.Type> x x [log64(c+1)]))
|
||||||
(MADDW a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
|
(MADDW a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log64(c/3)])
|
||||||
(MADDW a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
|
(MADDW a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log64(c/5)])
|
||||||
(MADDW a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
|
(MADDW a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log64(c/7)])
|
||||||
(MADDW a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
|
(MADDW a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log64(c/9)])
|
||||||
|
|
||||||
(MSUB a x (MOVDconst [-1])) => (ADD a x)
|
(MSUB a x (MOVDconst [-1])) => (ADD a x)
|
||||||
(MSUB a _ (MOVDconst [0])) => a
|
(MSUB a _ (MOVDconst [0])) => a
|
||||||
(MSUB a x (MOVDconst [1])) => (SUB a x)
|
(MSUB a x (MOVDconst [1])) => (SUB a x)
|
||||||
(MSUB a x (MOVDconst [c])) && isPowerOfTwo(c) => (SUBshiftLL a x [log2(c)])
|
(MSUB a x (MOVDconst [c])) && isPowerOfTwo64(c) => (SUBshiftLL a x [log64(c)])
|
||||||
(MSUB a x (MOVDconst [c])) && isPowerOfTwo(c-1) && c>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MSUB a x (MOVDconst [c])) && isPowerOfTwo64(c-1) && c>=3 => (SUB a (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MSUB a x (MOVDconst [c])) && isPowerOfTwo(c+1) && c>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
|
(MSUB a x (MOVDconst [c])) && isPowerOfTwo64(c+1) && c>=7 => (ADD a (SUBshiftLL <x.Type> x x [log64(c+1)]))
|
||||||
(MSUB a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
|
(MSUB a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log64(c/3)])
|
||||||
(MSUB a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
|
(MSUB a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log64(c/5)])
|
||||||
(MSUB a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
|
(MSUB a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log64(c/7)])
|
||||||
(MSUB a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
|
(MSUB a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log64(c/9)])
|
||||||
|
|
||||||
(MSUB a (MOVDconst [-1]) x) => (ADD a x)
|
(MSUB a (MOVDconst [-1]) x) => (ADD a x)
|
||||||
(MSUB a (MOVDconst [0]) _) => a
|
(MSUB a (MOVDconst [0]) _) => a
|
||||||
(MSUB a (MOVDconst [1]) x) => (SUB a x)
|
(MSUB a (MOVDconst [1]) x) => (SUB a x)
|
||||||
(MSUB a (MOVDconst [c]) x) && isPowerOfTwo(c) => (SUBshiftLL a x [log2(c)])
|
(MSUB a (MOVDconst [c]) x) && isPowerOfTwo64(c) => (SUBshiftLL a x [log64(c)])
|
||||||
(MSUB a (MOVDconst [c]) x) && isPowerOfTwo(c-1) && c>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MSUB a (MOVDconst [c]) x) && isPowerOfTwo64(c-1) && c>=3 => (SUB a (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MSUB a (MOVDconst [c]) x) && isPowerOfTwo(c+1) && c>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
|
(MSUB a (MOVDconst [c]) x) && isPowerOfTwo64(c+1) && c>=7 => (ADD a (SUBshiftLL <x.Type> x x [log64(c+1)]))
|
||||||
(MSUB a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
|
(MSUB a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo64(c/3) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log64(c/3)])
|
||||||
(MSUB a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
|
(MSUB a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo64(c/5) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log64(c/5)])
|
||||||
(MSUB a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
|
(MSUB a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo64(c/7) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log64(c/7)])
|
||||||
(MSUB a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
|
(MSUB a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo64(c/9) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log64(c/9)])
|
||||||
|
|
||||||
(MSUBW a x (MOVDconst [c])) && int32(c)==-1 => (ADD a x)
|
(MSUBW a x (MOVDconst [c])) && int32(c)==-1 => (ADD a x)
|
||||||
(MSUBW a _ (MOVDconst [c])) && int32(c)==0 => a
|
(MSUBW a _ (MOVDconst [c])) && int32(c)==0 => a
|
||||||
(MSUBW a x (MOVDconst [c])) && int32(c)==1 => (SUB a x)
|
(MSUBW a x (MOVDconst [c])) && int32(c)==1 => (SUB a x)
|
||||||
(MSUBW a x (MOVDconst [c])) && isPowerOfTwo(c) => (SUBshiftLL a x [log2(c)])
|
(MSUBW a x (MOVDconst [c])) && isPowerOfTwo64(c) => (SUBshiftLL a x [log64(c)])
|
||||||
(MSUBW a x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c)>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MSUBW a x (MOVDconst [c])) && isPowerOfTwo64(c-1) && int32(c)>=3 => (SUB a (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MSUBW a x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c)>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
|
(MSUBW a x (MOVDconst [c])) && isPowerOfTwo64(c+1) && int32(c)>=7 => (ADD a (SUBshiftLL <x.Type> x x [log64(c+1)]))
|
||||||
(MSUBW a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
|
(MSUBW a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log64(c/3)])
|
||||||
(MSUBW a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
|
(MSUBW a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log64(c/5)])
|
||||||
(MSUBW a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
|
(MSUBW a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log64(c/7)])
|
||||||
(MSUBW a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
|
(MSUBW a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log64(c/9)])
|
||||||
|
|
||||||
(MSUBW a (MOVDconst [c]) x) && int32(c)==-1 => (ADD a x)
|
(MSUBW a (MOVDconst [c]) x) && int32(c)==-1 => (ADD a x)
|
||||||
(MSUBW a (MOVDconst [c]) _) && int32(c)==0 => a
|
(MSUBW a (MOVDconst [c]) _) && int32(c)==0 => a
|
||||||
(MSUBW a (MOVDconst [c]) x) && int32(c)==1 => (SUB a x)
|
(MSUBW a (MOVDconst [c]) x) && int32(c)==1 => (SUB a x)
|
||||||
(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo(c) => (SUBshiftLL a x [log2(c)])
|
(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo64(c) => (SUBshiftLL a x [log64(c)])
|
||||||
(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo(c-1) && int32(c)>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
|
(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo64(c-1) && int32(c)>=3 => (SUB a (ADDshiftLL <x.Type> x x [log64(c-1)]))
|
||||||
(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo(c+1) && int32(c)>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
|
(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo64(c+1) && int32(c)>=7 => (ADD a (SUBshiftLL <x.Type> x x [log64(c+1)]))
|
||||||
(MSUBW a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
|
(MSUBW a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log64(c/3)])
|
||||||
(MSUBW a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
|
(MSUBW a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log64(c/5)])
|
||||||
(MSUBW a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
|
(MSUBW a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log64(c/7)])
|
||||||
(MSUBW a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
|
(MSUBW a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log64(c/9)])
|
||||||
|
|
||||||
// div by constant
|
// div by constant
|
||||||
(UDIV x (MOVDconst [1])) => x
|
(UDIV x (MOVDconst [1])) => x
|
||||||
(UDIV x (MOVDconst [c])) && isPowerOfTwo(c) => (SRLconst [log2(c)] x)
|
(UDIV x (MOVDconst [c])) && isPowerOfTwo64(c) => (SRLconst [log64(c)] x)
|
||||||
(UDIVW x (MOVDconst [c])) && uint32(c)==1 => x
|
(UDIVW x (MOVDconst [c])) && uint32(c)==1 => x
|
||||||
(UDIVW x (MOVDconst [c])) && isPowerOfTwo(c) && is32Bit(c) => (SRLconst [log2(c)] x)
|
(UDIVW x (MOVDconst [c])) && isPowerOfTwo64(c) && is32Bit(c) => (SRLconst [log64(c)] x)
|
||||||
(UMOD _ (MOVDconst [1])) => (MOVDconst [0])
|
(UMOD _ (MOVDconst [1])) => (MOVDconst [0])
|
||||||
(UMOD x (MOVDconst [c])) && isPowerOfTwo(c) => (ANDconst [c-1] x)
|
(UMOD x (MOVDconst [c])) && isPowerOfTwo64(c) => (ANDconst [c-1] x)
|
||||||
(UMODW _ (MOVDconst [c])) && uint32(c)==1 => (MOVDconst [0])
|
(UMODW _ (MOVDconst [c])) && uint32(c)==1 => (MOVDconst [0])
|
||||||
(UMODW x (MOVDconst [c])) && isPowerOfTwo(c) && is32Bit(c) => (ANDconst [c-1] x)
|
(UMODW x (MOVDconst [c])) && isPowerOfTwo64(c) && is32Bit(c) => (ANDconst [c-1] x)
|
||||||
|
|
||||||
// generic simplifications
|
// generic simplifications
|
||||||
(ADD x (NEG y)) => (SUB x y)
|
(ADD x (NEG y)) => (SUB x y)
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue