mirror of
https://github.com/golang/go.git
synced 2026-02-03 01:15:04 +03:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a16e30d162 |
501
api/go1.16.txt
501
api/go1.16.txt
@@ -1,501 +0,0 @@
|
||||
pkg archive/zip, method (*ReadCloser) Open(string) (fs.File, error)
|
||||
pkg archive/zip, method (*Reader) Open(string) (fs.File, error)
|
||||
pkg crypto/x509, method (SystemRootsError) Unwrap() error
|
||||
pkg debug/elf, const DT_ADDRRNGHI = 1879047935
|
||||
pkg debug/elf, const DT_ADDRRNGHI DynTag
|
||||
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, EmbedPatternPos map[string][]token.Position
|
||||
pkg go/build, type Package struct, IgnoredOtherFiles []string
|
||||
pkg go/build, type Package struct, TestEmbedPatterns []string
|
||||
pkg go/build, type Package struct, TestEmbedPatternPos map[string][]token.Position
|
||||
pkg go/build, type Package struct, XTestEmbedPatterns []string
|
||||
pkg go/build, type Package struct, XTestEmbedPatternPos map[string][]token.Position
|
||||
pkg go/build/constraint, func IsGoBuild(string) bool
|
||||
pkg go/build/constraint, func IsPlusBuild(string) bool
|
||||
pkg go/build/constraint, func Parse(string) (Expr, error)
|
||||
pkg go/build/constraint, func PlusBuildLines(Expr) ([]string, error)
|
||||
pkg go/build/constraint, method (*AndExpr) Eval(func(string) bool) bool
|
||||
pkg go/build/constraint, method (*AndExpr) String() string
|
||||
pkg go/build/constraint, method (*NotExpr) Eval(func(string) bool) bool
|
||||
pkg go/build/constraint, method (*NotExpr) String() string
|
||||
pkg go/build/constraint, method (*OrExpr) Eval(func(string) bool) bool
|
||||
pkg go/build/constraint, method (*OrExpr) String() string
|
||||
pkg go/build/constraint, method (*SyntaxError) Error() string
|
||||
pkg go/build/constraint, method (*TagExpr) Eval(func(string) bool) bool
|
||||
pkg go/build/constraint, method (*TagExpr) String() string
|
||||
pkg go/build/constraint, type AndExpr struct
|
||||
pkg go/build/constraint, type AndExpr struct, X Expr
|
||||
pkg go/build/constraint, type AndExpr struct, Y Expr
|
||||
pkg go/build/constraint, type Expr interface, Eval(func(string) bool) bool
|
||||
pkg go/build/constraint, type Expr interface, String() string
|
||||
pkg go/build/constraint, type Expr interface, unexported methods
|
||||
pkg go/build/constraint, type NotExpr struct
|
||||
pkg go/build/constraint, type NotExpr struct, X Expr
|
||||
pkg go/build/constraint, type OrExpr struct
|
||||
pkg go/build/constraint, type OrExpr struct, X Expr
|
||||
pkg go/build/constraint, type OrExpr struct, Y Expr
|
||||
pkg go/build/constraint, type SyntaxError struct
|
||||
pkg go/build/constraint, type SyntaxError struct, Err string
|
||||
pkg go/build/constraint, type SyntaxError struct, Offset int
|
||||
pkg go/build/constraint, type TagExpr struct
|
||||
pkg go/build/constraint, type TagExpr struct, Tag 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 Sub(FS, string) (FS, error)
|
||||
pkg io/fs, func ValidPath(string) bool
|
||||
pkg io/fs, func WalkDir(FS, string, WalkDirFunc) error
|
||||
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, type SubFS interface { Open, Sub }
|
||||
pkg io/fs, type SubFS interface, Open(string) (File, error)
|
||||
pkg io/fs, type SubFS interface, Sub(string) (FS, error)
|
||||
pkg io/fs, type WalkDirFunc func(string, DirEntry, error) 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 io/fs, var SkipDir 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 CreateTemp(string, string) (*File, 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 MkdirTemp(string, string) (string, error)
|
||||
pkg os, func OpenFile(string, int, fs.FileMode) (*File, error)
|
||||
pkg os, func ReadDir(string) ([]fs.DirEntry, error)
|
||||
pkg os, func ReadFile(string) ([]uint8, error)
|
||||
pkg os, func SameFile(fs.FileInfo, fs.FileInfo) bool
|
||||
pkg os, func Stat(string) (fs.FileInfo, error)
|
||||
pkg os, func WriteFile(string, []uint8, fs.FileMode) 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, var ErrProcessDone error
|
||||
pkg os/signal, func NotifyContext(context.Context, ...os.Signal) (context.Context, context.CancelFunc)
|
||||
pkg path/filepath, func WalkDir(string, fs.WalkDirFunc) error
|
||||
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 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), method (*DLLError) Unwrap() error
|
||||
pkg syscall (windows-386), type SysProcAttr struct, NoInheritHandles bool
|
||||
pkg syscall (windows-amd64), method (*DLLError) Unwrap() error
|
||||
pkg syscall (windows-amd64), type SysProcAttr struct, NoInheritHandles bool
|
||||
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, method (MapFS) Sub(string) (fs.FS, 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 NodeType
|
||||
pkg text/template/parse, const ParseComments = 1
|
||||
pkg text/template/parse, const ParseComments Mode
|
||||
pkg text/template/parse, method (*CommentNode) Copy() Node
|
||||
pkg text/template/parse, method (*CommentNode) String() string
|
||||
pkg text/template/parse, method (CommentNode) Position() Pos
|
||||
pkg text/template/parse, method (CommentNode) Type() NodeType
|
||||
pkg text/template/parse, type CommentNode struct
|
||||
pkg text/template/parse, type CommentNode struct, Text string
|
||||
pkg text/template/parse, type CommentNode struct, embedded NodeType
|
||||
pkg text/template/parse, type CommentNode struct, embedded Pos
|
||||
pkg text/template/parse, type Mode uint
|
||||
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
|
||||
337
api/next.txt
337
api/next.txt
@@ -0,0 +1,337 @@
|
||||
pkg debug/elf, const DT_ADDRRNGHI = 1879047935
|
||||
pkg debug/elf, const DT_ADDRRNGHI DynTag
|
||||
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 flag, func Func(string, string, func(string) error)
|
||||
pkg flag, method (*FlagSet) Func(string, string, func(string) error)
|
||||
pkg go/build, type Package struct, IgnoredOtherFiles []string
|
||||
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/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, 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 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 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, 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 net, var ErrClosed error
|
||||
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 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) ([]DirEntry, error)
|
||||
pkg os, method (*File) Readdir(int) ([]fs.FileInfo, error)
|
||||
pkg os, method (*File) Stat() (fs.FileInfo, error)
|
||||
pkg os, type DirEntry interface { Info, IsDir, Name, Type }
|
||||
pkg os, type DirEntry interface, Info() (fs.FileInfo, error)
|
||||
pkg os, type DirEntry interface, IsDir() bool
|
||||
pkg os, type DirEntry interface, Name() string
|
||||
pkg os, type DirEntry interface, Type() fs.FileMode
|
||||
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 testing/iotest, func ErrReader(error) io.Reader
|
||||
pkg text/template/parse, const NodeComment = 20
|
||||
pkg text/template/parse, const NodeComment NodeType
|
||||
pkg text/template/parse, const ParseComments = 1
|
||||
pkg text/template/parse, const ParseComments Mode
|
||||
pkg text/template/parse, method (*CommentNode) Copy() Node
|
||||
pkg text/template/parse, method (*CommentNode) String() string
|
||||
pkg text/template/parse, method (CommentNode) Position() Pos
|
||||
pkg text/template/parse, method (CommentNode) Type() NodeType
|
||||
pkg text/template/parse, type CommentNode struct
|
||||
pkg text/template/parse, type CommentNode struct, Text string
|
||||
pkg text/template/parse, type CommentNode struct, embedded NodeType
|
||||
pkg text/template/parse, type CommentNode struct, embedded Pos
|
||||
pkg text/template/parse, type Mode uint
|
||||
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
|
||||
|
||||
@@ -418,7 +418,7 @@ close(c)
|
||||
<code>linux/amd64</code>, <code>linux/ppc64le</code>,
|
||||
<code>linux/arm64</code>, <code>freebsd/amd64</code>,
|
||||
<code>netbsd/amd64</code>, <code>darwin/amd64</code>,
|
||||
<code>darwin/arm64</code>, and <code>windows/amd64</code>.
|
||||
and <code>windows/amd64</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="Runtime_Overheads">Runtime Overhead</h2>
|
||||
|
||||
72
doc/asm.html
72
doc/asm.html
@@ -464,57 +464,6 @@ Function is the top of the call stack. Traceback should stop at this function.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="data-offsets">Interacting with Go types and constants</h3>
|
||||
|
||||
<p>
|
||||
If a package has any .s files, then <code>go build</code> will direct
|
||||
the compiler to emit a special header called <code>go_asm.h</code>,
|
||||
which the .s files can then <code>#include</code>.
|
||||
The file contains symbolic <code>#define</code> constants for the
|
||||
offsets of Go struct fields, the sizes of Go struct types, and most
|
||||
Go <code>const</code> declarations defined in the current package.
|
||||
Go assembly should avoid making assumptions about the layout of Go
|
||||
types and instead use these constants.
|
||||
This improves the readability of assembly code, and keeps it robust to
|
||||
changes in data layout either in the Go type definitions or in the
|
||||
layout rules used by the Go compiler.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Constants are of the form <code>const_<i>name</i></code>.
|
||||
For example, given the Go declaration <code>const bufSize =
|
||||
1024</code>, assembly code can refer to the value of this constant
|
||||
as <code>const_bufSize</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Field offsets are of the form <code><i>type</i>_<i>field</i></code>.
|
||||
Struct sizes are of the form <code><i>type</i>__size</code>.
|
||||
For example, consider the following Go definition:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type reader struct {
|
||||
buf [bufSize]byte
|
||||
r int
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Assembly can refer to the size of this struct
|
||||
as <code>reader__size</code> and the offsets of the two fields
|
||||
as <code>reader_buf</code> and <code>reader_r</code>.
|
||||
Hence, if register <code>R1</code> contains a pointer to
|
||||
a <code>reader</code>, assembly can reference the <code>r</code> field
|
||||
as <code>reader_r(R1)</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If any of these <code>#define</code> names are ambiguous (for example,
|
||||
a struct with a <code>_size</code> field), <code>#include
|
||||
"go_asm.h"</code> will fail with a "redefinition of macro" error.
|
||||
</p>
|
||||
|
||||
<h3 id="runtime">Runtime Coordination</h3>
|
||||
|
||||
<p>
|
||||
@@ -666,15 +615,21 @@ Here follow some descriptions of key Go-specific details for the supported archi
|
||||
<p>
|
||||
The runtime pointer to the <code>g</code> structure is maintained
|
||||
through the value of an otherwise unused (as far as Go is concerned) register in the MMU.
|
||||
In the runtime package, assembly code can include <code>go_tls.h</code>, which defines
|
||||
an OS- and architecture-dependent macro <code>get_tls</code> for accessing this register.
|
||||
The <code>get_tls</code> macro takes one argument, which is the register to load the
|
||||
<code>g</code> pointer into.
|
||||
An OS-dependent macro <code>get_tls</code> is defined for the assembler if the source is
|
||||
in the <code>runtime</code> package and includes a special header, <code>go_tls.h</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
#include "go_tls.h"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
For example, the sequence to load <code>g</code> and <code>m</code>
|
||||
using <code>CX</code> looks like this:
|
||||
Within the runtime, the <code>get_tls</code> macro loads its argument register
|
||||
with a pointer to the <code>g</code> pointer, and the <code>g</code> struct
|
||||
contains the <code>m</code> pointer.
|
||||
There's another special header containing the offsets for each
|
||||
element of <code>g</code>, called <code>go_asm.h</code>.
|
||||
The sequence to load <code>g</code> and <code>m</code> using <code>CX</code> looks like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@@ -687,7 +642,8 @@ MOVL g_m(AX), BX // Move g.m into BX.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>get_tls</code> macro is also defined on <a href="#amd64">amd64</a>.
|
||||
Note: The code above works only in the <code>runtime</code> package, while <code>go_tls.h</code> also
|
||||
applies to <a href="#arm">arm</a>, <a href="#amd64">amd64</a> and amd64p32, and <code>go_asm.h</code> applies to all architectures.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -947,18 +947,10 @@ The Gerrit voting system involves an integer in the range -2 to +2:
|
||||
</li>
|
||||
</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>
|
||||
|
||||
<p>
|
||||
After the code has been +2'ed and Trust+1'ed, an approver will
|
||||
After the code has been +2'ed, an approver will
|
||||
apply it to the master branch using the Gerrit user interface.
|
||||
This is called "submitting the change".
|
||||
</p>
|
||||
@@ -1023,13 +1015,13 @@ New files that you contribute should use the standard copyright header:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// 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.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(Use the current year if you're reading this in 2022 or beyond.)
|
||||
(Use the current year if you're reading this in 2021 or beyond.)
|
||||
Files in the repository are copyrighted the year they are added.
|
||||
Do not update the copyright year on files that you change.
|
||||
</p>
|
||||
@@ -1129,7 +1121,7 @@ sometimes required because the standard library code you're modifying
|
||||
might require a newer version than the stable one you have installed).
|
||||
|
||||
<pre>
|
||||
$ cd $GODIR/src/crypto/sha1
|
||||
$ cd $GODIR/src/hash/sha1
|
||||
$ [make changes...]
|
||||
$ $GODIR/bin/go test .
|
||||
</pre>
|
||||
|
||||
@@ -455,7 +455,7 @@ environmental variable is set accordingly.</p>
|
||||
each collection, summarizing the amount of memory collected
|
||||
and the length of the pause.</li>
|
||||
<li>GODEBUG=inittrace=1 prints a summary of execution time and memory allocation
|
||||
information for completed package initialization work.</li>
|
||||
information for completed package initilization work.</li>
|
||||
<li>GODEBUG=schedtrace=X prints scheduling events every X milliseconds.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -19,11 +19,13 @@ editing, navigation, testing, and debugging experience.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/fatih/vim-go">vim</a>: vim-go plugin provides Go programming language support</li>
|
||||
<li><a href="https://marketplace.visualstudio.com/items?itemName=golang.go">Visual Studio Code</a>:
|
||||
Go extension provides support for the Go programming language</li>
|
||||
<li><a href="https://www.jetbrains.com/go">GoLand</a>: GoLand is distributed either as a standalone IDE
|
||||
or as a plugin for IntelliJ IDEA Ultimate</li>
|
||||
<li><a href="https://github.com/fatih/vim-go">vim</a>: vim-go plugin provides Go programming language support</li>
|
||||
<li><a href="https://atom.io/packages/go-plus">Atom</a>: Go-Plus is an Atom package that provides enhanced Go support</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Note that these are only a few top solutions; a more comprehensive
|
||||
|
||||
@@ -397,19 +397,6 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
documentation</a> for more information.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 250940 -->
|
||||
In Go 1.15.3 and later, cgo will not permit Go code to allocate an
|
||||
undefined struct type (a C struct defined as just <code>struct
|
||||
S;</code> or similar) on the stack or heap.
|
||||
Go code will only be permitted to use pointers to those types.
|
||||
Allocating an instance of such a struct and passing a pointer, or a
|
||||
full struct value, to C code was always unsafe and unlikely to work
|
||||
correctly; it is now forbidden.
|
||||
The fix is to either rewrite the Go code to use only pointers, or to
|
||||
ensure that the Go code sees the full definition of the struct by
|
||||
including the appropriate C header file.
|
||||
</p>
|
||||
|
||||
<h3 id="commonname">X.509 CommonName deprecation</h3>
|
||||
|
||||
<p><!-- CL 231379 -->
|
||||
|
||||
1012
doc/go1.16.html
1012
doc/go1.16.html
File diff suppressed because it is too large
Load Diff
@@ -1647,14 +1647,14 @@ c := signal.Incoming()
|
||||
is
|
||||
</p>
|
||||
<pre>
|
||||
c := make(chan os.Signal, 1)
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c) // ask for all signals
|
||||
</pre>
|
||||
<p>
|
||||
but most code should list the specific signals it wants to handle instead:
|
||||
</p>
|
||||
<pre>
|
||||
c := make(chan os.Signal, 1)
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT)
|
||||
</pre>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of Oct 7, 2020",
|
||||
"Subtitle": "Version of Sep 24, 2020",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
@@ -3594,34 +3594,24 @@ replaced by its left operand alone.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a [1024]byte
|
||||
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 j int32 = 1<<s // 1 has type int32; j == 0
|
||||
var k = uint64(1<<s) // 1 has type uint64; k == 1<<33
|
||||
var m int = 1.0<<s // 1.0 has type int; m == 1<<33
|
||||
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 == false
|
||||
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 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 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; w == 1<<33
|
||||
var x = a[1.0<<s] // panics: 1.0 has type int, but 1<<33 overflows array bounds
|
||||
var b = make([]byte, 1.0<<s) // 1.0 has type int; len(b) == 1<<33
|
||||
|
||||
// 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
|
||||
var i = 1<<s // 1 has type int
|
||||
var j int32 = 1<<s // 1 has type int32; j == 0
|
||||
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 n = 1.0<<s == j // 1.0 has type int32; n == true
|
||||
var o = 1<<s == 2<<s // 1 and 2 have type int; o == true if ints are 32bits in size
|
||||
var p = 1<<s == 1<<33 // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
|
||||
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 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 w int64 = 1.0<<33 // 1.0<<33 is a constant shift expression
|
||||
var x = a[1.0<<s] // 1.0 has type int; x == a[0] if ints are 32bits in size
|
||||
var a = make([]byte, 1.0<<s) // 1.0 has type int; len(a) == 0 if ints are 32bits in size
|
||||
</pre>
|
||||
|
||||
|
||||
<h4 id="Operator_precedence">Operator precedence</h4>
|
||||
<p>
|
||||
Unary operators have the highest precedence.
|
||||
|
||||
@@ -119,26 +119,11 @@ The Go toolchain is written in Go. To build it, you need a Go compiler installed
|
||||
The scripts that do the initial build of the tools look for a "go" command
|
||||
in <code>$PATH</code>, so as long as you have Go installed in your
|
||||
system and configured in your <code>$PATH</code>, you are ready to build Go
|
||||
from source.
|
||||
from source.
|
||||
Or if you prefer you can set <code>$GOROOT_BOOTSTRAP</code> to the
|
||||
root of a Go installation to use to build the new Go toolchain;
|
||||
<code>$GOROOT_BOOTSTRAP/bin/go</code> should be the go command to use.</p>
|
||||
|
||||
<p>
|
||||
There are four possible ways to obtain a bootstrap toolchain:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Download a recent binary release of Go.
|
||||
<li>Cross-compile a toolchain using a system with a working Go installation.
|
||||
<li>Use gccgo.
|
||||
<li>Compile a toolchain from Go 1.4, the last Go release with a compiler written in C.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
These approaches are detailed below.
|
||||
</p>
|
||||
|
||||
<h3 id="bootstrapFromBinaryRelease">Bootstrap toolchain from binary release</h3>
|
||||
|
||||
<p>
|
||||
@@ -147,6 +132,30 @@ To use a binary release as a bootstrap toolchain, see
|
||||
packaged Go distribution.
|
||||
</p>
|
||||
|
||||
<h3 id="bootstrapFromSource">Bootstrap toolchain from source</h3>
|
||||
|
||||
<p>
|
||||
To build a bootstrap toolchain from source, use
|
||||
either the git branch <code>release-branch.go1.4</code> or
|
||||
<a href="https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz">go1.4-bootstrap-20171003.tar.gz</a>,
|
||||
which contains the Go 1.4 source code plus accumulated fixes
|
||||
to keep the tools running on newer operating systems.
|
||||
(Go 1.4 was the last distribution in which the toolchain was written in C.)
|
||||
After unpacking the Go 1.4 source, <code>cd</code> to
|
||||
the <code>src</code> subdirectory, set <code>CGO_ENABLED=0</code> in
|
||||
the environment, and run <code>make.bash</code> (or,
|
||||
on Windows, <code>make.bat</code>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Once the Go 1.4 source has been unpacked into your GOROOT_BOOTSTRAP directory,
|
||||
you must keep this git clone instance checked out to branch
|
||||
<code>release-branch.go1.4</code>. Specifically, do not attempt to reuse
|
||||
this git clone in the later step named "Fetch the repository." The go1.4
|
||||
bootstrap toolchain <b>must be able</b> to properly traverse the go1.4 sources
|
||||
that it assumes are present under this repository root.
|
||||
</p>
|
||||
|
||||
<h3 id="bootstrapFromCrosscompiledSource">Bootstrap toolchain from cross-compiled source</h3>
|
||||
|
||||
<p>
|
||||
@@ -185,36 +194,6 @@ $ sudo update-alternatives --set go /usr/bin/go-5
|
||||
$ GOROOT_BOOTSTRAP=/usr ./make.bash
|
||||
</pre>
|
||||
|
||||
<h3 id="bootstrapFromSource">Bootstrap toolchain from C source code</h3>
|
||||
|
||||
<p>
|
||||
To build a bootstrap toolchain from C source code, use
|
||||
either the git branch <code>release-branch.go1.4</code> or
|
||||
<a href="https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz">go1.4-bootstrap-20171003.tar.gz</a>,
|
||||
which contains the Go 1.4 source code plus accumulated fixes
|
||||
to keep the tools running on newer operating systems.
|
||||
(Go 1.4 was the last distribution in which the toolchain was written in C.)
|
||||
After unpacking the Go 1.4 source, <code>cd</code> to
|
||||
the <code>src</code> subdirectory, set <code>CGO_ENABLED=0</code> in
|
||||
the environment, and run <code>make.bash</code> (or,
|
||||
on Windows, <code>make.bat</code>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Once the Go 1.4 source has been unpacked into your GOROOT_BOOTSTRAP directory,
|
||||
you must keep this git clone instance checked out to branch
|
||||
<code>release-branch.go1.4</code>. Specifically, do not attempt to reuse
|
||||
this git clone in the later step named "Fetch the repository." The go1.4
|
||||
bootstrap toolchain <b>must be able</b> to properly traverse the go1.4 sources
|
||||
that it assumes are present under this repository root.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that Go 1.4 does not run on all systems that later versions of Go do.
|
||||
In particular, Go 1.4 does not support current versions of macOS.
|
||||
On such systems, the bootstrap toolchain must be obtained using one of the other methods.
|
||||
</p>
|
||||
|
||||
<h2 id="git">Install Git, if needed</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
# Consult https://www.iana.org/time-zones for the latest versions.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2021a
|
||||
DATA=2021a
|
||||
CODE=2020d
|
||||
DATA=2020d
|
||||
|
||||
set -e
|
||||
rm -rf work
|
||||
|
||||
Binary file not shown.
@@ -1,216 +0,0 @@
|
||||
// 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 errorstest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// A manually modified object file could pass unexpected characters
|
||||
// into the files generated by cgo.
|
||||
|
||||
const magicInput = "abcdefghijklmnopqrstuvwxyz0123"
|
||||
const magicReplace = "\n//go:cgo_ldflag \"-badflag\"\n//"
|
||||
|
||||
const cSymbol = "BadSymbol" + magicInput + "Name"
|
||||
const cDefSource = "int " + cSymbol + " = 1;"
|
||||
const cRefSource = "extern int " + cSymbol + "; int F() { return " + cSymbol + "; }"
|
||||
|
||||
// goSource is the source code for the trivial Go file we use.
|
||||
// We will replace TMPDIR with the temporary directory name.
|
||||
const goSource = `
|
||||
package main
|
||||
|
||||
// #cgo LDFLAGS: TMPDIR/cbad.o TMPDIR/cbad.so
|
||||
// extern int F();
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
println(C.F())
|
||||
}
|
||||
`
|
||||
|
||||
func TestBadSymbol(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
mkdir := func(base string) string {
|
||||
ret := filepath.Join(dir, base)
|
||||
if err := os.Mkdir(ret, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
cdir := mkdir("c")
|
||||
godir := mkdir("go")
|
||||
|
||||
makeFile := func(mdir, base, source string) string {
|
||||
ret := filepath.Join(mdir, base)
|
||||
if err := ioutil.WriteFile(ret, []byte(source), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
cDefFile := makeFile(cdir, "cdef.c", cDefSource)
|
||||
cRefFile := makeFile(cdir, "cref.c", cRefSource)
|
||||
|
||||
ccCmd := cCompilerCmd(t)
|
||||
|
||||
cCompile := func(arg, base, src string) string {
|
||||
out := filepath.Join(cdir, base)
|
||||
run := append(ccCmd, arg, "-o", out, src)
|
||||
output, err := exec.Command(run[0], run[1:]...).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Log(run)
|
||||
t.Logf("%s", output)
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Remove(src); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Build a shared library that defines a symbol whose name
|
||||
// contains magicInput.
|
||||
|
||||
cShared := cCompile("-shared", "c.so", cDefFile)
|
||||
|
||||
// Build an object file that refers to the symbol whose name
|
||||
// contains magicInput.
|
||||
|
||||
cObj := cCompile("-c", "c.o", cRefFile)
|
||||
|
||||
// Rewrite the shared library and the object file, replacing
|
||||
// magicInput with magicReplace. This will have the effect of
|
||||
// introducing a symbol whose name looks like a cgo command.
|
||||
// The cgo tool will use that name when it generates the
|
||||
// _cgo_import.go file, thus smuggling a magic //go:cgo_ldflag
|
||||
// pragma into a Go file. We used to not check the pragmas in
|
||||
// _cgo_import.go.
|
||||
|
||||
rewrite := func(from, to string) {
|
||||
obj, err := ioutil.ReadFile(from)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if bytes.Count(obj, []byte(magicInput)) == 0 {
|
||||
t.Fatalf("%s: did not find magic string", from)
|
||||
}
|
||||
|
||||
if len(magicInput) != len(magicReplace) {
|
||||
t.Fatalf("internal test error: different magic lengths: %d != %d", len(magicInput), len(magicReplace))
|
||||
}
|
||||
|
||||
obj = bytes.ReplaceAll(obj, []byte(magicInput), []byte(magicReplace))
|
||||
|
||||
if err := ioutil.WriteFile(to, obj, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
cBadShared := filepath.Join(godir, "cbad.so")
|
||||
rewrite(cShared, cBadShared)
|
||||
|
||||
cBadObj := filepath.Join(godir, "cbad.o")
|
||||
rewrite(cObj, cBadObj)
|
||||
|
||||
goSourceBadObject := strings.ReplaceAll(goSource, "TMPDIR", godir)
|
||||
makeFile(godir, "go.go", goSourceBadObject)
|
||||
|
||||
makeFile(godir, "go.mod", "module badsym")
|
||||
|
||||
// Try to build our little package.
|
||||
cmd := exec.Command("go", "build", "-ldflags=-v")
|
||||
cmd.Dir = godir
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
||||
// The build should fail, but we want it to fail because we
|
||||
// detected the error, not because we passed a bad flag to the
|
||||
// C linker.
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("go build succeeded unexpectedly")
|
||||
}
|
||||
|
||||
t.Logf("%s", output)
|
||||
|
||||
for _, line := range bytes.Split(output, []byte("\n")) {
|
||||
if bytes.Contains(line, []byte("dynamic symbol")) && bytes.Contains(line, []byte("contains unsupported character")) {
|
||||
// This is the error from cgo.
|
||||
continue
|
||||
}
|
||||
|
||||
// We passed -ldflags=-v to see the external linker invocation,
|
||||
// which should not include -badflag.
|
||||
if bytes.Contains(line, []byte("-badflag")) {
|
||||
t.Error("output should not mention -badflag")
|
||||
}
|
||||
|
||||
// Also check for compiler errors, just in case.
|
||||
// GCC says "unrecognized command line option".
|
||||
// clang says "unknown argument".
|
||||
if bytes.Contains(line, []byte("unrecognized")) || bytes.Contains(output, []byte("unknown")) {
|
||||
t.Error("problem should have been caught before invoking C linker")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cCompilerCmd(t *testing.T) []string {
|
||||
cc := []string{goEnv(t, "CC")}
|
||||
|
||||
out := goEnv(t, "GOGCCFLAGS")
|
||||
quote := '\000'
|
||||
start := 0
|
||||
lastSpace := true
|
||||
backslash := false
|
||||
s := string(out)
|
||||
for i, c := range s {
|
||||
if quote == '\000' && unicode.IsSpace(c) {
|
||||
if !lastSpace {
|
||||
cc = append(cc, s[start:i])
|
||||
lastSpace = true
|
||||
}
|
||||
} else {
|
||||
if lastSpace {
|
||||
start = i
|
||||
lastSpace = false
|
||||
}
|
||||
if quote == '\000' && !backslash && (c == '"' || c == '\'') {
|
||||
quote = c
|
||||
backslash = false
|
||||
} else if !backslash && quote == c {
|
||||
quote = '\000'
|
||||
} else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
|
||||
backslash = true
|
||||
} else {
|
||||
backslash = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if !lastSpace {
|
||||
cc = append(cc, s[start:])
|
||||
}
|
||||
return cc
|
||||
}
|
||||
|
||||
func goEnv(t *testing.T, key string) string {
|
||||
out, err := exec.Command("go", "env", key).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Logf("go env %s\n", key)
|
||||
t.Logf("%s", out)
|
||||
t.Fatal(err)
|
||||
}
|
||||
return strings.TrimSpace(string(out))
|
||||
}
|
||||
@@ -62,60 +62,28 @@ 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 + expect
|
||||
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)
|
||||
}
|
||||
expectedProc := fmt.Sprintf("Pid:\t%d", pid)
|
||||
foundAThread := false
|
||||
for _, f := range fs {
|
||||
tf := fmt.Sprintf("/proc/%s/status", f.Name())
|
||||
d, err := ioutil.ReadFile(tf)
|
||||
if err != nil {
|
||||
// There are a surprising number of ways this
|
||||
// can error out on linux. We've seen all of
|
||||
// the following, so treat any error here as
|
||||
// equivalent to the "process is gone":
|
||||
// os.IsNotExist(err),
|
||||
// "... : no such process",
|
||||
// "... : bad file descriptor.
|
||||
continue
|
||||
return fmt.Errorf("unable to read %q: %v", tf, err)
|
||||
}
|
||||
lines := strings.Split(string(d), "\n")
|
||||
for _, line := range lines {
|
||||
// Different kernel vintages pad differently.
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "Pid:\t") {
|
||||
// On loaded systems, it is possible
|
||||
// for a TID to be reused really
|
||||
// quickly. As such, we need to
|
||||
// validate that the thread status
|
||||
// info we just read is a task of the
|
||||
// same process PID as we are
|
||||
// currently running, and not a
|
||||
// recently terminated thread
|
||||
// resurfaced in a different process.
|
||||
if line != expectedProc {
|
||||
break
|
||||
}
|
||||
// Fall through in the unlikely case
|
||||
// that filter at some point is
|
||||
// "Pid:\t".
|
||||
}
|
||||
if strings.HasPrefix(line, filter) {
|
||||
if line != expected {
|
||||
return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc)
|
||||
return fmt.Errorf("%s %s (bad)\n", tf, line)
|
||||
}
|
||||
foundAThread = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !foundAThread {
|
||||
return fmt.Errorf("found no thread /proc/<TID>/status files for process %q", expectedProc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -142,34 +110,34 @@ func test1435(t *testing.T) {
|
||||
fn func() error
|
||||
filter, expect string
|
||||
}{
|
||||
{call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "\t0\t1\t0\t1"},
|
||||
{call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
|
||||
{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: "\t0\t1\t0\t1"},
|
||||
{call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "\t0\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: "\t1\t1\t1\t1"},
|
||||
{call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "\t0\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: "\t0 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: "\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: "\t101\t0\t0\t0"},
|
||||
{call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "\t0\t102\t102\t102"},
|
||||
{call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
|
||||
{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: "\t1\t0\t0\t0"},
|
||||
{call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "\t0\t2\t2\t2"},
|
||||
{call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "\t0\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: "\t101\t0\t102\t0"},
|
||||
{call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "\t0\t102\t101\t102"},
|
||||
{call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "\t0\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: "\t1\t0\t2\t0"},
|
||||
{call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "\t0\t2\t1\t2"},
|
||||
{call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "\t0\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 {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// 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 cgotest
|
||||
|
||||
// typedef struct { } T42495A;
|
||||
// typedef struct { int x[0]; } T42495B;
|
||||
import "C"
|
||||
|
||||
//export Issue42495A
|
||||
func Issue42495A(C.T42495A) {}
|
||||
|
||||
//export Issue42495B
|
||||
func Issue42495B(C.T42495B) {}
|
||||
@@ -30,7 +30,7 @@ func TestCrossPackageTests(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "android":
|
||||
t.Skip("Can't exec cmd/go subprocess on Android.")
|
||||
case "ios":
|
||||
case "darwin", "ios":
|
||||
switch runtime.GOARCH {
|
||||
case "arm64":
|
||||
t.Skip("Can't exec cmd/go subprocess on iOS.")
|
||||
|
||||
31
misc/cgo/test/testdata/issue9400/asm_riscv64.s
vendored
31
misc/cgo/test/testdata/issue9400/asm_riscv64.s
vendored
@@ -1,31 +0,0 @@
|
||||
// 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
|
||||
@@ -118,6 +118,11 @@ func testMain(m *testing.M) int {
|
||||
cc = append(cc, s[start:])
|
||||
}
|
||||
|
||||
if GOOS == "darwin" || GOOS == "ios" {
|
||||
// For Darwin/ARM.
|
||||
// TODO: do we still need this?
|
||||
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
|
||||
}
|
||||
if GOOS == "aix" {
|
||||
// -Wl,-bnoobjreorder is mandatory to keep the same layout
|
||||
// in .text section.
|
||||
|
||||
@@ -401,7 +401,7 @@ func main() {
|
||||
defer f.Close()
|
||||
section := f.Section(".edata")
|
||||
if section == nil {
|
||||
t.Fatalf(".edata section is not present")
|
||||
t.Error(".edata section is not present")
|
||||
}
|
||||
|
||||
// TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
|
||||
@@ -418,8 +418,7 @@ func main() {
|
||||
t.Fatalf("binary.Read failed: %v", err)
|
||||
}
|
||||
|
||||
// Only the two exported functions and _cgo_dummy_export should be exported
|
||||
expectedNumber := uint32(3)
|
||||
expectedNumber := uint32(2)
|
||||
|
||||
if exportAllSymbols {
|
||||
if e.NumberOfFunctions <= expectedNumber {
|
||||
@@ -430,10 +429,10 @@ func main() {
|
||||
}
|
||||
} else {
|
||||
if e.NumberOfFunctions != expectedNumber {
|
||||
t.Fatalf("got %d exported functions; want %d", e.NumberOfFunctions, expectedNumber)
|
||||
t.Fatalf("too many exported functions: %v", e.NumberOfFunctions)
|
||||
}
|
||||
if e.NumberOfNames != expectedNumber {
|
||||
t.Fatalf("got %d exported names; want %d", e.NumberOfNames, expectedNumber)
|
||||
t.Fatalf("too many exported names: %v", e.NumberOfNames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,17 +196,3 @@ func TestIssue25756(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMethod(t *testing.T) {
|
||||
// Exported symbol's method must be live.
|
||||
goCmd(t, "build", "-buildmode=plugin", "-o", "plugin.so", "./method/plugin.go")
|
||||
goCmd(t, "build", "-o", "method.exe", "./method/main.go")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, "./method.exe")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out)
|
||||
}
|
||||
}
|
||||
|
||||
26
misc/cgo/testplugin/testdata/method/main.go
vendored
26
misc/cgo/testplugin/testdata/method/main.go
vendored
@@ -1,26 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// Issue 42579: methods of symbols exported from plugin must be live.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"plugin"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func main() {
|
||||
p, err := plugin.Open("plugin.so")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
x, err := p.Lookup("X")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
reflect.ValueOf(x).Elem().MethodByName("M").Call(nil)
|
||||
}
|
||||
13
misc/cgo/testplugin/testdata/method/plugin.go
vendored
13
misc/cgo/testplugin/testdata/method/plugin.go
vendored
@@ -1,13 +0,0 @@
|
||||
// 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 main
|
||||
|
||||
func main() {}
|
||||
|
||||
type T int
|
||||
|
||||
func (T) M() { println("M") }
|
||||
|
||||
var X T
|
||||
@@ -28,7 +28,6 @@ func TestMSAN(t *testing.T) {
|
||||
{src: "msan4.go"},
|
||||
{src: "msan5.go"},
|
||||
{src: "msan6.go"},
|
||||
{src: "msan7.go"},
|
||||
{src: "msan_fail.go", wantErr: true},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
|
||||
38
misc/cgo/testsanitizers/testdata/msan7.go
vendored
38
misc/cgo/testsanitizers/testdata/msan7.go
vendored
@@ -1,38 +0,0 @@
|
||||
// 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 main
|
||||
|
||||
// Test passing C struct to exported Go function.
|
||||
|
||||
/*
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// T is a C struct with alignment padding after b.
|
||||
// The padding bytes are not considered initialized by MSAN.
|
||||
// It is big enough to be passed on stack in C ABI (and least
|
||||
// on AMD64).
|
||||
typedef struct { char b; uintptr_t x, y; } T;
|
||||
|
||||
extern void F(T);
|
||||
|
||||
// Use weak as a hack to permit defining a function even though we use export.
|
||||
void CF(int x) __attribute__ ((weak));
|
||||
void CF(int x) {
|
||||
T *t = malloc(sizeof(T));
|
||||
t->b = (char)x;
|
||||
t->x = x;
|
||||
t->y = x;
|
||||
F(*t);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
//export F
|
||||
func F(t C.T) { println(t.b, t.x, t.y) }
|
||||
|
||||
func main() {
|
||||
C.CF(C.int(0))
|
||||
}
|
||||
@@ -7,13 +7,6 @@ set to the clang wrapper that invokes clang for iOS. For example, this command r
|
||||
|
||||
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
|
||||
|
||||
If CC_FOR_TARGET is not set when the toolchain is built (make.bash or all.bash), CC
|
||||
can be set on the command line. For example,
|
||||
|
||||
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC=$(go env GOROOT)/misc/ios/clangwrap.sh go build
|
||||
|
||||
Setting CC is not necessary if the toolchain is built with CC_FOR_TARGET set.
|
||||
|
||||
To use the go tool to run individual programs and tests, put $GOROOT/bin into PATH to ensure
|
||||
the go_ios_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests:
|
||||
|
||||
|
||||
@@ -503,9 +503,6 @@
|
||||
}
|
||||
|
||||
async run(instance) {
|
||||
if (!(instance instanceof WebAssembly.Instance)) {
|
||||
throw new Error("Go.run: WebAssembly.Instance expected");
|
||||
}
|
||||
this._inst = instance;
|
||||
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
@@ -772,7 +773,7 @@ func TestReadTruncation(t *testing.T) {
|
||||
"testdata/pax-path-hdr.tar",
|
||||
"testdata/sparse-formats.tar",
|
||||
} {
|
||||
buf, err := os.ReadFile(p)
|
||||
buf, err := ioutil.ReadFile(p)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func isASCII(s string) bool {
|
||||
}
|
||||
|
||||
// toASCII converts the input to an ASCII C-style string.
|
||||
// This is a best effort conversion, so invalid characters are dropped.
|
||||
// This a best effort conversion, so invalid characters are dropped.
|
||||
func toASCII(s string) string {
|
||||
if isASCII(s) {
|
||||
return s
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
@@ -262,7 +263,7 @@ func TestFileInfoHeaderDir(t *testing.T) {
|
||||
func TestFileInfoHeaderSymlink(t *testing.T) {
|
||||
testenv.MustHaveSymlink(t)
|
||||
|
||||
tmpdir, err := os.MkdirTemp("", "TestFileInfoHeaderSymlink")
|
||||
tmpdir, err := ioutil.TempDir("", "TestFileInfoHeaderSymlink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
@@ -519,7 +520,7 @@ func TestWriter(t *testing.T) {
|
||||
}
|
||||
|
||||
if v.file != "" {
|
||||
want, err := os.ReadFile(v.file)
|
||||
want, err := ioutil.ReadFile(v.file)
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile() = %v, want nil", err)
|
||||
}
|
||||
|
||||
@@ -695,7 +695,7 @@ func fileEntryLess(x, y string) bool {
|
||||
}
|
||||
|
||||
// Open opens the named file in the ZIP archive,
|
||||
// using the semantics of fs.FS.Open:
|
||||
// using the semantics of io.FS.Open:
|
||||
// paths are always slash separated, with no
|
||||
// leading / or ../ elements.
|
||||
func (r *Reader) Open(name string) (fs.File, error) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"internal/obscuretestdata"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
@@ -628,7 +629,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
|
||||
var c []byte
|
||||
if ft.Content != nil {
|
||||
c = ft.Content
|
||||
} else if c, err = os.ReadFile("testdata/" + ft.File); err != nil {
|
||||
} else if c, err = ioutil.ReadFile("testdata/" + ft.File); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
@@ -684,7 +685,7 @@ func TestInvalidFiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) {
|
||||
data, err := os.ReadFile(filepath.Join("testdata", fileName))
|
||||
data, err := ioutil.ReadFile(filepath.Join("testdata", fileName))
|
||||
if err != nil {
|
||||
panic("Error reading " + fileName + ": " + err.Error())
|
||||
}
|
||||
@@ -791,17 +792,17 @@ func returnRecursiveZip() (r io.ReaderAt, size int64) {
|
||||
//
|
||||
// func main() {
|
||||
// bigZip := makeZip("big.file", io.LimitReader(zeros{}, 1<<32-1))
|
||||
// if err := os.WriteFile("/tmp/big.zip", bigZip, 0666); err != nil {
|
||||
// if err := ioutil.WriteFile("/tmp/big.zip", bigZip, 0666); err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// biggerZip := makeZip("big.zip", bytes.NewReader(bigZip))
|
||||
// if err := os.WriteFile("/tmp/bigger.zip", biggerZip, 0666); err != nil {
|
||||
// if err := ioutil.WriteFile("/tmp/bigger.zip", biggerZip, 0666); err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// biggestZip := makeZip("bigger.zip", bytes.NewReader(biggerZip))
|
||||
// if err := os.WriteFile("/tmp/biggest.zip", biggestZip, 0666); err != nil {
|
||||
// if err := ioutil.WriteFile("/tmp/biggest.zip", biggestZip, 0666); err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -237,7 +237,7 @@ func TestWriterTime(t *testing.T) {
|
||||
t.Fatalf("unexpected Close error: %v", err)
|
||||
}
|
||||
|
||||
want, err := os.ReadFile("testdata/time-go.zip")
|
||||
want, err := ioutil.ReadFile("testdata/time-go.zip")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected ReadFile error: %v", err)
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ func TestReader(t *testing.T) {
|
||||
for i := 0; i < len(texts)-1; i++ {
|
||||
texts[i] = str + "\n"
|
||||
all += texts[i]
|
||||
str += string(rune(i%26 + 'a'))
|
||||
str += string(rune(i)%26 + 'a')
|
||||
}
|
||||
texts[len(texts)-1] = all
|
||||
|
||||
|
||||
@@ -30,13 +30,6 @@ func ExampleBuffer_reader() {
|
||||
// Output: Gophers rule!
|
||||
}
|
||||
|
||||
func ExampleBuffer_Bytes() {
|
||||
buf := bytes.Buffer{}
|
||||
buf.Write([]byte{'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'})
|
||||
os.Stdout.Write(buf.Bytes())
|
||||
// Output: hello world
|
||||
}
|
||||
|
||||
func ExampleBuffer_Grow() {
|
||||
var b bytes.Buffer
|
||||
b.Grow(64)
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -97,8 +98,8 @@ func testAddr2Line(t *testing.T, exepath, addr string) {
|
||||
if !os.SameFile(fi1, fi2) {
|
||||
t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
|
||||
}
|
||||
if srcLineNo != "106" {
|
||||
t.Fatalf("line number = %v; want 106", srcLineNo)
|
||||
if srcLineNo != "107" {
|
||||
t.Fatalf("line number = %v; want 107", srcLineNo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ func testAddr2Line(t *testing.T, exepath, addr string) {
|
||||
func TestAddr2Line(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
tmpDir, err := os.MkdirTemp("", "TestAddr2Line")
|
||||
tmpDir, err := ioutil.TempDir("", "TestAddr2Line")
|
||||
if err != nil {
|
||||
t.Fatal("TempDir failed: ", err)
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ import (
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
@@ -341,7 +342,7 @@ func fileFeatures(filename string) []string {
|
||||
if filename == "" {
|
||||
return nil
|
||||
}
|
||||
bs, err := os.ReadFile(filename)
|
||||
bs, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading file %s: %v", filename, err)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@@ -74,7 +75,7 @@ func TestGolden(t *testing.T) {
|
||||
f.Close()
|
||||
}
|
||||
|
||||
bs, err := os.ReadFile(goldenFile)
|
||||
bs, err := ioutil.ReadFile(goldenFile)
|
||||
if err != nil {
|
||||
t.Fatalf("opening golden.txt for package %q: %v", fi.Name(), err)
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
@@ -535,9 +535,6 @@ func archRISCV64() *Arch {
|
||||
|
||||
// Standard register names.
|
||||
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)
|
||||
register[name] = int16(i)
|
||||
}
|
||||
@@ -574,7 +571,7 @@ func archRISCV64() *Arch {
|
||||
register["S8"] = riscv.REG_S8
|
||||
register["S9"] = riscv.REG_S9
|
||||
register["S10"] = riscv.REG_S10
|
||||
// Skip S11 as it is the g register.
|
||||
register["S11"] = riscv.REG_S11
|
||||
register["T3"] = riscv.REG_T3
|
||||
register["T4"] = riscv.REG_T4
|
||||
register["T5"] = riscv.REG_T5
|
||||
|
||||
@@ -75,7 +75,7 @@ func IsARM64STLXR(op obj.As) bool {
|
||||
arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
|
||||
return true
|
||||
}
|
||||
// LDADDx/SWPx/CASx atomic instructions
|
||||
// atomic instructions
|
||||
if arm64.IsAtomicInstruction(op) {
|
||||
return true
|
||||
}
|
||||
@@ -93,17 +93,6 @@ func IsARM64TBL(op obj.As) bool {
|
||||
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.
|
||||
// It returns a boolean to indicate success; failure means
|
||||
// cond was unrecognized.
|
||||
|
||||
@@ -637,18 +637,6 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||
prog.From = a[0]
|
||||
prog.SetFrom3(a[1])
|
||||
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:
|
||||
prog.From = a[0]
|
||||
prog.Reg = p.getRegister(prog, op, &a[1])
|
||||
@@ -737,7 +725,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||
}
|
||||
if p.arch.Family == sys.AMD64 {
|
||||
prog.From = a[0]
|
||||
prog.SetRestArgs([]obj.Addr{a[1], a[2]})
|
||||
prog.RestArgs = []obj.Addr{a[1], a[2]}
|
||||
prog.To = a[3]
|
||||
break
|
||||
}
|
||||
@@ -820,13 +808,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
|
||||
}
|
||||
if p.arch.Family == sys.AMD64 {
|
||||
prog.From = a[0]
|
||||
prog.SetRestArgs([]obj.Addr{a[1], a[2], a[3]})
|
||||
prog.RestArgs = []obj.Addr{a[1], a[2], a[3]}
|
||||
prog.To = a[4]
|
||||
break
|
||||
}
|
||||
if p.arch.Family == sys.S390X {
|
||||
prog.From = a[0]
|
||||
prog.SetRestArgs([]obj.Addr{a[1], a[2], a[3]})
|
||||
prog.RestArgs = []obj.Addr{a[1], a[2], a[3]}
|
||||
prog.To = a[4]
|
||||
break
|
||||
}
|
||||
|
||||
@@ -390,7 +390,12 @@ func TestARM64Errors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAMD64EndToEnd(t *testing.T) {
|
||||
testEndToEnd(t, "amd64", "amd64")
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
func Test386Encoder(t *testing.T) {
|
||||
|
||||
779
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
779
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@@ -10,8 +10,14 @@
|
||||
|
||||
TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
|
||||
|
||||
// arithmetic operations
|
||||
//
|
||||
// ADD
|
||||
//
|
||||
// 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 R1, R2, R3
|
||||
ADDW R1, ZR, R3
|
||||
@@ -19,29 +25,18 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
ADD R1, R2, R3
|
||||
ADD R1, ZR, 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 // ADD $2730, R2 // 42a82a91
|
||||
ADD $0xaaa000, R2, R3 // ADD $11182080, R2, R3 // 43a86a91
|
||||
ADD $0xaaa000, R2 // ADD $11182080, R2 // 42a86a91
|
||||
ADD $0xaaaaaa, R2, R3 // ADD $11184810, R2, R3 // 43a82a9163a86a91
|
||||
ADD $0xaaaaaa, R2 // ADD $11184810, R2 // 42a82a9142a86a91
|
||||
SUB $0x000aaa, R2, R3 // SUB $2730, R2, R3 // 43a82ad1
|
||||
SUB $0x000aaa, R2 // SUB $2730, R2 // 42a82ad1
|
||||
SUB $0xaaa000, R2, R3 // SUB $11182080, R2, R3 // 43a86ad1
|
||||
SUB $0xaaa000, R2 // SUB $11182080, R2 // 42a86ad1
|
||||
SUB $0xaaaaaa, R2, R3 // SUB $11184810, R2, R3 // 43a82ad163a86ad1
|
||||
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 $0x000aaa, R2, R3 // ADD $2730, R2, R3 // 43a82a91
|
||||
ADD $0x000aaa, R2 // ADD $2730, R2 // 42a82a91
|
||||
ADD $0xaaa000, R2, R3 // ADD $11182080, R2, R3 // 43a86a91
|
||||
ADD $0xaaa000, R2 // ADD $11182080, R2 // 42a86a91
|
||||
ADD $0xaaaaaa, R2, R3 // ADD $11184810, R2, R3 // 43a82a9163a86a91
|
||||
ADD $0xaaaaaa, R2 // ADD $11184810, R2 // 42a82a9142a86a91
|
||||
SUB $0x000aaa, R2, R3 // SUB $2730, R2, R3 // 43a82ad1
|
||||
SUB $0x000aaa, R2 // SUB $2730, R2 // 42a82ad1
|
||||
SUB $0xaaa000, R2, R3 // SUB $11182080, R2, R3 // 43a86ad1
|
||||
SUB $0xaaa000, R2 // SUB $11182080, R2 // 42a86ad1
|
||||
SUB $0xaaaaaa, R2, R3 // SUB $11184810, R2, R3 // 43a82ad163a86ad1
|
||||
SUB $0xaaaaaa, R2 // SUB $11184810, R2 // 42a82ad142a86ad1
|
||||
ADD R1>>11, R2, R3
|
||||
ADD R1<<22, R2, R3
|
||||
ADD R1->33, R2, R3
|
||||
@@ -64,30 +59,6 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
CMN R1.SXTX<<2, R10 // 5fe921ab
|
||||
CMPW R2.UXTH<<3, R11 // 7f2d226b
|
||||
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.S4, V2.S4, V3.S4 // 43bca14e
|
||||
VADDP V1.D2, V2.D2, V3.D2 // 43bce14e
|
||||
@@ -96,6 +67,22 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
VORR V5.B16, V4.B16, V3.B16 // 831ca54e
|
||||
VADD V16.S4, V5.S4, V9.S4 // a984b04e
|
||||
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
|
||||
VMOVI $82, V0.B16 // 40e6024f
|
||||
VUADDLV V6.B16, V6 // c638306e
|
||||
@@ -109,6 +96,10 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
VFMLS V1.D2, V12.D2, V1.D2 // 81cde14e
|
||||
VFMLS V1.S2, V12.S2, V1.S2 // 81cda10e
|
||||
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 $8, V2.B16, V1.B16, V3.B16 // 2340026e
|
||||
VRBIT V24.B16, V24.B16 // 185b606e
|
||||
@@ -134,14 +125,6 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
VSRI $8, V1.H8, V2.H8 // 2244186f
|
||||
VSRI $2, V1.B8, V2.B8 // 22440e2f
|
||||
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 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
|
||||
@@ -158,6 +141,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
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 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
|
||||
VZIP2 V22.D2, V25.D2, V21.D2 // 357bd64e
|
||||
VZIP1 V6.D2, V9.D2, V11.D2 // 2b39c64e
|
||||
@@ -195,95 +180,114 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
VUSHLL2 $31, V30.S4, V2.D2 // c2a73f6f
|
||||
VBIF V0.B8, V30.B8, V1.B8 // c11fe02e
|
||||
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
|
||||
FMOVD $(4.0), F0 // 0010621e
|
||||
FMOVS $(0.265625), F1 // 01302a1e
|
||||
FMOVD $(0.1796875), F2 // 02f0681e
|
||||
FMOVS $(0.96875), F3 // 03f02d1e
|
||||
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
|
||||
|
||||
// special
|
||||
PRFM (R2), PLDL1KEEP // 400080f9
|
||||
PRFM 16(R2), PLDL1KEEP // 400880f9
|
||||
PRFM 48(R6), PSTL2STRM // d31880f9
|
||||
PRFM 8(R12), PLIL3STRM // 8d0580f9
|
||||
PRFM (R8), $25 // 190180f9
|
||||
PRFM 8(R9), $30 // 3e0580f9
|
||||
NOOP // 1f2003d5
|
||||
HINT $0 // 1f2003d5
|
||||
DMB $1
|
||||
SVC
|
||||
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
|
||||
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
|
||||
|
||||
// encryption
|
||||
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
|
||||
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
|
||||
VEOR3 V2.B16, V7.B16, V12.B16, V25.B16 // 990907ce
|
||||
VBCAX V1.B16, V2.B16, V26.B16, V31.B16 // 5f0722ce
|
||||
VREV32 V5.B16, V5.B16 // a508206e
|
||||
VREV64 V2.S2, V3.S2 // 4308a00e
|
||||
VREV64 V2.S4, V3.S4 // 4308a04e
|
||||
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
|
||||
ADD $0x186a0, R2, R5 // ADD $100000, R2, R5 // 45801a91a5604091
|
||||
SUB $0xe7791f700, R3, R1 // SUB $62135596800, R3, R1 // 1be09ed23bf2aef2db01c0f261001bcb
|
||||
CMP $3343198598084851058, R3 // 5bae8ed2db8daef23badcdf2bbcce5f27f001beb
|
||||
ADD $0x3fffffffc000, R5 // ADD $70368744161280, R5 // fb7f72b2a5001b8b
|
||||
// LTYPE1 imsr ',' spreg ','
|
||||
// {
|
||||
// outcode($1, &$2, $4, &nullgen);
|
||||
// }
|
||||
// LTYPE1 imsr ',' reg
|
||||
// {
|
||||
// outcode($1, &$2, NREG, &$4);
|
||||
// }
|
||||
ADDW $1, R2
|
||||
ADDW R1, R2
|
||||
ADD $1, R2
|
||||
ADD R1, R2
|
||||
ADD R1>>11, R2
|
||||
ADD R1<<22, R2
|
||||
ADD R1->33, R2
|
||||
AND R1@>33, R2
|
||||
|
||||
// logical ops
|
||||
//
|
||||
// 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-1), R1 // AND $9223372036854775807, R1 // 21f84092
|
||||
ORR $(1<<63), R1 // ORR $-9223372036854775808, R1 // 210041b2
|
||||
ORR $(1<<63-1), R1 // ORR $9223372036854775807, R1 // 21f840b2
|
||||
EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2
|
||||
EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2
|
||||
ANDW $0x3ff00000, R2 // ANDW $1072693248, R2 // 42240c12
|
||||
BICW $0x3ff00000, R2 // BICW $1072693248, R2 // 42540212
|
||||
ORRW $0x3ff00000, R2 // ORRW $1072693248, R2 // 42240c32
|
||||
ORNW $0x3ff00000, R2 // ORNW $1072693248, R2 // 42540232
|
||||
EORW $0x3ff00000, R2 // EORW $1072693248, R2 // 42240c52
|
||||
EONW $0x3ff00000, R2 // EONW $1072693248, R2 // 42540252
|
||||
AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a
|
||||
ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa
|
||||
EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca
|
||||
BIC $0x22220000, R3, R4 // BIC $572653568, R3, R4 // 5b44a4d264003b8a
|
||||
ORN $0x22220000, R3, R4 // ORN $572653568, R3, R4 // 5b44a4d264003baa
|
||||
EON $0x22220000, R3, R4 // EON $572653568, R3, R4 // 5b44a4d264003bca
|
||||
ANDS $0x22220000, R3, R4 // ANDS $572653568, R3, R4 // 5b44a4d264001bea
|
||||
BICS $0x22220000, R3, R4 // BICS $572653568, R3, R4 // 5b44a4d264003bea
|
||||
AND $(1<<63), R1 // AND $-9223372036854775808, R1 // 21004192
|
||||
AND $(1<<63-1), R1 // AND $9223372036854775807, R1 // 21f84092
|
||||
ORR $(1<<63), R1 // ORR $-9223372036854775808, R1 // 210041b2
|
||||
ORR $(1<<63-1), R1 // ORR $9223372036854775807, R1 // 21f840b2
|
||||
EOR $(1<<63), R1 // EOR $-9223372036854775808, R1 // 210041d2
|
||||
EOR $(1<<63-1), R1 // EOR $9223372036854775807, R1 // 21f840d2
|
||||
|
||||
ANDW $0x3ff00000, R2 // ANDW $1072693248, R2 // 42240c12
|
||||
BICW $0x3ff00000, R2 // BICW $1072693248, R2 // 42540212
|
||||
ORRW $0x3ff00000, R2 // ORRW $1072693248, R2 // 42240c32
|
||||
ORNW $0x3ff00000, R2 // ORNW $1072693248, R2 // 42540232
|
||||
EORW $0x3ff00000, R2 // EORW $1072693248, R2 // 42240c52
|
||||
EONW $0x3ff00000, R2 // EONW $1072693248, R2 // 42540252
|
||||
|
||||
AND $0x22220000, R3, R4 // AND $572653568, R3, R4 // 5b44a4d264001b8a
|
||||
ORR $0x22220000, R3, R4 // ORR $572653568, R3, R4 // 5b44a4d264001baa
|
||||
EOR $0x22220000, R3, R4 // EOR $572653568, R3, R4 // 5b44a4d264001bca
|
||||
BIC $0x22220000, R3, R4 // BIC $572653568, R3, R4 // 5b44a4d264003b8a
|
||||
ORN $0x22220000, R3, R4 // ORN $572653568, R3, R4 // 5b44a4d264003baa
|
||||
EON $0x22220000, R3, R4 // EON $572653568, R3, R4 // 5b44a4d264003bca
|
||||
ANDS $0x22220000, R3, R4 // ANDS $572653568, R3, R4 // 5b44a4d264001bea
|
||||
BICS $0x22220000, R3, R4 // BICS $572653568, R3, R4 // 5b44a4d264003bea
|
||||
|
||||
EOR $0xe03fffffffffffff, R20, R22 // EOR $-2287828610704211969, R20, R22 // 96e243d2
|
||||
TSTW $0x600000006, R1 // TSTW $25769803782, R1 // 3f041f72
|
||||
TST $0x4900000049, R0 // TST $313532612681, R0 // 3b0980d23b09c0f21f001bea
|
||||
@@ -312,22 +316,19 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
EONW $0x6006000060060, R5 // EONW $1689262177517664, R5 // 1b0c8052db00a072a5003b4a
|
||||
ORNW $0x6006000060060, R5 // ORNW $1689262177517664, R5 // 1b0c8052db00a072a5003b2a
|
||||
BICSW $0x6006000060060, R5 // BICSW $1689262177517664, R5 // 1b0c8052db00a072a5003b6a
|
||||
// TODO: this could have better encoding
|
||||
ANDW $-1, R10 // 1b0080124a011b0a
|
||||
AND $8, R0, RSP // 1f007d92
|
||||
ORR $8, R0, RSP // 1f007db2
|
||||
EOR $8, R0, RSP // 1f007dd2
|
||||
BIC $8, R0, RSP // 1ff87c92
|
||||
ORN $8, R0, RSP // 1ff87cb2
|
||||
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
|
||||
ADDW $0x60060, R2 // ADDW $393312, R2 // 4280011142804111
|
||||
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
|
||||
|
||||
// TODO: this could have better encoding
|
||||
ANDW $-1, R10 // 1b0080124a011b0a
|
||||
|
||||
AND $8, R0, RSP // 1f007d92
|
||||
ORR $8, R0, RSP // 1f007db2
|
||||
EOR $8, R0, RSP // 1f007dd2
|
||||
BIC $8, R0, RSP // 1ff87c92
|
||||
ORN $8, R0, RSP // 1ff87cb2
|
||||
EON $8, R0, RSP // 1ff87cd2
|
||||
|
||||
// move an immediate to a Rn.
|
||||
MOVD $0x3fffffffc000, R0 // MOVD $70368744161280, R0 // e07f72b2
|
||||
MOVW $1000000, R4 // 04488852e401a072
|
||||
MOVW $0xaaaa0000, R1 // MOVW $2863267840, R1 // 4155b552
|
||||
@@ -347,37 +348,46 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
MOVD $-1, R1 // 01008092
|
||||
MOVD $0x210000, R0 // MOVD $2162688, R0 // 2004a0d2
|
||||
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 $0x1708(RSP), RSP // MOVD $5896(RSP), RSP // fb0740917f231c91
|
||||
MOVD $0x2001(R7), R1 // MOVD $8193(R7), R1 // fb08409161070091
|
||||
MOVD $0xffffff(R7), R1 // MOVD $16777215(R7), R1 // fbfc7f9161ff3f91
|
||||
|
||||
MOVD $-0x1(R7), R1 // MOVD $-1(R7), R1 // e10400d1
|
||||
MOVD $-0x30(R7), R1 // MOVD $-48(R7), R1 // e1c000d1
|
||||
MOVD $-0x708(R7), R1 // MOVD $-1800(R7), R1 // e1201cd1
|
||||
MOVD $-0x2000(RSP), R1 // MOVD $-8192(RSP), R1 // e10b40d1
|
||||
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 ZR, R1
|
||||
MOVW R1, ZR
|
||||
MOVW $1, ZR
|
||||
MOVW $1, R1
|
||||
MOVW ZR, (R1)
|
||||
MOVD R1, R2
|
||||
MOVD ZR, R1
|
||||
|
||||
// store and load
|
||||
//
|
||||
// LD1/ST1
|
||||
MOVD $1, ZR
|
||||
MOVD $1, R1
|
||||
MOVD ZR, (R1)
|
||||
VLD1 (R8), [V1.B16, V2.B16] // 01a1404c
|
||||
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
|
||||
@@ -435,42 +445,23 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
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 [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23) // VST4.P [V24.B8, V25.B8, V26.B8, V27.B8], (R3)(R23*1) // 7800970c
|
||||
|
||||
// pre/post-indexed
|
||||
FMOVS F20, (R0) // 140000bd
|
||||
FMOVS.P F20, 4(R0) // 144400bc
|
||||
FMOVS.W F20, 4(R0) // 144c00bc
|
||||
FMOVD.P F20, 8(R1) // 348400fc
|
||||
FMOVQ.P F13, 11(R10) // 4db5803c
|
||||
FMOVQ.W F15, 11(R20) // 8fbe803c
|
||||
|
||||
FMOVS (R0), F20 // 140040bd
|
||||
FMOVS.P 8(R0), F20 // 148440bc
|
||||
FMOVS.W 8(R0), F20 // 148c40bc
|
||||
FMOVD F20, (R2) // 540000fd
|
||||
FMOVD.P F20, 8(R1) // 348400fc
|
||||
FMOVD.W 8(R1), F20 // 348c40fc
|
||||
FMOVQ.P 11(R10), F13 // 4db5c03c
|
||||
FMOVQ.W 11(R20), F15 // 8fbec03c
|
||||
|
||||
// small offset fits into instructions
|
||||
MOVB R1, 1(R2) // 41040039
|
||||
MOVH R1, 1(R2) // 41100078
|
||||
MOVH R1, 2(R2) // 41040079
|
||||
MOVW R1, 1(R2) // 411000b8
|
||||
MOVW R1, 4(R2) // 410400b9
|
||||
MOVD R1, 1(R2) // 411000f8
|
||||
MOVD R1, 8(R2) // 410400f9
|
||||
MOVD ZR, (R1)
|
||||
MOVW ZR, (R1)
|
||||
FMOVS F1, 1(R2) // 411000bc
|
||||
FMOVS F1, 4(R2) // 410400bd
|
||||
FMOVS F20, (R0) // 140000bd
|
||||
FMOVD F1, 1(R2) // 411000fc
|
||||
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
|
||||
PRFM (R2), PLDL1KEEP // 400080f9
|
||||
PRFM 16(R2), PLDL1KEEP // 400880f9
|
||||
PRFM 48(R6), PSTL2STRM // d31880f9
|
||||
PRFM 8(R12), PLIL3STRM // 8d0580f9
|
||||
PRFM (R8), $25 // 190180f9
|
||||
PRFM 8(R9), $30 // 3e0580f9
|
||||
|
||||
// small offset fits into instructions
|
||||
MOVB 1(R1), R2 // 22048039
|
||||
MOVH 1(R1), R2 // 22108078
|
||||
MOVH 2(R1), R2 // 22048079
|
||||
@@ -478,16 +469,29 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
MOVW 4(R1), R2 // 220480b9
|
||||
MOVD 1(R1), R2 // 221040f8
|
||||
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
|
||||
MOVB R1, 1(R2) // 41040039
|
||||
MOVH R1, 1(R2) // 41100078
|
||||
MOVH R1, 2(R2) // 41040079
|
||||
MOVW R1, 1(R2) // 411000b8
|
||||
MOVW R1, 4(R2) // 410400b9
|
||||
MOVD R1, 1(R2) // 411000f8
|
||||
MOVD R1, 8(R2) // 410400f9
|
||||
FMOVS F1, 1(R2) // 411000bc
|
||||
FMOVS F1, 4(R2) // 410400bd
|
||||
FMOVD F1, 1(R2) // 411000fc
|
||||
FMOVD F1, 8(R2) // 410400fd
|
||||
|
||||
// large aligned offset, use two instructions(add+ldr/store).
|
||||
// large aligned offset, use two instructions
|
||||
MOVB 0x1001(R1), R2 // MOVB 4097(R1), R2 // 3b04409162078039
|
||||
MOVH 0x2002(R1), R2 // MOVH 8194(R1), R2 // 3b08409162078079
|
||||
MOVW 0x4004(R1), R2 // MOVW 16388(R1), R2 // 3b104091620780b9
|
||||
MOVD 0x8008(R1), R2 // MOVD 32776(R1), R2 // 3b204091620740f9
|
||||
FMOVS 0x4004(R1), F2 // FMOVS 16388(R1), F2 // 3b104091620740bd
|
||||
FMOVD 0x8008(R1), F2 // FMOVD 32776(R1), F2 // 3b204091620740fd
|
||||
MOVB R1, 0x1001(R2) // MOVB R1, 4097(R2) // 5b04409161070039
|
||||
MOVH R1, 0x2002(R2) // MOVH R1, 8194(R2) // 5b08409161070079
|
||||
MOVW R1, 0x4004(R2) // MOVW R1, 16388(R2) // 5b104091610700b9
|
||||
@@ -495,16 +499,15 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
FMOVS F1, 0x4004(R2) // FMOVS F1, 16388(R2) // 5b104091610700bd
|
||||
FMOVD F1, 0x8008(R2) // FMOVD F1, 32776(R2) // 5b204091610700fd
|
||||
|
||||
MOVB 0x1001(R1), R2 // MOVB 4097(R1), R2 // 3b04409162078039
|
||||
MOVH 0x2002(R1), R2 // MOVH 8194(R1), R2 // 3b08409162078079
|
||||
MOVW 0x4004(R1), R2 // MOVW 16388(R1), R2 // 3b104091620780b9
|
||||
MOVD 0x8008(R1), R2 // MOVD 32776(R1), R2 // 3b204091620740f9
|
||||
FMOVS 0x4004(R1), F2 // FMOVS 16388(R1), F2 // 3b104091620740bd
|
||||
FMOVD 0x8008(R1), F2 // FMOVD 32776(R1), F2 // 3b204091620740fd
|
||||
|
||||
// very large or unaligned offset uses constant pool.
|
||||
// the encoding cannot be checked as the address of the constant pool is unknown.
|
||||
// here we only test that they can be assembled.
|
||||
// very large or unaligned offset uses constant pool
|
||||
// the encoding cannot be checked as the address of the constant pool is unknown.
|
||||
// here we only test that they can be assembled.
|
||||
MOVB 0x44332211(R1), R2 // MOVB 1144201745(R1), R2
|
||||
MOVH 0x44332211(R1), R2 // MOVH 1144201745(R1), R2
|
||||
MOVW 0x44332211(R1), R2 // MOVW 1144201745(R1), R2
|
||||
MOVD 0x44332211(R1), R2 // MOVD 1144201745(R1), R2
|
||||
FMOVS 0x44332211(R1), F2 // FMOVS 1144201745(R1), F2
|
||||
FMOVD 0x44332211(R1), F2 // FMOVD 1144201745(R1), F2
|
||||
MOVB R1, 0x44332211(R2) // MOVB R1, 1144201745(R2)
|
||||
MOVH R1, 0x44332211(R2) // MOVH R1, 1144201745(R2)
|
||||
MOVW R1, 0x44332211(R2) // MOVW R1, 1144201745(R2)
|
||||
@@ -512,59 +515,14 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
FMOVS F1, 0x44332211(R2) // FMOVS F1, 1144201745(R2)
|
||||
FMOVD F1, 0x44332211(R2) // FMOVD F1, 1144201745(R2)
|
||||
|
||||
MOVB 0x44332211(R1), R2 // MOVB 1144201745(R1), R2
|
||||
MOVH 0x44332211(R1), R2 // MOVH 1144201745(R1), R2
|
||||
MOVW 0x44332211(R1), R2 // MOVW 1144201745(R1), R2
|
||||
MOVD 0x44332211(R1), R2 // MOVD 1144201745(R1), R2
|
||||
FMOVS 0x44332211(R1), F2 // FMOVS 1144201745(R1), F2
|
||||
FMOVD 0x44332211(R1), F2 // FMOVD 1144201745(R1), F2
|
||||
|
||||
// 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
|
||||
//
|
||||
// MOVK
|
||||
//
|
||||
// LMOVK imm ',' reg
|
||||
// {
|
||||
// outcode($1, &$2, NREG, &$4);
|
||||
// }
|
||||
MOVK $1, R1
|
||||
VMOV V8.S[1], R1 // 013d0c0e
|
||||
VMOV V0.D[0], R11 // 0b3c084e
|
||||
VMOV V0.D[1], R11 // 0b3c184e
|
||||
@@ -579,28 +537,205 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
VMOV V9.H[0], V12.H[1] // 2c05066e
|
||||
VMOV V8.B[0], V12.B[1] // 0c05036e
|
||||
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
|
||||
//
|
||||
// LTYPE8 reg ',' rel
|
||||
// {
|
||||
// outcode($1, &$2, NREG, &$4);
|
||||
// }
|
||||
again:
|
||||
CBZ R1, again // CBZ R1
|
||||
|
||||
// conditional operations
|
||||
CSET GT, R1 // e1d79f9a
|
||||
CSETW HI, R2 // e2979f1a
|
||||
//
|
||||
// CSET
|
||||
//
|
||||
// LTYPER cond ',' reg
|
||||
// {
|
||||
// outcode($1, &$2, NREG, &$4);
|
||||
// }
|
||||
CSET GT, R1 // e1d79f9a
|
||||
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
|
||||
CSELW LT, R2, R3, R4 // 44b0831a
|
||||
CSINC GT, R1, ZR, R3 // 23c49f9a
|
||||
CSNEG MI, R1, R2, R3 // 234482da
|
||||
CSINV CS, R1, R2, R3 // CSINV HS, R1, R2, R3 // 232082da
|
||||
CSINVW MI, R2, ZR, R2 // 42409f5a
|
||||
|
||||
// LTYPES cond ',' reg ',' reg
|
||||
// {
|
||||
// outcode($1, &$2, $4.reg, &$6);
|
||||
// }
|
||||
CINC EQ, R4, R9 // 8914849a
|
||||
CINCW PL, R2, ZR // 5f44821a
|
||||
CINV PL, R11, R22 // 76418bda
|
||||
CINVW LS, R7, R13 // ed80875a
|
||||
CNEG LS, R13, R7 // a7858dda
|
||||
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
|
||||
LDARH (R5), R7 // a7fcdf48
|
||||
LDAXPW (R10), (R20, R16) // 54c17f88
|
||||
@@ -681,38 +816,38 @@ again:
|
||||
LDADDLH R5, (RSP), R7 // e7036578
|
||||
LDADDLB R5, (R6), R7 // c7006538
|
||||
LDADDLB R5, (RSP), R7 // e7036538
|
||||
LDCLRAD R5, (R6), R7 // c710a5f8
|
||||
LDCLRAD R5, (RSP), R7 // e713a5f8
|
||||
LDCLRAW R5, (R6), R7 // c710a5b8
|
||||
LDCLRAW R5, (RSP), R7 // e713a5b8
|
||||
LDCLRAH R5, (R6), R7 // c710a578
|
||||
LDCLRAH R5, (RSP), R7 // e713a578
|
||||
LDCLRAB R5, (R6), R7 // c710a538
|
||||
LDCLRAB R5, (RSP), R7 // e713a538
|
||||
LDCLRALD R5, (R6), R7 // c710e5f8
|
||||
LDCLRALD R5, (RSP), R7 // e713e5f8
|
||||
LDCLRALW R5, (R6), R7 // c710e5b8
|
||||
LDCLRALW R5, (RSP), R7 // e713e5b8
|
||||
LDCLRALH R5, (R6), R7 // c710e578
|
||||
LDCLRALH R5, (RSP), R7 // e713e578
|
||||
LDCLRALB R5, (R6), R7 // c710e538
|
||||
LDCLRALB R5, (RSP), R7 // e713e538
|
||||
LDCLRD R5, (R6), R7 // c71025f8
|
||||
LDCLRD R5, (RSP), R7 // e71325f8
|
||||
LDCLRW R5, (R6), R7 // c71025b8
|
||||
LDCLRW R5, (RSP), R7 // e71325b8
|
||||
LDCLRH R5, (R6), R7 // c7102578
|
||||
LDCLRH R5, (RSP), R7 // e7132578
|
||||
LDCLRB R5, (R6), R7 // c7102538
|
||||
LDCLRB R5, (RSP), R7 // e7132538
|
||||
LDCLRLD R5, (R6), R7 // c71065f8
|
||||
LDCLRLD R5, (RSP), R7 // e71365f8
|
||||
LDCLRLW R5, (R6), R7 // c71065b8
|
||||
LDCLRLW R5, (RSP), R7 // e71365b8
|
||||
LDCLRLH R5, (R6), R7 // c7106578
|
||||
LDCLRLH R5, (RSP), R7 // e7136578
|
||||
LDCLRLB R5, (R6), R7 // c7106538
|
||||
LDCLRLB R5, (RSP), R7 // e7136538
|
||||
LDANDAD R5, (R6), R7 // c710a5f8
|
||||
LDANDAD R5, (RSP), R7 // e713a5f8
|
||||
LDANDAW R5, (R6), R7 // c710a5b8
|
||||
LDANDAW R5, (RSP), R7 // e713a5b8
|
||||
LDANDAH R5, (R6), R7 // c710a578
|
||||
LDANDAH R5, (RSP), R7 // e713a578
|
||||
LDANDAB R5, (R6), R7 // c710a538
|
||||
LDANDAB R5, (RSP), R7 // e713a538
|
||||
LDANDALD R5, (R6), R7 // c710e5f8
|
||||
LDANDALD R5, (RSP), R7 // e713e5f8
|
||||
LDANDALW R5, (R6), R7 // c710e5b8
|
||||
LDANDALW R5, (RSP), R7 // e713e5b8
|
||||
LDANDALH R5, (R6), R7 // c710e578
|
||||
LDANDALH R5, (RSP), R7 // e713e578
|
||||
LDANDALB R5, (R6), R7 // c710e538
|
||||
LDANDALB R5, (RSP), R7 // e713e538
|
||||
LDANDD R5, (R6), R7 // c71025f8
|
||||
LDANDD R5, (RSP), R7 // e71325f8
|
||||
LDANDW R5, (R6), R7 // c71025b8
|
||||
LDANDW R5, (RSP), R7 // e71325b8
|
||||
LDANDH R5, (R6), R7 // c7102578
|
||||
LDANDH R5, (RSP), R7 // e7132578
|
||||
LDANDB R5, (R6), R7 // c7102538
|
||||
LDANDB R5, (RSP), R7 // e7132538
|
||||
LDANDLD R5, (R6), R7 // c71065f8
|
||||
LDANDLD R5, (RSP), R7 // e71365f8
|
||||
LDANDLW R5, (R6), R7 // c71065b8
|
||||
LDANDLW R5, (RSP), R7 // e71365b8
|
||||
LDANDLH R5, (R6), R7 // c7106578
|
||||
LDANDLH R5, (RSP), R7 // e7136578
|
||||
LDANDLB R5, (R6), R7 // c7106538
|
||||
LDANDLB R5, (RSP), R7 // e7136538
|
||||
LDEORAD R5, (R6), R7 // c720a5f8
|
||||
LDEORAD R5, (RSP), R7 // e723a5f8
|
||||
LDEORAW R5, (R6), R7 // c720a5b8
|
||||
@@ -777,36 +912,21 @@ again:
|
||||
LDORLH R5, (RSP), R7 // e7336578
|
||||
LDORLB R5, (R6), R7 // c7306538
|
||||
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
|
||||
//
|
||||
// LTYPEA comma
|
||||
// {
|
||||
// outcode($1, &nullgen, NREG, &nullgen);
|
||||
// }
|
||||
BEQ 2(PC)
|
||||
RET
|
||||
RET foo(SB)
|
||||
|
||||
// B/BL/B.cond cases, and canonical names JMP, CALL.
|
||||
BL 1(PC) // CALL 1(PC)
|
||||
BL (R2) // CALL (R2)
|
||||
BL foo(SB) // CALL foo(SB)
|
||||
BL bar<>(SB) // CALL bar<>(SB)
|
||||
B foo(SB) // JMP foo(SB)
|
||||
BEQ 1(PC)
|
||||
// More B/BL cases, and canonical names JMP, CALL.
|
||||
|
||||
BEQ 2(PC)
|
||||
B foo(SB) // JMP foo(SB)
|
||||
BL foo(SB) // CALL foo(SB)
|
||||
BEQ 2(PC)
|
||||
TBZ $1, R1, 2(PC)
|
||||
TBNZ $2, R2, 2(PC)
|
||||
@@ -981,6 +1101,8 @@ again:
|
||||
FSTPS (F3, F4), 1024(RSP) // fb0310916313002d
|
||||
FSTPS (F3, F4), x(SB)
|
||||
FSTPS (F3, F4), x+8(SB)
|
||||
NOOP // 1f2003d5
|
||||
HINT $0 // 1f2003d5
|
||||
|
||||
// System Register
|
||||
MSR $1, SPSel // bf4100d5
|
||||
@@ -1542,4 +1664,11 @@ again:
|
||||
MSR R13, ZCR_EL1 // 0d1218d5
|
||||
MRS ZCR_EL1, R23 // 171238d5
|
||||
MSR R17, ZCR_EL1 // 111218d5
|
||||
|
||||
// END
|
||||
//
|
||||
// LTYPEE comma
|
||||
// {
|
||||
// outcode($1, &nullgen, NREG, &nullgen);
|
||||
// }
|
||||
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 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.H4, V2.H4, V3.Q1 // ERROR "operand mismatch"
|
||||
VPMULL V1.D2, V2.D2, V3.Q1 // ERROR "operand mismatch"
|
||||
VPMULL V1.B16, V2.B16, V3.H8 // ERROR "operand mismatch"
|
||||
VPMULL V1.H4, V2.H4, V3.Q1 // ERROR "invalid arrangement"
|
||||
VPMULL V1.D2, V2.D2, V3.Q1 // ERROR "invalid arrangement"
|
||||
VPMULL V1.B16, V2.B16, V3.H8 // ERROR "invalid arrangement"
|
||||
VPMULL2 V1.D2, 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 "operand mismatch"
|
||||
VPMULL2 V1.B8, V2.B8, V3.H8 // ERROR "operand mismatch"
|
||||
VPMULL2 V1.H4, V2.H4, V3.Q1 // ERROR "invalid arrangement"
|
||||
VPMULL2 V1.D1, V2.D1, V3.Q1 // ERROR "invalid arrangement"
|
||||
VPMULL2 V1.B8, V2.B8, V3.H8 // 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"
|
||||
VRBIT V1.B16, V2.B8 // ERROR "invalid arrangement"
|
||||
@@ -123,14 +123,14 @@ TEXT errors(SB),$0
|
||||
LDADDLW R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDADDLH R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDADDLB R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDCLRD R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDCLRW R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDCLRH R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDCLRB R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDCLRLD R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDCLRLW R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDCLRLH R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDCLRLB R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDANDD R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDANDW R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDANDH R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDANDB R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDANDLD R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDANDLW R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDANDLH R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDANDLB R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDEORD R5, (R6), ZR // ERROR "illegal destination register"
|
||||
LDEORW 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"
|
||||
LDADDLH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDADDLB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRAD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRAW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRAH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRAB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRALD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRALW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRALH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRALB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRLD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRLW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRLH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDCLRLB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDAD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDAW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDAH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDAB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDALD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDALW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDALH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDALB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDLD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDLW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDLH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDANDLB R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDEORAD R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDEORAW R5, (R6), RSP // ERROR "illegal destination register"
|
||||
LDEORAH R5, (R6), RSP // ERROR "illegal destination register"
|
||||
@@ -353,12 +353,4 @@ TEXT errors(SB),$0
|
||||
VUSHLL2 $32, V30.S4, V2.D2 // ERROR "shift amount out of range"
|
||||
VBIF V0.B8, V1.B8, V2.B16 // ERROR "operand mismatch"
|
||||
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
|
||||
|
||||
2
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
2
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
@@ -282,9 +282,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
RLWMI $7, R3, $65535, R6 // 50663c3e
|
||||
RLWMICC $7, R3, $65535, R6 // 50663c3f
|
||||
RLWNM $3, R4, $7, R6 // 54861f7e
|
||||
RLWNM R3, R4, $7, R6 // 5c861f7e
|
||||
RLWNMCC $3, R4, $7, R6 // 54861f7f
|
||||
RLWNMCC R3, R4, $7, R6 // 5c861f7f
|
||||
RLDMI $0, R4, $7, R6 // 7886076c
|
||||
RLDMICC $0, R4, $7, R6 // 7886076d
|
||||
RLDIMI $0, R4, $7, R6 // 788601cc
|
||||
|
||||
8
src/cmd/asm/internal/asm/testdata/riscvenc.s
vendored
8
src/cmd/asm/internal/asm/testdata/riscvenc.s
vendored
@@ -340,11 +340,11 @@ start:
|
||||
// Branch pseudo-instructions
|
||||
BEQZ X5, start // BEQZ X5, 2 // e38602c0
|
||||
BGEZ X5, start // BGEZ X5, 2 // e3d402c0
|
||||
BGT X5, X6, start // BGT X5, X6, 2 // e34253c0
|
||||
BGTU X5, X6, start // BGTU X5, X6, 2 // e36053c0
|
||||
BGT X5, X6, start // BGT X5, X6, 2 // e3c262c0
|
||||
BGTU X5, X6, start // BGTU X5, X6, 2 // e3e062c0
|
||||
BGTZ X5, start // BGTZ X5, 2 // e34e50be
|
||||
BLE X5, X6, start // BLE X5, X6, 2 // e35c53be
|
||||
BLEU X5, X6, start // BLEU X5, X6, 2 // e37a53be
|
||||
BLE X5, X6, start // BLE X5, X6, 2 // e3dc62be
|
||||
BLEU X5, X6, start // BLEU X5, X6, 2 // e3fa62be
|
||||
BLEZ X5, start // BLEZ X5, 2 // e35850be
|
||||
BLTZ X5, start // BLTZ X5, 2 // e3c602be
|
||||
BNEZ X5, start // BNEZ X5, 2 // e39402be
|
||||
|
||||
2
src/cmd/asm/internal/asm/testdata/s390x.s
vendored
2
src/cmd/asm/internal/asm/testdata/s390x.s
vendored
@@ -412,8 +412,6 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
|
||||
UNDEF // 00000000
|
||||
NOPH // 0700
|
||||
|
||||
SYNC // 07e0
|
||||
|
||||
// vector add and sub instructions
|
||||
VAB V3, V4, V4 // e743400000f3
|
||||
VAH V3, V4, V4 // e743400010f3
|
||||
|
||||
@@ -20,7 +20,6 @@ var (
|
||||
TrimPath = flag.String("trimpath", "", "remove prefix from recorded source file paths")
|
||||
Shared = flag.Bool("shared", false, "generate code that can be linked into a shared library")
|
||||
Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
|
||||
Linkshared = flag.Bool("linkshared", false, "generate code that will be linked against Go shared libraries")
|
||||
AllErrors = flag.Bool("e", false, "no limit on number of errors reported")
|
||||
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")
|
||||
|
||||
@@ -37,7 +37,6 @@ func main() {
|
||||
ctxt := obj.Linknew(architecture.LinkArch)
|
||||
ctxt.Debugasm = flags.PrintOut
|
||||
ctxt.Flag_dynlink = *flags.Dynlink
|
||||
ctxt.Flag_linkshared = *flags.Linkshared
|
||||
ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
|
||||
ctxt.IsAsm = true
|
||||
ctxt.Pkgpath = *flags.Importpath
|
||||
|
||||
@@ -22,6 +22,21 @@ func usage() {
|
||||
|
||||
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() {
|
||||
log.SetPrefix("buildid: ")
|
||||
log.SetFlags(0)
|
||||
@@ -48,12 +63,12 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
matches, hash, err := buildid.FindAndHash(f, id, 0)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
newID := id[:strings.LastIndex(id, "/")] + "/" + buildid.HashToString(hash)
|
||||
newID := id[:strings.LastIndex(id, "/")] + "/" + hashToString(hash)
|
||||
if len(newID) != len(id) {
|
||||
log.Fatalf("%s: build ID length mismatch %q vs %q", file, id, newID)
|
||||
}
|
||||
@@ -62,7 +77,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
f, err = os.OpenFile(file, os.O_RDWR, 0)
|
||||
f, err = os.OpenFile(file, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -43,7 +44,14 @@ func sourceLine(n ast.Node) int {
|
||||
// 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
|
||||
// printed.
|
||||
func (f *File) ParseGo(abspath string, src []byte) {
|
||||
func (f *File) ParseGo(name 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.
|
||||
// The printer is not good enough at printing comments in the
|
||||
// right place when we start editing the AST behind its back,
|
||||
@@ -52,8 +60,8 @@ func (f *File) ParseGo(abspath string, src []byte) {
|
||||
// and reprinting.
|
||||
// In cgo mode, we ignore ast2 and just apply edits directly
|
||||
// the text behind ast1. In godefs mode we modify and print ast2.
|
||||
ast1 := parse(abspath, src, parser.ParseComments)
|
||||
ast2 := parse(abspath, src, 0)
|
||||
ast1 := parse(name, src, parser.ParseComments)
|
||||
ast2 := parse(name, src, 0)
|
||||
|
||||
f.Package = ast1.Name.Name
|
||||
f.Name = make(map[string]*Name)
|
||||
@@ -80,7 +88,7 @@ func (f *File) ParseGo(abspath string, src []byte) {
|
||||
cg = d.Doc
|
||||
}
|
||||
if cg != nil {
|
||||
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), abspath)
|
||||
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
|
||||
f.Preamble += commentText(cg) + "\n"
|
||||
f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
|
||||
}
|
||||
|
||||
@@ -1549,14 +1549,7 @@ func (p *Package) gccBaseCmd() []string {
|
||||
func (p *Package) gccMachine() []string {
|
||||
switch goarch {
|
||||
case "amd64":
|
||||
if goos == "darwin" {
|
||||
return []string{"-arch", "x86_64", "-m64"}
|
||||
}
|
||||
return []string{"-m64"}
|
||||
case "arm64":
|
||||
if goos == "darwin" {
|
||||
return []string{"-arch", "arm64"}
|
||||
}
|
||||
case "386":
|
||||
return []string{"-m32"}
|
||||
case "arm":
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
// godefs returns the output for -godefs mode.
|
||||
func (p *Package) godefs(f *File) string {
|
||||
func (p *Package) godefs(f *File, srcfile string) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
|
||||
|
||||
@@ -243,8 +243,6 @@ var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used wit
|
||||
var gccgoMangler func(string) string
|
||||
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 trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
|
||||
|
||||
var goarch, goos string
|
||||
|
||||
func main() {
|
||||
@@ -324,13 +322,6 @@ func main() {
|
||||
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)
|
||||
if err != nil {
|
||||
fatalf("%s", err)
|
||||
@@ -339,10 +330,6 @@ func main() {
|
||||
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.Edit = edit.NewBuffer(b)
|
||||
f.ParseGo(input, b)
|
||||
@@ -380,7 +367,7 @@ func main() {
|
||||
p.PackagePath = f.Package
|
||||
p.Record(f)
|
||||
if *godefs {
|
||||
os.Stdout.WriteString(p.godefs(f))
|
||||
os.Stdout.WriteString(p.godefs(f, input))
|
||||
} else {
|
||||
p.writeOutput(f, input)
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ import (
|
||||
"go/ast"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"internal/xcoff"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
@@ -186,7 +186,7 @@ func (p *Package) writeDefs() {
|
||||
panic(fmt.Errorf("invalid var kind %q", n.Kind))
|
||||
}
|
||||
if *gccgo {
|
||||
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, gccgoToSymbol(n.Mangle))
|
||||
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
|
||||
fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
|
||||
fmt.Fprintf(fc, "\n")
|
||||
}
|
||||
@@ -337,8 +337,6 @@ func dynimport(obj string) {
|
||||
if s.Version != "" {
|
||||
targ += "#" + s.Version
|
||||
}
|
||||
checkImportSymName(s.Name)
|
||||
checkImportSymName(targ)
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
|
||||
}
|
||||
lib, _ := f.ImportedLibraries()
|
||||
@@ -354,7 +352,6 @@ func dynimport(obj string) {
|
||||
if len(s) > 0 && s[0] == '_' {
|
||||
s = s[1:]
|
||||
}
|
||||
checkImportSymName(s)
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
|
||||
}
|
||||
lib, _ := f.ImportedLibraries()
|
||||
@@ -369,8 +366,6 @@ func dynimport(obj string) {
|
||||
for _, s := range sym {
|
||||
ss := strings.Split(s, ":")
|
||||
name := strings.Split(ss[0], "@")[0]
|
||||
checkImportSymName(name)
|
||||
checkImportSymName(ss[0])
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
|
||||
}
|
||||
return
|
||||
@@ -388,7 +383,6 @@ func dynimport(obj string) {
|
||||
// Go symbols.
|
||||
continue
|
||||
}
|
||||
checkImportSymName(s.Name)
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
|
||||
}
|
||||
lib, err := f.ImportedLibraries()
|
||||
@@ -404,23 +398,6 @@ func dynimport(obj string) {
|
||||
fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj)
|
||||
}
|
||||
|
||||
// checkImportSymName checks a symbol name we are going to emit as part
|
||||
// of a //go:cgo_import_dynamic pragma. These names come from object
|
||||
// files, so they may be corrupt. We are going to emit them unquoted,
|
||||
// so while they don't need to be valid symbol names (and in some cases,
|
||||
// involving symbol versions, they won't be) they must contain only
|
||||
// graphic characters and must not contain Go comments.
|
||||
func checkImportSymName(s string) {
|
||||
for _, c := range s {
|
||||
if !unicode.IsGraphic(c) || unicode.IsSpace(c) {
|
||||
fatalf("dynamic symbol %q contains unsupported character", s)
|
||||
}
|
||||
}
|
||||
if strings.Index(s, "//") >= 0 || strings.Index(s, "/*") >= 0 {
|
||||
fatalf("dynamic symbol %q contains Go comment")
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a gcc struct matching the gc argument frame.
|
||||
// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
|
||||
// These assumptions are checked by the gccProlog.
|
||||
@@ -953,9 +930,9 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
// Build the wrapper function compiled by gcc.
|
||||
gccExport := ""
|
||||
if goos == "windows" {
|
||||
gccExport = "__declspec(dllexport) "
|
||||
gccExport = "__declspec(dllexport)"
|
||||
}
|
||||
s := fmt.Sprintf("%s%s %s(", gccExport, gccResult, exp.ExpName)
|
||||
s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName)
|
||||
if fn.Recv != nil {
|
||||
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
||||
s += " recv"
|
||||
@@ -985,15 +962,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
// 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.
|
||||
//
|
||||
// We use a local static variable to get the zeroed
|
||||
// value of the argument type. This avoids including
|
||||
// string.h for memset, and is also robust to C++
|
||||
// types with constructors. Both GCC and LLVM optimize
|
||||
// this into just zeroing _cgo_a.
|
||||
fmt.Fprintf(fgcc, "\ttypedef %s %v _cgo_argtype;\n", ctype, p.packedAttribute())
|
||||
fmt.Fprintf(fgcc, "\tstatic _cgo_argtype _cgo_zero;\n")
|
||||
fmt.Fprintf(fgcc, "\t_cgo_argtype _cgo_a = _cgo_zero;\n")
|
||||
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) {
|
||||
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
||||
}
|
||||
@@ -1148,7 +1117,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
// will not be able to link against it from the C
|
||||
// code.
|
||||
goName := "Cgoexp_" + exp.ExpName
|
||||
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, gccgoToSymbol(goName))
|
||||
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
|
||||
fmt.Fprint(fgcc, "\n")
|
||||
|
||||
fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
|
||||
@@ -1182,7 +1151,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
fmt.Fprint(fgcc, "}\n")
|
||||
|
||||
// Dummy declaration for _cgo_main.c
|
||||
fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, gccgoToSymbol(goName))
|
||||
fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName)
|
||||
fmt.Fprint(fm, "\n")
|
||||
|
||||
// For gccgo we use a wrapper function in Go, in order
|
||||
@@ -1266,8 +1235,9 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
|
||||
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
|
||||
}
|
||||
|
||||
// gccgoToSymbol converts a name to a mangled symbol for gccgo.
|
||||
func gccgoToSymbol(ppath string) string {
|
||||
// gccgoPkgpathToSymbol converts a package path to a mangled packagepath
|
||||
// symbol.
|
||||
func gccgoPkgpathToSymbol(ppath string) string {
|
||||
if gccgoMangler == nil {
|
||||
var err error
|
||||
cmd := os.Getenv("GCCGO")
|
||||
@@ -1292,12 +1262,12 @@ func (p *Package) gccgoSymbolPrefix() string {
|
||||
}
|
||||
|
||||
if *gccgopkgpath != "" {
|
||||
return gccgoToSymbol(*gccgopkgpath)
|
||||
return gccgoPkgpathToSymbol(*gccgopkgpath)
|
||||
}
|
||||
if *gccgoprefix == "" && p.PackageName == "main" {
|
||||
return "main"
|
||||
}
|
||||
prefix := gccgoToSymbol(*gccgoprefix)
|
||||
prefix := gccgoPkgpathToSymbol(*gccgoprefix)
|
||||
if prefix == "" {
|
||||
prefix = "go"
|
||||
}
|
||||
@@ -1686,12 +1656,8 @@ void _cgoPREFIX_Cfunc__Cmalloc(void *v) {
|
||||
`
|
||||
|
||||
func (p *Package) cPrologGccgo() string {
|
||||
r := strings.NewReplacer(
|
||||
"PREFIX", cPrefix,
|
||||
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(),
|
||||
"_cgoCheckPointer", gccgoToSymbol("_cgoCheckPointer"),
|
||||
"_cgoCheckResult", gccgoToSymbol("_cgoCheckResult"))
|
||||
return r.Replace(cPrologGccgo)
|
||||
return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
|
||||
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
|
||||
}
|
||||
|
||||
const cPrologGccgo = `
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// run runs the command argv, feeding in stdin on standard input.
|
||||
@@ -63,7 +63,7 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
||||
p.Env = append(os.Environ(), "TERM=dumb")
|
||||
err := p.Run()
|
||||
if _, ok := err.(*exec.ExitError); err != nil && !ok {
|
||||
fatalf("exec %s: %s", argv[0], err)
|
||||
fatalf("%s", err)
|
||||
}
|
||||
ok = p.ProcessState.Success()
|
||||
stdout, stderr = bout.Bytes(), berr.Bytes()
|
||||
@@ -88,7 +88,7 @@ func fatalf(msg string, args ...interface{}) {
|
||||
// If we've already printed other errors, they might have
|
||||
// caused the fatal condition. Assume they're enough.
|
||||
if nerrors == 0 {
|
||||
fmt.Fprintf(os.Stderr, "cgo: "+msg+"\n", args...)
|
||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
||||
}
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ import (
|
||||
"go/types"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
@@ -90,7 +89,7 @@ func TestFormats(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok
|
||||
|
||||
// process all directories
|
||||
filepath.WalkDir(".", func(path string, info fs.DirEntry, err error) error {
|
||||
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
if info.Name() == "testdata" {
|
||||
return filepath.SkipDir
|
||||
|
||||
@@ -105,8 +105,10 @@ var knownFormats = map[string]string{
|
||||
"cmd/compile/internal/ssa.GCNode %v": "",
|
||||
"cmd/compile/internal/ssa.ID %d": "",
|
||||
"cmd/compile/internal/ssa.ID %v": "",
|
||||
"cmd/compile/internal/ssa.LocPair %s": "",
|
||||
"cmd/compile/internal/ssa.LocalSlot %s": "",
|
||||
"cmd/compile/internal/ssa.LocalSlot %v": "",
|
||||
"cmd/compile/internal/ssa.Location %T": "",
|
||||
"cmd/compile/internal/ssa.Location %s": "",
|
||||
"cmd/compile/internal/ssa.Op %s": "",
|
||||
"cmd/compile/internal/ssa.Op %v": "",
|
||||
@@ -134,6 +136,7 @@ var knownFormats = map[string]string{
|
||||
"cmd/compile/internal/types.EType %s": "",
|
||||
"cmd/compile/internal/types.EType %v": "",
|
||||
"cmd/internal/obj.ABI %v": "",
|
||||
"cmd/internal/src.XPos %v": "",
|
||||
"error %v": "",
|
||||
"float64 %.2f": "",
|
||||
"float64 %.3f": "",
|
||||
|
||||
@@ -42,11 +42,10 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
|
||||
// loadByType returns the load instruction of the given type.
|
||||
func loadByType(t *types.Type) obj.As {
|
||||
// Avoid partial register write
|
||||
if !t.IsFloat() {
|
||||
switch t.Size() {
|
||||
case 1:
|
||||
if !t.IsFloat() && t.Size() <= 2 {
|
||||
if t.Size() == 1 {
|
||||
return x86.AMOVBLZX
|
||||
case 2:
|
||||
} else {
|
||||
return x86.AMOVWLZX
|
||||
}
|
||||
}
|
||||
@@ -76,7 +75,7 @@ func storeByType(t *types.Type) obj.As {
|
||||
return x86.AMOVQ
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("bad store type %v", t))
|
||||
panic("bad store type")
|
||||
}
|
||||
|
||||
// moveByType returns the reg->reg move instruction of the given type.
|
||||
@@ -101,7 +100,7 @@ func moveByType(t *types.Type) obj.As {
|
||||
case 16:
|
||||
return x86.AMOVUPS // int128s are in SSE registers
|
||||
default:
|
||||
panic(fmt.Sprintf("bad int register width %d:%v", t.Size(), t))
|
||||
panic(fmt.Sprintf("bad int register width %d:%s", t.Size(), t))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1071,7 +1070,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p := s.Prog(v.Op.Asm())
|
||||
val := v.AuxInt
|
||||
// 0 means math.RoundToEven, 1 Floor, 2 Ceil, 3 Trunc
|
||||
if val < 0 || val > 3 {
|
||||
if val != 0 && val != 1 && val != 2 && val != 3 {
|
||||
v.Fatalf("Invalid rounding mode")
|
||||
}
|
||||
p.From.Offset = val
|
||||
|
||||
@@ -581,24 +581,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p2.From.Reg = arm64.REGTMP
|
||||
p2.To.Type = obj.TYPE_BRANCH
|
||||
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,
|
||||
ssa.OpARM64LoweredAtomicAdd32:
|
||||
// LDAXR (Rarg0), Rout
|
||||
@@ -705,56 +687,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p5.To.Type = obj.TYPE_REG
|
||||
p5.To.Reg = out
|
||||
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,
|
||||
ssa.OpARM64LoweredAtomicAnd32,
|
||||
ssa.OpARM64LoweredAtomicOr8,
|
||||
@@ -793,63 +725,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p3.From.Reg = arm64.REGTMP
|
||||
p3.To.Type = obj.TYPE_BRANCH
|
||||
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,
|
||||
ssa.OpARM64MOVBUreg,
|
||||
ssa.OpARM64MOVHreg,
|
||||
@@ -1054,11 +929,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
ssa.OpARM64LessThanF,
|
||||
ssa.OpARM64LessEqualF,
|
||||
ssa.OpARM64GreaterThanF,
|
||||
ssa.OpARM64GreaterEqualF,
|
||||
ssa.OpARM64NotLessThanF,
|
||||
ssa.OpARM64NotLessEqualF,
|
||||
ssa.OpARM64NotGreaterThanF,
|
||||
ssa.OpARM64NotGreaterEqualF:
|
||||
ssa.OpARM64GreaterEqualF:
|
||||
// generate boolean values using CSET
|
||||
p := s.Prog(arm64.ACSET)
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
@@ -1102,16 +973,10 @@ var condBits = map[ssa.Op]int16{
|
||||
ssa.OpARM64GreaterThanU: arm64.COND_HI,
|
||||
ssa.OpARM64GreaterEqual: arm64.COND_GE,
|
||||
ssa.OpARM64GreaterEqualU: arm64.COND_HS,
|
||||
ssa.OpARM64LessThanF: arm64.COND_MI, // Less than
|
||||
ssa.OpARM64LessEqualF: arm64.COND_LS, // Less than or equal to
|
||||
ssa.OpARM64GreaterThanF: arm64.COND_GT, // Greater than
|
||||
ssa.OpARM64GreaterEqualF: arm64.COND_GE, // Greater than or equal to
|
||||
|
||||
// The following condition codes have unordered to handle comparisons related to NaN.
|
||||
ssa.OpARM64NotLessThanF: arm64.COND_PL, // Greater than, equal to, or unordered
|
||||
ssa.OpARM64NotLessEqualF: arm64.COND_HI, // Greater than or unordered
|
||||
ssa.OpARM64NotGreaterThanF: arm64.COND_LE, // Less than, equal to or unordered
|
||||
ssa.OpARM64NotGreaterEqualF: arm64.COND_LT, // Less than or unordered
|
||||
ssa.OpARM64LessThanF: arm64.COND_MI,
|
||||
ssa.OpARM64LessEqualF: arm64.COND_LS,
|
||||
ssa.OpARM64GreaterThanF: arm64.COND_GT,
|
||||
ssa.OpARM64GreaterEqualF: arm64.COND_GE,
|
||||
}
|
||||
|
||||
var blockJump = map[ssa.BlockKind]struct {
|
||||
|
||||
@@ -184,17 +184,16 @@ var runtimeDecls = [...]struct {
|
||||
{"racewriterange", funcTag, 121},
|
||||
{"msanread", funcTag, 121},
|
||||
{"msanwrite", funcTag, 121},
|
||||
{"msanmove", funcTag, 122},
|
||||
{"checkptrAlignment", funcTag, 123},
|
||||
{"checkptrArithmetic", funcTag, 125},
|
||||
{"libfuzzerTraceCmp1", funcTag, 127},
|
||||
{"libfuzzerTraceCmp2", funcTag, 129},
|
||||
{"libfuzzerTraceCmp4", funcTag, 130},
|
||||
{"libfuzzerTraceCmp8", funcTag, 131},
|
||||
{"libfuzzerTraceConstCmp1", funcTag, 127},
|
||||
{"libfuzzerTraceConstCmp2", funcTag, 129},
|
||||
{"libfuzzerTraceConstCmp4", funcTag, 130},
|
||||
{"libfuzzerTraceConstCmp8", funcTag, 131},
|
||||
{"checkptrAlignment", funcTag, 122},
|
||||
{"checkptrArithmetic", funcTag, 124},
|
||||
{"libfuzzerTraceCmp1", funcTag, 126},
|
||||
{"libfuzzerTraceCmp2", funcTag, 128},
|
||||
{"libfuzzerTraceCmp4", funcTag, 129},
|
||||
{"libfuzzerTraceCmp8", funcTag, 130},
|
||||
{"libfuzzerTraceConstCmp1", funcTag, 126},
|
||||
{"libfuzzerTraceConstCmp2", funcTag, 128},
|
||||
{"libfuzzerTraceConstCmp4", funcTag, 129},
|
||||
{"libfuzzerTraceConstCmp8", funcTag, 130},
|
||||
{"x86HasPOPCNT", varTag, 6},
|
||||
{"x86HasSSE41", varTag, 6},
|
||||
{"x86HasFMA", varTag, 6},
|
||||
@@ -203,7 +202,7 @@ var runtimeDecls = [...]struct {
|
||||
}
|
||||
|
||||
func runtimeTypes() []*types.Type {
|
||||
var typs [132]*types.Type
|
||||
var typs [131]*types.Type
|
||||
typs[0] = types.Bytetype
|
||||
typs[1] = types.NewPtr(typs[0])
|
||||
typs[2] = types.Types[TANY]
|
||||
@@ -326,15 +325,14 @@ func runtimeTypes() []*types.Type {
|
||||
typs[119] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
|
||||
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[122] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5]), anonfield(typs[5])}, nil)
|
||||
typs[123] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
|
||||
typs[124] = types.NewSlice(typs[7])
|
||||
typs[125] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[124])}, nil)
|
||||
typs[126] = types.Types[TUINT8]
|
||||
typs[127] = functype(nil, []*Node{anonfield(typs[126]), anonfield(typs[126])}, nil)
|
||||
typs[128] = types.Types[TUINT16]
|
||||
typs[129] = functype(nil, []*Node{anonfield(typs[128]), anonfield(typs[128])}, nil)
|
||||
typs[130] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
|
||||
typs[131] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
|
||||
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
|
||||
typs[123] = types.NewSlice(typs[7])
|
||||
typs[124] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
|
||||
typs[125] = types.Types[TUINT8]
|
||||
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
|
||||
typs[127] = types.Types[TUINT16]
|
||||
typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, 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)
|
||||
return typs[:]
|
||||
}
|
||||
|
||||
@@ -237,7 +237,6 @@ func racewriterange(addr, size uintptr)
|
||||
// memory sanitizer
|
||||
func msanread(addr, size uintptr)
|
||||
func msanwrite(addr, size uintptr)
|
||||
func msanmove(dst, src, size uintptr)
|
||||
|
||||
func checkptrAlignment(unsafe.Pointer, *byte, uintptr)
|
||||
func checkptrArithmetic(unsafe.Pointer, []unsafe.Pointer)
|
||||
|
||||
@@ -71,10 +71,6 @@ func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
|
||||
return clo
|
||||
}
|
||||
|
||||
// typecheckclosure typechecks an OCLOSURE node. It also creates the named
|
||||
// function associated with the closure.
|
||||
// TODO: This creation of the named function should probably really be done in a
|
||||
// separate pass from type-checking.
|
||||
func typecheckclosure(clo *Node, top int) {
|
||||
xfunc := clo.Func.Closure
|
||||
// Set current associated iota value, so iota can be used inside
|
||||
|
||||
@@ -257,8 +257,6 @@ func symfield(s *types.Sym, typ *types.Type) *Node {
|
||||
|
||||
// oldname returns the Node that declares symbol s in the current scope.
|
||||
// If no such Node currently exists, an ONONAME Node is returned instead.
|
||||
// Automatically creates a new closure variable if the referenced symbol was
|
||||
// declared in a different (containing) function.
|
||||
func oldname(s *types.Sym) *Node {
|
||||
n := asNode(s.Def)
|
||||
if n == nil {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -171,32 +170,12 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
|
||||
addRange(inlcalls.Calls, start, fnsym.Size, curii, imap)
|
||||
}
|
||||
|
||||
// Issue 33188: if II foo is a child of II bar, then ensure that
|
||||
// bar's ranges include the ranges of foo (the loop above will produce
|
||||
// disjoint ranges).
|
||||
for k, c := range inlcalls.Calls {
|
||||
if c.Root {
|
||||
unifyCallRanges(inlcalls, k)
|
||||
}
|
||||
}
|
||||
|
||||
// Debugging
|
||||
if Debug_gendwarfinl != 0 {
|
||||
dumpInlCalls(inlcalls)
|
||||
dumpInlVars(dwVars)
|
||||
}
|
||||
|
||||
// Perform a consistency check on inlined routine PC ranges
|
||||
// produced by unifyCallRanges above. In particular, complain in
|
||||
// cases where you have A -> B -> C (e.g. C is inlined into B, and
|
||||
// B is inlined into A) and the ranges for B are not enclosed
|
||||
// within the ranges for A, or C within B.
|
||||
for k, c := range inlcalls.Calls {
|
||||
if c.Root {
|
||||
checkInlCall(fnsym.Name, inlcalls, fnsym.Size, k, -1)
|
||||
}
|
||||
}
|
||||
|
||||
return inlcalls
|
||||
}
|
||||
|
||||
@@ -376,74 +355,3 @@ func dumpInlVars(dwvars []*dwarf.Var) {
|
||||
Ctxt.Logf("V%d: %s CI:%d II:%d IA:%d %s\n", i, dwv.Name, dwv.ChildIndex, dwv.InlIndex-1, ia, typ)
|
||||
}
|
||||
}
|
||||
|
||||
func rangesContains(par []dwarf.Range, rng dwarf.Range) (bool, string) {
|
||||
for _, r := range par {
|
||||
if rng.Start >= r.Start && rng.End <= r.End {
|
||||
return true, ""
|
||||
}
|
||||
}
|
||||
msg := fmt.Sprintf("range [%d,%d) not contained in {", rng.Start, rng.End)
|
||||
for _, r := range par {
|
||||
msg += fmt.Sprintf(" [%d,%d)", r.Start, r.End)
|
||||
}
|
||||
msg += " }"
|
||||
return false, msg
|
||||
}
|
||||
|
||||
func rangesContainsAll(parent, child []dwarf.Range) (bool, string) {
|
||||
for _, r := range child {
|
||||
c, m := rangesContains(parent, r)
|
||||
if !c {
|
||||
return false, m
|
||||
}
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// checkInlCall verifies that the PC ranges for inline info 'idx' are
|
||||
// enclosed/contained within the ranges of its parent inline (or if
|
||||
// this is a root/toplevel inline, checks that the ranges fall within
|
||||
// the extent of the top level function). A panic is issued if a
|
||||
// malformed range is found.
|
||||
func checkInlCall(funcName string, inlCalls dwarf.InlCalls, funcSize int64, idx, parentIdx int) {
|
||||
|
||||
// Callee
|
||||
ic := inlCalls.Calls[idx]
|
||||
callee := Ctxt.InlTree.InlinedFunction(ic.InlIndex).Name
|
||||
calleeRanges := ic.Ranges
|
||||
|
||||
// Caller
|
||||
caller := funcName
|
||||
parentRanges := []dwarf.Range{dwarf.Range{Start: int64(0), End: funcSize}}
|
||||
if parentIdx != -1 {
|
||||
pic := inlCalls.Calls[parentIdx]
|
||||
caller = Ctxt.InlTree.InlinedFunction(pic.InlIndex).Name
|
||||
parentRanges = pic.Ranges
|
||||
}
|
||||
|
||||
// Callee ranges contained in caller ranges?
|
||||
c, m := rangesContainsAll(parentRanges, calleeRanges)
|
||||
if !c {
|
||||
Fatalf("** malformed inlined routine range in %s: caller %s callee %s II=%d %s\n", funcName, caller, callee, idx, m)
|
||||
}
|
||||
|
||||
// Now visit kids
|
||||
for _, k := range ic.Children {
|
||||
checkInlCall(funcName, inlCalls, funcSize, k, idx)
|
||||
}
|
||||
}
|
||||
|
||||
// unifyCallRanges ensures that the ranges for a given inline
|
||||
// transitively include all of the ranges for its child inlines.
|
||||
func unifyCallRanges(inlcalls dwarf.InlCalls, idx int) {
|
||||
ic := &inlcalls.Calls[idx]
|
||||
for _, childIdx := range ic.Children {
|
||||
// First make sure child ranges are unified.
|
||||
unifyCallRanges(inlcalls, childIdx)
|
||||
|
||||
// Then merge child ranges into ranges for this inline.
|
||||
cic := inlcalls.Calls[childIdx]
|
||||
ic.Ranges = dwarf.MergeRanges(ic.Ranges, cic.Ranges)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ const (
|
||||
embedFiles
|
||||
)
|
||||
|
||||
func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []PragmaEmbed) {
|
||||
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)
|
||||
@@ -65,48 +67,44 @@ func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []Pragma
|
||||
pos := embeds[0].Pos
|
||||
if !haveEmbed {
|
||||
p.yyerrorpos(pos, "invalid go:embed: missing import \"embed\"")
|
||||
return
|
||||
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
|
||||
return exprs
|
||||
}
|
||||
if len(exprs) > 0 {
|
||||
p.yyerrorpos(pos, "go:embed cannot apply to var with initializer")
|
||||
return
|
||||
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
|
||||
}
|
||||
if dclcontext != PEXTERN {
|
||||
p.yyerrorpos(pos, "go:embed cannot apply to var inside func")
|
||||
return
|
||||
return exprs
|
||||
}
|
||||
|
||||
var list []irEmbed
|
||||
for _, e := range embeds {
|
||||
list = append(list, irEmbed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns})
|
||||
kind := embedKindApprox(typ)
|
||||
if kind == embedUnknown {
|
||||
p.yyerrorpos(pos, "go:embed cannot apply to var of type %v", typ)
|
||||
return exprs
|
||||
}
|
||||
v := names[0]
|
||||
v.Name.Param.SetEmbedList(list)
|
||||
embedlist = append(embedlist, v)
|
||||
}
|
||||
|
||||
func embedFileList(v *Node, kind int) []string {
|
||||
// Build list of files to store.
|
||||
have := make(map[string]bool)
|
||||
var list []string
|
||||
for _, e := range v.Name.Param.EmbedList() {
|
||||
for _, e := range embeds {
|
||||
for _, pattern := range e.Patterns {
|
||||
files, ok := embedCfg.Patterns[pattern]
|
||||
if !ok {
|
||||
yyerrorl(e.Pos, "invalid go:embed: build system did not map pattern: %s", pattern)
|
||||
p.yyerrorpos(e.Pos, "invalid go:embed: build system did not map pattern: %s", pattern)
|
||||
}
|
||||
for _, file := range files {
|
||||
if embedCfg.Files[file] == "" {
|
||||
yyerrorl(e.Pos, "invalid go:embed: build system did not map file: %s", file)
|
||||
p.yyerrorpos(e.Pos, "invalid go:embed: build system did not map file: %s", file)
|
||||
continue
|
||||
}
|
||||
if !have[file] {
|
||||
@@ -128,12 +126,46 @@ func embedFileList(v *Node, kind int) []string {
|
||||
|
||||
if kind == embedString || kind == embedBytes {
|
||||
if len(list) > 1 {
|
||||
yyerrorl(v.Pos, "invalid go:embed: multiple files for type %v", v.Type)
|
||||
return nil
|
||||
p.yyerrorpos(pos, "invalid go:embed: multiple files for type %v", typ)
|
||||
return exprs
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
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.
|
||||
@@ -141,10 +173,10 @@ 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.Etype == types.TSTRING {
|
||||
if typ == types.Types[TSTRING] {
|
||||
return embedString
|
||||
}
|
||||
if typ.Etype == types.TSLICE && typ.Elem().Etype == types.TUINT8 {
|
||||
if typ.Sym == nil && typ.IsSlice() && typ.Elem() == types.Bytetype {
|
||||
return embedBytes
|
||||
}
|
||||
return embedUnknown
|
||||
@@ -182,26 +214,11 @@ func dumpembeds() {
|
||||
// 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) {
|
||||
commentPos := v.Name.Param.EmbedList()[0].Pos
|
||||
if !langSupported(1, 16, localpkg) {
|
||||
lno := lineno
|
||||
lineno = commentPos
|
||||
yyerrorv("go1.16", "go:embed")
|
||||
lineno = lno
|
||||
return
|
||||
}
|
||||
if embedCfg.Patterns == nil {
|
||||
yyerrorl(commentPos, "invalid go:embed: build system did not supply embed configuration")
|
||||
return
|
||||
}
|
||||
kind := embedKind(v.Type)
|
||||
if kind == embedUnknown {
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
files := embedFileList(v, kind)
|
||||
switch kind {
|
||||
case embedString, embedBytes:
|
||||
file := files[0]
|
||||
fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], kind == embedString, nil)
|
||||
|
||||
@@ -419,19 +419,10 @@ func (n *Node) format(s fmt.State, verb rune, mode fmtMode) {
|
||||
func (n *Node) jconv(s fmt.State, flag FmtFlag) {
|
||||
c := flag & FmtShort
|
||||
|
||||
// Useful to see which nodes in a Node Dump/dumplist are actually identical
|
||||
if Debug_dumpptrs != 0 {
|
||||
fmt.Fprintf(s, " p(%p)", n)
|
||||
}
|
||||
if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
|
||||
fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
|
||||
}
|
||||
|
||||
if Debug_dumpptrs != 0 && 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() {
|
||||
pfx := ""
|
||||
switch n.Pos.IsStmt() {
|
||||
@@ -501,15 +492,6 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) {
|
||||
if n.Name.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() {
|
||||
fmt.Fprint(s, " bounded")
|
||||
@@ -1728,9 +1710,6 @@ 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 {
|
||||
mode.Fprintf(s, " %v", n.Sym)
|
||||
}
|
||||
@@ -1746,16 +1725,6 @@ func (n *Node) nodedump(s fmt.State, flag FmtFlag, mode fmtMode) {
|
||||
if n.Right != nil {
|
||||
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 {
|
||||
indent(s)
|
||||
mode.Fprintf(s, "%v-list%v", n.Op, n.List)
|
||||
|
||||
@@ -309,7 +309,6 @@ var (
|
||||
growslice,
|
||||
msanread,
|
||||
msanwrite,
|
||||
msanmove,
|
||||
newobject,
|
||||
newproc,
|
||||
panicdivide,
|
||||
|
||||
@@ -70,8 +70,12 @@ func newProgs(fn *Node, worker int) *Progs {
|
||||
pp.pos = fn.Pos
|
||||
pp.settext(fn)
|
||||
// PCDATA tables implicitly start with index -1.
|
||||
pp.prevLive = LivenessIndex{-1, false}
|
||||
pp.nextLive = pp.prevLive
|
||||
pp.prevLive = LivenessIndex{-1, -1, false}
|
||||
if go115ReduceLiveness {
|
||||
pp.nextLive = pp.prevLive
|
||||
} else {
|
||||
pp.nextLive = LivenessInvalid
|
||||
}
|
||||
return pp
|
||||
}
|
||||
|
||||
@@ -116,15 +120,31 @@ func (pp *Progs) Prog(as obj.As) *obj.Prog {
|
||||
Addrconst(&p.From, objabi.PCDATA_StackMapIndex)
|
||||
Addrconst(&p.To, int64(idx))
|
||||
}
|
||||
if pp.nextLive.isUnsafePoint != pp.prevLive.isUnsafePoint {
|
||||
// Emit unsafe-point marker.
|
||||
pp.prevLive.isUnsafePoint = pp.nextLive.isUnsafePoint
|
||||
p := pp.Prog(obj.APCDATA)
|
||||
Addrconst(&p.From, objabi.PCDATA_UnsafePoint)
|
||||
if !go115ReduceLiveness {
|
||||
if pp.nextLive.isUnsafePoint {
|
||||
Addrconst(&p.To, objabi.PCDATA_UnsafePointUnsafe)
|
||||
} else {
|
||||
Addrconst(&p.To, objabi.PCDATA_UnsafePointSafe)
|
||||
// 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 {
|
||||
// Emit unsafe-point marker.
|
||||
pp.prevLive.isUnsafePoint = pp.nextLive.isUnsafePoint
|
||||
p := pp.Prog(obj.APCDATA)
|
||||
Addrconst(&p.From, objabi.PCDATA_UnsafePoint)
|
||||
if pp.nextLive.isUnsafePoint {
|
||||
Addrconst(&p.To, objabi.PCDATA_UnsafePointUnsafe)
|
||||
} else {
|
||||
Addrconst(&p.To, objabi.PCDATA_UnsafePointSafe)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,12 +322,6 @@ func ggloblnod(nam *Node) {
|
||||
if nam.Name.LibfuzzerExtraCounter() {
|
||||
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) {
|
||||
|
||||
@@ -1138,10 +1138,13 @@ func (w *exportWriter) stmt(n *Node) {
|
||||
w.pos(n.Pos)
|
||||
w.stmtList(n.Ninit)
|
||||
w.exprsOrNil(n.Left, nil)
|
||||
w.caseList(n)
|
||||
w.stmtList(n.List)
|
||||
|
||||
// case OCASE:
|
||||
// handled by caseList
|
||||
case OCASE:
|
||||
w.op(OCASE)
|
||||
w.pos(n.Pos)
|
||||
w.stmtList(n.List)
|
||||
w.stmtList(n.Nbody)
|
||||
|
||||
case OFALL:
|
||||
w.op(OFALL)
|
||||
@@ -1165,24 +1168,6 @@ 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) {
|
||||
for _, n := range list.Slice() {
|
||||
w.expr(n)
|
||||
@@ -1247,19 +1232,6 @@ func (w *exportWriter) expr(n *Node) {
|
||||
w.op(OTYPE)
|
||||
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:
|
||||
// should have been resolved by typechecking - handled by default case
|
||||
|
||||
|
||||
@@ -784,28 +784,6 @@ func (r *importReader) stmtList() []*Node {
|
||||
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 {
|
||||
var list []*Node
|
||||
for {
|
||||
@@ -853,14 +831,6 @@ func (r *importReader) node() *Node {
|
||||
case OTYPE:
|
||||
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:
|
||||
// unreachable - should have been resolved by typechecking
|
||||
|
||||
@@ -1055,11 +1025,16 @@ func (r *importReader) node() *Node {
|
||||
n := nodl(r.pos(), op, nil, nil)
|
||||
n.Ninit.Set(r.stmtList())
|
||||
n.Left, _ = r.exprsOrNil()
|
||||
n.List.Set(r.caseList(n))
|
||||
n.List.Set(r.stmtList())
|
||||
return n
|
||||
|
||||
// case OCASE:
|
||||
// handled by caseList
|
||||
case OCASE:
|
||||
n := nodl(r.pos(), OCASE, nil, nil)
|
||||
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:
|
||||
n := nodl(r.pos(), OFALL, nil, nil)
|
||||
|
||||
@@ -108,7 +108,7 @@ func initOrder(l []*Node) []*Node {
|
||||
errorexit()
|
||||
}
|
||||
|
||||
findInitLoopAndExit(firstLHS(n), new([]*Node), make(map[*Node]bool))
|
||||
findInitLoopAndExit(firstLHS(n), new([]*Node))
|
||||
Fatalf("initialization unfinished, but failed to identify loop")
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,10 @@ func (o *InitOrder) flushReady(initialize func(*Node)) {
|
||||
// path points to a slice used for tracking the sequence of
|
||||
// variables/functions visited. Using a pointer to a slice allows the
|
||||
// slice capacity to grow and limit reallocations.
|
||||
func findInitLoopAndExit(n *Node, path *[]*Node, ok map[*Node]bool) {
|
||||
func findInitLoopAndExit(n *Node, path *[]*Node) {
|
||||
// We implement a simple DFS loop-finding algorithm. This
|
||||
// could be faster, but initialization cycles are rare.
|
||||
|
||||
for i, x := range *path {
|
||||
if x == n {
|
||||
reportInitLoopAndExit((*path)[i:])
|
||||
@@ -198,18 +201,12 @@ func findInitLoopAndExit(n *Node, path *[]*Node, ok map[*Node]bool) {
|
||||
*path = append(*path, n)
|
||||
for _, ref := range refers {
|
||||
// Short-circuit variables that were initialized.
|
||||
if ref.Class() == PEXTERN && ref.Name.Defn.Initorder() == InitDone || ok[ref] {
|
||||
if ref.Class() == PEXTERN && ref.Name.Defn.Initorder() == InitDone {
|
||||
continue
|
||||
}
|
||||
findInitLoopAndExit(ref, path, ok)
|
||||
|
||||
findInitLoopAndExit(ref, path)
|
||||
}
|
||||
|
||||
// n is not involved in a cycle.
|
||||
// Record that fact to avoid checking it again when reached another way,
|
||||
// or else this traversal will take exponential time traversing all paths
|
||||
// through the part of the package's call graph implicated in the cycle.
|
||||
ok[n] = true
|
||||
|
||||
*path = (*path)[:len(*path)-1]
|
||||
}
|
||||
|
||||
|
||||
@@ -94,11 +94,10 @@ func typecheckinl(fn *Node) {
|
||||
typecheckslice(fn.Func.Inl.Body, ctxStmt)
|
||||
Curfn = savefn
|
||||
|
||||
// During expandInline (which imports fn.Func.Inl.Body),
|
||||
// declarations are added to fn.Func.Dcl by funcHdr(). Move them
|
||||
// to fn.Func.Inl.Dcl for consistency with how local functions
|
||||
// behave. (Append because typecheckinl may be called multiple
|
||||
// times.)
|
||||
// During typechecking, declarations are added to
|
||||
// Curfn.Func.Dcl. Move them to Inl.Dcl for consistency with
|
||||
// how local functions behave. (Append because typecheckinl
|
||||
// may be called multiple times.)
|
||||
fn.Func.Inl.Dcl = append(fn.Func.Inl.Dcl, fn.Func.Dcl...)
|
||||
fn.Func.Dcl = nil
|
||||
|
||||
@@ -258,39 +257,21 @@ func inlFlood(n *Node) {
|
||||
|
||||
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 {
|
||||
switch n.Op {
|
||||
case ONAME:
|
||||
switch n.Class() {
|
||||
case PFUNC:
|
||||
if n.isMethodExpression() {
|
||||
inlFlood(asNode(n.Type.Nname()))
|
||||
} else {
|
||||
inlFlood(n)
|
||||
exportsym(n)
|
||||
}
|
||||
case PEXTERN:
|
||||
// Mark any referenced global variables or
|
||||
// functions for reexport. Skip methods,
|
||||
// because they're reexported alongside their
|
||||
// receiver type.
|
||||
if n.Class() == PEXTERN || n.Class() == PFUNC && !n.isMethodExpression() {
|
||||
exportsym(n)
|
||||
}
|
||||
|
||||
case ODOTMETH:
|
||||
fn := asNode(n.Type.Nname())
|
||||
inlFlood(fn)
|
||||
|
||||
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")
|
||||
case OCALLFUNC, OCALLMETH:
|
||||
// Recursively flood any functions called by
|
||||
// this one.
|
||||
inlFlood(asNode(n.Left.Type.Nname()))
|
||||
}
|
||||
return true
|
||||
})
|
||||
@@ -393,9 +374,13 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
||||
v.reason = "call to recover"
|
||||
return true
|
||||
|
||||
case OCALLPART:
|
||||
// OCALLPART is inlineable, but no extra cost to the budget
|
||||
|
||||
case OCLOSURE,
|
||||
ORANGE,
|
||||
OSELECT,
|
||||
OTYPESW,
|
||||
OGO,
|
||||
ODEFER,
|
||||
ODCLTYPE, // can't print yet
|
||||
@@ -449,9 +434,9 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
||||
v.visitList(n.Ninit) || v.visitList(n.Nbody)
|
||||
}
|
||||
|
||||
// inlcopylist (together with inlcopy) recursively copies a list of nodes, except
|
||||
// that it keeps the same ONAME, OTYPE, and OLITERAL nodes. It is used for copying
|
||||
// the body and dcls of an inlineable function.
|
||||
// Inlcopy and inlcopylist recursively copy the body of a function.
|
||||
// Any name-like node of non-local class is marked for re-export by adding it to
|
||||
// the exportlist.
|
||||
func inlcopylist(ll []*Node) []*Node {
|
||||
s := make([]*Node, 0, len(ll))
|
||||
for _, n := range ll {
|
||||
@@ -589,11 +574,13 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
}
|
||||
|
||||
switch n.Op {
|
||||
// inhibit inlining of their argument
|
||||
case ODEFER, OGO:
|
||||
switch n.Left.Op {
|
||||
case OCALLFUNC, OCALLMETH:
|
||||
n.Left.SetNoInline(true)
|
||||
}
|
||||
return n
|
||||
|
||||
// TODO do them here (or earlier),
|
||||
// so escape analysis can avoid more heapmoves.
|
||||
@@ -721,14 +708,7 @@ func inlCallee(fn *Node) *Node {
|
||||
switch {
|
||||
case fn.Op == ONAME && fn.Class() == PFUNC:
|
||||
if fn.isMethodExpression() {
|
||||
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 asNode(fn.Sym.Def)
|
||||
}
|
||||
return fn
|
||||
case fn.Op == OCLOSURE:
|
||||
@@ -741,11 +721,6 @@ func inlCallee(fn *Node) *Node {
|
||||
|
||||
func staticValue(n *Node) *Node {
|
||||
for {
|
||||
if n.Op == OCONVNOP {
|
||||
n = n.Left
|
||||
continue
|
||||
}
|
||||
|
||||
n1 := staticValue1(n)
|
||||
if n1 == nil {
|
||||
return n
|
||||
@@ -832,20 +807,18 @@ func (v *reassignVisitor) visit(n *Node) *Node {
|
||||
return nil
|
||||
}
|
||||
switch n.Op {
|
||||
case OAS, OSELRECV:
|
||||
case OAS:
|
||||
if n.Left == v.name && n != v.name.Name.Defn {
|
||||
return n
|
||||
}
|
||||
case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
|
||||
return nil
|
||||
case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE:
|
||||
for _, p := range n.List.Slice() {
|
||||
if p == v.name && n != v.name.Name.Defn {
|
||||
return n
|
||||
}
|
||||
}
|
||||
case OSELRECV2:
|
||||
if (n.Left == v.name || n.List.First() == v.name) && n != v.name.Name.Defn {
|
||||
return n
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if a := v.visit(n.Left); a != nil {
|
||||
return a
|
||||
@@ -894,10 +867,10 @@ func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
|
||||
|
||||
var inlgen int
|
||||
|
||||
// If n is a call node (OCALLFUNC or OCALLMETH), and fn is an ONAME node for a
|
||||
// function with an inlinable body, return an OINLCALL node that can replace n.
|
||||
// The returned node's Ninit has the parameter assignments, the Nbody is the
|
||||
// inlined function body, and (List, Rlist) contain the (input, output)
|
||||
// If n is a call, and fn is a function with an inlinable body,
|
||||
// return an OINLCALL.
|
||||
// On return ninit has the parameter assignments, the nbody is the
|
||||
// inlined function body and list, rlist contain the input, output
|
||||
// parameters.
|
||||
// The result of mkinlcall MUST be assigned back to n, e.g.
|
||||
// n.Left = mkinlcall(n.Left, fn, isddd)
|
||||
@@ -967,21 +940,6 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
|
||||
ninit := n.Ninit
|
||||
|
||||
// For normal function calls, the function callee expression
|
||||
// may contain side effects (e.g., added by addinit during
|
||||
// inlconv2expr or inlconv2list). Make sure to preserve these,
|
||||
// if necessary (#42703).
|
||||
if n.Op == OCALLFUNC {
|
||||
callee := n.Left
|
||||
for callee.Op == OCONVNOP {
|
||||
ninit.AppendNodes(&callee.Ninit)
|
||||
callee = callee.Left
|
||||
}
|
||||
if callee.Op != ONAME && callee.Op != OCLOSURE {
|
||||
Fatalf("unexpected callee expression: %v", callee)
|
||||
}
|
||||
}
|
||||
|
||||
// Make temp names to use instead of the originals.
|
||||
inlvars := make(map[*Node]*Node)
|
||||
|
||||
@@ -1053,28 +1011,15 @@ 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.
|
||||
var retvars []*Node
|
||||
for i, t := range fn.Type.Results().Fields().Slice() {
|
||||
var m *Node
|
||||
if n := asNode(t.Nname); n != nil && !n.isBlank() && !strings.HasPrefix(n.Sym.Name, "~r") {
|
||||
mpos := t.Pos
|
||||
if n := asNode(t.Nname); n != nil && !n.isBlank() {
|
||||
m = inlvar(n)
|
||||
m = typecheck(m, ctxExpr)
|
||||
inlvars[n] = m
|
||||
delayretvars = false // found a named result parameter
|
||||
} else {
|
||||
// anonymous return values, synthesize names for use in assignment that replaces return
|
||||
m = retvar(t, i)
|
||||
@@ -1086,11 +1031,12 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
// were not part of the original callee.
|
||||
if !strings.HasPrefix(m.Sym.Name, "~R") {
|
||||
m.Name.SetInlFormal(true)
|
||||
m.Pos = t.Pos
|
||||
m.Pos = mpos
|
||||
inlfvars = append(inlfvars, m)
|
||||
}
|
||||
}
|
||||
|
||||
ninit.Append(nod(ODCL, m, nil))
|
||||
retvars = append(retvars, m)
|
||||
}
|
||||
|
||||
@@ -1151,14 +1097,11 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
ninit.Append(vas)
|
||||
}
|
||||
|
||||
if !delayretvars {
|
||||
// Zero the return parameters.
|
||||
for _, n := range retvars {
|
||||
ninit.Append(nod(ODCL, n, nil))
|
||||
ras := nod(OAS, n, nil)
|
||||
ras = typecheck(ras, ctxStmt)
|
||||
ninit.Append(ras)
|
||||
}
|
||||
// Zero the return parameters.
|
||||
for _, n := range retvars {
|
||||
ras := nod(OAS, n, nil)
|
||||
ras = typecheck(ras, ctxStmt)
|
||||
ninit.Append(ras)
|
||||
}
|
||||
|
||||
retlabel := autolabel(".i")
|
||||
@@ -1189,12 +1132,11 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
}
|
||||
|
||||
subst := inlsubst{
|
||||
retlabel: retlabel,
|
||||
retvars: retvars,
|
||||
delayretvars: delayretvars,
|
||||
inlvars: inlvars,
|
||||
bases: make(map[*src.PosBase]*src.PosBase),
|
||||
newInlIndex: newIndex,
|
||||
retlabel: retlabel,
|
||||
retvars: retvars,
|
||||
inlvars: inlvars,
|
||||
bases: make(map[*src.PosBase]*src.PosBase),
|
||||
newInlIndex: newIndex,
|
||||
}
|
||||
|
||||
body := subst.list(asNodes(fn.Func.Inl.Body))
|
||||
@@ -1290,10 +1232,6 @@ type inlsubst struct {
|
||||
// Temporary result variables.
|
||||
retvars []*Node
|
||||
|
||||
// Whether result variables should be initialized at the
|
||||
// "return" statement.
|
||||
delayretvars bool
|
||||
|
||||
inlvars map[*Node]*Node
|
||||
|
||||
// bases maps from original PosBase to PosBase with an extra
|
||||
@@ -1362,14 +1300,6 @@ func (subst *inlsubst) node(n *Node) *Node {
|
||||
as.List.Append(n)
|
||||
}
|
||||
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)
|
||||
m.Ninit.Append(as)
|
||||
}
|
||||
@@ -1432,68 +1362,3 @@ func pruneUnusedAutos(ll []*Node, vis *hairyVisitor) []*Node {
|
||||
}
|
||||
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,7 +51,6 @@ func TestIntendedInlining(t *testing.T) {
|
||||
"funcPC",
|
||||
"getArgInfoFast",
|
||||
"getm",
|
||||
"getMCache",
|
||||
"isDirectIface",
|
||||
"itabHashFunc",
|
||||
"noescape",
|
||||
|
||||
@@ -46,7 +46,6 @@ var (
|
||||
Debug_closure int
|
||||
Debug_compilelater int
|
||||
debug_dclstack int
|
||||
Debug_dumpptrs int
|
||||
Debug_libfuzzer int
|
||||
Debug_panic int
|
||||
Debug_slice int
|
||||
@@ -76,7 +75,6 @@ var debugtab = []struct {
|
||||
{"compilelater", "compile functions as late as possible", &Debug_compilelater},
|
||||
{"disablenil", "disable nil checks", &disable_checknil},
|
||||
{"dclstack", "run internal dclstack check", &debug_dclstack},
|
||||
{"dumpptrs", "show Node pointer values in Dump/dumplist output", &Debug_dumpptrs},
|
||||
{"gcprog", "print dump of GC programs", &Debug_gcprog},
|
||||
{"libfuzzer", "coverage instrumentation for libfuzzer", &Debug_libfuzzer},
|
||||
{"nil", "print information about nil checks", &Debug_checknil},
|
||||
@@ -91,7 +89,6 @@ var debugtab = []struct {
|
||||
{"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl},
|
||||
{"softfloat", "force compiler to emit soft-float code", &Debug_softfloat},
|
||||
{"defer", "print information about defer compilation", &Debug_defer},
|
||||
{"fieldtrack", "enable fieldtracking", &objabi.Fieldtrack_enabled},
|
||||
}
|
||||
|
||||
const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
|
||||
@@ -704,13 +701,6 @@ func Main(archInit func(*Arch)) {
|
||||
})
|
||||
}
|
||||
|
||||
for _, n := range xtop {
|
||||
if n.Op == ODCLFUNC {
|
||||
devirtualize(n)
|
||||
}
|
||||
}
|
||||
Curfn = nil
|
||||
|
||||
// Phase 6: Escape analysis.
|
||||
// Required for moving heap allocations onto stack,
|
||||
// which in turn is required by the closure implementation,
|
||||
|
||||
@@ -397,7 +397,7 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
|
||||
p.yyerrorpos(e.Pos, "//go:embed only allowed in Go files that import \"embed\"")
|
||||
}
|
||||
} else {
|
||||
varEmbed(p, names, typ, exprs, pragma.Embeds)
|
||||
exprs = varEmbed(p, names, typ, exprs, pragma.Embeds)
|
||||
}
|
||||
pragma.Embeds = nil
|
||||
}
|
||||
|
||||
@@ -312,7 +312,7 @@ func addGCLocals() {
|
||||
if fn == nil {
|
||||
continue
|
||||
}
|
||||
for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals} {
|
||||
for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals, fn.GCRegs} {
|
||||
if gcsym != nil && !gcsym.OnList() {
|
||||
ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
|
||||
}
|
||||
|
||||
@@ -891,7 +891,7 @@ func (o *Order) stmt(n *Node) {
|
||||
// c is always evaluated; x and ok are only evaluated when assigned.
|
||||
r.Right.Left = o.expr(r.Right.Left, nil)
|
||||
|
||||
if !r.Right.Left.IsAutoTmp() {
|
||||
if r.Right.Left.Op != ONAME {
|
||||
r.Right.Left = o.copyExpr(r.Right.Left, r.Right.Left.Type, false)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,16 @@ import (
|
||||
"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
|
||||
// where a complete initialization (definition) of a variable begins.
|
||||
// Since the liveness analysis can see initialization of single-word
|
||||
@@ -86,15 +96,15 @@ type BlockEffects struct {
|
||||
//
|
||||
// uevar: upward exposed variables (used before set in block)
|
||||
// varkill: killed variables (set in block)
|
||||
uevar bvec
|
||||
varkill bvec
|
||||
uevar varRegVec
|
||||
varkill varRegVec
|
||||
|
||||
// Computed during Liveness.solve using control flow information:
|
||||
//
|
||||
// livein: variables live at block entry
|
||||
// liveout: variables live at block exit
|
||||
livein bvec
|
||||
liveout bvec
|
||||
livein varRegVec
|
||||
liveout varRegVec
|
||||
}
|
||||
|
||||
// A collection of global state used by liveness analysis.
|
||||
@@ -118,14 +128,16 @@ type Liveness struct {
|
||||
// current Block during Liveness.epilogue. Indexed in Value
|
||||
// order for that block. Additionally, for the entry block
|
||||
// livevars[0] is the entry bitmap. Liveness.compact moves
|
||||
// these to stackMaps.
|
||||
livevars []bvec
|
||||
// these to stackMaps and regMaps.
|
||||
livevars []varRegVec
|
||||
|
||||
// livenessMap maps from safe points (i.e., CALLs) to their
|
||||
// liveness map indexes.
|
||||
livenessMap LivenessMap
|
||||
stackMapSet bvecSet
|
||||
stackMaps []bvec
|
||||
regMapSet map[liveRegMask]int
|
||||
regMaps []liveRegMask
|
||||
|
||||
cache progeffectscache
|
||||
}
|
||||
@@ -146,7 +158,7 @@ func (m *LivenessMap) reset() {
|
||||
delete(m.vals, k)
|
||||
}
|
||||
}
|
||||
m.deferreturn = LivenessDontCare
|
||||
m.deferreturn = LivenessInvalid
|
||||
}
|
||||
|
||||
func (m *LivenessMap) set(v *ssa.Value, i LivenessIndex) {
|
||||
@@ -154,17 +166,27 @@ func (m *LivenessMap) set(v *ssa.Value, i 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
|
||||
// unsafe-point.
|
||||
if idx, ok := m.vals[v.ID]; ok {
|
||||
return idx
|
||||
}
|
||||
return LivenessIndex{StackMapDontCare, false}
|
||||
return LivenessIndex{StackMapDontCare, StackMapDontCare, false}
|
||||
}
|
||||
|
||||
// LivenessIndex stores the liveness map information for a Value.
|
||||
type LivenessIndex struct {
|
||||
stackMapIndex int
|
||||
regMapIndex int // only for !go115ReduceLiveness
|
||||
|
||||
// isUnsafePoint indicates that this is an unsafe-point.
|
||||
//
|
||||
@@ -175,10 +197,8 @@ type LivenessIndex struct {
|
||||
isUnsafePoint bool
|
||||
}
|
||||
|
||||
// LivenessDontCare indicates that the liveness information doesn't
|
||||
// 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}
|
||||
// LivenessInvalid indicates an unsafe point with no stack map.
|
||||
var LivenessInvalid = LivenessIndex{StackMapDontCare, StackMapDontCare, true} // only for !go115ReduceLiveness
|
||||
|
||||
// StackMapDontCare indicates that the stack map index at a Value
|
||||
// doesn't matter.
|
||||
@@ -192,12 +212,46 @@ func (idx LivenessIndex) StackMapValid() bool {
|
||||
return idx.stackMapIndex != StackMapDontCare
|
||||
}
|
||||
|
||||
func (idx LivenessIndex) RegMapValid() bool {
|
||||
return idx.regMapIndex != StackMapDontCare
|
||||
}
|
||||
|
||||
type progeffectscache struct {
|
||||
retuevar []int32
|
||||
tailuevar []int32
|
||||
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
|
||||
// should track the variable n.
|
||||
// We don't care about variables that have no pointers,
|
||||
@@ -346,6 +400,110 @@ 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 {
|
||||
be []BlockEffects
|
||||
livenessMap LivenessMap
|
||||
@@ -361,6 +519,8 @@ func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkpt
|
||||
vars: vars,
|
||||
idx: idx,
|
||||
stkptrsize: stkptrsize,
|
||||
|
||||
regMapSet: make(map[liveRegMask]int),
|
||||
}
|
||||
|
||||
// Significant sources of allocation are kept in the ssa.Cache
|
||||
@@ -373,7 +533,7 @@ func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkpt
|
||||
if cap(lc.be) >= f.NumBlocks() {
|
||||
lv.be = lc.be[:f.NumBlocks()]
|
||||
}
|
||||
lv.livenessMap = LivenessMap{vals: lc.livenessMap.vals, deferreturn: LivenessDontCare}
|
||||
lv.livenessMap = LivenessMap{vals: lc.livenessMap.vals, deferreturn: LivenessInvalid}
|
||||
lc.livenessMap.vals = nil
|
||||
}
|
||||
if lv.be == nil {
|
||||
@@ -386,10 +546,10 @@ func newliveness(fn *Node, f *ssa.Func, vars []*Node, idx map[*Node]int32, stkpt
|
||||
for _, b := range f.Blocks {
|
||||
be := lv.blockEffects(b)
|
||||
|
||||
be.uevar = bulk.next()
|
||||
be.varkill = bulk.next()
|
||||
be.livein = bulk.next()
|
||||
be.liveout = bulk.next()
|
||||
be.uevar = varRegVec{vars: bulk.next()}
|
||||
be.varkill = varRegVec{vars: bulk.next()}
|
||||
be.livein = varRegVec{vars: bulk.next()}
|
||||
be.liveout = varRegVec{vars: bulk.next()}
|
||||
}
|
||||
lv.livenessMap.reset()
|
||||
|
||||
@@ -477,6 +637,20 @@ 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
|
||||
// this argument and the in arguments are always assumed live. The vars
|
||||
// argument is a slice of *Nodes.
|
||||
@@ -677,16 +851,31 @@ func (lv *Liveness) markUnsafePoints() {
|
||||
// particular, call Values can have a stack map in case the callee
|
||||
// grows the stack, but not themselves be a safe-point.
|
||||
func (lv *Liveness) hasStackMap(v *ssa.Value) bool {
|
||||
if !v.Op.IsCall() {
|
||||
// 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() {
|
||||
return false
|
||||
}
|
||||
// typedmemclr and typedmemmove are write barriers and
|
||||
// deeply non-preemptible. They are unsafe points and
|
||||
// hence should not have liveness maps.
|
||||
if sym, ok := v.Aux.(*ssa.AuxCall); ok && (sym.Fn == typedmemclr || sym.Fn == typedmemmove) {
|
||||
return false
|
||||
}
|
||||
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
|
||||
}
|
||||
// typedmemclr and typedmemmove are write barriers and
|
||||
// deeply non-preemptible. They are unsafe points and
|
||||
// hence should not have liveness maps.
|
||||
if sym, ok := v.Aux.(*ssa.AuxCall); ok && (sym.Fn == typedmemclr || sym.Fn == typedmemmove) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return !lv.unsafePoints.Get(int32(v.ID))
|
||||
}
|
||||
|
||||
// Initializes the sets for solving the live variables. Visits all the
|
||||
@@ -702,13 +891,17 @@ func (lv *Liveness) prologue() {
|
||||
// effects with the each prog effects.
|
||||
for j := len(b.Values) - 1; j >= 0; j-- {
|
||||
pos, e := lv.valueEffects(b.Values[j])
|
||||
regUevar, regKill := lv.regEffects(b.Values[j])
|
||||
if e&varkill != 0 {
|
||||
be.varkill.Set(pos)
|
||||
be.uevar.Unset(pos)
|
||||
be.varkill.vars.Set(pos)
|
||||
be.uevar.vars.Unset(pos)
|
||||
}
|
||||
be.varkill.regs |= regKill
|
||||
be.uevar.regs &^= regKill
|
||||
if e&uevar != 0 {
|
||||
be.uevar.Set(pos)
|
||||
be.uevar.vars.Set(pos)
|
||||
}
|
||||
be.uevar.regs |= regUevar
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -718,8 +911,8 @@ func (lv *Liveness) solve() {
|
||||
// These temporary bitvectors exist to avoid successive allocations and
|
||||
// frees within the loop.
|
||||
nvars := int32(len(lv.vars))
|
||||
newlivein := bvalloc(nvars)
|
||||
newliveout := bvalloc(nvars)
|
||||
newlivein := varRegVec{vars: bvalloc(nvars)}
|
||||
newliveout := varRegVec{vars: bvalloc(nvars)}
|
||||
|
||||
// Walk blocks in postorder ordering. This improves convergence.
|
||||
po := lv.f.Postorder()
|
||||
@@ -737,11 +930,11 @@ func (lv *Liveness) solve() {
|
||||
switch b.Kind {
|
||||
case ssa.BlockRet:
|
||||
for _, pos := range lv.cache.retuevar {
|
||||
newliveout.Set(pos)
|
||||
newliveout.vars.Set(pos)
|
||||
}
|
||||
case ssa.BlockRetJmp:
|
||||
for _, pos := range lv.cache.tailuevar {
|
||||
newliveout.Set(pos)
|
||||
newliveout.vars.Set(pos)
|
||||
}
|
||||
case ssa.BlockExit:
|
||||
// panic exit - nothing to do
|
||||
@@ -776,7 +969,7 @@ func (lv *Liveness) solve() {
|
||||
// variables at each safe point locations.
|
||||
func (lv *Liveness) epilogue() {
|
||||
nvars := int32(len(lv.vars))
|
||||
liveout := bvalloc(nvars)
|
||||
liveout := varRegVec{vars: bvalloc(nvars)}
|
||||
livedefer := bvalloc(nvars) // always-live variables
|
||||
|
||||
// If there is a defer (that could recover), then all output
|
||||
@@ -832,11 +1025,12 @@ func (lv *Liveness) epilogue() {
|
||||
{
|
||||
// Reserve an entry for function entry.
|
||||
live := bvalloc(nvars)
|
||||
lv.livevars = append(lv.livevars, live)
|
||||
lv.livevars = append(lv.livevars, varRegVec{vars: live})
|
||||
}
|
||||
|
||||
for _, b := range lv.f.Blocks {
|
||||
be := lv.blockEffects(b)
|
||||
firstBitmapIndex := len(lv.livevars)
|
||||
|
||||
// Walk forward through the basic block instructions and
|
||||
// allocate liveness maps for those instructions that need them.
|
||||
@@ -846,7 +1040,7 @@ func (lv *Liveness) epilogue() {
|
||||
}
|
||||
|
||||
live := bvalloc(nvars)
|
||||
lv.livevars = append(lv.livevars, live)
|
||||
lv.livevars = append(lv.livevars, varRegVec{vars: live})
|
||||
}
|
||||
|
||||
// walk backward, construct maps at each safe point
|
||||
@@ -862,18 +1056,21 @@ func (lv *Liveness) epilogue() {
|
||||
|
||||
live := &lv.livevars[index]
|
||||
live.Or(*live, liveout)
|
||||
live.Or(*live, livedefer) // only for non-entry safe points
|
||||
live.vars.Or(live.vars, livedefer) // only for non-entry safe points
|
||||
index--
|
||||
}
|
||||
|
||||
// Update liveness information.
|
||||
pos, e := lv.valueEffects(v)
|
||||
regUevar, regKill := lv.regEffects(v)
|
||||
if e&varkill != 0 {
|
||||
liveout.Unset(pos)
|
||||
liveout.vars.Unset(pos)
|
||||
}
|
||||
liveout.regs &^= regKill
|
||||
if e&uevar != 0 {
|
||||
liveout.Set(pos)
|
||||
liveout.vars.Set(pos)
|
||||
}
|
||||
liveout.regs |= regUevar
|
||||
}
|
||||
|
||||
if b == lv.f.Entry {
|
||||
@@ -883,7 +1080,7 @@ func (lv *Liveness) epilogue() {
|
||||
|
||||
// Check to make sure only input variables are live.
|
||||
for i, n := range lv.vars {
|
||||
if !liveout.Get(int32(i)) {
|
||||
if !liveout.vars.Get(int32(i)) {
|
||||
continue
|
||||
}
|
||||
if n.Class() == PPARAM {
|
||||
@@ -897,16 +1094,32 @@ func (lv *Liveness) epilogue() {
|
||||
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.
|
||||
lv.compact(b)
|
||||
}
|
||||
|
||||
// If we have an open-coded deferreturn call, make a liveness map for it.
|
||||
if lv.fn.Func.OpenCodedDeferDisallowed() {
|
||||
lv.livenessMap.deferreturn = LivenessDontCare
|
||||
lv.livenessMap.deferreturn = LivenessInvalid
|
||||
} else {
|
||||
lv.livenessMap.deferreturn = LivenessIndex{
|
||||
stackMapIndex: lv.stackMapSet.add(livedefer),
|
||||
regMapIndex: 0, // entry regMap, containing no live registers
|
||||
isUnsafePoint: false,
|
||||
}
|
||||
}
|
||||
@@ -923,10 +1136,20 @@ func (lv *Liveness) epilogue() {
|
||||
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
|
||||
// lv.stackMapSet.
|
||||
// lv.stackMapSet and lv.regMaps.
|
||||
//
|
||||
// Compact clears lv.livevars.
|
||||
//
|
||||
@@ -942,23 +1165,45 @@ func (lv *Liveness) epilogue() {
|
||||
// PCDATA tables cost about 100k. So for now we keep using a single index for
|
||||
// both bitmap lists.
|
||||
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
|
||||
if b == lv.f.Entry {
|
||||
// Handle entry stack map.
|
||||
lv.stackMapSet.add(lv.livevars[0])
|
||||
if !go115ReduceLiveness {
|
||||
add(lv.livevars[0], false)
|
||||
} else {
|
||||
lv.stackMapSet.add(lv.livevars[0].vars)
|
||||
}
|
||||
pos++
|
||||
}
|
||||
for _, v := range b.Values {
|
||||
hasStackMap := lv.hasStackMap(v)
|
||||
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
|
||||
idx := LivenessIndex{StackMapDontCare, isUnsafePoint}
|
||||
if hasStackMap {
|
||||
idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos])
|
||||
if go115ReduceLiveness {
|
||||
hasStackMap := lv.hasStackMap(v)
|
||||
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
|
||||
idx := LivenessIndex{StackMapDontCare, StackMapDontCare, isUnsafePoint}
|
||||
if hasStackMap {
|
||||
idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos].vars)
|
||||
pos++
|
||||
}
|
||||
if hasStackMap || isUnsafePoint {
|
||||
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++
|
||||
}
|
||||
if hasStackMap || isUnsafePoint {
|
||||
lv.livenessMap.set(v, idx)
|
||||
}
|
||||
}
|
||||
|
||||
// Reset livevars.
|
||||
@@ -1005,8 +1250,8 @@ func (lv *Liveness) showlive(v *ssa.Value, live bvec) {
|
||||
Warnl(pos, s)
|
||||
}
|
||||
|
||||
func (lv *Liveness) printbvec(printed bool, name string, live bvec) bool {
|
||||
if live.IsEmpty() {
|
||||
func (lv *Liveness) printbvec(printed bool, name string, live varRegVec) bool {
|
||||
if live.vars.IsEmpty() && live.regs == 0 {
|
||||
return printed
|
||||
}
|
||||
|
||||
@@ -1019,18 +1264,19 @@ func (lv *Liveness) printbvec(printed bool, name string, live bvec) bool {
|
||||
|
||||
comma := ""
|
||||
for i, n := range lv.vars {
|
||||
if !live.Get(int32(i)) {
|
||||
if !live.vars.Get(int32(i)) {
|
||||
continue
|
||||
}
|
||||
fmt.Printf("%s%s", comma, n.Sym.Name)
|
||||
comma = ","
|
||||
}
|
||||
fmt.Printf("%s%s", comma, live.regs.niceString(lv.f.Config))
|
||||
return true
|
||||
}
|
||||
|
||||
// printeffect is like printbvec, but for valueEffects.
|
||||
func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool) bool {
|
||||
if !x {
|
||||
// printeffect is like printbvec, but for valueEffects and regEffects.
|
||||
func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool, regMask liveRegMask) bool {
|
||||
if !x && regMask == 0 {
|
||||
return printed
|
||||
}
|
||||
if !printed {
|
||||
@@ -1042,7 +1288,15 @@ func (lv *Liveness) printeffect(printed bool, name string, pos int32, x bool) bo
|
||||
if x {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1110,14 +1364,15 @@ func (lv *Liveness) printDebug() {
|
||||
pcdata := lv.livenessMap.Get(v)
|
||||
|
||||
pos, effect := lv.valueEffects(v)
|
||||
regUevar, regKill := lv.regEffects(v)
|
||||
printed = false
|
||||
printed = lv.printeffect(printed, "uevar", pos, effect&uevar != 0)
|
||||
printed = lv.printeffect(printed, "varkill", pos, effect&varkill != 0)
|
||||
printed = lv.printeffect(printed, "uevar", pos, effect&uevar != 0, regUevar)
|
||||
printed = lv.printeffect(printed, "varkill", pos, effect&varkill != 0, regKill)
|
||||
if printed {
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
if pcdata.StackMapValid() {
|
||||
if pcdata.StackMapValid() || pcdata.RegMapValid() {
|
||||
fmt.Printf("\tlive=")
|
||||
printed = false
|
||||
if pcdata.StackMapValid() {
|
||||
@@ -1133,6 +1388,16 @@ func (lv *Liveness) printDebug() {
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -1158,7 +1423,7 @@ func (lv *Liveness) printDebug() {
|
||||
// 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
|
||||
// remaining bytes are the raw bitmaps.
|
||||
func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) {
|
||||
func (lv *Liveness) emit() (argsSym, liveSym, regsSym *obj.LSym) {
|
||||
// Size args bitmaps to be just large enough to hold the largest pointer.
|
||||
// First, find the largest Xoffset node we care about.
|
||||
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
|
||||
@@ -1187,7 +1452,7 @@ func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) {
|
||||
maxLocals := lv.stkptrsize
|
||||
|
||||
// Temporary symbols for encoding bitmaps.
|
||||
var argsSymTmp, liveSymTmp obj.LSym
|
||||
var argsSymTmp, liveSymTmp, regsSymTmp obj.LSym
|
||||
|
||||
args := bvalloc(int32(maxArgs / int64(Widthptr)))
|
||||
aoff := duint32(&argsSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
|
||||
@@ -1207,6 +1472,24 @@ func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) {
|
||||
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,
|
||||
// so that they can be de-duplicated.
|
||||
// This provides significant binary size savings.
|
||||
@@ -1219,7 +1502,11 @@ func (lv *Liveness) emit() (argsSym, liveSym *obj.LSym) {
|
||||
lsym.Set(obj.AttrContentAddressable, true)
|
||||
})
|
||||
}
|
||||
return makeSym(&argsSymTmp), makeSym(&liveSymTmp)
|
||||
if !go115ReduceLiveness {
|
||||
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
|
||||
@@ -1266,7 +1553,7 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
|
||||
// Emit the live pointer map data structures
|
||||
ls := e.curfn.Func.lsym
|
||||
fninfo := ls.Func()
|
||||
fninfo.GCArgs, fninfo.GCLocals = lv.emit()
|
||||
fninfo.GCArgs, fninfo.GCLocals, fninfo.GCRegs = lv.emit()
|
||||
|
||||
p := pp.Prog(obj.AFUNCDATA)
|
||||
Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
|
||||
@@ -1280,6 +1567,14 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
|
||||
p.To.Name = obj.NAME_EXTERN
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -1275,8 +1275,9 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
}
|
||||
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 = duintptr(lsym, ot, uint64(n))
|
||||
ot = duintptr(lsym, ot, uint64(xcount))
|
||||
ot = duintptr(lsym, ot, uint64(n))
|
||||
dataAdd := imethodSize() * n
|
||||
ot = dextratype(lsym, ot, t, dataAdd)
|
||||
@@ -1591,12 +1592,8 @@ func dumptabs() {
|
||||
// typ typeOff // pointer to symbol
|
||||
// }
|
||||
nsym := dname(p.s.Name, "", nil, true)
|
||||
tsym := dtypesym(p.t)
|
||||
ot = dsymptrOff(s, ot, nsym)
|
||||
ot = dsymptrOff(s, ot, tsym)
|
||||
// Plugin exports symbols as interfaces. Mark their types
|
||||
// as UsedInIface.
|
||||
tsym.Set(obj.AttrUsedInIface, true)
|
||||
ot = dsymptrOff(s, ot, dtypesym(p.t))
|
||||
}
|
||||
ggloblsym(s, int32(ot), int16(obj.RODATA))
|
||||
|
||||
|
||||
@@ -75,19 +75,8 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
|
||||
|
||||
inspectList(n.Nbody, func(n *Node) bool {
|
||||
switch n.Op {
|
||||
case ONAME:
|
||||
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())
|
||||
case OCALLFUNC, OCALLMETH:
|
||||
fn := asNode(n.Left.Type.Nname())
|
||||
if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil {
|
||||
if m := v.visit(fn.Name.Defn); m < min {
|
||||
min = m
|
||||
|
||||
@@ -72,14 +72,13 @@ func initssaconfig() {
|
||||
deferproc = sysfunc("deferproc")
|
||||
deferprocStack = sysfunc("deferprocStack")
|
||||
Deferreturn = sysfunc("deferreturn")
|
||||
Duffcopy = sysfunc("duffcopy")
|
||||
Duffzero = sysfunc("duffzero")
|
||||
gcWriteBarrier = sysfunc("gcWriteBarrier")
|
||||
Duffcopy = sysvar("duffcopy") // asm func with special ABI
|
||||
Duffzero = sysvar("duffzero") // asm func with special ABI
|
||||
gcWriteBarrier = sysvar("gcWriteBarrier") // asm func with special ABI
|
||||
goschedguarded = sysfunc("goschedguarded")
|
||||
growslice = sysfunc("growslice")
|
||||
msanread = sysfunc("msanread")
|
||||
msanwrite = sysfunc("msanwrite")
|
||||
msanmove = sysfunc("msanmove")
|
||||
newobject = sysfunc("newobject")
|
||||
newproc = sysfunc("newproc")
|
||||
panicdivide = sysfunc("panicdivide")
|
||||
@@ -106,51 +105,51 @@ func initssaconfig() {
|
||||
// asm funcs with special ABI
|
||||
if thearch.LinkArch.Name == "amd64" {
|
||||
GCWriteBarrierReg = map[int16]*obj.LSym{
|
||||
x86.REG_AX: sysfunc("gcWriteBarrier"),
|
||||
x86.REG_CX: sysfunc("gcWriteBarrierCX"),
|
||||
x86.REG_DX: sysfunc("gcWriteBarrierDX"),
|
||||
x86.REG_BX: sysfunc("gcWriteBarrierBX"),
|
||||
x86.REG_BP: sysfunc("gcWriteBarrierBP"),
|
||||
x86.REG_SI: sysfunc("gcWriteBarrierSI"),
|
||||
x86.REG_R8: sysfunc("gcWriteBarrierR8"),
|
||||
x86.REG_R9: sysfunc("gcWriteBarrierR9"),
|
||||
x86.REG_AX: sysvar("gcWriteBarrier"),
|
||||
x86.REG_CX: sysvar("gcWriteBarrierCX"),
|
||||
x86.REG_DX: sysvar("gcWriteBarrierDX"),
|
||||
x86.REG_BX: sysvar("gcWriteBarrierBX"),
|
||||
x86.REG_BP: sysvar("gcWriteBarrierBP"),
|
||||
x86.REG_SI: sysvar("gcWriteBarrierSI"),
|
||||
x86.REG_R8: sysvar("gcWriteBarrierR8"),
|
||||
x86.REG_R9: sysvar("gcWriteBarrierR9"),
|
||||
}
|
||||
}
|
||||
|
||||
if thearch.LinkArch.Family == sys.Wasm {
|
||||
BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("goPanicIndex")
|
||||
BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("goPanicIndexU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("goPanicSliceAlen")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("goPanicSliceAlenU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("goPanicSliceAcap")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("goPanicSliceAcapU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("goPanicSliceB")
|
||||
BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("goPanicSliceBU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("goPanicSlice3Alen")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("goPanicSlice3AlenU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("goPanicSlice3Acap")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("goPanicSlice3AcapU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("goPanicSlice3B")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("goPanicSlice3BU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("goPanicSlice3C")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("goPanicSlice3CU")
|
||||
BoundsCheckFunc[ssa.BoundsIndex] = sysvar("goPanicIndex")
|
||||
BoundsCheckFunc[ssa.BoundsIndexU] = sysvar("goPanicIndexU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAlen] = sysvar("goPanicSliceAlen")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysvar("goPanicSliceAlenU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAcap] = sysvar("goPanicSliceAcap")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysvar("goPanicSliceAcapU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceB] = sysvar("goPanicSliceB")
|
||||
BoundsCheckFunc[ssa.BoundsSliceBU] = sysvar("goPanicSliceBU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysvar("goPanicSlice3Alen")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysvar("goPanicSlice3AlenU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysvar("goPanicSlice3Acap")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysvar("goPanicSlice3AcapU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3B] = sysvar("goPanicSlice3B")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3BU] = sysvar("goPanicSlice3BU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3C] = sysvar("goPanicSlice3C")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3CU] = sysvar("goPanicSlice3CU")
|
||||
} else {
|
||||
BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("panicIndex")
|
||||
BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("panicIndexU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("panicSliceAlen")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("panicSliceAlenU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("panicSliceAcap")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("panicSliceAcapU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("panicSliceB")
|
||||
BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("panicSliceBU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("panicSlice3Alen")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("panicSlice3AlenU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("panicSlice3Acap")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("panicSlice3AcapU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("panicSlice3B")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("panicSlice3BU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("panicSlice3C")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("panicSlice3CU")
|
||||
BoundsCheckFunc[ssa.BoundsIndex] = sysvar("panicIndex")
|
||||
BoundsCheckFunc[ssa.BoundsIndexU] = sysvar("panicIndexU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAlen] = sysvar("panicSliceAlen")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysvar("panicSliceAlenU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAcap] = sysvar("panicSliceAcap")
|
||||
BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysvar("panicSliceAcapU")
|
||||
BoundsCheckFunc[ssa.BoundsSliceB] = sysvar("panicSliceB")
|
||||
BoundsCheckFunc[ssa.BoundsSliceBU] = sysvar("panicSliceBU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysvar("panicSlice3Alen")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysvar("panicSlice3AlenU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysvar("panicSlice3Acap")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysvar("panicSlice3AcapU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3B] = sysvar("panicSlice3B")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3BU] = sysvar("panicSlice3BU")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3C] = sysvar("panicSlice3C")
|
||||
BoundsCheckFunc[ssa.BoundsSlice3CU] = sysvar("panicSlice3CU")
|
||||
}
|
||||
if thearch.LinkArch.PtrSize == 4 {
|
||||
ExtendCheckFunc[ssa.BoundsIndex] = sysvar("panicExtendIndex")
|
||||
@@ -410,17 +409,11 @@ func buildssa(fn *Node, worker int) *ssa.Func {
|
||||
|
||||
// Generate addresses of local declarations
|
||||
s.decladdrs = map[*Node]*ssa.Value{}
|
||||
var args []ssa.Param
|
||||
var results []ssa.Param
|
||||
for _, n := range fn.Func.Dcl {
|
||||
switch n.Class() {
|
||||
case PPARAM:
|
||||
case PPARAM, PPARAMOUT:
|
||||
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem)
|
||||
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) {
|
||||
if n.Class() == PPARAMOUT && s.canSSA(n) {
|
||||
// Save ssa-able PPARAMOUT variables so we can
|
||||
// store them back to the stack at the end of
|
||||
// the function.
|
||||
@@ -967,45 +960,7 @@ func (s *state) newValueOrSfCall2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Valu
|
||||
return s.newValue2(op, t, arg0, arg1)
|
||||
}
|
||||
|
||||
type instrumentKind uint8
|
||||
|
||||
const (
|
||||
instrumentRead = iota
|
||||
instrumentWrite
|
||||
instrumentMove
|
||||
)
|
||||
|
||||
func (s *state) instrument(t *types.Type, addr *ssa.Value, kind instrumentKind) {
|
||||
s.instrument2(t, addr, nil, kind)
|
||||
}
|
||||
|
||||
// instrumentFields instruments a read/write operation on addr.
|
||||
// If it is instrumenting for MSAN and t is a struct type, it instruments
|
||||
// operation for each field, instead of for the whole struct.
|
||||
func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrumentKind) {
|
||||
if !flag_msan || !t.IsStruct() {
|
||||
s.instrument(t, addr, kind)
|
||||
return
|
||||
}
|
||||
for _, f := range t.Fields().Slice() {
|
||||
if f.Sym.IsBlank() {
|
||||
continue
|
||||
}
|
||||
offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr)
|
||||
s.instrumentFields(f.Type, offptr, kind)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *state) instrumentMove(t *types.Type, dst, src *ssa.Value) {
|
||||
if flag_msan {
|
||||
s.instrument2(t, dst, src, instrumentMove)
|
||||
} else {
|
||||
s.instrument(t, src, instrumentRead)
|
||||
s.instrument(t, dst, instrumentWrite)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *state) instrument2(t *types.Type, addr, addr2 *ssa.Value, kind instrumentKind) {
|
||||
func (s *state) instrument(t *types.Type, addr *ssa.Value, wr bool) {
|
||||
if !s.curfn.Func.InstrumentBody() {
|
||||
return
|
||||
}
|
||||
@@ -1022,54 +977,33 @@ func (s *state) instrument2(t *types.Type, addr, addr2 *ssa.Value, kind instrume
|
||||
var fn *obj.LSym
|
||||
needWidth := false
|
||||
|
||||
if addr2 != nil && kind != instrumentMove {
|
||||
panic("instrument2: non-nil addr2 for non-move instrumentation")
|
||||
}
|
||||
|
||||
if flag_msan {
|
||||
switch kind {
|
||||
case instrumentRead:
|
||||
fn = msanread
|
||||
case instrumentWrite:
|
||||
fn = msanread
|
||||
if wr {
|
||||
fn = msanwrite
|
||||
case instrumentMove:
|
||||
fn = msanmove
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
needWidth = true
|
||||
} else if flag_race && t.NumComponents(types.CountBlankFields) > 1 {
|
||||
// for composite objects we have to write every address
|
||||
// because a write might happen to any subobject.
|
||||
// composites with only one element don't have subobjects, though.
|
||||
switch kind {
|
||||
case instrumentRead:
|
||||
fn = racereadrange
|
||||
case instrumentWrite:
|
||||
fn = racereadrange
|
||||
if wr {
|
||||
fn = racewriterange
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
needWidth = true
|
||||
} else if flag_race {
|
||||
// for non-composite objects we can write just the start
|
||||
// address, as any write must write the first byte.
|
||||
switch kind {
|
||||
case instrumentRead:
|
||||
fn = raceread
|
||||
case instrumentWrite:
|
||||
fn = raceread
|
||||
if wr {
|
||||
fn = racewrite
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
} else {
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
args := []*ssa.Value{addr}
|
||||
if addr2 != nil {
|
||||
args = append(args, addr2)
|
||||
}
|
||||
if needWidth {
|
||||
args = append(args, s.constInt(types.Types[TUINTPTR], w))
|
||||
}
|
||||
@@ -1077,7 +1011,7 @@ func (s *state) instrument2(t *types.Type, addr, addr2 *ssa.Value, kind instrume
|
||||
}
|
||||
|
||||
func (s *state) load(t *types.Type, src *ssa.Value) *ssa.Value {
|
||||
s.instrumentFields(t, src, instrumentRead)
|
||||
s.instrument(t, src, false)
|
||||
return s.rawLoad(t, src)
|
||||
}
|
||||
|
||||
@@ -1090,14 +1024,15 @@ func (s *state) store(t *types.Type, dst, val *ssa.Value) {
|
||||
}
|
||||
|
||||
func (s *state) zero(t *types.Type, dst *ssa.Value) {
|
||||
s.instrument(t, dst, instrumentWrite)
|
||||
s.instrument(t, dst, true)
|
||||
store := s.newValue2I(ssa.OpZero, types.TypeMem, t.Size(), dst, s.mem())
|
||||
store.Aux = t
|
||||
s.vars[&memVar] = store
|
||||
}
|
||||
|
||||
func (s *state) move(t *types.Type, dst, src *ssa.Value) {
|
||||
s.instrumentMove(t, dst, src)
|
||||
s.instrument(t, src, false)
|
||||
s.instrument(t, dst, true)
|
||||
store := s.newValue3I(ssa.OpMove, types.TypeMem, t.Size(), dst, src, s.mem())
|
||||
store.Aux = t
|
||||
s.vars[&memVar] = store
|
||||
@@ -3517,64 +3452,14 @@ func init() {
|
||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
|
||||
},
|
||||
sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "Xchg64",
|
||||
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())
|
||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||
return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
|
||||
},
|
||||
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)
|
||||
sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||
|
||||
addF("runtime/internal/atomic", "Xadd",
|
||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||
@@ -3591,11 +3476,46 @@ func init() {
|
||||
},
|
||||
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",
|
||||
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, TUINT32, TUINT32, atomicXchgXaddEmitterARM64),
|
||||
makeXaddARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, TUINT32),
|
||||
sys.ARM64)
|
||||
addF("runtime/internal/atomic", "Xadd64",
|
||||
makeAtomicGuardedIntrinsicARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, TUINT64, TUINT64, atomicXchgXaddEmitterARM64),
|
||||
makeXaddARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, TUINT64),
|
||||
sys.ARM64)
|
||||
|
||||
addF("runtime/internal/atomic", "Cas",
|
||||
@@ -3604,14 +3524,14 @@ func init() {
|
||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||
return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
|
||||
},
|
||||
sys.AMD64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "Cas64",
|
||||
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())
|
||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||
return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v)
|
||||
},
|
||||
sys.AMD64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||
sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "CasRel",
|
||||
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())
|
||||
@@ -3620,31 +3540,18 @@ func init() {
|
||||
},
|
||||
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",
|
||||
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())
|
||||
return nil
|
||||
},
|
||||
sys.AMD64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||
sys.AMD64, sys.ARM64, 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)
|
||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "Or8",
|
||||
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())
|
||||
@@ -3656,24 +3563,7 @@ func init() {
|
||||
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)
|
||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||
|
||||
alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...)
|
||||
alias("runtime/internal/atomic", "Xaddint64", "runtime/internal/atomic", "Xadd64", all...)
|
||||
@@ -5019,7 +4909,7 @@ func (s *state) canSSA(n *Node) bool {
|
||||
if n.Class() == PPARAM && n.Sym != nil && n.Sym.Name == ".this" {
|
||||
// wrappers generated by genwrapper need to update
|
||||
// the .this pointer in place.
|
||||
// TODO: treat as a PPARAMOUT?
|
||||
// TODO: treat as a PPARMOUT?
|
||||
return false
|
||||
}
|
||||
return canSSAType(n.Type)
|
||||
@@ -5307,7 +5197,7 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
|
||||
|
||||
// do *left = right for type t.
|
||||
func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask, leftIsStmt bool) {
|
||||
s.instrument(t, left, instrumentWrite)
|
||||
s.instrument(t, left, true)
|
||||
|
||||
if skip == 0 && (!t.HasPointers() || ssa.IsStackAddr(left)) {
|
||||
// Known to not have write barrier. Store the whole type.
|
||||
@@ -5925,7 +5815,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
|
||||
// Load type out of itab, build interface with existing idata.
|
||||
off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), itab)
|
||||
typ := s.load(byteptr, off)
|
||||
idata := s.newValue1(ssa.OpIData, byteptr, iface)
|
||||
idata := s.newValue1(ssa.OpIData, n.Type, iface)
|
||||
res = s.newValue2(ssa.OpIMake, n.Type, typ, idata)
|
||||
return
|
||||
}
|
||||
@@ -5947,7 +5837,7 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
|
||||
bOk.AddEdgeTo(bEnd)
|
||||
bFail.AddEdgeTo(bEnd)
|
||||
s.startBlock(bEnd)
|
||||
idata := s.newValue1(ssa.OpIData, byteptr, iface)
|
||||
idata := s.newValue1(ssa.OpIData, n.Type, iface)
|
||||
res = s.newValue2(ssa.OpIMake, n.Type, s.variable(&typVar, byteptr), idata)
|
||||
resok = cond
|
||||
delete(s.vars, &typVar)
|
||||
@@ -6369,7 +6259,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
// instruction. We won't use the actual liveness map on a
|
||||
// control instruction. Just mark it something that is
|
||||
// preemptible, unless this function is "all unsafe".
|
||||
s.pp.nextLive = LivenessIndex{-1, allUnsafe(f)}
|
||||
s.pp.nextLive = LivenessIndex{-1, -1, allUnsafe(f)}
|
||||
|
||||
// Emit values in block
|
||||
thearch.SSAMarkMoves(&s, b)
|
||||
|
||||
@@ -344,22 +344,14 @@ func (n *Node) CanBeAnSSASym() {
|
||||
|
||||
// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
|
||||
type Name struct {
|
||||
Pack *Node // real package for import . names
|
||||
Pkg *types.Pkg // pkg for OPACK nodes
|
||||
// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
|
||||
// For a closure var, the ONAME node of the outer captured variable
|
||||
Defn *Node
|
||||
// The ODCLFUNC node (for a static function/method or a closure) in which
|
||||
// local variable or param is declared.
|
||||
Curfn *Node
|
||||
Param *Param // additional fields for ONAME, OTYPE
|
||||
Decldepth int32 // declaration loop depth, increased for every loop or label
|
||||
// Unique number for ONAME nodes within a function. Function outputs
|
||||
// (results) are numbered starting at one, followed by function inputs
|
||||
// (parameters), and then local variables. Vargen is used to distinguish
|
||||
// local variables/params with the same name.
|
||||
Vargen int32
|
||||
flags bitset16
|
||||
Pack *Node // real package for import . names
|
||||
Pkg *types.Pkg // pkg for OPACK nodes
|
||||
Defn *Node // initializing assignment
|
||||
Curfn *Node // function for local variables
|
||||
Param *Param // additional fields for ONAME, OTYPE
|
||||
Decldepth int32 // declaration loop depth, increased for every loop or label
|
||||
Vargen int32 // unique name for ONAME within a function. Function outputs are numbered starting at one.
|
||||
flags bitset16
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -499,12 +491,7 @@ type paramType struct {
|
||||
alias bool
|
||||
}
|
||||
|
||||
type irEmbed struct {
|
||||
Pos src.XPos
|
||||
Patterns []string
|
||||
}
|
||||
|
||||
type embedList []irEmbed
|
||||
type embedFileList []string
|
||||
|
||||
// Pragma returns the PragmaFlag for p, which must be for an OTYPE.
|
||||
func (p *Param) Pragma() PragmaFlag {
|
||||
@@ -552,28 +539,28 @@ func (p *Param) SetAlias(alias bool) {
|
||||
(*p.Extra).(*paramType).alias = alias
|
||||
}
|
||||
|
||||
// EmbedList returns the list of embedded files for p,
|
||||
// EmbedFiles returns the list of embedded files for p,
|
||||
// which must be for an ONAME var.
|
||||
func (p *Param) EmbedList() []irEmbed {
|
||||
func (p *Param) EmbedFiles() []string {
|
||||
if p.Extra == nil {
|
||||
return nil
|
||||
}
|
||||
return *(*p.Extra).(*embedList)
|
||||
return *(*p.Extra).(*embedFileList)
|
||||
}
|
||||
|
||||
// SetEmbedList sets the list of embedded files for p,
|
||||
// SetEmbedFiles sets the list of embedded files for p,
|
||||
// which must be for an ONAME var.
|
||||
func (p *Param) SetEmbedList(list []irEmbed) {
|
||||
func (p *Param) SetEmbedFiles(list []string) {
|
||||
if p.Extra == nil {
|
||||
if len(list) == 0 {
|
||||
return
|
||||
}
|
||||
f := embedList(list)
|
||||
f := embedFileList(list)
|
||||
p.Extra = new(interface{})
|
||||
*p.Extra = &f
|
||||
return
|
||||
}
|
||||
*(*p.Extra).(*embedList) = list
|
||||
*(*p.Extra).(*embedFileList) = list
|
||||
}
|
||||
|
||||
// Functions
|
||||
@@ -621,16 +608,10 @@ func (p *Param) SetEmbedList(list []irEmbed) {
|
||||
// Func holds Node fields used only with function-like nodes.
|
||||
type Func struct {
|
||||
Shortname *types.Sym
|
||||
// Extra entry code for the function. For example, allocate and initialize
|
||||
// memory for escaping parameters. However, just for OCLOSURE, Enter is a
|
||||
// list of ONAME nodes of captured variables
|
||||
Enter Nodes
|
||||
Exit Nodes
|
||||
// ONAME nodes for closure params, each should have closurevar set
|
||||
Cvars Nodes
|
||||
// ONAME nodes for all params/locals for this func/closure, does NOT
|
||||
// include closurevars until transformclosure runs.
|
||||
Dcl []*Node
|
||||
Enter Nodes // for example, allocate and initialize memory for escaping parameters
|
||||
Exit Nodes
|
||||
Cvars Nodes // closure params
|
||||
Dcl []*Node // autodcl for this func/closure
|
||||
|
||||
// Parents records the parent scope of each scope within a
|
||||
// function. The root scope (0) has no parent, so the i'th
|
||||
@@ -649,8 +630,8 @@ type Func struct {
|
||||
DebugInfo *ssa.FuncDebug
|
||||
Ntype *Node // signature
|
||||
Top int // top context (ctxCallee, etc)
|
||||
Closure *Node // OCLOSURE <-> ODCLFUNC (see header comment above)
|
||||
Nname *Node // The ONAME node associated with an ODCLFUNC (both have same Type)
|
||||
Closure *Node // OCLOSURE <-> ODCLFUNC
|
||||
Nname *Node
|
||||
lsym *obj.LSym
|
||||
|
||||
Inl *Inline
|
||||
@@ -699,8 +680,6 @@ const (
|
||||
funcWrapper // is method wrapper
|
||||
funcNeedctxt // function uses context register (has closure variables)
|
||||
funcReflectMethod // function calls reflect.Type.Method or MethodByName
|
||||
// true if closure inside a function; false if a simple function or a
|
||||
// closure in a global variable initialization
|
||||
funcIsHiddenClosure
|
||||
funcHasDefer // contains a defer statement
|
||||
funcNilCheckDisabled // disable nil checks when compiling this function
|
||||
@@ -752,10 +731,8 @@ const (
|
||||
OXXX Op = iota
|
||||
|
||||
// names
|
||||
ONAME // var or func name
|
||||
// Unnamed arg or return value: f(int, string) (int, error) { etc }
|
||||
// Also used for a qualified package identifier that hasn't been resolved yet.
|
||||
ONONAME
|
||||
ONAME // var or func name
|
||||
ONONAME // unnamed arg or return value: f(int, string) (int, error) { etc }
|
||||
OTYPE // type name
|
||||
OPACK // import
|
||||
OLITERAL // literal
|
||||
@@ -775,18 +752,14 @@ const (
|
||||
OSTR2BYTES // Type(Left) (Type is []byte, Left is a string)
|
||||
OSTR2BYTESTMP // Type(Left) (Type is []byte, Left is a string, ephemeral)
|
||||
OSTR2RUNES // Type(Left) (Type is []rune, Left is a string)
|
||||
// Left = Right or (if Colas=true) Left := Right
|
||||
// If Colas, then Ninit includes a DCL node for Left.
|
||||
OAS
|
||||
// List = Rlist (x, y, z = a, b, c) or (if Colas=true) List := Rlist
|
||||
// If Colas, then Ninit includes DCL nodes for List
|
||||
OAS2
|
||||
OAS2DOTTYPE // List = Right (x, ok = I.(int))
|
||||
OAS2FUNC // List = Right (x, y = f())
|
||||
OAS2MAPR // List = Right (x, ok = m["foo"])
|
||||
OAS2RECV // List = Right (x, ok = <-c)
|
||||
OASOP // Left Etype= Right (x += y)
|
||||
OCALL // Left(List) (function call, method call or type conversion)
|
||||
OAS // Left = Right or (if Colas=true) Left := Right
|
||||
OAS2 // List = Rlist (x, y, z = a, b, c)
|
||||
OAS2DOTTYPE // List = Right (x, ok = I.(int))
|
||||
OAS2FUNC // List = Right (x, y = f())
|
||||
OAS2MAPR // List = Right (x, ok = m["foo"])
|
||||
OAS2RECV // List = Right (x, ok = <-c)
|
||||
OASOP // Left Etype= Right (x += y)
|
||||
OCALL // Left(List) (function call, method call or type conversion)
|
||||
|
||||
// OCALLFUNC, OCALLMETH, and OCALLINTER have the same structure.
|
||||
// Prior to walk, they are: Left(List), where List is all regular arguments.
|
||||
@@ -800,7 +773,7 @@ const (
|
||||
OCALLPART // Left.Right (method expression x.Method, not called)
|
||||
OCAP // cap(Left)
|
||||
OCLOSE // close(Left)
|
||||
OCLOSURE // func Type { Func.Closure.Nbody } (func literal)
|
||||
OCLOSURE // func Type { Body } (func literal)
|
||||
OCOMPLIT // Right{List} (composite literal, not yet lowered to specific form)
|
||||
OMAPLIT // Type{List} (composite literal, Type is map)
|
||||
OSTRUCTLIT // Type{List} (composite literal, Type is struct)
|
||||
@@ -890,14 +863,9 @@ const (
|
||||
OSIZEOF // unsafe.Sizeof(Left)
|
||||
|
||||
// statements
|
||||
OBLOCK // { List } (block of code)
|
||||
OBREAK // break [Sym]
|
||||
// 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
|
||||
OBLOCK // { List } (block of code)
|
||||
OBREAK // break [Sym]
|
||||
OCASE // case List: Nbody (List==nil means default)
|
||||
OCONTINUE // continue [Sym]
|
||||
ODEFER // defer Left (Left must be call)
|
||||
OEMPTY // no-op (empty statement)
|
||||
@@ -921,19 +889,15 @@ const (
|
||||
ORETURN // return List
|
||||
OSELECT // select { List } (List is list of OCASE)
|
||||
OSWITCH // switch Ninit; Left { List } (List is a list of OCASE)
|
||||
// OTYPESW: Left := Right.(type) (appears as .Left of OSWITCH)
|
||||
// Left is nil if there is no type-switch variable
|
||||
OTYPESW
|
||||
OTYPESW // Left = Right.(type) (appears as .Left of OSWITCH)
|
||||
|
||||
// types
|
||||
OTCHAN // chan int
|
||||
OTMAP // map[string]int
|
||||
OTSTRUCT // struct{}
|
||||
OTINTER // interface{}
|
||||
// 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
|
||||
OTFUNC // func()
|
||||
OTARRAY // []int, [8]int, [N]int or [...]int
|
||||
|
||||
// misc
|
||||
ODDD // func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}.
|
||||
|
||||
@@ -6,6 +6,7 @@ package gc
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/objabi"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
@@ -2064,6 +2065,11 @@ func typecheck1(n *Node, top int) (res *Node) {
|
||||
n.Type = nil
|
||||
return n
|
||||
|
||||
case OCASE:
|
||||
ok |= ctxStmt
|
||||
typecheckslice(n.List.Slice(), ctxExpr)
|
||||
typecheckslice(n.Nbody.Slice(), ctxStmt)
|
||||
|
||||
case ODCLFUNC:
|
||||
ok |= ctxStmt
|
||||
typecheckfunc(n)
|
||||
@@ -2441,6 +2447,15 @@ func derefall(t *types.Type) *types.Type {
|
||||
return t
|
||||
}
|
||||
|
||||
type typeSymKey struct {
|
||||
t *types.Type
|
||||
s *types.Sym
|
||||
}
|
||||
|
||||
// dotField maps (*types.Type, *types.Sym) pairs to the corresponding struct field (*types.Type with Etype==TFIELD).
|
||||
// It is a cache for use during usefield in walk.go, only enabled when field tracking.
|
||||
var dotField = map[typeSymKey]*types.Field{}
|
||||
|
||||
func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
|
||||
s := n.Sym
|
||||
|
||||
@@ -2471,6 +2486,9 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
|
||||
}
|
||||
n.Xoffset = f1.Offset
|
||||
n.Type = f1.Type
|
||||
if objabi.Fieldtrack_enabled > 0 {
|
||||
dotField[typeSymKey{t.Orig, s}] = f1
|
||||
}
|
||||
if t.IsInterface() {
|
||||
if n.Left.Type.IsPtr() {
|
||||
n.Left = nod(ODEREF, n.Left, nil) // implicitstar
|
||||
@@ -2479,8 +2497,6 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
|
||||
}
|
||||
|
||||
n.Op = ODOTINTER
|
||||
} else {
|
||||
n.SetOpt(f1)
|
||||
}
|
||||
|
||||
return f1
|
||||
|
||||
@@ -267,7 +267,7 @@ func walkstmt(n *Node) *Node {
|
||||
if n.List.Len() == 0 {
|
||||
break
|
||||
}
|
||||
if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) || Curfn.Func.HasDefer() {
|
||||
if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
|
||||
// assign to the function out parameters,
|
||||
// so that reorder3 can fix up conflicts
|
||||
var rl []*Node
|
||||
@@ -989,7 +989,7 @@ opswitch:
|
||||
// runtime calls late in SSA processing.
|
||||
if Widthreg < 8 && (et == TINT64 || et == TUINT64) {
|
||||
if n.Right.Op == OLITERAL {
|
||||
// Leave div/mod by constant powers of 2 or small 16-bit constants.
|
||||
// Leave div/mod by constant powers of 2.
|
||||
// The SSA backend will handle those.
|
||||
switch et {
|
||||
case TINT64:
|
||||
@@ -1002,9 +1002,6 @@ opswitch:
|
||||
}
|
||||
case TUINT64:
|
||||
c := uint64(n.Right.Int64Val())
|
||||
if c < 1<<16 {
|
||||
break opswitch
|
||||
}
|
||||
if c != 0 && c&(c-1) == 0 {
|
||||
break opswitch
|
||||
}
|
||||
@@ -2233,15 +2230,7 @@ func aliased(r *Node, all []*Node) bool {
|
||||
memwrite = true
|
||||
continue
|
||||
|
||||
case PPARAMOUT:
|
||||
// Assignments to a result parameter in a function with defers
|
||||
// becomes visible early if evaluation of any later expression
|
||||
// panics (#43835).
|
||||
if Curfn.Func.HasDefer() {
|
||||
return true
|
||||
}
|
||||
fallthrough
|
||||
case PAUTO, PPARAM:
|
||||
case PAUTO, PPARAM, PPARAMOUT:
|
||||
if l.Name.Addrtaken() {
|
||||
memwrite = true
|
||||
continue
|
||||
@@ -3742,13 +3731,10 @@ func usefield(n *Node) {
|
||||
if t.IsPtr() {
|
||||
t = t.Elem()
|
||||
}
|
||||
field := n.Opt().(*types.Field)
|
||||
field := dotField[typeSymKey{t.Orig, n.Sym}]
|
||||
if field == nil {
|
||||
Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
|
||||
}
|
||||
if field.Sym != n.Sym || field.Offset != n.Xoffset {
|
||||
Fatalf("field inconsistency: %v,%v != %v,%v", field.Sym, field.Offset, n.Sym, n.Xoffset)
|
||||
}
|
||||
if !strings.Contains(field.Note, "go:\"track\"") {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ func want(t *testing.T, out string, desired string) {
|
||||
|
||||
func wantN(t *testing.T, out string, desired string, n int) {
|
||||
if strings.Count(out, desired) != n {
|
||||
t.Errorf("expected exactly %d occurrences of %s in \n%s", n, desired, out)
|
||||
t.Errorf("expected exactly %d occurences of %s in \n%s", n, desired, out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,15 +213,15 @@ func s15a8(x *[15]int64) [15]int64 {
|
||||
`"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: 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: ~R0 = y:"},`+
|
||||
`{"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":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":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":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 ~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 = ~R0:"},`+
|
||||
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":3},"end":{"line":9,"character":3}}},"message":"escflow: from return (*int)(~R0) (return)"}]}`)
|
||||
`{"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":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: from return (*int)(~r1) (return)"}]}`)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1781,9 +1781,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
pp := s.Call(v)
|
||||
pp.To.Reg = ppc64.REG_LR
|
||||
|
||||
// Insert a hint this is not a subroutine return.
|
||||
pp.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: 1})
|
||||
|
||||
if gc.Ctxt.Flag_shared {
|
||||
// When compiling Go into PIC, the function we just
|
||||
// called via pointer might have been implemented in
|
||||
|
||||
@@ -182,23 +182,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
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{
|
||||
p.RestArgs = []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}
|
||||
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}
|
||||
case ssa.OpS390XADD, ssa.OpS390XADDW,
|
||||
ssa.OpS390XSUB, ssa.OpS390XSUBW,
|
||||
@@ -372,7 +360,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst,
|
||||
ssa.OpS390XSRDconst, ssa.OpS390XSRWconst,
|
||||
ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst,
|
||||
ssa.OpS390XRLLconst:
|
||||
ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = v.AuxInt
|
||||
@@ -925,7 +913,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = int64(s390x.NotEqual & s390x.NotUnordered) // unordered is not possible
|
||||
p.Reg = s390x.REG_R3
|
||||
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: 0})
|
||||
p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: 0}}
|
||||
if b.Succs[0].Block() != next {
|
||||
s.Br(s390x.ABR, b.Succs[0].Block())
|
||||
}
|
||||
@@ -968,17 +956,17 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
||||
p.Reg = b.Controls[0].Reg()
|
||||
p.SetFrom3(obj.Addr{Type: obj.TYPE_REG, Reg: b.Controls[1].Reg()})
|
||||
p.RestArgs = []obj.Addr{{Type: obj.TYPE_REG, Reg: b.Controls[1].Reg()}}
|
||||
case ssa.BlockS390XCGIJ, ssa.BlockS390XCIJ:
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
||||
p.Reg = b.Controls[0].Reg()
|
||||
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(int8(b.AuxInt))})
|
||||
p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: int64(int8(b.AuxInt))}}
|
||||
case ssa.BlockS390XCLGIJ, ssa.BlockS390XCLIJ:
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = int64(mask & s390x.NotUnordered) // unordered is not possible
|
||||
p.Reg = b.Controls[0].Reg()
|
||||
p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(uint8(b.AuxInt))})
|
||||
p.RestArgs = []obj.Addr{{Type: obj.TYPE_CONST, Offset: int64(uint8(b.AuxInt))}}
|
||||
default:
|
||||
b.Fatalf("branch not implemented: %s", b.LongString())
|
||||
}
|
||||
|
||||
@@ -147,11 +147,6 @@ func checkFunc(f *Func) {
|
||||
canHaveAuxInt = true
|
||||
case auxInt128:
|
||||
// AuxInt must be zero, so leave canHaveAuxInt set to false.
|
||||
case auxUInt8:
|
||||
if v.AuxInt != int64(uint8(v.AuxInt)) {
|
||||
f.Fatalf("bad uint8 AuxInt value for %v", v)
|
||||
}
|
||||
canHaveAuxInt = true
|
||||
case auxFloat32:
|
||||
canHaveAuxInt = true
|
||||
if math.IsNaN(v.AuxFloat()) {
|
||||
|
||||
@@ -304,39 +304,37 @@ commas. For example:
|
||||
`
|
||||
}
|
||||
|
||||
if phase == "check" {
|
||||
switch flag {
|
||||
case "on":
|
||||
checkEnabled = val != 0
|
||||
debugPoset = checkEnabled // also turn on advanced self-checking in prove's datastructure
|
||||
return ""
|
||||
case "off":
|
||||
checkEnabled = val == 0
|
||||
debugPoset = checkEnabled
|
||||
return ""
|
||||
case "seed":
|
||||
checkEnabled = true
|
||||
checkRandSeed = val
|
||||
debugPoset = checkEnabled
|
||||
return ""
|
||||
}
|
||||
if phase == "check" && flag == "on" {
|
||||
checkEnabled = val != 0
|
||||
debugPoset = checkEnabled // also turn on advanced self-checking in prove's datastructure
|
||||
return ""
|
||||
}
|
||||
if phase == "check" && flag == "off" {
|
||||
checkEnabled = val == 0
|
||||
debugPoset = checkEnabled
|
||||
return ""
|
||||
}
|
||||
if phase == "check" && flag == "seed" {
|
||||
checkEnabled = true
|
||||
checkRandSeed = val
|
||||
debugPoset = checkEnabled
|
||||
return ""
|
||||
}
|
||||
|
||||
alltime := false
|
||||
allmem := false
|
||||
alldump := false
|
||||
if phase == "all" {
|
||||
switch flag {
|
||||
case "time":
|
||||
if flag == "time" {
|
||||
alltime = val != 0
|
||||
case "mem":
|
||||
} else if flag == "mem" {
|
||||
allmem = val != 0
|
||||
case "dump":
|
||||
} else if flag == "dump" {
|
||||
alldump = val != 0
|
||||
if alldump {
|
||||
BuildDump = valString
|
||||
}
|
||||
default:
|
||||
} else {
|
||||
return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
|
||||
}
|
||||
}
|
||||
@@ -431,7 +429,7 @@ var passes = [...]pass{
|
||||
{name: "early copyelim", fn: copyelim},
|
||||
{name: "early deadcode", fn: deadcode}, // remove generated dead code to avoid doing pointless work during opt
|
||||
{name: "short circuit", fn: shortcircuit},
|
||||
{name: "decompose args", fn: decomposeArgs, required: !go116lateCallExpansion, disabled: go116lateCallExpansion}, // handled by late call lowering
|
||||
{name: "decompose args", fn: decomposeArgs, required: true},
|
||||
{name: "decompose user", fn: decomposeUser, required: true},
|
||||
{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
|
||||
|
||||
@@ -199,9 +199,9 @@ const (
|
||||
const go116lateCallExpansion = true
|
||||
|
||||
// LateCallExpansionEnabledWithin returns true if late call expansion should be tested
|
||||
// within compilation of a function/method.
|
||||
// within compilation of a function/method triggered by GOSSAHASH (defaults to "yes").
|
||||
func LateCallExpansionEnabledWithin(f *Func) bool {
|
||||
return go116lateCallExpansion
|
||||
return go116lateCallExpansion && f.DebugTest // Currently set up for GOSSAHASH bug searches
|
||||
}
|
||||
|
||||
// NewConfig returns a new configuration object for the given architecture.
|
||||
|
||||
@@ -15,7 +15,7 @@ type selKey struct {
|
||||
from *Value
|
||||
offset int64
|
||||
size int64
|
||||
typ *types.Type
|
||||
typ types.EType
|
||||
}
|
||||
|
||||
type offsetKey struct {
|
||||
@@ -27,8 +27,7 @@ type offsetKey struct {
|
||||
// expandCalls converts LE (Late Expansion) calls that act like they receive value args into a lower-level form
|
||||
// that is more oriented to a platform's ABI. The SelectN operations that extract results are rewritten into
|
||||
// more appropriate forms, and any StructMake or ArrayMake inputs are decomposed until non-struct values are
|
||||
// reached. On the callee side, OpArg nodes are not decomposed until this phase is run.
|
||||
// TODO results should not be lowered until this phase.
|
||||
// reached.
|
||||
func expandCalls(f *Func) {
|
||||
// Calls that need lowering have some number of inputs, including a memory input,
|
||||
// and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able.
|
||||
@@ -43,10 +42,6 @@ func expandCalls(f *Func) {
|
||||
}
|
||||
debug := f.pass.debug > 0
|
||||
|
||||
if debug {
|
||||
fmt.Printf("\nexpandsCalls(%s)\n", f.Name)
|
||||
}
|
||||
|
||||
canSSAType := f.fe.CanSSA
|
||||
regSize := f.Config.RegSize
|
||||
sp, _ := f.spSb()
|
||||
@@ -63,10 +58,6 @@ func expandCalls(f *Func) {
|
||||
|
||||
namedSelects := make(map[*Value][]namedVal)
|
||||
|
||||
sdom := f.Sdom()
|
||||
|
||||
common := make(map[selKey]*Value)
|
||||
|
||||
// intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target
|
||||
// that has no 64-bit integer registers.
|
||||
intPairTypes := func(et types.EType) (tHi, tLo *types.Type) {
|
||||
@@ -116,7 +107,6 @@ func expandCalls(f *Func) {
|
||||
return v
|
||||
}
|
||||
|
||||
// splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates.
|
||||
splitSlots := func(ls []LocalSlot, sfx string, offset int64, ty *types.Type) []LocalSlot {
|
||||
var locs []LocalSlot
|
||||
for i := range ls {
|
||||
@@ -157,104 +147,21 @@ func expandCalls(f *Func) {
|
||||
// With the current ABI, the outputs need to be converted to loads, which will all use the call's
|
||||
// memory output as their input.
|
||||
|
||||
// rewriteSelect recursively walks from leaf selector to a root (OpSelectN, OpLoad, OpArg)
|
||||
// through a chain of Struct/Array/builtin Select operations. If the chain of selectors does not
|
||||
// end in an expected root, it does nothing (this can happen depending on compiler phase ordering).
|
||||
// The "leaf" provides the type, the root supplies the container, and the leaf-to-root path
|
||||
// accumulates the offset.
|
||||
// It emits the code necessary to implement the leaf select operation that leads to the root.
|
||||
//
|
||||
// rewriteSelect recursively walks leaf selector to a root (OpSelectN) through
|
||||
// a chain of Struct/Array Select operations. If the chain of selectors does not
|
||||
// end in OpSelectN, it does nothing (this can happen depending on compiler phase ordering).
|
||||
// It emits the code necessary to implement the leaf select operation that leads to the call.
|
||||
// TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
|
||||
var rewriteSelect func(leaf *Value, selector *Value, offset int64) []LocalSlot
|
||||
rewriteSelect = func(leaf *Value, selector *Value, offset int64) []LocalSlot {
|
||||
if debug {
|
||||
fmt.Printf("rewriteSelect(%s, %s, %d)\n", leaf.LongString(), selector.LongString(), offset)
|
||||
}
|
||||
var locs []LocalSlot
|
||||
leafType := leaf.Type
|
||||
if len(selector.Args) > 0 {
|
||||
w := selector.Args[0]
|
||||
if w.Op == OpCopy {
|
||||
for w.Op == OpCopy {
|
||||
w = w.Args[0]
|
||||
}
|
||||
selector.SetArg(0, w)
|
||||
}
|
||||
}
|
||||
switch selector.Op {
|
||||
case OpArg:
|
||||
if !isAlreadyExpandedAggregateType(selector.Type) {
|
||||
if leafType == selector.Type { // OpIData leads us here, sometimes.
|
||||
leaf.copyOf(selector)
|
||||
} else {
|
||||
f.Fatalf("Unexpected OpArg type, selector=%s, leaf=%s\n", selector.LongString(), leaf.LongString())
|
||||
}
|
||||
if debug {
|
||||
fmt.Printf("\tOpArg, break\n")
|
||||
}
|
||||
break
|
||||
}
|
||||
switch leaf.Op {
|
||||
case OpIData, OpStructSelect, OpArraySelect:
|
||||
leafType = removeTrivialWrapperTypes(leaf.Type)
|
||||
}
|
||||
aux := selector.Aux
|
||||
auxInt := selector.AuxInt + offset
|
||||
if leaf.Block == selector.Block {
|
||||
leaf.reset(OpArg)
|
||||
leaf.Aux = aux
|
||||
leaf.AuxInt = auxInt
|
||||
leaf.Type = leafType
|
||||
} else {
|
||||
w := selector.Block.NewValue0IA(leaf.Pos, OpArg, leafType, auxInt, aux)
|
||||
leaf.copyOf(w)
|
||||
if debug {
|
||||
fmt.Printf("\tnew %s\n", w.LongString())
|
||||
}
|
||||
}
|
||||
for _, s := range namedSelects[selector] {
|
||||
locs = append(locs, f.Names[s.locIndex])
|
||||
}
|
||||
|
||||
case OpLoad: // We end up here because of IData of immediate structures.
|
||||
// Failure case:
|
||||
// (note the failure case is very rare; w/o this case, make.bash and run.bash both pass, as well as
|
||||
// the hard cases of building {syscall,math,math/cmplx,math/bits,go/constant} on ppc64le and mips-softfloat).
|
||||
//
|
||||
// GOSSAFUNC='(*dumper).dump' go build -gcflags=-l -tags=math_big_pure_go cmd/compile/internal/gc
|
||||
// cmd/compile/internal/gc/dump.go:136:14: internal compiler error: '(*dumper).dump': not lowered: v827, StructSelect PTR PTR
|
||||
// b2: ← b1
|
||||
// v20 (+142) = StaticLECall <interface {},mem> {AuxCall{reflect.Value.Interface([reflect.Value,0])[interface {},24]}} [40] v8 v1
|
||||
// v21 (142) = SelectN <mem> [1] v20
|
||||
// v22 (142) = SelectN <interface {}> [0] v20
|
||||
// b15: ← b8
|
||||
// v71 (+143) = IData <Nodes> v22 (v[Nodes])
|
||||
// v73 (+146) = StaticLECall <[]*Node,mem> {AuxCall{"".Nodes.Slice([Nodes,0])[[]*Node,8]}} [32] v71 v21
|
||||
//
|
||||
// translates (w/o the "case OpLoad:" above) to:
|
||||
//
|
||||
// b2: ← b1
|
||||
// v20 (+142) = StaticCall <mem> {AuxCall{reflect.Value.Interface([reflect.Value,0])[interface {},24]}} [40] v715
|
||||
// v23 (142) = Load <*uintptr> v19 v20
|
||||
// v823 (142) = IsNonNil <bool> v23
|
||||
// v67 (+143) = Load <*[]*Node> v880 v20
|
||||
// b15: ← b8
|
||||
// v827 (146) = StructSelect <*[]*Node> [0] v67
|
||||
// v846 (146) = Store <mem> {*[]*Node} v769 v827 v20
|
||||
// v73 (+146) = StaticCall <mem> {AuxCall{"".Nodes.Slice([Nodes,0])[[]*Node,8]}} [32] v846
|
||||
// i.e., the struct select is generated and remains in because it is not applied to an actual structure.
|
||||
// The OpLoad was created to load the single field of the IData
|
||||
// This case removes that StructSelect.
|
||||
if leafType != selector.Type {
|
||||
f.Fatalf("Unexpected Load as selector, leaf=%s, selector=%s\n", leaf.LongString(), selector.LongString())
|
||||
}
|
||||
leaf.copyOf(selector)
|
||||
for _, s := range namedSelects[selector] {
|
||||
locs = append(locs, f.Names[s.locIndex])
|
||||
}
|
||||
|
||||
case OpSelectN:
|
||||
// TODO these may be duplicated. Should memoize. Intermediate selectors will go dead, no worries there.
|
||||
for _, s := range namedSelects[selector] {
|
||||
locs = append(locs, f.Names[s.locIndex])
|
||||
}
|
||||
call := selector.Args[0]
|
||||
aux := call.Aux.(*AuxCall)
|
||||
which := selector.AuxInt
|
||||
@@ -264,6 +171,10 @@ func expandCalls(f *Func) {
|
||||
} else {
|
||||
leafType := removeTrivialWrapperTypes(leaf.Type)
|
||||
if canSSAType(leafType) {
|
||||
for leafType.Etype == types.TSTRUCT && leafType.NumFields() == 1 {
|
||||
// This may not be adequately general -- consider [1]etc but this is caused by immediate IDATA
|
||||
leafType = leafType.Field(0).Type
|
||||
}
|
||||
pt := types.NewPtr(leafType)
|
||||
off := offsetFrom(sp, offset+aux.OffsetOfResult(which), pt)
|
||||
// Any selection right out of the arg area/registers has to be same Block as call, use call as mem input.
|
||||
@@ -274,29 +185,22 @@ func expandCalls(f *Func) {
|
||||
} else {
|
||||
w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call)
|
||||
leaf.copyOf(w)
|
||||
if debug {
|
||||
fmt.Printf("\tnew %s\n", w.LongString())
|
||||
}
|
||||
}
|
||||
for _, s := range namedSelects[selector] {
|
||||
locs = append(locs, f.Names[s.locIndex])
|
||||
}
|
||||
} else {
|
||||
f.Fatalf("Should not have non-SSA-able OpSelectN, selector=%s", selector.LongString())
|
||||
}
|
||||
}
|
||||
|
||||
case OpStructSelect:
|
||||
w := selector.Args[0]
|
||||
var ls []LocalSlot
|
||||
if w.Type.Etype != types.TSTRUCT { // IData artifact
|
||||
if w.Type.Etype != types.TSTRUCT {
|
||||
f.Fatalf("Bad type for w: v=%v; sel=%v; w=%v; ,f=%s\n", leaf.LongString(), selector.LongString(), w.LongString(), f.Name)
|
||||
// Artifact of immediate interface idata
|
||||
ls = rewriteSelect(leaf, w, offset)
|
||||
} else {
|
||||
ls = rewriteSelect(leaf, w, offset+w.Type.FieldOff(int(selector.AuxInt)))
|
||||
if w.Op != OpIData {
|
||||
for _, l := range ls {
|
||||
locs = append(locs, f.fe.SplitStruct(l, int(selector.AuxInt)))
|
||||
}
|
||||
for _, l := range ls {
|
||||
locs = append(locs, f.fe.SplitStruct(l, int(selector.AuxInt)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,7 +221,9 @@ func expandCalls(f *Func) {
|
||||
case OpStringPtr:
|
||||
ls := rewriteSelect(leaf, selector.Args[0], offset)
|
||||
locs = splitSlots(ls, ".ptr", 0, typ.BytePtr)
|
||||
|
||||
//for i := range ls {
|
||||
// locs = append(locs, f.fe.SplitSlot(&ls[i], ".ptr", 0, typ.BytePtr))
|
||||
//}
|
||||
case OpSlicePtr:
|
||||
w := selector.Args[0]
|
||||
ls := rewriteSelect(leaf, w, offset)
|
||||
@@ -366,130 +272,32 @@ func expandCalls(f *Func) {
|
||||
return locs
|
||||
}
|
||||
|
||||
// storeArgOrLoad converts stores of SSA-able aggregate arguments (passed to a call) into a series of primitive-typed
|
||||
// stores of non-aggregate types. It recursively walks up a chain of selectors until it reaches a Load or an Arg.
|
||||
// If it does not reach a Load or an Arg, nothing happens; this allows a little freedom in phase ordering.
|
||||
var storeArgOrLoad func(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64) *Value
|
||||
|
||||
// decomposeArgOrLoad is a helper for storeArgOrLoad.
|
||||
// It decomposes a Load or an Arg into smaller parts, parameterized by the decomposeOne and decomposeTwo functions
|
||||
// passed to it, and returns the new mem. If the type does not match one of the expected aggregate types, it returns nil instead.
|
||||
decomposeArgOrLoad := func(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64,
|
||||
decomposeOne func(pos src.XPos, b *Block, base, source, mem *Value, t1 *types.Type, offArg, offStore int64) *Value,
|
||||
decomposeTwo func(pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64) *Value) *Value {
|
||||
u := source.Type
|
||||
switch u.Etype {
|
||||
case types.TARRAY:
|
||||
elem := u.Elem()
|
||||
for i := int64(0); i < u.NumElem(); i++ {
|
||||
elemOff := i * elem.Size()
|
||||
mem = decomposeOne(pos, b, base, source, mem, elem, source.AuxInt+elemOff, offset+elemOff)
|
||||
pos = pos.WithNotStmt()
|
||||
}
|
||||
return mem
|
||||
case types.TSTRUCT:
|
||||
for i := 0; i < u.NumFields(); i++ {
|
||||
fld := u.Field(i)
|
||||
mem = decomposeOne(pos, b, base, source, mem, fld.Type, source.AuxInt+fld.Offset, offset+fld.Offset)
|
||||
pos = pos.WithNotStmt()
|
||||
}
|
||||
return mem
|
||||
case types.TINT64, types.TUINT64:
|
||||
if t.Width == regSize {
|
||||
break
|
||||
}
|
||||
tHi, tLo := intPairTypes(t.Etype)
|
||||
mem = decomposeOne(pos, b, base, source, mem, tHi, source.AuxInt+hiOffset, offset+hiOffset)
|
||||
pos = pos.WithNotStmt()
|
||||
return decomposeOne(pos, b, base, source, mem, tLo, source.AuxInt+lowOffset, offset+lowOffset)
|
||||
case types.TINTER:
|
||||
return decomposeTwo(pos, b, base, source, mem, typ.Uintptr, typ.BytePtr, source.AuxInt, offset)
|
||||
case types.TSTRING:
|
||||
return decomposeTwo(pos, b, base, source, mem, typ.BytePtr, typ.Int, source.AuxInt, offset)
|
||||
case types.TCOMPLEX64:
|
||||
return decomposeTwo(pos, b, base, source, mem, typ.Float32, typ.Float32, source.AuxInt, offset)
|
||||
case types.TCOMPLEX128:
|
||||
return decomposeTwo(pos, b, base, source, mem, typ.Float64, typ.Float64, source.AuxInt, offset)
|
||||
case types.TSLICE:
|
||||
mem = decomposeTwo(pos, b, base, source, mem, typ.BytePtr, typ.Int, source.AuxInt, offset)
|
||||
return decomposeOne(pos, b, base, source, mem, typ.Int, source.AuxInt+2*ptrSize, offset+2*ptrSize)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// storeOneArg creates a decomposed (one step) arg that is then stored.
|
||||
// pos and b locate the store instruction, base is the base of the store target, source is the "base" of the value input,
|
||||
// mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases.
|
||||
storeOneArg := func(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64) *Value {
|
||||
w := common[selKey{source, offArg, t.Width, t}]
|
||||
if w == nil {
|
||||
w = source.Block.NewValue0IA(source.Pos, OpArg, t, offArg, source.Aux)
|
||||
common[selKey{source, offArg, t.Width, t}] = w
|
||||
}
|
||||
return storeArgOrLoad(pos, b, base, w, mem, t, offStore)
|
||||
}
|
||||
|
||||
// storeOneLoad creates a decomposed (one step) load that is then stored.
|
||||
storeOneLoad := func(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64) *Value {
|
||||
from := offsetFrom(source.Args[0], offArg, types.NewPtr(t))
|
||||
w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem)
|
||||
return storeArgOrLoad(pos, b, base, w, mem, t, offStore)
|
||||
}
|
||||
|
||||
storeTwoArg := func(pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64) *Value {
|
||||
mem = storeOneArg(pos, b, base, source, mem, t1, offArg, offStore)
|
||||
pos = pos.WithNotStmt()
|
||||
t1Size := t1.Size()
|
||||
return storeOneArg(pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size)
|
||||
}
|
||||
|
||||
storeTwoLoad := func(pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64) *Value {
|
||||
mem = storeOneLoad(pos, b, base, source, mem, t1, offArg, offStore)
|
||||
pos = pos.WithNotStmt()
|
||||
t1Size := t1.Size()
|
||||
return storeOneLoad(pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size)
|
||||
}
|
||||
|
||||
storeArgOrLoad = func(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64) *Value {
|
||||
// storeArg converts stores of SSA-able aggregate arguments (passed to a call) into a series of stores of
|
||||
// smaller types into individual parameter slots.
|
||||
var storeArg func(pos src.XPos, b *Block, a *Value, t *types.Type, offset int64, mem *Value) *Value
|
||||
storeArg = func(pos src.XPos, b *Block, a *Value, t *types.Type, offset int64, mem *Value) *Value {
|
||||
if debug {
|
||||
fmt.Printf("\tstoreArgOrLoad(%s; %s; %s; %s; %d)\n", base.LongString(), source.LongString(), mem.String(), t.String(), offset)
|
||||
fmt.Printf("\tstoreArg(%s; %s; %v; %d; %s)\n", b, a.LongString(), t, offset, mem.String())
|
||||
}
|
||||
|
||||
switch source.Op {
|
||||
case OpCopy:
|
||||
return storeArgOrLoad(pos, b, base, source.Args[0], mem, t, offset)
|
||||
|
||||
case OpLoad:
|
||||
ret := decomposeArgOrLoad(pos, b, base, source, mem, t, offset, storeOneLoad, storeTwoLoad)
|
||||
if ret != nil {
|
||||
return ret
|
||||
}
|
||||
|
||||
case OpArg:
|
||||
ret := decomposeArgOrLoad(pos, b, base, source, mem, t, offset, storeOneArg, storeTwoArg)
|
||||
if ret != nil {
|
||||
return ret
|
||||
}
|
||||
|
||||
switch a.Op {
|
||||
case OpArrayMake0, OpStructMake0:
|
||||
return mem
|
||||
|
||||
case OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4:
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
fld := t.Field(i)
|
||||
mem = storeArgOrLoad(pos, b, base, source.Args[i], mem, fld.Type, offset+fld.Offset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = storeArg(pos, b, a.Args[i], fld.Type, offset+fld.Offset, mem)
|
||||
}
|
||||
return mem
|
||||
|
||||
case OpArrayMake1:
|
||||
return storeArgOrLoad(pos, b, base, source.Args[0], mem, t.Elem(), offset)
|
||||
return storeArg(pos, b, a.Args[0], t.Elem(), offset, mem)
|
||||
|
||||
case OpInt64Make:
|
||||
tHi, tLo := intPairTypes(t.Etype)
|
||||
mem = storeArgOrLoad(pos, b, base, source.Args[0], mem, tHi, offset+hiOffset)
|
||||
pos = pos.WithNotStmt()
|
||||
return storeArgOrLoad(pos, b, base, source.Args[1], mem, tLo, offset+lowOffset)
|
||||
mem = storeArg(pos, b, a.Args[0], tHi, offset+hiOffset, mem)
|
||||
return storeArg(pos, b, a.Args[1], tLo, offset+lowOffset, mem)
|
||||
|
||||
case OpComplexMake:
|
||||
tPart := typ.Float32
|
||||
@@ -497,45 +305,59 @@ func expandCalls(f *Func) {
|
||||
if wPart == 8 {
|
||||
tPart = typ.Float64
|
||||
}
|
||||
mem = storeArgOrLoad(pos, b, base, source.Args[0], mem, tPart, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
return storeArgOrLoad(pos, b, base, source.Args[1], mem, tPart, offset+wPart)
|
||||
mem = storeArg(pos, b, a.Args[0], tPart, offset, mem)
|
||||
return storeArg(pos, b, a.Args[1], tPart, offset+wPart, mem)
|
||||
|
||||
case OpIMake:
|
||||
mem = storeArgOrLoad(pos, b, base, source.Args[0], mem, typ.Uintptr, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
return storeArgOrLoad(pos, b, base, source.Args[1], mem, typ.BytePtr, offset+ptrSize)
|
||||
mem = storeArg(pos, b, a.Args[0], typ.Uintptr, offset, mem)
|
||||
return storeArg(pos, b, a.Args[1], typ.BytePtr, offset+ptrSize, mem)
|
||||
|
||||
case OpStringMake:
|
||||
mem = storeArgOrLoad(pos, b, base, source.Args[0], mem, typ.BytePtr, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
return storeArgOrLoad(pos, b, base, source.Args[1], mem, typ.Int, offset+ptrSize)
|
||||
mem = storeArg(pos, b, a.Args[0], typ.BytePtr, offset, mem)
|
||||
return storeArg(pos, b, a.Args[1], typ.Int, offset+ptrSize, mem)
|
||||
|
||||
case OpSliceMake:
|
||||
mem = storeArgOrLoad(pos, b, base, source.Args[0], mem, typ.BytePtr, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = storeArgOrLoad(pos, b, base, source.Args[1], mem, typ.Int, offset+ptrSize)
|
||||
return storeArgOrLoad(pos, b, base, source.Args[2], mem, typ.Int, offset+2*ptrSize)
|
||||
mem = storeArg(pos, b, a.Args[0], typ.BytePtr, offset, mem)
|
||||
mem = storeArg(pos, b, a.Args[1], typ.Int, offset+ptrSize, mem)
|
||||
return storeArg(pos, b, a.Args[2], typ.Int, offset+2*ptrSize, mem)
|
||||
}
|
||||
|
||||
// For nodes that cannot be taken apart -- OpSelectN, other structure selectors.
|
||||
dst := offsetFrom(sp, offset, types.NewPtr(t))
|
||||
x := b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, a, mem)
|
||||
if debug {
|
||||
fmt.Printf("\t\tstoreArg returns %s\n", x.LongString())
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// splitStore converts a store of an SSA-able aggregate into a series of smaller stores, emitting
|
||||
// appropriate Struct/Array Select operations (which will soon go dead) to obtain the parts.
|
||||
// This has to handle aggregate types that have already been lowered by an earlier phase.
|
||||
var splitStore func(dest, source, mem, v *Value, t *types.Type, offset int64, firstStorePos src.XPos) *Value
|
||||
splitStore = func(dest, source, mem, v *Value, t *types.Type, offset int64, firstStorePos src.XPos) *Value {
|
||||
if debug {
|
||||
fmt.Printf("\tsplitStore(%s; %s; %s; %s; %v; %d; %v)\n", dest.LongString(), source.LongString(), mem.String(), v.LongString(), t, offset, firstStorePos)
|
||||
}
|
||||
pos := v.Pos.WithNotStmt()
|
||||
switch t.Etype {
|
||||
case types.TARRAY:
|
||||
elt := t.Elem()
|
||||
if source.Type != t && t.NumElem() == 1 && elt.Width == t.Width && t.Width == regSize {
|
||||
if t.NumElem() == 1 && t.Width == regSize && elt.Width == regSize {
|
||||
t = removeTrivialWrapperTypes(t)
|
||||
// it could be a leaf type, but the "leaf" could be complex64 (for example)
|
||||
return storeArgOrLoad(pos, b, base, source, mem, t, offset)
|
||||
if t.Etype == types.TSTRUCT || t.Etype == types.TARRAY {
|
||||
f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct/array in it")
|
||||
}
|
||||
break // handle the leaf type.
|
||||
}
|
||||
for i := int64(0); i < t.NumElem(); i++ {
|
||||
sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, elt, offset+i*elt.Width)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = splitStore(dest, sel, mem, v, elt, offset+i*elt.Width, firstStorePos)
|
||||
firstStorePos = firstStorePos.WithNotStmt()
|
||||
}
|
||||
return mem
|
||||
|
||||
case types.TSTRUCT:
|
||||
if source.Type != t && t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == regSize {
|
||||
if t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == regSize {
|
||||
// This peculiar test deals with accesses to immediate interface data.
|
||||
// It works okay because everything is the same size.
|
||||
// Example code that triggers this can be found in go/constant/value.go, function ToComplex
|
||||
@@ -555,15 +377,16 @@ func expandCalls(f *Func) {
|
||||
// v139 is later stored as an intVal == struct{val *big.Int} which naively requires the fields of
|
||||
// of a *uint8, which does not succeed.
|
||||
t = removeTrivialWrapperTypes(t)
|
||||
|
||||
// it could be a leaf type, but the "leaf" could be complex64 (for example)
|
||||
return storeArgOrLoad(pos, b, base, source, mem, t, offset)
|
||||
return splitStore(dest, source, mem, v, t, offset, firstStorePos)
|
||||
}
|
||||
|
||||
for i := 0; i < t.NumFields(); i++ {
|
||||
fld := t.Field(i)
|
||||
sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, fld.Type, offset+fld.Offset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = splitStore(dest, sel, mem, v, fld.Type, offset+fld.Offset, firstStorePos)
|
||||
firstStorePos = firstStorePos.WithNotStmt()
|
||||
}
|
||||
return mem
|
||||
|
||||
@@ -573,55 +396,56 @@ func expandCalls(f *Func) {
|
||||
}
|
||||
tHi, tLo := intPairTypes(t.Etype)
|
||||
sel := source.Block.NewValue1(pos, OpInt64Hi, tHi, source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, tHi, offset+hiOffset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = splitStore(dest, sel, mem, v, tHi, offset+hiOffset, firstStorePos)
|
||||
firstStorePos = firstStorePos.WithNotStmt()
|
||||
sel = source.Block.NewValue1(pos, OpInt64Lo, tLo, source)
|
||||
return storeArgOrLoad(pos, b, base, sel, mem, tLo, offset+lowOffset)
|
||||
return splitStore(dest, sel, mem, v, tLo, offset+lowOffset, firstStorePos)
|
||||
|
||||
case types.TINTER:
|
||||
sel := source.Block.NewValue1(pos, OpITab, typ.BytePtr, source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, typ.BytePtr, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = splitStore(dest, sel, mem, v, typ.BytePtr, offset, firstStorePos)
|
||||
firstStorePos = firstStorePos.WithNotStmt()
|
||||
sel = source.Block.NewValue1(pos, OpIData, typ.BytePtr, source)
|
||||
return storeArgOrLoad(pos, b, base, sel, mem, typ.BytePtr, offset+ptrSize)
|
||||
return splitStore(dest, sel, mem, v, typ.BytePtr, offset+ptrSize, firstStorePos)
|
||||
|
||||
case types.TSTRING:
|
||||
sel := source.Block.NewValue1(pos, OpStringPtr, typ.BytePtr, source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, typ.BytePtr, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = splitStore(dest, sel, mem, v, typ.BytePtr, offset, firstStorePos)
|
||||
firstStorePos = firstStorePos.WithNotStmt()
|
||||
sel = source.Block.NewValue1(pos, OpStringLen, typ.Int, source)
|
||||
return storeArgOrLoad(pos, b, base, sel, mem, typ.Int, offset+ptrSize)
|
||||
return splitStore(dest, sel, mem, v, typ.Int, offset+ptrSize, firstStorePos)
|
||||
|
||||
case types.TSLICE:
|
||||
et := types.NewPtr(t.Elem())
|
||||
sel := source.Block.NewValue1(pos, OpSlicePtr, et, source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, et, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = splitStore(dest, sel, mem, v, et, offset, firstStorePos)
|
||||
firstStorePos = firstStorePos.WithNotStmt()
|
||||
sel = source.Block.NewValue1(pos, OpSliceLen, typ.Int, source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, typ.Int, offset+ptrSize)
|
||||
mem = splitStore(dest, sel, mem, v, typ.Int, offset+ptrSize, firstStorePos)
|
||||
sel = source.Block.NewValue1(pos, OpSliceCap, typ.Int, source)
|
||||
return storeArgOrLoad(pos, b, base, sel, mem, typ.Int, offset+2*ptrSize)
|
||||
return splitStore(dest, sel, mem, v, typ.Int, offset+2*ptrSize, firstStorePos)
|
||||
|
||||
case types.TCOMPLEX64:
|
||||
sel := source.Block.NewValue1(pos, OpComplexReal, typ.Float32, source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, typ.Float32, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = splitStore(dest, sel, mem, v, typ.Float32, offset, firstStorePos)
|
||||
firstStorePos = firstStorePos.WithNotStmt()
|
||||
sel = source.Block.NewValue1(pos, OpComplexImag, typ.Float32, source)
|
||||
return storeArgOrLoad(pos, b, base, sel, mem, typ.Float32, offset+4)
|
||||
return splitStore(dest, sel, mem, v, typ.Float32, offset+4, firstStorePos)
|
||||
|
||||
case types.TCOMPLEX128:
|
||||
sel := source.Block.NewValue1(pos, OpComplexReal, typ.Float64, source)
|
||||
mem = storeArgOrLoad(pos, b, base, sel, mem, typ.Float64, offset)
|
||||
pos = pos.WithNotStmt()
|
||||
mem = splitStore(dest, sel, mem, v, typ.Float64, offset, firstStorePos)
|
||||
firstStorePos = firstStorePos.WithNotStmt()
|
||||
sel = source.Block.NewValue1(pos, OpComplexImag, typ.Float64, source)
|
||||
return storeArgOrLoad(pos, b, base, sel, mem, typ.Float64, offset+8)
|
||||
return splitStore(dest, sel, mem, v, typ.Float64, offset+8, firstStorePos)
|
||||
}
|
||||
// Default, including for aggregates whose single element exactly fills their container
|
||||
// TODO this will be a problem for cast interfaces containing floats when we move to registers.
|
||||
x := v.Block.NewValue3A(firstStorePos, OpStore, types.TypeMem, t, offsetFrom(dest, offset, types.NewPtr(t)), source, mem)
|
||||
if debug {
|
||||
fmt.Printf("\t\tsplitStore returns %s\n", x.LongString())
|
||||
}
|
||||
|
||||
dst := offsetFrom(base, offset, types.NewPtr(t))
|
||||
x := b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem)
|
||||
if debug {
|
||||
fmt.Printf("\t\tstoreArg returns %s\n", x.LongString())
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
@@ -666,7 +490,7 @@ func expandCalls(f *Func) {
|
||||
if debug {
|
||||
fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aux.TypeOfArg(auxI), aux.OffsetOfArg(auxI))
|
||||
}
|
||||
mem = storeArgOrLoad(pos, v.Block, sp, a, mem, aux.TypeOfArg(auxI), aux.OffsetOfArg(auxI))
|
||||
mem = storeArg(pos, v.Block, a, aux.TypeOfArg(auxI), aux.OffsetOfArg(auxI), mem)
|
||||
}
|
||||
}
|
||||
v.resetArgs()
|
||||
@@ -699,7 +523,7 @@ func expandCalls(f *Func) {
|
||||
t := name.Type
|
||||
if isAlreadyExpandedAggregateType(t) {
|
||||
for j, v := range f.NamedValues[name] {
|
||||
if v.Op == OpSelectN || v.Op == OpArg && isAlreadyExpandedAggregateType(v.Type) {
|
||||
if v.Op == OpSelectN {
|
||||
ns := namedSelects[v]
|
||||
namedSelects[v] = append(ns, namedVal{locIndex: i, valIndex: j})
|
||||
}
|
||||
@@ -707,19 +531,17 @@ func expandCalls(f *Func) {
|
||||
}
|
||||
}
|
||||
|
||||
// Step 1: any stores of aggregates remaining are believed to be sourced from call results or args.
|
||||
// Step 1: any stores of aggregates remaining are believed to be sourced from call results.
|
||||
// Decompose those stores into a series of smaller stores, adding selection ops as necessary.
|
||||
for _, b := range f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
if v.Op == OpStore {
|
||||
t := v.Aux.(*types.Type)
|
||||
source := v.Args[1]
|
||||
tSrc := source.Type
|
||||
iAEATt := isAlreadyExpandedAggregateType(t)
|
||||
|
||||
if !iAEATt {
|
||||
// guarding against store immediate struct into interface data field -- store type is *uint8
|
||||
// TODO can this happen recursively?
|
||||
tSrc := v.Args[1].Type
|
||||
iAEATt = isAlreadyExpandedAggregateType(tSrc)
|
||||
if iAEATt {
|
||||
t = tSrc
|
||||
@@ -729,8 +551,8 @@ func expandCalls(f *Func) {
|
||||
if debug {
|
||||
fmt.Printf("Splitting store %s\n", v.LongString())
|
||||
}
|
||||
dst, mem := v.Args[0], v.Args[2]
|
||||
mem = storeArgOrLoad(v.Pos, b, dst, source, mem, t, 0)
|
||||
dst, source, mem := v.Args[0], v.Args[1], v.Args[2]
|
||||
mem = splitStore(dst, source, mem, v, t, 0, v.Pos)
|
||||
v.copyOf(mem)
|
||||
}
|
||||
}
|
||||
@@ -757,7 +579,7 @@ func expandCalls(f *Func) {
|
||||
OpInt64Hi, OpInt64Lo:
|
||||
w := v.Args[0]
|
||||
switch w.Op {
|
||||
case OpStructSelect, OpArraySelect, OpSelectN, OpArg:
|
||||
case OpStructSelect, OpArraySelect, OpSelectN:
|
||||
val2Preds[w] += 1
|
||||
if debug {
|
||||
fmt.Printf("v2p[%s] = %d\n", w.LongString(), val2Preds[w])
|
||||
@@ -773,17 +595,6 @@ func expandCalls(f *Func) {
|
||||
}
|
||||
}
|
||||
|
||||
case OpArg:
|
||||
if !isAlreadyExpandedAggregateType(v.Type) {
|
||||
continue
|
||||
}
|
||||
if _, ok := val2Preds[v]; !ok {
|
||||
val2Preds[v] = 0
|
||||
if debug {
|
||||
fmt.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v])
|
||||
}
|
||||
}
|
||||
|
||||
case OpSelectNAddr:
|
||||
// Do these directly, there are no chains of selectors.
|
||||
call := v.Args[0]
|
||||
@@ -801,6 +612,7 @@ func expandCalls(f *Func) {
|
||||
// then forwards to rewrite selectors.
|
||||
//
|
||||
// All chains of selectors end up in same block as the call.
|
||||
sdom := f.Sdom()
|
||||
|
||||
// Compilation must be deterministic, so sort after extracting first zeroes from map.
|
||||
// Sorting allows dominators-last order within each batch,
|
||||
@@ -828,11 +640,8 @@ func expandCalls(f *Func) {
|
||||
last = len(allOrdered)
|
||||
sort.SliceStable(toProcess, less)
|
||||
for _, v := range toProcess {
|
||||
delete(val2Preds, v)
|
||||
if v.Op == OpArg {
|
||||
continue // no Args[0], hence done.
|
||||
}
|
||||
w := v.Args[0]
|
||||
delete(val2Preds, v)
|
||||
n, ok := val2Preds[w]
|
||||
if !ok {
|
||||
continue
|
||||
@@ -846,19 +655,13 @@ func expandCalls(f *Func) {
|
||||
}
|
||||
}
|
||||
|
||||
common = make(map[selKey]*Value)
|
||||
common := make(map[selKey]*Value)
|
||||
// Rewrite duplicate selectors as copies where possible.
|
||||
for i := len(allOrdered) - 1; i >= 0; i-- {
|
||||
v := allOrdered[i]
|
||||
if v.Op == OpArg {
|
||||
continue
|
||||
}
|
||||
w := v.Args[0]
|
||||
if w.Op == OpCopy {
|
||||
for w.Op == OpCopy {
|
||||
w = w.Args[0]
|
||||
}
|
||||
v.SetArg(0, w)
|
||||
for w.Op == OpCopy {
|
||||
w = w.Args[0]
|
||||
}
|
||||
typ := v.Type
|
||||
if typ.IsMemory() {
|
||||
@@ -888,7 +691,7 @@ func expandCalls(f *Func) {
|
||||
case OpComplexImag:
|
||||
offset = size
|
||||
}
|
||||
sk := selKey{from: w, size: size, offset: offset, typ: typ}
|
||||
sk := selKey{from: w, size: size, offset: offset, typ: typ.Etype}
|
||||
dupe := common[sk]
|
||||
if dupe == nil {
|
||||
common[sk] = v
|
||||
|
||||
@@ -790,10 +790,10 @@ func (f *Func) spSb() (sp, sb *Value) {
|
||||
}
|
||||
}
|
||||
if sb == nil {
|
||||
sb = f.Entry.NewValue0(initpos.WithNotStmt(), OpSB, f.Config.Types.Uintptr)
|
||||
sb = f.Entry.NewValue0(initpos, OpSB, f.Config.Types.Uintptr)
|
||||
}
|
||||
if sp == nil {
|
||||
sp = f.Entry.NewValue0(initpos.WithNotStmt(), OpSP, f.Config.Types.Uintptr)
|
||||
sp = f.Entry.NewValue0(initpos, OpSP, f.Config.Types.Uintptr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -531,7 +531,6 @@
|
||||
// fold ADDL into LEAL
|
||||
(ADDLconst [c] (LEAL [d] {s} x)) && is32Bit(int64(c)+int64(d)) => (LEAL [c+d] {s} x)
|
||||
(LEAL [c] {s} (ADDLconst [d] x)) && is32Bit(int64(c)+int64(d)) => (LEAL [c+d] {s} x)
|
||||
(ADDLconst [c] x:(SP)) => (LEAL [c] x) // so it is rematerializeable
|
||||
(LEAL [c] {s} (ADDL x y)) && x.Op != OpSB && y.Op != OpSB => (LEAL1 [c] {s} x y)
|
||||
(ADDL x (LEAL [c] {s} y)) && x.Op != OpSB && y.Op != OpSB => (LEAL1 [c] {s} x y)
|
||||
|
||||
@@ -641,31 +640,31 @@
|
||||
// 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)
|
||||
&& (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOV(L|W|B|SS|SD|BLSX|WLSX)load [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
(MOV(L|W|B|SS|SD|BLSX|WLSX)load [off1+off2] {mergeSymTyped(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)
|
||||
&& (base.Op != OpSB || !config.ctxt.Flag_shared) =>
|
||||
(MOV(L|W|B|SS|SD)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
(MOV(L|W|B|SS|SD)store [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
||||
|
||||
(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) =>
|
||||
(MOV(L|W|B)storeconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||
(MOV(L|W|B)storeconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr 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) =>
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSymTyped(sym1,sym2)} val 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) =>
|
||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSymTyped(sym1,sym2)} val 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) =>
|
||||
((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSymTyped(sym1,sym2)} val base 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) =>
|
||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSymTyped(sym1,sym2)} base val 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) =>
|
||||
((ADD|AND|OR|XOR)Lconstmodify [valoff1.addOffset32(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||
((ADD|AND|OR|XOR)Lconstmodify [valoff1.addOffset32(off2)] {mergeSymTyped(sym1,sym2)} base mem)
|
||||
|
||||
// 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)
|
||||
@@ -680,37 +679,37 @@
|
||||
|
||||
// fold LEALs together
|
||||
(LEAL [off1] {sym1} (LEAL [off2] {sym2} x)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAL [off1+off2] {mergeSym(sym1,sym2)} x)
|
||||
(LEAL [off1+off2] {mergeSymTyped(sym1,sym2)} x)
|
||||
|
||||
// LEAL into LEAL1
|
||||
(LEAL1 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||
(LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAL1 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
|
||||
// LEAL1 into LEAL
|
||||
(LEAL [off1] {sym1} (LEAL1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAL1 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
|
||||
// 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+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAL2 [off1+off2] {mergeSymTyped(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+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAL4 [off1+off2] {mergeSymTyped(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+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAL8 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
|
||||
// LEAL[248] into LEAL
|
||||
(LEAL [off1] {sym1} (LEAL2 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAL2 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAL2 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
(LEAL [off1] {sym1} (LEAL4 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAL4 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAL4 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
(LEAL [off1] {sym1} (LEAL8 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAL8 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
|
||||
// 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) =>
|
||||
(LEAL2 [off1+off2] {mergeSym(sym1, sym2)} x y)
|
||||
(LEAL2 [off1+off2] {mergeSymTyped(sym1, sym2)} x y)
|
||||
(LEAL1 [off1] {sym1} x (LEAL1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAL2 [off1+off2] {mergeSym(sym1, sym2)} y x)
|
||||
(LEAL2 [off1+off2] {mergeSymTyped(sym1, sym2)} y x)
|
||||
(LEAL2 [off1] {sym} x (LEAL1 [off2] {nil} y y)) && is32Bit(int64(off1)+2*int64(off2)) =>
|
||||
(LEAL4 [off1+2*off2] {sym} x y)
|
||||
(LEAL4 [off1] {sym} x (LEAL1 [off2] {nil} y y)) && is32Bit(int64(off1)+4*int64(off2)) =>
|
||||
@@ -994,49 +993,49 @@
|
||||
&& x.Uses == 1
|
||||
&& a.Off() + 1 == c.Off()
|
||||
&& clobber(x)
|
||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p mem)
|
||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), int32(a.Off()))] {s} p mem)
|
||||
(MOVBstoreconst [a] {s} p x:(MOVBstoreconst [c] {s} p mem))
|
||||
&& x.Uses == 1
|
||||
&& a.Off() + 1 == c.Off()
|
||||
&& clobber(x)
|
||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p mem)
|
||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), int32(a.Off()))] {s} p mem)
|
||||
|
||||
(MOVBstoreconst [c] {s} p1 x:(MOVBstoreconst [a] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& a.Off() == c.Off()
|
||||
&& sequentialAddresses(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p0 mem)
|
||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), int32(a.Off()))] {s} p0 mem)
|
||||
(MOVBstoreconst [a] {s} p0 x:(MOVBstoreconst [c] {s} p1 mem))
|
||||
&& x.Uses == 1
|
||||
&& a.Off() == c.Off()
|
||||
&& sequentialAddresses(p0, p1, 1)
|
||||
&& clobber(x)
|
||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), a.Off32())] {s} p0 mem)
|
||||
=> (MOVWstoreconst [makeValAndOff32(int32(a.Val()&0xff | c.Val()<<8), int32(a.Off()))] {s} p0 mem)
|
||||
|
||||
(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
|
||||
&& x.Uses == 1
|
||||
&& a.Off() + 2 == c.Off()
|
||||
&& clobber(x)
|
||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p mem)
|
||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), int32(a.Off()))] {s} p mem)
|
||||
(MOVWstoreconst [a] {s} p x:(MOVWstoreconst [c] {s} p mem))
|
||||
&& x.Uses == 1
|
||||
&& ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
|
||||
&& clobber(x)
|
||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p mem)
|
||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), int32(a.Off()))] {s} p mem)
|
||||
|
||||
(MOVWstoreconst [c] {s} p1 x:(MOVWstoreconst [a] {s} p0 mem))
|
||||
&& x.Uses == 1
|
||||
&& a.Off() == c.Off()
|
||||
&& sequentialAddresses(p0, p1, 2)
|
||||
&& clobber(x)
|
||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p0 mem)
|
||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), int32(a.Off()))] {s} p0 mem)
|
||||
(MOVWstoreconst [a] {s} p0 x:(MOVWstoreconst [c] {s} p1 mem))
|
||||
&& x.Uses == 1
|
||||
&& a.Off() == c.Off()
|
||||
&& sequentialAddresses(p0, p1, 2)
|
||||
&& clobber(x)
|
||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), a.Off32())] {s} p0 mem)
|
||||
=> (MOVLstoreconst [makeValAndOff32(int32(a.Val()&0xffff | c.Val()<<16), int32(a.Off()))] {s} p0 mem)
|
||||
|
||||
// Combine stores into larger (unaligned) stores.
|
||||
(MOVBstore [i] {s} p (SHR(W|L)const [8] w) x:(MOVBstore [i-1] {s} p w mem))
|
||||
|
||||
@@ -583,7 +583,7 @@
|
||||
((NE|EQ) (TESTQconst [c] x)) && isUint64PowerOfTwo(int64(c))
|
||||
=> ((ULT|UGE) (BTQconst [int8(log32(c))] x))
|
||||
((NE|EQ) (TESTQ (MOVQconst [c]) x)) && isUint64PowerOfTwo(c)
|
||||
=> ((ULT|UGE) (BTQconst [int8(log64(c))] x))
|
||||
=> ((ULT|UGE) (BTQconst [int8(log2(c))] x))
|
||||
(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) (TESTLconst [c] x)) && isUint32PowerOfTwo(int64(c))
|
||||
@@ -591,7 +591,7 @@
|
||||
(SET(NE|EQ) (TESTQconst [c] x)) && isUint64PowerOfTwo(int64(c))
|
||||
=> (SET(B|AE) (BTQconst [int8(log32(c))] x))
|
||||
(SET(NE|EQ) (TESTQ (MOVQconst [c]) x)) && isUint64PowerOfTwo(c)
|
||||
=> (SET(B|AE) (BTQconst [int8(log64(c))] x))
|
||||
=> (SET(B|AE) (BTQconst [int8(log2(c))] x))
|
||||
// SET..store variant
|
||||
(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)
|
||||
@@ -602,7 +602,7 @@
|
||||
(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(NE|EQ)store [off] {sym} ptr (TESTQ (MOVQconst [c]) x) mem) && isUint64PowerOfTwo(c)
|
||||
=> (SET(B|AE)store [off] {sym} ptr (BTQconst [int8(log64(c))] x) mem)
|
||||
=> (SET(B|AE)store [off] {sym} ptr (BTQconst [int8(log2(c))] x) mem)
|
||||
|
||||
// Handle bit-testing in the form (a>>b)&1 != 0 by building the above rules
|
||||
// and further combining shifts.
|
||||
@@ -631,7 +631,7 @@
|
||||
((ORL|XORL)const [c] x) && isUint32PowerOfTwo(int64(c)) && uint64(c) >= 128
|
||||
=> (BT(S|C)Lconst [int8(log32(c))] x)
|
||||
((ORQ|XORQ) (MOVQconst [c]) x) && isUint64PowerOfTwo(c) && uint64(c) >= 128
|
||||
=> (BT(S|C)Qconst [int8(log64(c))] x)
|
||||
=> (BT(S|C)Qconst [int8(log2(c))] x)
|
||||
((ORL|XORL) (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(c)) && uint64(c) >= 128
|
||||
=> (BT(S|C)Lconst [int8(log32(c))] x)
|
||||
|
||||
@@ -642,7 +642,7 @@
|
||||
(ANDLconst [c] x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
|
||||
=> (BTRLconst [int8(log32(^c))] x)
|
||||
(ANDQ (MOVQconst [c]) x) && isUint64PowerOfTwo(^c) && uint64(^c) >= 128
|
||||
=> (BTRQconst [int8(log64(^c))] x)
|
||||
=> (BTRQconst [int8(log2(^c))] x)
|
||||
(ANDL (MOVLconst [c]) x) && isUint32PowerOfTwo(int64(^c)) && uint64(^c) >= 128
|
||||
=> (BTRLconst [int8(log32(^c))] x)
|
||||
|
||||
@@ -959,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 [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) && 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) && isPowerOfTwo64(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) && 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-4) && c >= 68 => (LEA(Q|L)4 (SHL(Q|L)const <v.Type> [int8(log32(c-4))] x) x)
|
||||
@@ -1137,80 +1137,80 @@
|
||||
// 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)
|
||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(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|BQSX|WQSX|LQSX)load [off1+off2] {mergeSymTyped(sym1,sym2)} base 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) =>
|
||||
(MOV(Q|L|W|B|SS|SD|O)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
(MOV(Q|L|W|B|SS|SD|O)store [off1+off2] {mergeSymTyped(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 [ValAndOff(sc).addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||
(MOV(Q|L|W|B)storeconst [ValAndOff(sc).addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr 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) =>
|
||||
(SET(L|G|B|A|LE|GE|BE|AE|EQ|NE)store [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
(SET(L|G|B|A|LE|GE|BE|AE|EQ|NE)store [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
||||
((ADD|SUB|AND|OR|XOR)Qload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
((ADD|SUB|AND|OR|XOR)Qload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|AND|OR|XOR)Qload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|AND|OR|XOR)Lload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
((ADD|SUB|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|AND|OR|XOR)Lload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
||||
(CMP(Q|L|W|B)load [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
|
||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(CMP(Q|L|W|B)load [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
(CMP(Q|L|W|B)load [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
||||
(CMP(Q|L|W|B)constload [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||
&& ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) =>
|
||||
(CMP(Q|L|W|B)constload [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||
(CMP(Q|L|W|B)constload [ValAndOff(valoff1).addOffset32(off2)] {mergeSymTyped(sym1,sym2)} base mem)
|
||||
|
||||
((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|MUL|DIV)SDload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem)
|
||||
&& is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSym(sym1,sym2)} val base mem)
|
||||
((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSymTyped(sym1,sym2)} val base mem)
|
||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||
&& ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) =>
|
||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Qconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSymTyped(sym1,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) =>
|
||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem)
|
||||
((ADD|AND|OR|XOR|BTC|BTR|BTS)Lconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSymTyped(sym1,sym2)} base 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) =>
|
||||
((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)Qmodify [off1+off2] {mergeSymTyped(sym1,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) =>
|
||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
((ADD|SUB|AND|OR|XOR|BTC|BTR|BTS)Lmodify [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
||||
|
||||
// fold LEAQs together
|
||||
(LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAQ [off1+off2] {mergeSym(sym1,sym2)} x)
|
||||
(LEAQ [off1+off2] {mergeSymTyped(sym1,sym2)} x)
|
||||
|
||||
// LEAQ into LEAQ1
|
||||
(LEAQ1 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) && x.Op != OpSB =>
|
||||
(LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAQ1 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
|
||||
// LEAQ1 into LEAQ
|
||||
(LEAQ [off1] {sym1} (LEAQ1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAQ1 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
|
||||
// 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+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAQ2 [off1+off2] {mergeSymTyped(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+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAQ4 [off1+off2] {mergeSymTyped(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+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAQ8 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
|
||||
// LEAQ[248] into LEAQ
|
||||
(LEAQ [off1] {sym1} (LEAQ2 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAQ2 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
(LEAQ [off1] {sym1} (LEAQ4 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAQ4 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
(LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
|
||||
(LEAQ8 [off1+off2] {mergeSymTyped(sym1,sym2)} x y)
|
||||
|
||||
// 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) =>
|
||||
(LEAQ2 [off1+off2] {mergeSym(sym1, sym2)} x y)
|
||||
(LEAQ2 [off1+off2] {mergeSymTyped(sym1, sym2)} x y)
|
||||
(LEAQ1 [off1] {sym1} x (LEAQ1 [off2] {sym2} x y)) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) =>
|
||||
(LEAQ2 [off1+off2] {mergeSym(sym1, sym2)} y x)
|
||||
(LEAQ2 [off1+off2] {mergeSymTyped(sym1, sym2)} y x)
|
||||
(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] {sym1} x (LEAQ1 [off2] {sym2} y y)) && is32Bit(int64(off1)+4*int64(off2)) && sym2 == nil =>
|
||||
@@ -2000,31 +2000,31 @@
|
||||
=> (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+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
(MOVQload [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
||||
(MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
(MOVLload [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
||||
(MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
(MOVWload [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
||||
(MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
(MOVBload [off1+off2] {mergeSymTyped(sym1,sym2)} base mem)
|
||||
|
||||
(MOVQstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(MOVQstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
(MOVQstore [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
||||
(MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
(MOVLstore [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
||||
(MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
(MOVWstore [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
||||
(MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
|
||||
(MOVBstore [off1+off2] {mergeSymTyped(sym1,sym2)} base val mem)
|
||||
|
||||
(MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
||||
(MOVQstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||
(MOVQstoreconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
||||
(MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
||||
(MOVLstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||
(MOVLstoreconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
||||
(MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
||||
(MOVWstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||
(MOVWstoreconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} ptr mem)
|
||||
(MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && sc.canAdd32(off) =>
|
||||
(MOVBstoreconst [sc.addOffset32(off)] {mergeSym(sym1, sym2)} ptr mem)
|
||||
(MOVBstoreconst [sc.addOffset32(off)] {mergeSymTyped(sym1, sym2)} 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)
|
||||
@@ -2060,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+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+off2] {mergeSym(sym1, sym2)} ptr mem)
|
||||
(MOV(Q|L|B)atomicload [off1+off2] {mergeSymTyped(sym1, sym2)} ptr mem)
|
||||
|
||||
// Merge ADDQconst and LEAQ into atomic stores.
|
||||
(XCHGQ [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(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+off2] {mergeSym(sym1,sym2)} val ptr mem)
|
||||
(XCHGQ [off1+off2] {mergeSymTyped(sym1,sym2)} val ptr mem)
|
||||
(XCHGL [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(int64(off1)+int64(off2)) =>
|
||||
(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+off2] {mergeSym(sym1,sym2)} val ptr mem)
|
||||
(XCHGL [off1+off2] {mergeSymTyped(sym1,sym2)} val ptr mem)
|
||||
|
||||
// Merge ADDQconst into atomic adds.
|
||||
// TODO: merging LEAQ doesn't work, assembler doesn't like the resulting instructions.
|
||||
|
||||
@@ -433,30 +433,30 @@
|
||||
(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+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVBload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
||||
(MOVBUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVBUload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
||||
(MOVHload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
||||
(MOVHUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVHUload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
||||
(MOVWload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
||||
(MOVFload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVFload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
||||
(MOVDload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVDload [off1+off2] {mergeSymTyped(sym1,sym2)} ptr mem)
|
||||
|
||||
(MOVBstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVBstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
||||
(MOVHstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVHstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
||||
(MOVWstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVWstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
||||
(MOVFstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVFstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
||||
(MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) =>
|
||||
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
(MOVDstore [off1+off2] {mergeSymTyped(sym1,sym2)} ptr val mem)
|
||||
|
||||
// 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)
|
||||
@@ -760,8 +760,8 @@
|
||||
(MUL (MOVWconst [c]) (MOVWconst [d])) => (MOVWconst [c*d])
|
||||
(MULA (MOVWconst [c]) (MOVWconst [d]) a) => (ADDconst [c*d] a)
|
||||
(MULS (MOVWconst [c]) (MOVWconst [d]) a) => (SUBconst [c*d] a)
|
||||
(Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) && d != 0 => (MOVWconst [int32(uint32(c)/uint32(d))])
|
||||
(Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) && d != 0 => (MOVWconst [int32(uint32(c)%uint32(d))])
|
||||
(Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [int32(uint32(c)/uint32(d))])
|
||||
(Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) => (MOVWconst [int32(uint32(c)%uint32(d))])
|
||||
(ANDconst [c] (MOVWconst [d])) => (MOVWconst [c&d])
|
||||
(ANDconst [c] (ANDconst [d] x)) => (ANDconst [c&d] x)
|
||||
(ORconst [c] (MOVWconst [d])) => (MOVWconst [c|d])
|
||||
@@ -1369,38 +1369,38 @@
|
||||
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (CMNshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LTnoov (TST x y) yes no)
|
||||
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LTnoov (TSTconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LTnoov (TSTshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LTnoov (TSTshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LEnoov (TST x y) yes no)
|
||||
(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LEnoov (TSTconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LEnoov (TSTshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (TSTshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LTnoov (TEQ x y) yes no)
|
||||
(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LTnoov (TEQconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LTnoov (TEQshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LTnoov (TEQshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LEnoov (TEQ x y) yes no)
|
||||
(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LEnoov (TEQconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LEnoov (TEQshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LEnoov (TEQshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LT (TST x y) yes no)
|
||||
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LT (TSTconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LT (TSTshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LT (TSTshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (LE (TST x y) yes no)
|
||||
(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (LE (TSTconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (LE (TSTshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (LE (TSTshiftRAreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LT (TEQ x y) yes no)
|
||||
(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LT (TEQconst [c] x) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftLL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftRL x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LT (TEQshiftRA x y [c]) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftLLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftRLreg x y z) yes no)
|
||||
(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LT (TEQshiftRAreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (LE (TEQ x y) yes no)
|
||||
(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (LE (TEQconst [c] x) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftLL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftRL x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (LE (TEQshiftRA x y [c]) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftLLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftRLreg x y z) yes no)
|
||||
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (LE (TEQshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (GTnoov (CMP x y) yes no)
|
||||
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (GTnoov (CMPconst [c] x) yes no)
|
||||
@@ -1436,39 +1436,39 @@
|
||||
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (CMNshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GT (TST x y) yes no)
|
||||
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 => (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GTnoov (TST x y) yes no)
|
||||
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TSTconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GTnoov (TSTshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TSTshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GEnoov (TST x y) yes no)
|
||||
(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TSTconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GEnoov (TSTshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TSTshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GTnoov (TEQ x y) yes no)
|
||||
(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GTnoov (TEQconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GTnoov (TEQshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GTnoov (TEQshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GEnoov (TEQ x y) yes no)
|
||||
(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GEnoov (TEQconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GEnoov (TEQshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GEnoov (TEQshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GT (TSTconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TSTshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TSTshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 => (GE (TST x y) yes no)
|
||||
(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 => (GE (TSTconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 => (GE (TSTshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftLLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRLreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TSTshiftRAreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GT (TEQ x y) yes no)
|
||||
(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GT (TEQconst [c] x) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftLL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRL x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GT (TEQshiftRA x y [c]) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftLLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRLreg x y z) yes no)
|
||||
(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GT (TEQshiftRAreg x y z) yes no)
|
||||
(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 => (GE (TEQ x y) yes no)
|
||||
(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 => (GE (TEQconst [c] x) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftLL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRL x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 => (GE (TEQshiftRA x y [c]) yes no)
|
||||
(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftLLreg 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)
|
||||
|
||||
(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read8(sym, int64(off)))])
|
||||
(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user