[dev.simd] all: merge master (4c4cefc) into dev.simd

Merge List:

+ 2025-09-03 4c4cefc19a cmd/gofmt: simplify logic to process arguments
+ 2025-09-03 925a3cdcd1 unicode/utf8: make DecodeRune{,InString} inlineable
+ 2025-09-03 3e596d448f math: rename Modf parameter int to integer
+ 2025-09-02 2a7f1d47b0 runtime: use one more address bit for tagged pointers
+ 2025-09-02 b09068041a cmd/dist: run racebench tests only in longtest mode
+ 2025-09-02 355370ac52 runtime: add comment for concatstring2
+ 2025-09-02 1eec830f54 go/doc: linkify interface methods
+ 2025-08-31 7bba745820 cmd/compile: use generated loops instead of DUFFZERO on loong64
+ 2025-08-31 882335e2cb cmd/internal/obj/loong64: add LDPTR.{W/D} and STPTR.{W/D} instructions support
+ 2025-08-31 d4b17f5869 internal/runtime/atomic: reset wrong jump target in Cas{,64} on loong64
+ 2025-08-31 6a08e80399 net/http: skip redirecting in ServeMux when URL path for CONNECT is empty
+ 2025-08-29 8bcda6c79d runtime/race: add race detector support for linux/riscv64
+ 2025-08-29 8377adafc5 cmd/cgo: split loadDWARF into two parts
+ 2025-08-29 a7d9d5a80a cmd/cgo: move typedefs and typedefList out of Package
+ 2025-08-29 1d459c4357 all: delete more windows/arm remnants
+ 2025-08-29 27ce6e4e26 cmd/compile: remove sign extension before MULW on riscv64
+ 2025-08-29 84b070bfb1 cmd/compile/internal/ssa: make oneBit function generic
+ 2025-08-29 fe42628dae internal/cpu: inline DebugOptions
+ 2025-08-29 94b7d519bd net: update document on limitation of iprawsock on Windows
+ 2025-08-29 ba9e1ddccf testing: allow specify temp dir by GOTMPDIR environment variable
+ 2025-08-29 9f6936b8da cmd/link: disallow linkname of runtime.addmoduledata
+ 2025-08-29 89d41d254a bytes, strings: speed up TrimSpace
+ 2025-08-29 38204e0872 testing/synctest: call out common issues with tests
+ 2025-08-29 252c901125 os,syscall: pass file flags to CreateFile on Windows
+ 2025-08-29 53515fb0a9 crypto/tls: use hash.Cloner
+ 2025-08-28 13bb48e6fb go/constant: fix complex != unknown comparison
+ 2025-08-28 ba1109feb5 net: remove redundant cgoLookupCNAME return parameter
+ 2025-08-28 f74ed44ed9 net/http/httputil: remove redundant pw.Close() call in DumpRequestOut
+ 2025-08-28 a9689d2e0b time: skip TestLongAdjustTimers in short mode on single CPU systems
+ 2025-08-28 ebc763f76d syscall: only get parent PID if SysProcAttr.Pdeathsig is set
+ 2025-08-28 7f1864b0a8 strings: remove redundant "runs" from string.Fields docstring
+ 2025-08-28 90c21fa5b6 net/textproto: eliminate some bounds checks
+ 2025-08-27 e47d88beae os: return nil slice when ReadDir is used with a file on file_windows
+ 2025-08-27 6b837a64db cmd/internal/obj/loong64: simplify buildop
+ 2025-08-27 765905e3bd debug/elf: don't panic if symtab too small
+ 2025-08-27 2ee4b31242 net/http: Ensure that CONNECT proxied requests respect MaxResponseHeaderBytes
+ 2025-08-27 b21867b1a2 net/http: require exact match for CrossSiteProtection bypass patterns
+ 2025-08-27 d19e377f6e cmd/cgo: make it safe to run gcc in parallel
+ 2025-08-27 49a2f3ed87 net: allow zero value destination address in WriteMsgUDPAddrPort
+ 2025-08-26 afc51ed007 internall/poll: remove bufs field from Windows' poll.operation
+ 2025-08-26 801b74eb95 internal/poll: remove rsa field from Windows' poll.operation
+ 2025-08-26 fa18c547cd syscall: sort Windows env block in StartProcess
+ 2025-08-26 bfd130db02 internal/poll: don't use stack-allocated WSAMsg parameters
+ 2025-08-26 dae9e456ae runtime: identify virtual memory layout for riscv64
+ 2025-08-25 25c2d4109f math: use Trunc to implement Modf
+ 2025-08-25 4e05a070c4 math: implement IsInf using Abs
+ 2025-08-25 1eed4f32a0 math: optimize Signbit implementation slightly
+ 2025-08-25 bd71b94659 cmd/compile/internal: optimizing add+sll rule using ALSLV instruction on loong64
+ 2025-08-25 ea55ca3600 runtime: skip doInit of plugins in runtime.main
+ 2025-08-25 9ae2f1fb57 internal/trace: skip async preempt off tests on low end systems
+ 2025-08-25 bbd5342a62 net: fix cgoResSearch
+ 2025-08-25 ed7f804775 os: set full name for Roots created with Root.OpenRoot
+ 2025-08-25 a21249436b internal/poll: use fdMutex to provide read/write locking on Windows
+ 2025-08-24 44c5956bf7 test/codegen: add Mul2 and DivPow2 test for loong64
+ 2025-08-24 0aa8019e94 test/codegen: add Mul* test for loong64
+ 2025-08-24 83420974b7 test/codegen: add sqrt* abs and copysign test for loong64
+ 2025-08-23 f2db0dca0b net/http/httptest: redirect example.com requests to server
+ 2025-08-22 d86ec92499 internal/syscall/windows: increase internal Windows O_ flags values
+ 2025-08-22 9d3f7fda70 crypto/tls: fix quic comment typo
+ 2025-08-22 78a05c541f internal/poll: don't pass non-nil WSAMsg.Name with 0 namelen on windows
+ 2025-08-22 52c3f73fda runtime/metrics: improve doc
+ 2025-08-22 a076f49757 os: fix Root.MkdirAll to handle race of directory creation
+ 2025-08-22 98238fd495 all: delete remaining windows/arm code
+ 2025-08-21 1ad30844d9 cmd/asm: process forward jump to PCALIGN
+ 2025-08-21 13c082601d internal/poll: permit nil destination address in WriteMsg{Inet4,Inet6}
+ 2025-08-21 9b0a507735 runtime: remove remaining windows/arm files and comments
+ 2025-08-21 1843f1e9c0 cmd/compile: use zero register instead of specialized *zero instructions on loong64
+ 2025-08-21 e0870a0a12 cmd/compile: simplify zerorange on loong64
+ 2025-08-21 fb8bbe46d5 cmd/compile/internal/ssa: eliminate unnecessary extension operations
+ 2025-08-21 9632ba8160 cmd/compile: optimize some patterns into revb2h/revb4h instruction on loong64
+ 2025-08-21 8dcab6f450 syscall: simplify execve handling on libc platforms
+ 2025-08-21 ba840c1bf9 cmd/compile: deduplication in the source code generated by mknode
+ 2025-08-21 fa706ea50f cmd/compile: optimize rule (x + x) << c to x << c+1 on loong64
+ 2025-08-21 ffc85ee1f1 cmd/internal/objabi,cmd/link: add support for additional riscv64 relocations

Change-Id: I3896f74b1a3cc0a52b29ca48767bb0ba84620f71
This commit is contained in:
Cherry Mui 2025-09-03 11:19:43 -04:00
commit 7c8b9115bc
155 changed files with 3151 additions and 2796 deletions

View file

@ -0,0 +1,2 @@
The HTTP client returned by [Server.Client] will now redirect requests for
`example.com` and any subdomains to the server being tested.

View file

@ -0,0 +1,4 @@
On Windows, the [OpenFile] `flag` parameter can now contain any combination of
Windows-specific file flags, such as `FILE_FLAG_OVERLAPPED` and
`FILE_FLAG_SEQUENTIAL_SCAN`, for control of file or device caching behavior,
access modes, and other special-purpose flags.

View file

@ -311,10 +311,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
if b.r == b.w { if b.r == b.w {
return 0, 0, b.readErr() return 0, 0, b.readErr()
} }
r, size = rune(b.buf[b.r]), 1 r, size = utf8.DecodeRune(b.buf[b.r:b.w])
if r >= utf8.RuneSelf {
r, size = utf8.DecodeRune(b.buf[b.r:b.w])
}
b.r += size b.r += size
b.lastByte = int(b.buf[b.r-1]) b.lastByte = int(b.buf[b.r-1])
b.lastRuneSize = size b.lastRuneSize = size

View file

@ -528,11 +528,7 @@ func FieldsFunc(s []byte, f func(rune) bool) [][]byte {
// more efficient, possibly due to cache effects. // more efficient, possibly due to cache effects.
start := -1 // valid span start if >= 0 start := -1 // valid span start if >= 0
for i := 0; i < len(s); { for i := 0; i < len(s); {
size := 1 r, size := utf8.DecodeRune(s[i:])
r := rune(s[i])
if r >= utf8.RuneSelf {
r, size = utf8.DecodeRune(s[i:])
}
if f(r) { if f(r) {
if start >= 0 { if start >= 0 {
spans = append(spans, span{start, i}) spans = append(spans, span{start, i})
@ -614,11 +610,7 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
// fine. It could also shrink but that falls out naturally. // fine. It could also shrink but that falls out naturally.
b := make([]byte, 0, len(s)) b := make([]byte, 0, len(s))
for i := 0; i < len(s); { for i := 0; i < len(s); {
wid := 1 r, wid := utf8.DecodeRune(s[i:])
r := rune(s[i])
if r >= utf8.RuneSelf {
r, wid = utf8.DecodeRune(s[i:])
}
r = mapping(r) r = mapping(r)
if r >= 0 { if r >= 0 {
b = utf8.AppendRune(b, r) b = utf8.AppendRune(b, r)
@ -917,11 +909,7 @@ func LastIndexFunc(s []byte, f func(r rune) bool) int {
func indexFunc(s []byte, f func(r rune) bool, truth bool) int { func indexFunc(s []byte, f func(r rune) bool, truth bool) int {
start := 0 start := 0
for start < len(s) { for start < len(s) {
wid := 1 r, wid := utf8.DecodeRune(s[start:])
r := rune(s[start])
if r >= utf8.RuneSelf {
r, wid = utf8.DecodeRune(s[start:])
}
if f(r) == truth { if f(r) == truth {
return start return start
} }
@ -1052,10 +1040,7 @@ func trimLeftASCII(s []byte, as *asciiSet) []byte {
func trimLeftUnicode(s []byte, cutset string) []byte { func trimLeftUnicode(s []byte, cutset string) []byte {
for len(s) > 0 { for len(s) > 0 {
r, n := rune(s[0]), 1 r, n := utf8.DecodeRune(s)
if r >= utf8.RuneSelf {
r, n = utf8.DecodeRune(s)
}
if !containsRune(cutset, r) { if !containsRune(cutset, r) {
break break
} }
@ -1117,41 +1102,34 @@ func trimRightUnicode(s []byte, cutset string) []byte {
// TrimSpace returns a subslice of s by slicing off all leading and // TrimSpace returns a subslice of s by slicing off all leading and
// trailing white space, as defined by Unicode. // trailing white space, as defined by Unicode.
func TrimSpace(s []byte) []byte { func TrimSpace(s []byte) []byte {
// Fast path for ASCII: look for the first ASCII non-space byte // Fast path for ASCII: look for the first ASCII non-space byte.
start := 0 for lo, c := range s {
for ; start < len(s); start++ {
c := s[start]
if c >= utf8.RuneSelf { if c >= utf8.RuneSelf {
// If we run into a non-ASCII byte, fall back to the // If we run into a non-ASCII byte, fall back to the
// slower unicode-aware method on the remaining bytes // slower unicode-aware method on the remaining bytes.
return TrimFunc(s[start:], unicode.IsSpace) return TrimFunc(s[lo:], unicode.IsSpace)
} }
if asciiSpace[c] == 0 { if asciiSpace[c] != 0 {
break continue
}
s = s[lo:]
// Now look for the first ASCII non-space byte from the end.
for hi := len(s) - 1; hi >= 0; hi-- {
c := s[hi]
if c >= utf8.RuneSelf {
return TrimFunc(s[:hi+1], unicode.IsSpace)
}
if asciiSpace[c] == 0 {
// At this point, s[:hi+1] starts and ends with ASCII
// non-space bytes, so we're done. Non-ASCII cases have
// already been handled above.
return s[:hi+1]
}
} }
} }
// Special case to preserve previous TrimLeftFunc behavior,
// Now look for the first ASCII non-space byte from the end // returning nil instead of empty slice if all spaces.
stop := len(s) return nil
for ; stop > start; stop-- {
c := s[stop-1]
if c >= utf8.RuneSelf {
return TrimFunc(s[start:stop], unicode.IsSpace)
}
if asciiSpace[c] == 0 {
break
}
}
// At this point s[start:stop] starts and ends with an ASCII
// non-space bytes, so we're done. Non-ASCII cases have already
// been handled above.
if start == stop {
// Special case to preserve previous TrimLeftFunc behavior,
// returning nil instead of empty slice if all spaces.
return nil
}
return s[start:stop]
} }
// Runes interprets s as a sequence of UTF-8-encoded code points. // Runes interprets s as a sequence of UTF-8-encoded code points.
@ -1258,19 +1236,10 @@ hasUnicode:
t = t[i:] t = t[i:]
for len(s) != 0 && len(t) != 0 { for len(s) != 0 && len(t) != 0 {
// Extract first rune from each. // Extract first rune from each.
var sr, tr rune sr, size := utf8.DecodeRune(s)
if s[0] < utf8.RuneSelf { s = s[size:]
sr, s = rune(s[0]), s[1:] tr, size := utf8.DecodeRune(t)
} else { t = t[size:]
r, size := utf8.DecodeRune(s)
sr, s = r, s[size:]
}
if t[0] < utf8.RuneSelf {
tr, t = rune(t[0]), t[1:]
} else {
r, size := utf8.DecodeRune(t)
tr, t = r, t[size:]
}
// If they match, keep going; if not, return false. // If they match, keep going; if not, return false.

View file

@ -117,11 +117,7 @@ func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
return func(yield func([]byte) bool) { return func(yield func([]byte) bool) {
start := -1 start := -1
for i := 0; i < len(s); { for i := 0; i < len(s); {
size := 1 r, size := utf8.DecodeRune(s[i:])
r := rune(s[i])
if r >= utf8.RuneSelf {
r, size = utf8.DecodeRune(s[i:])
}
if f(r) { if f(r) {
if start >= 0 { if start >= 0 {
if !yield(s[start:i:i]) { if !yield(s[start:i:i]) {

View file

@ -260,6 +260,28 @@ lable2:
MOVV FCC0, R4 // 04dc1401 MOVV FCC0, R4 // 04dc1401
MOVV R4, FCC0 // 80d81401 MOVV R4, FCC0 // 80d81401
// LDPTR.{W/D} and STPTR.{W/D} instructions
MOVWP R5, -32768(R4) // 85008025
MOVWP R5, 32764(R4) // 85fc7f25
MOVWP R5, 32(R4) // 85200025
MOVWP R5, 4(R4) // 85040025
MOVWP R5, (R4) // 85000025
MOVVP R5, -32768(R4) // 85008027
MOVVP R5, 32764(R4) // 85fc7f27
MOVVP R5, 32(R4) // 85200027
MOVVP R5, 4(R4) // 85040027
MOVVP R5, (R4) // 85000027
MOVWP -32768(R5), R4 // a4008024
MOVWP 32764(R5), R4 // a4fc7f24
MOVWP 32(R5), R4 // a4200024
MOVWP 4(R5), R4 // a4040024
MOVWP (R5), R4 // a4000024
MOVVP -32768(R5), R4 // a4008026
MOVVP 32764(R5), R4 // a4fc7f26
MOVVP 32(R5), R4 // a4200026
MOVVP 4(R5), R4 // a4040026
MOVVP (R5), R4 // a4000026
// Loong64 atomic memory access instructions // Loong64 atomic memory access instructions
AMSWAPB R14, (R13), R12 // ac395c38 AMSWAPB R14, (R13), R12 // ac395c38
AMSWAPH R14, (R13), R12 // acb95c38 AMSWAPH R14, (R13), R12 // acb95c38

View file

@ -27,6 +27,7 @@ import (
"slices" "slices"
"strconv" "strconv"
"strings" "strings"
"sync/atomic"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
@ -194,13 +195,12 @@ func (p *Package) Translate(f *File) {
var conv typeConv var conv typeConv
conv.Init(p.PtrSize, p.IntSize) conv.Init(p.PtrSize, p.IntSize)
p.typedefs = map[string]bool{} ft := fileTypedefs{typedefs: make(map[string]bool)}
p.typedefList = nil
numTypedefs := -1 numTypedefs := -1
for len(p.typedefs) > numTypedefs { for len(ft.typedefs) > numTypedefs {
numTypedefs = len(p.typedefs) numTypedefs = len(ft.typedefs)
// Also ask about any typedefs we've seen so far. // Also ask about any typedefs we've seen so far.
for _, info := range p.typedefList { for _, info := range ft.typedefList {
if f.Name[info.typedef] != nil { if f.Name[info.typedef] != nil {
continue continue
} }
@ -213,7 +213,8 @@ func (p *Package) Translate(f *File) {
} }
needType := p.guessKinds(f) needType := p.guessKinds(f)
if len(needType) > 0 { if len(needType) > 0 {
p.loadDWARF(f, &conv, needType) d := p.loadDWARF(f, &ft, needType)
p.recordTypes(f, d, &conv)
} }
// In godefs mode we're OK with the typedefs, which // In godefs mode we're OK with the typedefs, which
@ -522,7 +523,7 @@ func (p *Package) guessKinds(f *File) []*Name {
// loadDWARF parses the DWARF debug information generated // loadDWARF parses the DWARF debug information generated
// by gcc to learn the details of the constants, variables, and types // by gcc to learn the details of the constants, variables, and types
// being referred to as C.xxx. // being referred to as C.xxx.
func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) { func (p *Package) loadDWARF(f *File, ft *fileTypedefs, names []*Name) *debug {
// Extract the types from the DWARF section of an object // Extract the types from the DWARF section of an object
// from a well-formed C program. Gcc only generates DWARF info // from a well-formed C program. Gcc only generates DWARF info
// for symbols in the object file, so it is not enough to print the // for symbols in the object file, so it is not enough to print the
@ -636,13 +637,28 @@ func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) {
fatalf("malformed __cgo__ name: %s", name) fatalf("malformed __cgo__ name: %s", name)
} }
types[i] = t.Type types[i] = t.Type
p.recordTypedefs(t.Type, f.NamePos[names[i]]) ft.recordTypedefs(t.Type, f.NamePos[names[i]])
} }
if e.Tag != dwarf.TagCompileUnit { if e.Tag != dwarf.TagCompileUnit {
r.SkipChildren() r.SkipChildren()
} }
} }
return &debug{names, types, ints, floats, strs}
}
// debug is the data extracted by running an iteration of loadDWARF on a file.
type debug struct {
names []*Name
types []dwarf.Type
ints []int64
floats []float64
strs []string
}
func (p *Package) recordTypes(f *File, data *debug, conv *typeConv) {
names, types, ints, floats, strs := data.names, data.types, data.ints, data.floats, data.strs
// Record types and typedef information. // Record types and typedef information.
for i, n := range names { for i, n := range names {
if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" { if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
@ -701,12 +717,17 @@ func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) {
} }
} }
// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children. type fileTypedefs struct {
func (p *Package) recordTypedefs(dtype dwarf.Type, pos token.Pos) { typedefs map[string]bool // type names that appear in the types of the objects we're interested in
p.recordTypedefs1(dtype, pos, map[dwarf.Type]bool{}) typedefList []typedefInfo
} }
func (p *Package) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[dwarf.Type]bool) { // recordTypedefs remembers in ft.typedefs all the typedefs used in dtypes and its children.
func (ft *fileTypedefs) recordTypedefs(dtype dwarf.Type, pos token.Pos) {
ft.recordTypedefs1(dtype, pos, map[dwarf.Type]bool{})
}
func (ft *fileTypedefs) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[dwarf.Type]bool) {
if dtype == nil { if dtype == nil {
return return
} }
@ -720,25 +741,25 @@ func (p *Package) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[d
// Don't look inside builtin types. There be dragons. // Don't look inside builtin types. There be dragons.
return return
} }
if !p.typedefs[dt.Name] { if !ft.typedefs[dt.Name] {
p.typedefs[dt.Name] = true ft.typedefs[dt.Name] = true
p.typedefList = append(p.typedefList, typedefInfo{dt.Name, pos}) ft.typedefList = append(ft.typedefList, typedefInfo{dt.Name, pos})
p.recordTypedefs1(dt.Type, pos, visited) ft.recordTypedefs1(dt.Type, pos, visited)
} }
case *dwarf.PtrType: case *dwarf.PtrType:
p.recordTypedefs1(dt.Type, pos, visited) ft.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.ArrayType: case *dwarf.ArrayType:
p.recordTypedefs1(dt.Type, pos, visited) ft.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.QualType: case *dwarf.QualType:
p.recordTypedefs1(dt.Type, pos, visited) ft.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.FuncType: case *dwarf.FuncType:
p.recordTypedefs1(dt.ReturnType, pos, visited) ft.recordTypedefs1(dt.ReturnType, pos, visited)
for _, a := range dt.ParamType { for _, a := range dt.ParamType {
p.recordTypedefs1(a, pos, visited) ft.recordTypedefs1(a, pos, visited)
} }
case *dwarf.StructType: case *dwarf.StructType:
for _, f := range dt.Field { for _, l := range dt.Field {
p.recordTypedefs1(f.Type, pos, visited) ft.recordTypedefs1(l.Type, pos, visited)
} }
} }
} }
@ -1756,20 +1777,23 @@ func gccMachine() []string {
return nil return nil
} }
var n atomic.Int64
func gccTmp() string { func gccTmp() string {
return *objDir + "_cgo_.o" c := strconv.Itoa(int(n.Add(1)))
return *objDir + "_cgo_" + c + ".o"
} }
// gccCmd returns the gcc command line to use for compiling // gccCmd returns the gcc command line to use for compiling
// the input. // the input.
func (p *Package) gccCmd() []string { func (p *Package) gccCmd(ofile string) []string {
c := append(gccBaseCmd, c := append(gccBaseCmd,
"-w", // no warnings "-w", // no warnings
"-Wno-error", // warnings are not errors "-Wno-error", // warnings are not errors
"-o"+gccTmp(), // write object to tmp "-o"+ofile, // write object to tmp
"-gdwarf-2", // generate DWARF v2 debugging symbols "-gdwarf-2", // generate DWARF v2 debugging symbols
"-c", // do not link "-c", // do not link
"-xc", // input language is C "-xc", // input language is C
) )
if p.GccIsClang { if p.GccIsClang {
c = append(c, c = append(c,
@ -1806,7 +1830,8 @@ func (p *Package) gccCmd() []string {
// gccDebug runs gcc -gdwarf-2 over the C program stdin and // gccDebug runs gcc -gdwarf-2 over the C program stdin and
// returns the corresponding DWARF data and, if present, debug data block. // returns the corresponding DWARF data and, if present, debug data block.
func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) { func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
runGcc(stdin, p.gccCmd()) ofile := gccTmp()
runGcc(stdin, p.gccCmd(ofile))
isDebugInts := func(s string) bool { isDebugInts := func(s string) bool {
// Some systems use leading _ to denote non-assembly symbols. // Some systems use leading _ to denote non-assembly symbols.
@ -1856,11 +1881,11 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
} }
} }
if f, err := macho.Open(gccTmp()); err == nil { if f, err := macho.Open(ofile); err == nil {
defer f.Close() defer f.Close()
d, err := f.DWARF() d, err := f.DWARF()
if err != nil { if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) fatalf("cannot load DWARF output from %s: %v", ofile, err)
} }
bo := f.ByteOrder bo := f.ByteOrder
if f.Symtab != nil { if f.Symtab != nil {
@ -1934,11 +1959,11 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
return d, ints, floats, strs return d, ints, floats, strs
} }
if f, err := elf.Open(gccTmp()); err == nil { if f, err := elf.Open(ofile); err == nil {
defer f.Close() defer f.Close()
d, err := f.DWARF() d, err := f.DWARF()
if err != nil { if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) fatalf("cannot load DWARF output from %s: %v", ofile, err)
} }
bo := f.ByteOrder bo := f.ByteOrder
symtab, err := f.Symbols() symtab, err := f.Symbols()
@ -2034,11 +2059,11 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
return d, ints, floats, strs return d, ints, floats, strs
} }
if f, err := pe.Open(gccTmp()); err == nil { if f, err := pe.Open(ofile); err == nil {
defer f.Close() defer f.Close()
d, err := f.DWARF() d, err := f.DWARF()
if err != nil { if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) fatalf("cannot load DWARF output from %s: %v", ofile, err)
} }
bo := binary.LittleEndian bo := binary.LittleEndian
for _, s := range f.Symbols { for _, s := range f.Symbols {
@ -2106,11 +2131,11 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
return d, ints, floats, strs return d, ints, floats, strs
} }
if f, err := xcoff.Open(gccTmp()); err == nil { if f, err := xcoff.Open(ofile); err == nil {
defer f.Close() defer f.Close()
d, err := f.DWARF() d, err := f.DWARF()
if err != nil { if err != nil {
fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) fatalf("cannot load DWARF output from %s: %v", ofile, err)
} }
bo := binary.BigEndian bo := binary.BigEndian
for _, s := range f.Symbols { for _, s := range f.Symbols {
@ -2176,7 +2201,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
buildStrings() buildStrings()
return d, ints, floats, strs return d, ints, floats, strs
} }
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp()) fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", ofile)
panic("not reached") panic("not reached")
} }
@ -2196,7 +2221,7 @@ func gccDefines(stdin []byte, gccOptions []string) string {
// gcc to fail. // gcc to fail.
func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string { func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string {
// TODO(rsc): require failure // TODO(rsc): require failure
args := p.gccCmd() args := p.gccCmd(gccTmp())
// Optimization options can confuse the error messages; remove them. // Optimization options can confuse the error messages; remove them.
nargs := make([]string, 0, len(args)+len(extraArgs)) nargs := make([]string, 0, len(args)+len(extraArgs))

View file

@ -422,3 +422,11 @@ func TestIssue67976(t *testing.T) {
globalSkip(t) globalSkip(t)
goCmd(t, "build", "-buildmode=plugin", "-o", "issue67976.so", "./issue67976/plugin.go") goCmd(t, "build", "-buildmode=plugin", "-o", "issue67976.so", "./issue67976/plugin.go")
} }
func TestIssue75102(t *testing.T) {
globalSkip(t)
// add gcflags different from the executable file to trigger plugin open failed.
goCmd(t, "build", "-gcflags=all=-N -l", "-buildmode=plugin", "-o", "issue75102.so", "./issue75102/plugin.go")
goCmd(t, "build", "-o", "issue75102.exe", "./issue75102/main.go")
run(t, "./issue75102.exe")
}

View file

@ -0,0 +1,21 @@
// Copyright 2025 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
import (
"fmt"
"plugin"
)
func init() {
_, err := plugin.Open("issue75102.so")
if err == nil {
panic("unexpected success to open a different version plugin")
}
}
func main() {
fmt.Println("done")
}

View file

@ -0,0 +1,11 @@
// Copyright 2025 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 init() {
panic("unexpected call to init")
}
func main() {}

View file

@ -49,8 +49,6 @@ type Package struct {
GoFiles []string // list of Go files GoFiles []string // list of Go files
GccFiles []string // list of gcc output files GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h Preamble string // collected preamble for _cgo_export.h
typedefs map[string]bool // type names that appear in the types of the objects we're interested in
typedefList []typedefInfo
noCallbacks map[string]bool // C function names with #cgo nocallback directive noCallbacks map[string]bool // C function names with #cgo nocallback directive
noEscapes map[string]bool // C function names with #cgo noescape directive noEscapes map[string]bool // C function names with #cgo noescape directive
} }

View file

@ -258,6 +258,7 @@ func processType(t *ast.TypeSpec) {
var doChildrenWithHiddenBody strings.Builder var doChildrenWithHiddenBody strings.Builder
var editChildrenBody strings.Builder var editChildrenBody strings.Builder
var editChildrenWithHiddenBody strings.Builder var editChildrenWithHiddenBody strings.Builder
var hasHidden bool
for _, f := range fields { for _, f := range fields {
names := f.Names names := f.Names
ft := f.Type ft := f.Type
@ -309,6 +310,7 @@ func processType(t *ast.TypeSpec) {
"if n.%s != nil {\nn.%s = edit(n.%s).(%s%s)\n}\n", name, name, name, ptr, ft) "if n.%s != nil {\nn.%s = edit(n.%s).(%s%s)\n}\n", name, name, name, ptr, ft)
} }
if hidden { if hidden {
hasHidden = true
continue continue
} }
if isSlice { if isSlice {
@ -327,19 +329,27 @@ func processType(t *ast.TypeSpec) {
} }
fmt.Fprintf(&buf, "func (n *%s) copy() Node {\nc := *n\n", name) fmt.Fprintf(&buf, "func (n *%s) copy() Node {\nc := *n\n", name)
buf.WriteString(copyBody.String()) buf.WriteString(copyBody.String())
fmt.Fprintf(&buf, "return &c\n}\n") buf.WriteString("return &c\n}\n")
fmt.Fprintf(&buf, "func (n *%s) doChildren(do func(Node) bool) bool {\n", name) fmt.Fprintf(&buf, "func (n *%s) doChildren(do func(Node) bool) bool {\n", name)
buf.WriteString(doChildrenBody.String()) buf.WriteString(doChildrenBody.String())
fmt.Fprintf(&buf, "return false\n}\n") buf.WriteString("return false\n}\n")
fmt.Fprintf(&buf, "func (n *%s) doChildrenWithHidden(do func(Node) bool) bool {\n", name) fmt.Fprintf(&buf, "func (n *%s) doChildrenWithHidden(do func(Node) bool) bool {\n", name)
buf.WriteString(doChildrenWithHiddenBody.String()) if hasHidden {
fmt.Fprintf(&buf, "return false\n}\n") buf.WriteString(doChildrenWithHiddenBody.String())
buf.WriteString("return false\n}\n")
} else {
buf.WriteString("return n.doChildren(do)\n}\n")
}
fmt.Fprintf(&buf, "func (n *%s) editChildren(edit func(Node) Node) {\n", name) fmt.Fprintf(&buf, "func (n *%s) editChildren(edit func(Node) Node) {\n", name)
buf.WriteString(editChildrenBody.String()) buf.WriteString(editChildrenBody.String())
fmt.Fprintf(&buf, "}\n") buf.WriteString("}\n")
fmt.Fprintf(&buf, "func (n *%s) editChildrenWithHidden(edit func(Node) Node) {\n", name) fmt.Fprintf(&buf, "func (n *%s) editChildrenWithHidden(edit func(Node) Node) {\n", name)
buf.WriteString(editChildrenWithHiddenBody.String()) if hasHidden {
fmt.Fprintf(&buf, "}\n") buf.WriteString(editChildrenWithHiddenBody.String())
} else {
buf.WriteString("n.editChildren(edit)\n")
}
buf.WriteString("}\n")
} }
func generateHelpers() { func generateHelpers() {

File diff suppressed because it is too large Load diff

View file

@ -6,49 +6,23 @@ package loong64
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw" "cmd/compile/internal/objw"
"cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/obj/loong64" "cmd/internal/obj/loong64"
) )
func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog { func zerorange(pp *objw.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
if cnt == 0 { if cnt%8 != 0 {
return p panic("zeroed region not aligned")
} }
// Adjust the frame to account for LR. // Adjust the frame to account for LR.
off += base.Ctxt.Arch.FixedFrameSize off += base.Ctxt.Arch.FixedFrameSize
if cnt < int64(4*types.PtrSize) { for cnt != 0 {
for i := int64(0); i < cnt; i += int64(types.PtrSize) { p = pp.Append(p, loong64.AMOVV, obj.TYPE_REG, loong64.REGZERO, 0, obj.TYPE_MEM, loong64.REGSP, off)
p = pp.Append(p, loong64.AMOVV, obj.TYPE_REG, loong64.REGZERO, 0, obj.TYPE_MEM, loong64.REGSP, off+i) off += 8
} cnt -= 8
} else if cnt <= int64(128*types.PtrSize) {
p = pp.Append(p, loong64.AADDV, obj.TYPE_CONST, 0, off, obj.TYPE_REG, loong64.REGRT1, 0)
p.Reg = loong64.REGSP
p = pp.Append(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
p.To.Name = obj.NAME_EXTERN
p.To.Sym = ir.Syms.Duffzero
p.To.Offset = 8 * (128 - cnt/int64(types.PtrSize))
} else {
// ADDV $(off), SP, r1
// ADDV $cnt, r1, r2
// loop:
// MOVV R0, (r1)
// ADDV $Widthptr, r1
// BNE r1, r2, loop
p = pp.Append(p, loong64.AADDV, obj.TYPE_CONST, 0, off, obj.TYPE_REG, loong64.REGRT1, 0)
p.Reg = loong64.REGSP
p = pp.Append(p, loong64.AADDV, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, loong64.REGRT2, 0)
p.Reg = loong64.REGRT1
p = pp.Append(p, loong64.AMOVV, obj.TYPE_REG, loong64.REGZERO, 0, obj.TYPE_MEM, loong64.REGRT1, 0)
loop := p
p = pp.Append(p, loong64.AADDV, obj.TYPE_CONST, 0, int64(types.PtrSize), obj.TYPE_REG, loong64.REGRT1, 0)
p = pp.Append(p, loong64.ABNE, obj.TYPE_REG, loong64.REGRT1, 0, obj.TYPE_BRANCH, 0, 0)
p.Reg = loong64.REGRT2
p.To.SetTarget(loop)
} }
return p return p

View file

@ -125,6 +125,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = y p.To.Reg = y
case ssa.OpLOONG64MOVVnop, case ssa.OpLOONG64MOVVnop,
ssa.OpLOONG64ZERO,
ssa.OpLOONG64LoweredRound32F, ssa.OpLOONG64LoweredRound32F,
ssa.OpLOONG64LoweredRound64F: ssa.OpLOONG64LoweredRound64F:
// nothing to do // nothing to do
@ -432,18 +433,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.To.Reg = v.Args[0].Reg() p.To.Reg = v.Args[0].Reg()
p.To.Index = v.Args[1].Reg() p.To.Index = v.Args[1].Reg()
case ssa.OpLOONG64MOVBstorezeroidx,
ssa.OpLOONG64MOVHstorezeroidx,
ssa.OpLOONG64MOVWstorezeroidx,
ssa.OpLOONG64MOVVstorezeroidx:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = loong64.REGZERO
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_NONE
p.To.Reg = v.Args[0].Reg()
p.To.Index = v.Args[1].Reg()
case ssa.OpLOONG64MOVBload, case ssa.OpLOONG64MOVBload,
ssa.OpLOONG64MOVBUload, ssa.OpLOONG64MOVBUload,
ssa.OpLOONG64MOVHload, ssa.OpLOONG64MOVHload,
@ -471,16 +460,6 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg() p.To.Reg = v.Args[0].Reg()
ssagen.AddAux(&p.To, v) ssagen.AddAux(&p.To, v)
case ssa.OpLOONG64MOVBstorezero,
ssa.OpLOONG64MOVHstorezero,
ssa.OpLOONG64MOVWstorezero,
ssa.OpLOONG64MOVVstorezero:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = loong64.REGZERO
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
ssagen.AddAux(&p.To, v)
case ssa.OpLOONG64MOVBreg, case ssa.OpLOONG64MOVBreg,
ssa.OpLOONG64MOVBUreg, ssa.OpLOONG64MOVBUreg,
ssa.OpLOONG64MOVHreg, ssa.OpLOONG64MOVHreg,
@ -543,6 +522,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
ssa.OpLOONG64SQRTF, ssa.OpLOONG64SQRTF,
ssa.OpLOONG64REVB2H, ssa.OpLOONG64REVB2H,
ssa.OpLOONG64REVB2W, ssa.OpLOONG64REVB2W,
ssa.OpLOONG64REVB4H,
ssa.OpLOONG64REVBV, ssa.OpLOONG64REVBV,
ssa.OpLOONG64BITREV4B, ssa.OpLOONG64BITREV4B,
ssa.OpLOONG64BITREVW, ssa.OpLOONG64BITREVW,
@ -580,28 +560,97 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.To.Sym = ir.Syms.Duffzero p.To.Sym = ir.Syms.Duffzero
p.To.Offset = v.AuxInt p.To.Offset = v.AuxInt
case ssa.OpLOONG64LoweredZero: case ssa.OpLOONG64LoweredZero:
// MOVx R0, (Rarg0) ptrReg := v.Args[0].Reg()
// ADDV $sz, Rarg0 n := v.AuxInt
// BGEU Rarg1, Rarg0, -2(PC) if n < 16 {
mov, sz := largestMove(v.AuxInt) v.Fatalf("Zero too small %d", n)
p := s.Prog(mov) }
// Generate Zeroing instructions.
var off int64
for n >= 8 {
// MOVV ZR, off(ptrReg)
zero8(s, ptrReg, off)
off += 8
n -= 8
}
if n != 0 {
// MOVV ZR, off+n-8(ptrReg)
zero8(s, ptrReg, off+n-8)
}
case ssa.OpLOONG64LoweredZeroLoop:
ptrReg := v.Args[0].Reg()
countReg := v.RegTmp()
var off int64
n := v.AuxInt
loopSize := int64(64)
if n < 3*loopSize {
// - a loop count of 0 won't work.
// - a loop count of 1 is useless.
// - a loop count of 2 is a code size ~tie
// 4 instructions to implement the loop
// 8 instructions in the loop body
// vs
// 16 instuctions in the straightline code
// Might as well use straightline code.
v.Fatalf("ZeroLoop size tool small %d", n)
}
// Put iteration count in a register.
// MOVV $n/loopSize, countReg
p := s.Prog(loong64.AMOVV)
p.From.Type = obj.TYPE_CONST
p.From.Offset = n / loopSize
p.To.Type = obj.TYPE_REG
p.To.Reg = countReg
cntInit := p
// Zero loopSize bytes starting at ptrReg.
for range loopSize / 8 {
// MOVV ZR, off(ptrReg)
zero8(s, ptrReg, off)
off += 8
}
// Increment ptrReg by loopSize.
// ADDV $loopSize, ptrReg
p = s.Prog(loong64.AADDV)
p.From.Type = obj.TYPE_CONST
p.From.Offset = loopSize
p.To.Type = obj.TYPE_REG
p.To.Reg = ptrReg
// Decrement loop count.
// SUBV $1, countReg
p = s.Prog(loong64.ASUBV)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 1
p.To.Type = obj.TYPE_REG
p.To.Reg = countReg
// Jump to loop header if we're not done yet.
// BNE countReg, loop header
p = s.Prog(loong64.ABNE)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = loong64.REGZERO p.From.Reg = countReg
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_BRANCH
p.To.Reg = v.Args[0].Reg() p.To.SetTarget(cntInit.Link)
p2 := s.Prog(loong64.AADDVU) // Multiples of the loop size are now done.
p2.From.Type = obj.TYPE_CONST n %= loopSize
p2.From.Offset = sz
p2.To.Type = obj.TYPE_REG
p2.To.Reg = v.Args[0].Reg()
p3 := s.Prog(loong64.ABGEU) off = 0
p3.From.Type = obj.TYPE_REG // Write any fractional portion.
p3.From.Reg = v.Args[1].Reg() for n >= 8 {
p3.Reg = v.Args[0].Reg() // MOVV ZR, off(ptrReg)
p3.To.Type = obj.TYPE_BRANCH zero8(s, ptrReg, off)
p3.To.SetTarget(p) off += 8
n -= 8
}
if n != 0 {
zero8(s, ptrReg, off+n-8)
}
case ssa.OpLOONG64DUFFCOPY: case ssa.OpLOONG64DUFFCOPY:
p := s.Prog(obj.ADUFFCOPY) p := s.Prog(obj.ADUFFCOPY)
@ -1175,3 +1224,14 @@ func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg in
p.Pos = p.Pos.WithNotStmt() p.Pos = p.Pos.WithNotStmt()
return p return p
} }
// zero8 zeroes 8 bytes at reg+off.
func zero8(s *ssagen.State, reg int16, off int64) {
// MOVV ZR, off(reg)
p := s.Prog(loong64.AMOVV)
p.From.Type = obj.TYPE_REG
p.From.Reg = loong64.REGZERO
p.To.Type = obj.TYPE_MEM
p.To.Reg = reg
p.To.Offset = off
}

View file

@ -136,6 +136,27 @@
(Rsh8x16 <t> x y) && !shiftIsBounded(v) => (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt16to64 y))) (Rsh8x16 <t> x y) && !shiftIsBounded(v) => (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt16to64 y)))
(Rsh8x8 <t> x y) && !shiftIsBounded(v) => (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt8to64 y))) (Rsh8x8 <t> x y) && !shiftIsBounded(v) => (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt8to64 y)))
// revb2h
// ((x>>8) | (x<<8)) => (REVB2H x), the type of x is uint16
((OR|XOR|ADDV) <typ.UInt16> (SRLVconst [8] <typ.UInt16> x) (SLLVconst [8] <typ.UInt16> x)) => (REVB2H x)
// ((x & 0xff00ff00)>>8) | ((x & 0x00ff00ff)<<8), the type of x is uint32
((OR|XOR|ADDV) (SRLconst [8] (ANDconst [c1] x)) (SLLconst [8] (ANDconst [c2] x)))
&& uint32(c1) == 0xff00ff00 && uint32(c2) == 0x00ff00ff
=> (REVB2H x)
// revb4h
// ((x & 0xff00ff00ff00ff00)>>8) | ((x & 0x00ff00ff00ff00ff)<<8), the type of x is uint64
((OR|XOR|ADDV) (SRLVconst [8] (AND (MOVVconst [c1]) x)) (SLLVconst [8] (AND (MOVVconst [c2]) x)))
&& uint64(c1) == 0xff00ff00ff00ff00 && uint64(c2) == 0x00ff00ff00ff00ff
=> (REVB4H x)
// ((x & 0xff00ff00)>>8) | ((x & 0x00ff00ff)<<8), the type of x is uint64
((OR|XOR|ADDV) (SRLVconst [8] (AND (MOVVconst [c1]) x)) (SLLVconst [8] (ANDconst [c2] x)))
&& uint64(c1) == 0xff00ff00 && uint64(c2) == 0x00ff00ff
=> (REVB4H (ANDconst <x.Type> [0xffffffff] x))
// bitfield ops // bitfield ops
// bstrpickv // bstrpickv
@ -352,24 +373,8 @@
(MOVVstore [8] ptr (MOVVconst [0]) (MOVVstore [8] ptr (MOVVconst [0])
(MOVVstore ptr (MOVVconst [0]) mem)) (MOVVstore ptr (MOVVconst [0]) mem))
// strip off fractional word zeroing (Zero [s] ptr mem) && s > 16 && s < 192 => (LoweredZero [s] ptr mem)
(Zero [s] ptr mem) && s%8 != 0 && s > 16 => (Zero [s] ptr mem) && s >= 192 => (LoweredZeroLoop [s] ptr mem)
(Zero [s%8]
(OffPtr <ptr.Type> ptr [s-s%8])
(Zero [s-s%8] ptr mem))
// medium zeroing uses a duff device
(Zero [s] ptr mem)
&& s%8 == 0 && s > 16 && s <= 8*128 =>
(DUFFZERO [8 * (128 - s/8)] ptr mem)
// large zeroing uses a loop
(Zero [s] ptr mem)
&& s%8 == 0 && s > 8*128 =>
(LoweredZero
ptr
(ADDVconst <ptr.Type> ptr [s-8])
mem)
// moves // moves
(Move [0] _ _ mem) => mem (Move [0] _ _ mem) => mem
@ -555,10 +560,6 @@
&& (ptr.Op != OpSB || !config.ctxt.Flag_dynlink) => && (ptr.Op != OpSB || !config.ctxt.Flag_dynlink) =>
(MOV(B|H|W|V|F|D)store [off1+int32(off2)] {sym} ptr val mem) (MOV(B|H|W|V|F|D)store [off1+int32(off2)] {sym} ptr val mem)
(MOV(B|H|W|V)storezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(int64(off1)+off2)
&& (ptr.Op != OpSB || !config.ctxt.Flag_dynlink) =>
(MOV(B|H|W|V)storezero [off1+int32(off2)] {sym} ptr mem)
(MOV(B|BU|H|HU|W|WU|V|F|D)load [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) (MOV(B|BU|H|HU|W|WU|V|F|D)load [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_dynlink) => && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_dynlink) =>
(MOV(B|BU|H|HU|W|WU|V|F|D)load [off1+int32(off2)] {mergeSym(sym1,sym2)} ptr mem) (MOV(B|BU|H|HU|W|WU|V|F|D)load [off1+int32(off2)] {mergeSym(sym1,sym2)} ptr mem)
@ -567,10 +568,6 @@
&& is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_dynlink) => && is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_dynlink) =>
(MOV(B|H|W|V|F|D)store [off1+int32(off2)] {mergeSym(sym1,sym2)} ptr val mem) (MOV(B|H|W|V|F|D)store [off1+int32(off2)] {mergeSym(sym1,sym2)} ptr val mem)
(MOV(B|H|W|V)storezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
&& is32Bit(int64(off1)+int64(off2)) && (ptr.Op != OpSB || !config.ctxt.Flag_dynlink) =>
(MOV(B|H|W|V)storezero [off1+int32(off2)] {mergeSym(sym1,sym2)} ptr mem)
// don't extend after proper load // don't extend after proper load
(MOVBreg x:(MOVBload _ _)) => (MOVVreg x) (MOVBreg x:(MOVBload _ _)) => (MOVVreg x)
(MOVBUreg x:(MOVBUload _ _)) => (MOVVreg x) (MOVBUreg x:(MOVBUload _ _)) => (MOVVreg x)
@ -587,6 +584,21 @@
(MOVWUreg x:(MOVBUload _ _)) => (MOVVreg x) (MOVWUreg x:(MOVBUload _ _)) => (MOVVreg x)
(MOVWUreg x:(MOVHUload _ _)) => (MOVVreg x) (MOVWUreg x:(MOVHUload _ _)) => (MOVVreg x)
(MOVWUreg x:(MOVWUload _ _)) => (MOVVreg x) (MOVWUreg x:(MOVWUload _ _)) => (MOVVreg x)
(MOVBreg x:(MOVBloadidx _ _ _)) => (MOVVreg x)
(MOVBUreg x:(MOVBUloadidx _ _ _)) => (MOVVreg x)
(MOVHreg x:(MOVBloadidx _ _ _)) => (MOVVreg x)
(MOVHreg x:(MOVBUloadidx _ _ _)) => (MOVVreg x)
(MOVHreg x:(MOVHloadidx _ _ _)) => (MOVVreg x)
(MOVHUreg x:(MOVBUloadidx _ _ _)) => (MOVVreg x)
(MOVHUreg x:(MOVHUloadidx _ _ _)) => (MOVVreg x)
(MOVWreg x:(MOVBloadidx _ _ _)) => (MOVVreg x)
(MOVWreg x:(MOVBUloadidx _ _ _)) => (MOVVreg x)
(MOVWreg x:(MOVHloadidx _ _ _)) => (MOVVreg x)
(MOVWreg x:(MOVHUloadidx _ _ _)) => (MOVVreg x)
(MOVWreg x:(MOVWloadidx _ _ _)) => (MOVVreg x)
(MOVWUreg x:(MOVBUloadidx _ _ _)) => (MOVVreg x)
(MOVWUreg x:(MOVHUloadidx _ _ _)) => (MOVVreg x)
(MOVWUreg x:(MOVWUloadidx _ _ _)) => (MOVVreg x)
// fold double extensions // fold double extensions
(MOVBreg x:(MOVBreg _)) => (MOVVreg x) (MOVBreg x:(MOVBreg _)) => (MOVVreg x)
@ -618,11 +630,6 @@
(MOVWstore [off] {sym} ptr (MOVWreg x) mem) => (MOVWstore [off] {sym} ptr x mem) (MOVWstore [off] {sym} ptr (MOVWreg x) mem) => (MOVWstore [off] {sym} ptr x mem)
(MOVWstore [off] {sym} ptr (MOVWUreg x) mem) => (MOVWstore [off] {sym} ptr x mem) (MOVWstore [off] {sym} ptr (MOVWUreg x) mem) => (MOVWstore [off] {sym} ptr x mem)
(MOVBstore [off] {sym} ptr (MOVVconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
(MOVHstore [off] {sym} ptr (MOVVconst [0]) mem) => (MOVHstorezero [off] {sym} ptr mem)
(MOVWstore [off] {sym} ptr (MOVVconst [0]) mem) => (MOVWstorezero [off] {sym} ptr mem)
(MOVVstore [off] {sym} ptr (MOVVconst [0]) mem) => (MOVVstorezero [off] {sym} ptr mem)
// register indexed load // register indexed load
(MOVVload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVVloadidx ptr idx mem) (MOVVload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVVloadidx ptr idx mem)
(MOVWUload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVWUloadidx ptr idx mem) (MOVWUload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVWUloadidx ptr idx mem)
@ -672,24 +679,6 @@
(MOVDstoreidx ptr (MOVVconst [c]) val mem) && is32Bit(c) => (MOVDstore [int32(c)] ptr val mem) (MOVDstoreidx ptr (MOVVconst [c]) val mem) && is32Bit(c) => (MOVDstore [int32(c)] ptr val mem)
(MOVDstoreidx (MOVVconst [c]) idx val mem) && is32Bit(c) => (MOVDstore [int32(c)] idx val mem) (MOVDstoreidx (MOVVconst [c]) idx val mem) && is32Bit(c) => (MOVDstore [int32(c)] idx val mem)
// register indexed store zero
(MOVVstorezero [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVVstorezeroidx ptr idx mem)
(MOVWstorezero [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVWstorezeroidx ptr idx mem)
(MOVHstorezero [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVHstorezeroidx ptr idx mem)
(MOVBstorezero [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVBstorezeroidx ptr idx mem)
(MOVVstoreidx ptr idx (MOVVconst [0]) mem) => (MOVVstorezeroidx ptr idx mem)
(MOVWstoreidx ptr idx (MOVVconst [0]) mem) => (MOVWstorezeroidx ptr idx mem)
(MOVHstoreidx ptr idx (MOVVconst [0]) mem) => (MOVHstorezeroidx ptr idx mem)
(MOVBstoreidx ptr idx (MOVVconst [0]) mem) => (MOVBstorezeroidx ptr idx mem)
(MOVVstorezeroidx ptr (MOVVconst [c]) mem) && is32Bit(c) => (MOVVstorezero [int32(c)] ptr mem)
(MOVVstorezeroidx (MOVVconst [c]) idx mem) && is32Bit(c) => (MOVVstorezero [int32(c)] idx mem)
(MOVWstorezeroidx ptr (MOVVconst [c]) mem) && is32Bit(c) => (MOVWstorezero [int32(c)] ptr mem)
(MOVWstorezeroidx (MOVVconst [c]) idx mem) && is32Bit(c) => (MOVWstorezero [int32(c)] idx mem)
(MOVHstorezeroidx ptr (MOVVconst [c]) mem) && is32Bit(c) => (MOVHstorezero [int32(c)] ptr mem)
(MOVHstorezeroidx (MOVVconst [c]) idx mem) && is32Bit(c) => (MOVHstorezero [int32(c)] idx mem)
(MOVBstorezeroidx ptr (MOVVconst [c]) mem) && is32Bit(c) => (MOVBstorezero [int32(c)] ptr mem)
(MOVBstorezeroidx (MOVVconst [c]) idx mem) && is32Bit(c) => (MOVBstorezero [int32(c)] idx mem)
// if a register move has only 1 use, just use the same register without emitting instruction // if a register move has only 1 use, just use the same register without emitting instruction
// MOVVnop doesn't emit instruction, only for ensuring the type. // MOVVnop doesn't emit instruction, only for ensuring the type.
(MOVVreg x) && x.Uses == 1 => (MOVVnop x) (MOVVreg x) && x.Uses == 1 => (MOVVnop x)
@ -749,6 +738,9 @@
(SRLVconst [rc] (MOVHUreg x)) && rc >= 16 => (MOVVconst [0]) (SRLVconst [rc] (MOVHUreg x)) && rc >= 16 => (MOVVconst [0])
(SRLVconst [rc] (MOVBUreg x)) && rc >= 8 => (MOVVconst [0]) (SRLVconst [rc] (MOVBUreg x)) && rc >= 8 => (MOVVconst [0])
// (x + x) << c -> x << c+1
((SLLV|SLL)const [c] (ADDV x x)) => ((SLLV|SLL)const [c+1] x)
// mul by constant // mul by constant
(MULV _ (MOVVconst [0])) => (MOVVconst [0]) (MULV _ (MOVVconst [0])) => (MOVVconst [0])
(MULV x (MOVVconst [1])) => x (MULV x (MOVVconst [1])) => x
@ -758,6 +750,8 @@
(MULV (NEGV x) (MOVVconst [c])) => (MULV x (MOVVconst [-c])) (MULV (NEGV x) (MOVVconst [c])) => (MULV x (MOVVconst [-c]))
(MULV (NEGV x) (NEGV y)) => (MULV x y) (MULV (NEGV x) (NEGV y)) => (MULV x y)
(ADDV x0 x1:(SLLVconst [c] y)) && x1.Uses == 1 && c > 0 && c <= 4 => (ADDshiftLLV x0 y [c])
// div by constant // div by constant
(DIVVU x (MOVVconst [1])) => x (DIVVU x (MOVVconst [1])) => x
(DIVVU x (MOVVconst [c])) && isPowerOfTwo(c) => (SRLVconst [log64(c)] x) (DIVVU x (MOVVconst [c])) && isPowerOfTwo(c) => (SRLVconst [log64(c)] x)

View file

@ -29,7 +29,7 @@ import "strings"
// so that regmask stays within int64 // so that regmask stays within int64
// Be careful when hand coding regmasks. // Be careful when hand coding regmasks.
var regNamesLOONG64 = []string{ var regNamesLOONG64 = []string{
"R0", // constant 0 "ZERO", // constant 0
"R1", "R1",
"SP", // aka R3 "SP", // aka R3
"R4", "R4",
@ -131,18 +131,18 @@ func init() {
fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31") fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31")
callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g
first16 = buildReg("R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19") first16 = buildReg("R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19")
rz = buildReg("ZERO")
) )
// Common regInfo // Common regInfo
var ( var (
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}} gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}} gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}} gp21 = regInfo{inputs: []regMask{gpg, gpg | rz}, outputs: []regMask{gp}}
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}} gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}} gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
gpstore0 = regInfo{inputs: []regMask{gpspsbg}} gpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg, gpg | rz}}
gpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}}
gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}} gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}} gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
preldreg = regInfo{inputs: []regMask{gpspg}} preldreg = regInfo{inputs: []regMask{gpspg}}
@ -177,6 +177,7 @@ func init() {
{name: "REVB2H", argLength: 1, reg: gp11, asm: "REVB2H"}, // Swap bytes: 0x11223344 -> 0x22114433 (sign extends to 64 bits) {name: "REVB2H", argLength: 1, reg: gp11, asm: "REVB2H"}, // Swap bytes: 0x11223344 -> 0x22114433 (sign extends to 64 bits)
{name: "REVB2W", argLength: 1, reg: gp11, asm: "REVB2W"}, // Swap bytes: 0x1122334455667788 -> 0x4433221188776655 {name: "REVB2W", argLength: 1, reg: gp11, asm: "REVB2W"}, // Swap bytes: 0x1122334455667788 -> 0x4433221188776655
{name: "REVB4H", argLength: 1, reg: gp11, asm: "REVB4H"}, // Swap bytes: 0x1122334455667788 -> 0x2211443366558877
{name: "REVBV", argLength: 1, reg: gp11, asm: "REVBV"}, // Swap bytes: 0x1122334455667788 -> 0x8877665544332211 {name: "REVBV", argLength: 1, reg: gp11, asm: "REVBV"}, // Swap bytes: 0x1122334455667788 -> 0x8877665544332211
{name: "BITREV4B", argLength: 1, reg: gp11, asm: "BITREV4B"}, // Reverse the bits of each byte inside a 32-bit arg[0] {name: "BITREV4B", argLength: 1, reg: gp11, asm: "BITREV4B"}, // Reverse the bits of each byte inside a 32-bit arg[0]
@ -304,12 +305,12 @@ func init() {
{name: "MOVFloadidx", argLength: 3, reg: fp2load, asm: "MOVF", typ: "Float32"}, // load 32-bit float from arg0 + arg1, arg2=mem. {name: "MOVFloadidx", argLength: 3, reg: fp2load, asm: "MOVF", typ: "Float32"}, // load 32-bit float from arg0 + arg1, arg2=mem.
{name: "MOVDloadidx", argLength: 3, reg: fp2load, asm: "MOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1, arg2=mem. {name: "MOVDloadidx", argLength: 3, reg: fp2load, asm: "MOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1, arg2=mem.
{name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVBstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg | rz}}, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVHstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg | rz}}, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVWstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg | rz}}, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "MOVVstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVVstore", argLength: 3, reg: regInfo{inputs: []regMask{gpspsbg, gpg | rz}}, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
// register indexed store // register indexed store
{name: "MOVBstoreidx", argLength: 4, reg: gpstore2, asm: "MOVB", typ: "Mem"}, // store 1 byte of arg2 to arg0 + arg1, arg3 = mem. {name: "MOVBstoreidx", argLength: 4, reg: gpstore2, asm: "MOVB", typ: "Mem"}, // store 1 byte of arg2 to arg0 + arg1, arg3 = mem.
@ -319,17 +320,6 @@ func init() {
{name: "MOVFstoreidx", argLength: 4, reg: fpstore2, asm: "MOVF", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1, arg3=mem. {name: "MOVFstoreidx", argLength: 4, reg: fpstore2, asm: "MOVF", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1, arg3=mem.
{name: "MOVDstoreidx", argLength: 4, reg: fpstore2, asm: "MOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1, arg3=mem. {name: "MOVDstoreidx", argLength: 4, reg: fpstore2, asm: "MOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1, arg3=mem.
{name: "MOVBstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of zero to arg0 + auxInt + aux. arg1=mem.
{name: "MOVHstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of zero to arg0 + auxInt + aux. arg1=mem.
{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of zero to arg0 + auxInt + aux. arg1=mem.
{name: "MOVVstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of zero to arg0 + auxInt + aux. ar12=mem.
// register indexed store zero
{name: "MOVBstorezeroidx", argLength: 3, reg: gpstore, asm: "MOVB", typ: "Mem"}, // store 1 byte of zero to arg0 + arg1, arg2 = mem.
{name: "MOVHstorezeroidx", argLength: 3, reg: gpstore, asm: "MOVH", typ: "Mem"}, // store 2 bytes of zero to arg0 + arg1, arg2 = mem.
{name: "MOVWstorezeroidx", argLength: 3, reg: gpstore, asm: "MOVW", typ: "Mem"}, // store 4 bytes of zero to arg0 + arg1, arg2 = mem.
{name: "MOVVstorezeroidx", argLength: 3, reg: gpstore, asm: "MOVV", typ: "Mem"}, // store 8 bytes of zero to arg0 + arg1, arg2 = mem.
// moves (no conversion) // moves (no conversion)
{name: "MOVWfpgp", argLength: 1, reg: fpgp, asm: "MOVW"}, // move float32 to int32 (no conversion). {name: "MOVWfpgp", argLength: 1, reg: fpgp, asm: "MOVW"}, // move float32 to int32 (no conversion).
{name: "MOVWgpfp", argLength: 1, reg: gpfp, asm: "MOVW"}, // move int32 to float32 (no conversion). {name: "MOVWgpfp", argLength: 1, reg: gpfp, asm: "MOVW"}, // move int32 to float32 (no conversion).
@ -386,6 +376,21 @@ func init() {
faultOnNilArg0: true, faultOnNilArg0: true,
}, },
// medium zeroing
// arg0 = address of memory to zero
// arg1 = mem
// auxint = number of bytes to zero
// returns mem
{
name: "LoweredZero",
aux: "Int64",
argLength: 2,
reg: regInfo{
inputs: []regMask{gp},
},
faultOnNilArg0: true,
},
// duffcopy // duffcopy
// arg0 = address of dst memory (in R21, changed as side effect) // arg0 = address of dst memory (in R21, changed as side effect)
// arg1 = address of src memory (in R20, changed as side effect) // arg1 = address of src memory (in R20, changed as side effect)
@ -405,25 +410,21 @@ func init() {
faultOnNilArg1: true, faultOnNilArg1: true,
}, },
// large or unaligned zeroing // large zeroing
// arg0 = address of memory to zero (in R20, changed as side effect) // arg0 = address of memory to zero
// arg1 = address of the last element to zero // arg1 = mem
// arg2 = mem // auxint = number of bytes to zero
// auxint = alignment
// returns mem // returns mem
// MOVx R0, (R20)
// ADDV $sz, R20
// BGEU Rarg1, R20, -2(PC)
{ {
name: "LoweredZero", name: "LoweredZeroLoop",
aux: "Int64", aux: "Int64",
argLength: 3, argLength: 2,
reg: regInfo{ reg: regInfo{
inputs: []regMask{buildReg("R20"), gp}, inputs: []regMask{gp},
clobbers: buildReg("R20"), clobbersArg0: true,
}, },
typ: "Mem",
faultOnNilArg0: true, faultOnNilArg0: true,
needIntTemp: true,
}, },
// large or unaligned move // large or unaligned move
@ -579,6 +580,7 @@ func init() {
{name: "PRELDX", argLength: 2, aux: "Int64", reg: preldreg, asm: "PRELDX", hasSideEffects: true}, {name: "PRELDX", argLength: 2, aux: "Int64", reg: preldreg, asm: "PRELDX", hasSideEffects: true},
{name: "ADDshiftLLV", argLength: 2, aux: "Int64", reg: gp21, asm: "ALSLV"}, // arg0 + arg1<<auxInt, the value of auxInt should be in the range [1, 4]. {name: "ADDshiftLLV", argLength: 2, aux: "Int64", reg: gp21, asm: "ALSLV"}, // arg0 + arg1<<auxInt, the value of auxInt should be in the range [1, 4].
{name: "ZERO", zeroWidth: true, fixedReg: true},
} }
blocks := []blockData{ blocks := []blockData{

View file

@ -7,3 +7,6 @@
(EQZ (XOR x y) yes no) => (BEQ x y yes no) (EQZ (XOR x y) yes no) => (BEQ x y yes no)
(NEZ (XOR x y) yes no) => (BNE x y yes no) (NEZ (XOR x y) yes no) => (BNE x y yes no)
// use zero register
(MOVVconst [0]) => (ZERO)

View file

@ -12,9 +12,7 @@
(Mul64 ...) => (MUL ...) (Mul64 ...) => (MUL ...)
(Mul64uhilo ...) => (LoweredMuluhilo ...) (Mul64uhilo ...) => (LoweredMuluhilo ...)
(Mul64uover ...) => (LoweredMuluover ...) (Mul64uover ...) => (LoweredMuluover ...)
(Mul32 ...) => (MULW ...) (Mul(32|16|8) ...) => (MULW ...)
(Mul16 x y) => (MULW (SignExt16to32 x) (SignExt16to32 y))
(Mul8 x y) => (MULW (SignExt8to32 x) (SignExt8to32 y))
(Mul(64|32)F ...) => (FMUL(D|S) ...) (Mul(64|32)F ...) => (FMUL(D|S) ...)
(Div(64|32)F ...) => (FDIV(D|S) ...) (Div(64|32)F ...) => (FDIV(D|S) ...)

View file

@ -1900,22 +1900,10 @@
(Neq(8|16|32|64) s:(Sub(8|16|32|64) x y) (Const(8|16|32|64) [0])) && s.Uses == 1 => (Neq(8|16|32|64) x y) (Neq(8|16|32|64) s:(Sub(8|16|32|64) x y) (Const(8|16|32|64) [0])) && s.Uses == 1 => (Neq(8|16|32|64) x y)
// Optimize bitsets // Optimize bitsets
(Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y])) && oneBit8(y) (Eq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [y])) (Const(8|16|32|64) <t> [y])) && oneBit(y)
=> (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0])) => (Neq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [y])) (Const(8|16|32|64) <t> [0]))
(Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y])) && oneBit16(y) (Neq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [y])) (Const(8|16|32|64) <t> [y])) && oneBit(y)
=> (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0])) => (Eq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [y])) (Const(8|16|32|64) <t> [0]))
(Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y])) && oneBit32(y)
=> (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0]))
(Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y])) && oneBit64(y)
=> (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0]))
(Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y])) && oneBit8(y)
=> (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0]))
(Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y])) && oneBit16(y)
=> (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0]))
(Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y])) && oneBit32(y)
=> (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0]))
(Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y])) && oneBit64(y)
=> (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0]))
// Reassociate expressions involving // Reassociate expressions involving
// constants such that constants come first, // constants such that constants come first,

View file

@ -3144,6 +3144,7 @@ const (
OpLOONG64CTZV OpLOONG64CTZV
OpLOONG64REVB2H OpLOONG64REVB2H
OpLOONG64REVB2W OpLOONG64REVB2W
OpLOONG64REVB4H
OpLOONG64REVBV OpLOONG64REVBV
OpLOONG64BITREV4B OpLOONG64BITREV4B
OpLOONG64BITREVW OpLOONG64BITREVW
@ -3257,14 +3258,6 @@ const (
OpLOONG64MOVVstoreidx OpLOONG64MOVVstoreidx
OpLOONG64MOVFstoreidx OpLOONG64MOVFstoreidx
OpLOONG64MOVDstoreidx OpLOONG64MOVDstoreidx
OpLOONG64MOVBstorezero
OpLOONG64MOVHstorezero
OpLOONG64MOVWstorezero
OpLOONG64MOVVstorezero
OpLOONG64MOVBstorezeroidx
OpLOONG64MOVHstorezeroidx
OpLOONG64MOVWstorezeroidx
OpLOONG64MOVVstorezeroidx
OpLOONG64MOVWfpgp OpLOONG64MOVWfpgp
OpLOONG64MOVWgpfp OpLOONG64MOVWgpfp
OpLOONG64MOVVfpgp OpLOONG64MOVVfpgp
@ -3294,8 +3287,9 @@ const (
OpLOONG64CALLclosure OpLOONG64CALLclosure
OpLOONG64CALLinter OpLOONG64CALLinter
OpLOONG64DUFFZERO OpLOONG64DUFFZERO
OpLOONG64DUFFCOPY
OpLOONG64LoweredZero OpLOONG64LoweredZero
OpLOONG64DUFFCOPY
OpLOONG64LoweredZeroLoop
OpLOONG64LoweredMove OpLOONG64LoweredMove
OpLOONG64LoweredAtomicLoad8 OpLOONG64LoweredAtomicLoad8
OpLOONG64LoweredAtomicLoad32 OpLOONG64LoweredAtomicLoad32
@ -3336,6 +3330,7 @@ const (
OpLOONG64PRELD OpLOONG64PRELD
OpLOONG64PRELDX OpLOONG64PRELDX
OpLOONG64ADDshiftLLV OpLOONG64ADDshiftLLV
OpLOONG64ZERO
OpMIPSADD OpMIPSADD
OpMIPSADDconst OpMIPSADDconst
@ -46695,6 +46690,19 @@ var opcodeTable = [...]opInfo{
}, },
}, },
}, },
{
name: "REVB4H",
argLen: 1,
asm: loong64.AREVB4H,
reg: regInfo{
inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
},
outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
},
},
},
{ {
name: "REVBV", name: "REVBV",
argLen: 1, argLen: 1,
@ -46794,7 +46802,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -46822,7 +46830,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -46851,7 +46859,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -46866,7 +46874,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -46881,7 +46889,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -46895,7 +46903,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -46909,7 +46917,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -46923,7 +46931,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -46937,7 +46945,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47068,7 +47076,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47097,7 +47105,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47126,7 +47134,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47155,7 +47163,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47183,7 +47191,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47197,7 +47205,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47403,7 +47411,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47417,7 +47425,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47445,7 +47453,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47459,7 +47467,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47501,7 +47509,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47515,7 +47523,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47557,7 +47565,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47571,7 +47579,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47613,7 +47621,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47627,7 +47635,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47669,7 +47677,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -47697,7 +47705,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
@ -48143,7 +48151,7 @@ var opcodeTable = [...]opInfo{
asm: loong64.AMOVB, asm: loong64.AMOVB,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB {0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
}, },
}, },
@ -48157,7 +48165,7 @@ var opcodeTable = [...]opInfo{
asm: loong64.AMOVH, asm: loong64.AMOVH,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB {0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
}, },
}, },
@ -48171,7 +48179,7 @@ var opcodeTable = [...]opInfo{
asm: loong64.AMOVW, asm: loong64.AMOVW,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB {0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
}, },
}, },
@ -48185,7 +48193,7 @@ var opcodeTable = [...]opInfo{
asm: loong64.AMOVV, asm: loong64.AMOVV,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB {0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
}, },
}, },
@ -48225,7 +48233,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{2, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {2, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB {0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
}, },
}, },
@ -48237,7 +48245,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{2, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {2, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB {0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
}, },
}, },
@ -48249,7 +48257,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{2, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {2, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB {0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
}, },
}, },
@ -48261,7 +48269,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{2, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {2, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB {0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
}, },
}, },
@ -48290,102 +48298,6 @@ var opcodeTable = [...]opInfo{
}, },
}, },
}, },
{
name: "MOVBstorezero",
auxType: auxSymOff,
argLen: 2,
faultOnNilArg0: true,
symEffect: SymWrite,
asm: loong64.AMOVB,
reg: regInfo{
inputs: []inputInfo{
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
},
},
},
{
name: "MOVHstorezero",
auxType: auxSymOff,
argLen: 2,
faultOnNilArg0: true,
symEffect: SymWrite,
asm: loong64.AMOVH,
reg: regInfo{
inputs: []inputInfo{
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
},
},
},
{
name: "MOVWstorezero",
auxType: auxSymOff,
argLen: 2,
faultOnNilArg0: true,
symEffect: SymWrite,
asm: loong64.AMOVW,
reg: regInfo{
inputs: []inputInfo{
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
},
},
},
{
name: "MOVVstorezero",
auxType: auxSymOff,
argLen: 2,
faultOnNilArg0: true,
symEffect: SymWrite,
asm: loong64.AMOVV,
reg: regInfo{
inputs: []inputInfo{
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
},
},
},
{
name: "MOVBstorezeroidx",
argLen: 3,
asm: loong64.AMOVB,
reg: regInfo{
inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
},
},
},
{
name: "MOVHstorezeroidx",
argLen: 3,
asm: loong64.AMOVH,
reg: regInfo{
inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
},
},
},
{
name: "MOVWstorezeroidx",
argLen: 3,
asm: loong64.AMOVW,
reg: regInfo{
inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
},
},
},
{
name: "MOVVstorezeroidx",
argLen: 3,
asm: loong64.AMOVV,
reg: regInfo{
inputs: []inputInfo{
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{0, 4611686019501129724}, // SP R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 SB
},
},
},
{ {
name: "MOVWfpgp", name: "MOVWfpgp",
argLen: 1, argLen: 1,
@ -48758,6 +48670,17 @@ var opcodeTable = [...]opInfo{
clobbers: 524290, // R1 R20 clobbers: 524290, // R1 R20
}, },
}, },
{
name: "LoweredZero",
auxType: auxInt64,
argLen: 2,
faultOnNilArg0: true,
reg: regInfo{
inputs: []inputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
},
},
},
{ {
name: "DUFFCOPY", name: "DUFFCOPY",
auxType: auxInt64, auxType: auxInt64,
@ -48773,16 +48696,16 @@ var opcodeTable = [...]opInfo{
}, },
}, },
{ {
name: "LoweredZero", name: "LoweredZeroLoop",
auxType: auxInt64, auxType: auxInt64,
argLen: 3, argLen: 2,
needIntTemp: true,
faultOnNilArg0: true, faultOnNilArg0: true,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 524288}, // R20 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
{1, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
}, },
clobbers: 524288, // R20 clobbersArg0: true,
}, },
}, },
{ {
@ -49316,13 +49239,20 @@ var opcodeTable = [...]opInfo{
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {0, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
{1, 1073741816}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31 {1, 1073741817}, // ZERO R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 g R23 R24 R25 R26 R27 R28 R29 R31
}, },
outputs: []outputInfo{ outputs: []outputInfo{
{0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31 {0, 1071644664}, // R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R23 R24 R25 R26 R27 R28 R29 R31
}, },
}, },
}, },
{
name: "ZERO",
argLen: 0,
zeroWidth: true,
fixedReg: true,
reg: regInfo{},
},
{ {
name: "ADD", name: "ADD",
@ -72765,7 +72695,7 @@ var specialRegMaskARM64 = regMask(0)
var framepointerRegARM64 = int8(-1) var framepointerRegARM64 = int8(-1)
var linkRegARM64 = int8(28) var linkRegARM64 = int8(28)
var registersLOONG64 = [...]Register{ var registersLOONG64 = [...]Register{
{0, loong64.REG_R0, "R0"}, {0, loong64.REGZERO, "ZERO"},
{1, loong64.REG_R1, "R1"}, {1, loong64.REG_R1, "R1"},
{2, loong64.REGSP, "SP"}, {2, loong64.REGSP, "SP"},
{3, loong64.REG_R4, "R4"}, {3, loong64.REG_R4, "R4"},

View file

@ -1438,7 +1438,7 @@ func (s *regAllocState) regalloc(f *Func) {
case OpSB: case OpSB:
s.assignReg(s.SBReg, v, v) s.assignReg(s.SBReg, v, v)
s.sb = v.ID s.sb = v.ID
case OpARM64ZERO: case OpARM64ZERO, OpLOONG64ZERO:
s.assignReg(s.ZeroIntReg, v, v) s.assignReg(s.ZeroIntReg, v, v)
case OpAMD64Zero128, OpAMD64Zero256, OpAMD64Zero512: case OpAMD64Zero128, OpAMD64Zero256, OpAMD64Zero512:
regspec := s.regspec(v) regspec := s.regspec(v)

View file

@ -470,11 +470,10 @@ func ntz32(x int32) int { return bits.TrailingZeros32(uint32(x)) }
func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) } func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) }
func ntz8(x int8) int { return bits.TrailingZeros8(uint8(x)) } func ntz8(x int8) int { return bits.TrailingZeros8(uint8(x)) }
func oneBit(x int64) bool { return x&(x-1) == 0 && x != 0 } // oneBit reports whether x contains exactly one set bit.
func oneBit8(x int8) bool { return x&(x-1) == 0 && x != 0 } func oneBit[T int8 | int16 | int32 | int64](x T) bool {
func oneBit16(x int16) bool { return x&(x-1) == 0 && x != 0 } return x&(x-1) == 0 && x != 0
func oneBit32(x int32) bool { return x&(x-1) == 0 && x != 0 } }
func oneBit64(x int64) bool { return x&(x-1) == 0 && x != 0 }
// nto returns the number of trailing ones. // nto returns the number of trailing ones.
func nto(x int64) int64 { func nto(x int64) int64 {

File diff suppressed because it is too large Load diff

View file

@ -4,11 +4,25 @@ package ssa
func rewriteValueLOONG64latelower(v *Value) bool { func rewriteValueLOONG64latelower(v *Value) bool {
switch v.Op { switch v.Op {
case OpLOONG64MOVVconst:
return rewriteValueLOONG64latelower_OpLOONG64MOVVconst(v)
case OpLOONG64SLLVconst: case OpLOONG64SLLVconst:
return rewriteValueLOONG64latelower_OpLOONG64SLLVconst(v) return rewriteValueLOONG64latelower_OpLOONG64SLLVconst(v)
} }
return false return false
} }
func rewriteValueLOONG64latelower_OpLOONG64MOVVconst(v *Value) bool {
// match: (MOVVconst [0])
// result: (ZERO)
for {
if auxIntToInt64(v.AuxInt) != 0 {
break
}
v.reset(OpLOONG64ZERO)
return true
}
return false
}
func rewriteValueLOONG64latelower_OpLOONG64SLLVconst(v *Value) bool { func rewriteValueLOONG64latelower_OpLOONG64SLLVconst(v *Value) bool {
v_0 := v.Args[0] v_0 := v.Args[0]
// match: (SLLVconst [1] x) // match: (SLLVconst [1] x)

View file

@ -405,7 +405,8 @@ func rewriteValueRISCV64(v *Value) bool {
case OpMove: case OpMove:
return rewriteValueRISCV64_OpMove(v) return rewriteValueRISCV64_OpMove(v)
case OpMul16: case OpMul16:
return rewriteValueRISCV64_OpMul16(v) v.Op = OpRISCV64MULW
return true
case OpMul32: case OpMul32:
v.Op = OpRISCV64MULW v.Op = OpRISCV64MULW
return true return true
@ -425,7 +426,8 @@ func rewriteValueRISCV64(v *Value) bool {
v.Op = OpRISCV64LoweredMuluover v.Op = OpRISCV64LoweredMuluover
return true return true
case OpMul8: case OpMul8:
return rewriteValueRISCV64_OpMul8(v) v.Op = OpRISCV64MULW
return true
case OpNeg16: case OpNeg16:
v.Op = OpRISCV64NEG v.Op = OpRISCV64NEG
return true return true
@ -3255,44 +3257,6 @@ func rewriteValueRISCV64_OpMove(v *Value) bool {
} }
return false return false
} }
func rewriteValueRISCV64_OpMul16(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (Mul16 x y)
// result: (MULW (SignExt16to32 x) (SignExt16to32 y))
for {
x := v_0
y := v_1
v.reset(OpRISCV64MULW)
v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
v0.AddArg(x)
v1 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
v1.AddArg(y)
v.AddArg2(v0, v1)
return true
}
}
func rewriteValueRISCV64_OpMul8(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
// match: (Mul8 x y)
// result: (MULW (SignExt8to32 x) (SignExt8to32 y))
for {
x := v_0
y := v_1
v.reset(OpRISCV64MULW)
v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
v0.AddArg(x)
v1 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
v1.AddArg(y)
v.AddArg2(v0, v1)
return true
}
}
func rewriteValueRISCV64_OpNeq16(v *Value) bool { func rewriteValueRISCV64_OpNeq16(v *Value) bool {
v_1 := v.Args[1] v_1 := v.Args[1]
v_0 := v.Args[0] v_0 := v.Args[0]

View file

@ -8798,7 +8798,7 @@ func rewriteValuegeneric_OpEq16(v *Value) bool {
break break
} }
// match: (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y])) // match: (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y]))
// cond: oneBit16(y) // cond: oneBit(y)
// result: (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0])) // result: (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0]))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@ -8815,7 +8815,7 @@ func rewriteValuegeneric_OpEq16(v *Value) bool {
continue continue
} }
y := auxIntToInt16(v_0_1.AuxInt) y := auxIntToInt16(v_0_1.AuxInt)
if v_1.Op != OpConst16 || v_1.Type != t || auxIntToInt16(v_1.AuxInt) != y || !(oneBit16(y)) { if v_1.Op != OpConst16 || v_1.Type != t || auxIntToInt16(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpNeq16) v.reset(OpNeq16)
@ -9662,7 +9662,7 @@ func rewriteValuegeneric_OpEq32(v *Value) bool {
break break
} }
// match: (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y])) // match: (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y]))
// cond: oneBit32(y) // cond: oneBit(y)
// result: (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0])) // result: (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0]))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@ -9679,7 +9679,7 @@ func rewriteValuegeneric_OpEq32(v *Value) bool {
continue continue
} }
y := auxIntToInt32(v_0_1.AuxInt) y := auxIntToInt32(v_0_1.AuxInt)
if v_1.Op != OpConst32 || v_1.Type != t || auxIntToInt32(v_1.AuxInt) != y || !(oneBit32(y)) { if v_1.Op != OpConst32 || v_1.Type != t || auxIntToInt32(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpNeq32) v.reset(OpNeq32)
@ -10243,7 +10243,7 @@ func rewriteValuegeneric_OpEq64(v *Value) bool {
break break
} }
// match: (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y])) // match: (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y]))
// cond: oneBit64(y) // cond: oneBit(y)
// result: (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0])) // result: (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0]))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@ -10260,7 +10260,7 @@ func rewriteValuegeneric_OpEq64(v *Value) bool {
continue continue
} }
y := auxIntToInt64(v_0_1.AuxInt) y := auxIntToInt64(v_0_1.AuxInt)
if v_1.Op != OpConst64 || v_1.Type != t || auxIntToInt64(v_1.AuxInt) != y || !(oneBit64(y)) { if v_1.Op != OpConst64 || v_1.Type != t || auxIntToInt64(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpNeq64) v.reset(OpNeq64)
@ -10665,7 +10665,7 @@ func rewriteValuegeneric_OpEq8(v *Value) bool {
break break
} }
// match: (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y])) // match: (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y]))
// cond: oneBit8(y) // cond: oneBit(y)
// result: (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0])) // result: (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0]))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@ -10682,7 +10682,7 @@ func rewriteValuegeneric_OpEq8(v *Value) bool {
continue continue
} }
y := auxIntToInt8(v_0_1.AuxInt) y := auxIntToInt8(v_0_1.AuxInt)
if v_1.Op != OpConst8 || v_1.Type != t || auxIntToInt8(v_1.AuxInt) != y || !(oneBit8(y)) { if v_1.Op != OpConst8 || v_1.Type != t || auxIntToInt8(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpNeq8) v.reset(OpNeq8)
@ -20311,7 +20311,7 @@ func rewriteValuegeneric_OpNeq16(v *Value) bool {
break break
} }
// match: (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y])) // match: (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y]))
// cond: oneBit16(y) // cond: oneBit(y)
// result: (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0])) // result: (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0]))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@ -20328,7 +20328,7 @@ func rewriteValuegeneric_OpNeq16(v *Value) bool {
continue continue
} }
y := auxIntToInt16(v_0_1.AuxInt) y := auxIntToInt16(v_0_1.AuxInt)
if v_1.Op != OpConst16 || v_1.Type != t || auxIntToInt16(v_1.AuxInt) != y || !(oneBit16(y)) { if v_1.Op != OpConst16 || v_1.Type != t || auxIntToInt16(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpEq16) v.reset(OpEq16)
@ -20498,7 +20498,7 @@ func rewriteValuegeneric_OpNeq32(v *Value) bool {
break break
} }
// match: (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y])) // match: (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y]))
// cond: oneBit32(y) // cond: oneBit(y)
// result: (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0])) // result: (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0]))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@ -20515,7 +20515,7 @@ func rewriteValuegeneric_OpNeq32(v *Value) bool {
continue continue
} }
y := auxIntToInt32(v_0_1.AuxInt) y := auxIntToInt32(v_0_1.AuxInt)
if v_1.Op != OpConst32 || v_1.Type != t || auxIntToInt32(v_1.AuxInt) != y || !(oneBit32(y)) { if v_1.Op != OpConst32 || v_1.Type != t || auxIntToInt32(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpEq32) v.reset(OpEq32)
@ -20708,7 +20708,7 @@ func rewriteValuegeneric_OpNeq64(v *Value) bool {
break break
} }
// match: (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y])) // match: (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y]))
// cond: oneBit64(y) // cond: oneBit(y)
// result: (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0])) // result: (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0]))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@ -20725,7 +20725,7 @@ func rewriteValuegeneric_OpNeq64(v *Value) bool {
continue continue
} }
y := auxIntToInt64(v_0_1.AuxInt) y := auxIntToInt64(v_0_1.AuxInt)
if v_1.Op != OpConst64 || v_1.Type != t || auxIntToInt64(v_1.AuxInt) != y || !(oneBit64(y)) { if v_1.Op != OpConst64 || v_1.Type != t || auxIntToInt64(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpEq64) v.reset(OpEq64)
@ -20918,7 +20918,7 @@ func rewriteValuegeneric_OpNeq8(v *Value) bool {
break break
} }
// match: (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y])) // match: (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y]))
// cond: oneBit8(y) // cond: oneBit(y)
// result: (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0])) // result: (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0]))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@ -20935,7 +20935,7 @@ func rewriteValuegeneric_OpNeq8(v *Value) bool {
continue continue
} }
y := auxIntToInt8(v_0_1.AuxInt) y := auxIntToInt8(v_0_1.AuxInt)
if v_1.Op != OpConst8 || v_1.Type != t || auxIntToInt8(v_1.AuxInt) != y || !(oneBit8(y)) { if v_1.Op != OpConst8 || v_1.Type != t || auxIntToInt8(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpEq8) v.reset(OpEq8)

View file

@ -125,6 +125,8 @@ func TestIntendedInlining(t *testing.T) {
"assemble64", "assemble64",
}, },
"unicode/utf8": { "unicode/utf8": {
"DecodeRune",
"DecodeRuneInString",
"FullRune", "FullRune",
"FullRuneInString", "FullRuneInString",
"RuneLen", "RuneLen",

View file

@ -677,7 +677,7 @@ func (t *tester) registerTests() {
} }
t.registerStdTest(pkg) t.registerStdTest(pkg)
} }
if t.race { if t.race && !t.short {
for _, pkg := range pkgs { for _, pkg := range pkgs {
if t.packageHasBenchmarks(pkg) { if t.packageHasBenchmarks(pkg) {
t.registerRaceBenchTest(pkg) t.registerRaceBenchTest(pkg)
@ -1700,7 +1700,7 @@ func (t *tester) makeGOROOTUnwritable() (undo func()) {
func raceDetectorSupported(goos, goarch string) bool { func raceDetectorSupported(goos, goarch string) bool {
switch goos { switch goos {
case "linux": case "linux":
return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" || goarch == "s390x" || goarch == "loong64" return goarch == "amd64" || goarch == "arm64" || goarch == "loong64" || goarch == "ppc64le" || goarch == "riscv64" || goarch == "s390x"
case "darwin": case "darwin":
return goarch == "amd64" || goarch == "arm64" return goarch == "amd64" || goarch == "arm64"
case "freebsd", "netbsd", "windows": case "freebsd", "netbsd", "windows":
@ -1775,7 +1775,7 @@ func buildModeSupported(compiler, buildmode, goos, goarch string) bool {
"ios/amd64", "ios/arm64", "ios/amd64", "ios/arm64",
"aix/ppc64", "aix/ppc64",
"openbsd/arm64", "openbsd/arm64",
"windows/386", "windows/amd64", "windows/arm", "windows/arm64": "windows/386", "windows/amd64", "windows/arm64":
return true return true
} }
return false return false
@ -1837,7 +1837,6 @@ func (t *tester) fipsSupported() bool {
switch { switch {
case goarch == "wasm", case goarch == "wasm",
goos == "windows" && goarch == "386", goos == "windows" && goarch == "386",
goos == "windows" && goarch == "arm",
goos == "openbsd", goos == "openbsd",
goos == "aix": goos == "aix":
return false return false

View file

@ -366,9 +366,8 @@ func xgetgoarm() string {
// If we're building on an actual arm system, and not building // If we're building on an actual arm system, and not building
// a cross-compiling toolchain, try to exec ourselves // a cross-compiling toolchain, try to exec ourselves
// to detect whether VFP is supported and set the default GOARM. // to detect whether VFP is supported and set the default GOARM.
// Windows requires ARMv7, so we can skip the check. // We've always assumed Android is ARMv7.
// We've always assumed Android is ARMv7 too. if gohostarch == "arm" && goarch == "arm" && goos == gohostos && goos != "android" {
if gohostarch == "arm" && goarch == "arm" && goos == gohostos && goos != "windows" && goos != "android" {
// Try to exec ourselves in a mode to detect VFP support. // Try to exec ourselves in a mode to detect VFP support.
// Seeing how far it gets determines which instructions failed. // Seeing how far it gets determines which instructions failed.
// The test is OS-agnostic. // The test is OS-agnostic.

View file

@ -121,8 +121,9 @@
// The default is GOMAXPROCS, normally the number of CPUs available. // The default is GOMAXPROCS, normally the number of CPUs available.
// -race // -race
// enable data race detection. // enable data race detection.
// Supported only on linux/amd64, freebsd/amd64, darwin/amd64, darwin/arm64, windows/amd64, // Supported only on darwin/amd64, darwin/arm64, freebsd/amd64, linux/amd64,
// linux/ppc64le and linux/arm64 (only for 48-bit VMA). // linux/arm64 (only for 48-bit VMA), linux/ppc64le, linux/riscv64 and
// windows/amd64.
// -msan // -msan
// enable interoperation with memory sanitizer. // enable interoperation with memory sanitizer.
// Supported only on linux/amd64, linux/arm64, linux/loong64, freebsd/amd64 // Supported only on linux/amd64, linux/arm64, linux/loong64, freebsd/amd64
@ -2407,8 +2408,10 @@
// The name of checksum database to use and optionally its public key and // The name of checksum database to use and optionally its public key and
// URL. See https://golang.org/ref/mod#authenticating. // URL. See https://golang.org/ref/mod#authenticating.
// GOTMPDIR // GOTMPDIR
// The directory where the go command will write // Temporary directory used by the go command and testing package.
// temporary source files, packages, and binaries. // Overrides the platform-specific temporary directory such as "/tmp".
// The go command and testing package will write temporary source files,
// packages, and binaries here.
// GOTOOLCHAIN // GOTOOLCHAIN
// Controls which Go toolchain is used. See https://go.dev/doc/toolchain. // Controls which Go toolchain is used. See https://go.dev/doc/toolchain.
// GOVCS // GOVCS

View file

@ -573,8 +573,10 @@ General-purpose environment variables:
The name of checksum database to use and optionally its public key and The name of checksum database to use and optionally its public key and
URL. See https://golang.org/ref/mod#authenticating. URL. See https://golang.org/ref/mod#authenticating.
GOTMPDIR GOTMPDIR
The directory where the go command will write Temporary directory used by the go command and testing package.
temporary source files, packages, and binaries. Overrides the platform-specific temporary directory such as "/tmp".
The go command and testing package will write temporary source files,
packages, and binaries here.
GOTOOLCHAIN GOTOOLCHAIN
Controls which Go toolchain is used. See https://go.dev/doc/toolchain. Controls which Go toolchain is used. See https://go.dev/doc/toolchain.
GOVCS GOVCS

View file

@ -77,8 +77,9 @@ and test commands:
The default is GOMAXPROCS, normally the number of CPUs available. The default is GOMAXPROCS, normally the number of CPUs available.
-race -race
enable data race detection. enable data race detection.
Supported only on linux/amd64, freebsd/amd64, darwin/amd64, darwin/arm64, windows/amd64, Supported only on darwin/amd64, darwin/arm64, freebsd/amd64, linux/amd64,
linux/ppc64le and linux/arm64 (only for 48-bit VMA). linux/arm64 (only for 48-bit VMA), linux/ppc64le, linux/riscv64 and
windows/amd64.
-msan -msan
enable interoperation with memory sanitizer. enable interoperation with memory sanitizer.
Supported only on linux/amd64, linux/arm64, linux/loong64, freebsd/amd64 Supported only on linux/amd64, linux/arm64, linux/loong64, freebsd/amd64

View file

@ -87,10 +87,8 @@ func initParserMode() {
} }
} }
func isGoFile(f fs.DirEntry) bool { func isGoFilename(name string) bool {
// ignore non-Go files return !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
name := f.Name()
return !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && !f.IsDir()
} }
// A sequencer performs concurrent tasks that may write output, but emits that // A sequencer performs concurrent tasks that may write output, but emits that
@ -411,34 +409,30 @@ func gofmtMain(s *sequencer) {
} }
for _, arg := range args { for _, arg := range args {
switch info, err := os.Stat(arg); { // Walk each given argument as a directory tree.
case err != nil: // If the argument is not a directory, it's always formatted as a Go file.
s.AddReport(err) // If the argument is a directory, we walk it, ignoring non-Go files.
case !info.IsDir(): if err := filepath.WalkDir(arg, func(path string, d fs.DirEntry, err error) error {
// Non-directory arguments are always formatted. switch {
arg := arg case err != nil:
s.Add(fileWeight(arg, info), func(r *reporter) error { return err
return processFile(arg, info, nil, r) case d.IsDir():
}) return nil // simply recurse into directories
default: case path == arg:
// Directories are walked, ignoring non-Go files. // non-directories given as explicit arguments are always formatted
err := filepath.WalkDir(arg, func(path string, f fs.DirEntry, err error) error { case !isGoFilename(d.Name()):
if err != nil || !isGoFile(f) { return nil // skip walked non-Go files
return err
}
info, err := f.Info()
if err != nil {
s.AddReport(err)
return nil
}
s.Add(fileWeight(path, info), func(r *reporter) error {
return processFile(path, info, nil, r)
})
return nil
})
if err != nil {
s.AddReport(err)
} }
info, err := d.Info()
if err != nil {
return err
}
s.Add(fileWeight(path, info), func(r *reporter) error {
return processFile(path, info, nil, r)
})
return nil
}); err != nil {
s.AddReport(err)
} }
} }
} }

View file

@ -115,7 +115,7 @@ func genFilenames(t *testing.T, filenames chan<- string) {
return nil return nil
} }
// don't descend into testdata directories // don't descend into testdata directories
if isGoFile(d) && !strings.Contains(filepath.ToSlash(filename), "/testdata/") { if !d.IsDir() && isGoFilename(d.Name()) && !strings.Contains(filepath.ToSlash(filename), "/testdata/") {
filenames <- filename filenames <- filename
nfiles++ nfiles++
} }

View file

@ -196,14 +196,8 @@ func EnableFIPS() bool {
// Perhaps the default should be changed back to -buildmode=exe, // Perhaps the default should be changed back to -buildmode=exe,
// after which we could remove this case, but until then, // after which we could remove this case, but until then,
// skip FIPS on windows-386. // skip FIPS on windows-386.
// if buildcfg.GOOS == "windows" && buildcfg.GOARCH == "386" {
// We don't know whether arm works, because it is too hard to get builder return false
// time to test it. Disable since it's not important right now.
if buildcfg.GOOS == "windows" {
switch buildcfg.GOARCH {
case "386", "arm":
return false
}
} }
// AIX doesn't just work, and it's not worth fixing. // AIX doesn't just work, and it's not worth fixing.

View file

@ -666,6 +666,10 @@ const (
ABSTRPICKW ABSTRPICKW
ABSTRPICKV ABSTRPICKV
// 2.2.5.3
AMOVWP
AMOVVP
// 2.2.5.4. Prefetch Instructions // 2.2.5.4. Prefetch Instructions
APRELD APRELD
APRELDX APRELDX

View file

@ -202,6 +202,8 @@ var Anames = []string{
"BSTRINSV", "BSTRINSV",
"BSTRPICKW", "BSTRPICKW",
"BSTRPICKV", "BSTRPICKV",
"MOVWP",
"MOVVP",
"PRELD", "PRELD",
"PRELDX", "PRELDX",
"CRCWBW", "CRCWBW",

View file

@ -212,6 +212,8 @@ var optab = []Optab{
{AMOVV, C_REG, C_NONE, C_NONE, C_TLS_LE, C_NONE, 53, 16, 0, 0}, {AMOVV, C_REG, C_NONE, C_NONE, C_TLS_LE, C_NONE, 53, 16, 0, 0},
{AMOVB, C_REG, C_NONE, C_NONE, C_TLS_LE, C_NONE, 53, 16, 0, 0}, {AMOVB, C_REG, C_NONE, C_NONE, C_TLS_LE, C_NONE, 53, 16, 0, 0},
{AMOVBU, C_REG, C_NONE, C_NONE, C_TLS_LE, C_NONE, 53, 16, 0, 0}, {AMOVBU, C_REG, C_NONE, C_NONE, C_TLS_LE, C_NONE, 53, 16, 0, 0},
{AMOVWP, C_REG, C_NONE, C_NONE, C_SOREG, C_NONE, 73, 4, 0, 0},
{AMOVWP, C_REG, C_NONE, C_NONE, C_LOREG, C_NONE, 73, 4, 0, 0},
{AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, C_NONE, 36, 12, REGSP, 0}, {AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, C_NONE, 36, 12, REGSP, 0},
{AMOVWU, C_LAUTO, C_NONE, C_NONE, C_REG, C_NONE, 36, 12, REGSP, 0}, {AMOVWU, C_LAUTO, C_NONE, C_NONE, C_REG, C_NONE, 36, 12, REGSP, 0},
@ -233,6 +235,8 @@ var optab = []Optab{
{AMOVV, C_TLS_LE, C_NONE, C_NONE, C_REG, C_NONE, 54, 16, 0, 0}, {AMOVV, C_TLS_LE, C_NONE, C_NONE, C_REG, C_NONE, 54, 16, 0, 0},
{AMOVB, C_TLS_LE, C_NONE, C_NONE, C_REG, C_NONE, 54, 16, 0, 0}, {AMOVB, C_TLS_LE, C_NONE, C_NONE, C_REG, C_NONE, 54, 16, 0, 0},
{AMOVBU, C_TLS_LE, C_NONE, C_NONE, C_REG, C_NONE, 54, 16, 0, 0}, {AMOVBU, C_TLS_LE, C_NONE, C_NONE, C_REG, C_NONE, 54, 16, 0, 0},
{AMOVWP, C_SOREG, C_NONE, C_NONE, C_REG, C_NONE, 74, 4, 0, 0},
{AMOVWP, C_LOREG, C_NONE, C_NONE, C_REG, C_NONE, 74, 4, 0, 0},
{AMOVW, C_SACON, C_NONE, C_NONE, C_REG, C_NONE, 3, 4, REGSP, 0}, {AMOVW, C_SACON, C_NONE, C_NONE, C_REG, C_NONE, 3, 4, REGSP, 0},
{AMOVV, C_SACON, C_NONE, C_NONE, C_REG, C_NONE, 3, 4, REGSP, 0}, {AMOVV, C_SACON, C_NONE, C_NONE, C_REG, C_NONE, 3, 4, REGSP, 0},
@ -438,8 +442,6 @@ var optab = []Optab{
{obj.ANOP, C_FREG, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0}, {obj.ANOP, C_FREG, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0},
{obj.ADUFFZERO, C_NONE, C_NONE, C_NONE, C_BRAN, C_NONE, 11, 4, 0, 0}, // same as AJMP {obj.ADUFFZERO, C_NONE, C_NONE, C_NONE, C_BRAN, C_NONE, 11, 4, 0, 0}, // same as AJMP
{obj.ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_BRAN, C_NONE, 11, 4, 0, 0}, // same as AJMP {obj.ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_BRAN, C_NONE, 11, 4, 0, 0}, // same as AJMP
{obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0},
} }
var atomicInst = map[obj.As]uint32{ var atomicInst = map[obj.As]uint32{
@ -1303,31 +1305,27 @@ func buildop(ctxt *obj.Link) {
return return
} }
var n int for i := range C_NCLASS {
for j := range C_NCLASS {
for i := 0; i < C_NCLASS; i++ { if cmp(j, i) {
for n = 0; n < C_NCLASS; n++ { xcmp[i][j] = true
if cmp(n, i) {
xcmp[i][n] = true
} }
} }
} }
for n = 0; optab[n].as != obj.AXXX; n++ {
}
slices.SortFunc(optab[:n], ocmp)
for i := 0; i < n; i++ {
r := optab[i].as
r0 := r & obj.AMask
start := i
for optab[i].as == r {
i++
}
oprange[r0] = optab[start:i]
i--
switch r { slices.SortFunc(optab, ocmp)
for i := 0; i < len(optab); i++ {
as, start := optab[i].as, i
for ; i < len(optab)-1; i++ {
if optab[i+1].as != as {
break
}
}
r0 := as & obj.AMask
oprange[r0] = optab[start : i+1]
switch as {
default: default:
ctxt.Diag("unknown op in build: %v", r) ctxt.Diag("unknown op in build: %v", as)
ctxt.DiagFlush() ctxt.DiagFlush()
log.Fatalf("bad code") log.Fatalf("bad code")
@ -1443,6 +1441,9 @@ func buildop(ctxt *obj.Link) {
case AMOVBU: case AMOVBU:
opset(AMOVHU, r0) opset(AMOVHU, r0)
case AMOVWP:
opset(AMOVVP, r0)
case AMUL: case AMUL:
opset(AMULU, r0) opset(AMULU, r0)
opset(AMULH, r0) opset(AMULH, r0)
@ -1970,6 +1971,10 @@ func OP_16IRR(op uint32, i uint32, r2 uint32, r3 uint32) uint32 {
return op | (i&0xFFFF)<<10 | (r2&0x1F)<<5 | (r3&0x1F)<<0 return op | (i&0xFFFF)<<10 | (r2&0x1F)<<5 | (r3&0x1F)<<0
} }
func OP_14IRR(op uint32, i uint32, r2 uint32, r3 uint32) uint32 {
return op | (i&0x3FFF)<<10 | (r2&0x1F)<<5 | (r3&0x1F)<<0
}
func OP_12IR_5I(op uint32, i1 uint32, r2 uint32, i2 uint32) uint32 { func OP_12IR_5I(op uint32, i1 uint32, r2 uint32, i2 uint32) uint32 {
return op | (i1&0xFFF)<<10 | (r2&0x1F)<<5 | (i2&0x1F)<<0 return op | (i1&0xFFF)<<10 | (r2&0x1F)<<5 | (i2&0x1F)<<0
} }
@ -2899,6 +2904,20 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
o3 = OP_12IRR(c.opirr(ALU52ID), uint32(v>>52), uint32(REGTMP), uint32(REGTMP)) o3 = OP_12IRR(c.opirr(ALU52ID), uint32(v>>52), uint32(REGTMP), uint32(REGTMP))
} }
o4 = OP_RRR(c.oprrr(p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg)) o4 = OP_RRR(c.oprrr(p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
case 73:
v := c.regoff(&p.To)
if v&3 != 0 {
c.ctxt.Diag("%v: offset must be a multiple of 4.\n", p)
}
o1 = OP_14IRR(c.opirr(p.As), uint32(v>>2), uint32(p.To.Reg), uint32(p.From.Reg))
case 74:
v := c.regoff(&p.From)
if v&3 != 0 {
c.ctxt.Diag("%v: offset must be a multiple of 4.\n", p)
}
o1 = OP_14IRR(c.opirr(-p.As), uint32(v>>2), uint32(p.From.Reg), uint32(p.To.Reg))
} }
out[0] = o1 out[0] = o1
@ -4032,6 +4051,10 @@ func (c *ctxt0) opirr(a obj.As) uint32 {
return 0x0ad << 22 return 0x0ad << 22
case AMOVD: case AMOVD:
return 0x0af << 22 return 0x0af << 22
case AMOVVP:
return 0x27 << 24 // stptr.d
case AMOVWP:
return 0x25 << 24 // stptr.w
case -AMOVB: case -AMOVB:
return 0x0a0 << 22 return 0x0a0 << 22
case -AMOVBU: case -AMOVBU:
@ -4050,6 +4073,10 @@ func (c *ctxt0) opirr(a obj.As) uint32 {
return 0x0ac << 22 return 0x0ac << 22
case -AMOVD: case -AMOVD:
return 0x0ae << 22 return 0x0ae << 22
case -AMOVVP:
return 0x26 << 24 // ldptr.d
case -AMOVWP:
return 0x24 << 24 // ldptr.w
case -AVMOVQ: case -AVMOVQ:
return 0x0b0 << 22 // vld return 0x0b0 << 22 // vld
case -AXVMOVQ: case -AXVMOVQ:

View file

@ -289,6 +289,34 @@ Note: In the following sections 3.1 to 3.6, "ui4" (4-bit unsigned int immediate)
Go assembly | instruction Encoding Go assembly | instruction Encoding
ALSLV $4, r4, r5, R6 | 002d9486 ALSLV $4, r4, r5, R6 | 002d9486
5. Note of special memory access instructions
Instruction format:
MOVWP offset(Rj), Rd
MOVVP offset(Rj), Rd
MOVWP Rd, offset(Rj)
MOVVP Rd, offset(Rj)
Mapping between Go and platform assembly:
Go assembly | platform assembly
MOVWP offset(Rj), Rd | ldptr.w rd, rj, si14
MOVVP offset(Rj), Rd | ldptr.d rd, rj, si14
MOVWP Rd, offset(Rj) | stptr.w rd, rj, si14
MOVVP Rd, offset(Rj) | stptr.d rd, rj, si14
note: In Go assembly, for ease of understanding, offset is a 16-bit immediate number representing
the actual address offset, but in platform assembly, it need a 14-bit immediate number.
si14 = offset>>2
The addressing calculation for the above instruction involves logically left-shifting the 14-bit
immediate number si14 by 2 bits, then sign-extending it, and finally adding it to the value in the
general-purpose register rj to obtain the sum.
For example:
Go assembly | platform assembly
MOVWP 8(R4), R5 | ldptr.w r5, r4, $2
*/ */
package loong64 package loong64

View file

@ -2120,19 +2120,6 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
c0 := c c0 := c
c = pjc.padJump(ctxt, s, p, c) c = pjc.padJump(ctxt, s, p, c)
if p.As == obj.APCALIGN || p.As == obj.APCALIGNMAX {
v := obj.AlignmentPadding(c, p, ctxt, s)
if v > 0 {
s.Grow(int64(c) + int64(v))
fillnop(s.P[c:], int(v))
}
p.Pc = int64(c)
c += int32(v)
pPrev = p
continue
}
if maxLoopPad > 0 && p.Back&branchLoopHead != 0 && c&(loopAlign-1) != 0 { if maxLoopPad > 0 && p.Back&branchLoopHead != 0 && c&(loopAlign-1) != 0 {
// pad with NOPs // pad with NOPs
v := -c & (loopAlign - 1) v := -c & (loopAlign - 1)
@ -2165,6 +2152,18 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
} }
} }
if p.As == obj.APCALIGN || p.As == obj.APCALIGNMAX {
v := obj.AlignmentPadding(c, p, ctxt, s)
if v > 0 {
s.Grow(int64(c) + int64(v))
fillnop(s.P[c:], int(v))
}
p.Pc = int64(c)
c += int32(v)
pPrev = p
continue
}
p.Rel = nil p.Rel = nil
p.Pc = int64(c) p.Pc = int64(c)

View file

@ -305,6 +305,14 @@ const (
// R_RISCV_BRANCH resolves a 12-bit PC-relative branch offset. // R_RISCV_BRANCH resolves a 12-bit PC-relative branch offset.
R_RISCV_BRANCH R_RISCV_BRANCH
// R_RISCV_ADD32 resolves a 32-bit label addition, being the stored value,
// plus the symbol address plus the addend (V + S + A).
R_RISCV_ADD32
// R_RISCV_SUB32 resolves a 32-bit label subtraction, being the stored value,
// minus the symbol address minus the addend (V - S - A).
R_RISCV_SUB32
// R_RISCV_RVC_BRANCH resolves an 8-bit PC-relative offset for a CB-type // R_RISCV_RVC_BRANCH resolves an 8-bit PC-relative offset for a CB-type
// instruction. // instruction.
R_RISCV_RVC_BRANCH R_RISCV_RVC_BRANCH

View file

@ -79,39 +79,41 @@ func _() {
_ = x[R_RISCV_PCREL_LO12_I-69] _ = x[R_RISCV_PCREL_LO12_I-69]
_ = x[R_RISCV_PCREL_LO12_S-70] _ = x[R_RISCV_PCREL_LO12_S-70]
_ = x[R_RISCV_BRANCH-71] _ = x[R_RISCV_BRANCH-71]
_ = x[R_RISCV_RVC_BRANCH-72] _ = x[R_RISCV_ADD32-72]
_ = x[R_RISCV_RVC_JUMP-73] _ = x[R_RISCV_SUB32-73]
_ = x[R_PCRELDBL-74] _ = x[R_RISCV_RVC_BRANCH-74]
_ = x[R_LOONG64_ADDR_HI-75] _ = x[R_RISCV_RVC_JUMP-75]
_ = x[R_LOONG64_ADDR_LO-76] _ = x[R_PCRELDBL-76]
_ = x[R_LOONG64_TLS_LE_HI-77] _ = x[R_LOONG64_ADDR_HI-77]
_ = x[R_LOONG64_TLS_LE_LO-78] _ = x[R_LOONG64_ADDR_LO-78]
_ = x[R_CALLLOONG64-79] _ = x[R_LOONG64_TLS_LE_HI-79]
_ = x[R_LOONG64_TLS_IE_HI-80] _ = x[R_LOONG64_TLS_LE_LO-80]
_ = x[R_LOONG64_TLS_IE_LO-81] _ = x[R_CALLLOONG64-81]
_ = x[R_LOONG64_GOT_HI-82] _ = x[R_LOONG64_TLS_IE_HI-82]
_ = x[R_LOONG64_GOT_LO-83] _ = x[R_LOONG64_TLS_IE_LO-83]
_ = x[R_LOONG64_ADD64-84] _ = x[R_LOONG64_GOT_HI-84]
_ = x[R_LOONG64_SUB64-85] _ = x[R_LOONG64_GOT_LO-85]
_ = x[R_JMP16LOONG64-86] _ = x[R_LOONG64_ADD64-86]
_ = x[R_JMP21LOONG64-87] _ = x[R_LOONG64_SUB64-87]
_ = x[R_JMPLOONG64-88] _ = x[R_JMP16LOONG64-88]
_ = x[R_ADDRMIPSU-89] _ = x[R_JMP21LOONG64-89]
_ = x[R_ADDRMIPSTLS-90] _ = x[R_JMPLOONG64-90]
_ = x[R_ADDRCUOFF-91] _ = x[R_ADDRMIPSU-91]
_ = x[R_WASMIMPORT-92] _ = x[R_ADDRMIPSTLS-92]
_ = x[R_XCOFFREF-93] _ = x[R_ADDRCUOFF-93]
_ = x[R_PEIMAGEOFF-94] _ = x[R_WASMIMPORT-94]
_ = x[R_INITORDER-95] _ = x[R_XCOFFREF-95]
_ = x[R_DWTXTADDR_U1-96] _ = x[R_PEIMAGEOFF-96]
_ = x[R_DWTXTADDR_U2-97] _ = x[R_INITORDER-97]
_ = x[R_DWTXTADDR_U3-98] _ = x[R_DWTXTADDR_U1-98]
_ = x[R_DWTXTADDR_U4-99] _ = x[R_DWTXTADDR_U2-99]
_ = x[R_DWTXTADDR_U3-100]
_ = x[R_DWTXTADDR_U4-101]
} }
const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USENAMEDMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_POWER_TLS_IE_PCREL34R_POWER_TLS_LE_TPREL34R_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_GOT_PCREL34R_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_ADDRPOWER_D34R_ADDRPOWER_PCREL34R_RISCV_JALR_RISCV_JAL_TRAMPR_RISCV_CALLR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IER_RISCV_TLS_LER_RISCV_GOT_HI20R_RISCV_GOT_PCREL_ITYPER_RISCV_PCREL_HI20R_RISCV_PCREL_LO12_IR_RISCV_PCREL_LO12_SR_RISCV_BRANCHR_RISCV_RVC_BRANCHR_RISCV_RVC_JUMPR_PCRELDBLR_LOONG64_ADDR_HIR_LOONG64_ADDR_LOR_LOONG64_TLS_LE_HIR_LOONG64_TLS_LE_LOR_CALLLOONG64R_LOONG64_TLS_IE_HIR_LOONG64_TLS_IE_LOR_LOONG64_GOT_HIR_LOONG64_GOT_LOR_LOONG64_ADD64R_LOONG64_SUB64R_JMP16LOONG64R_JMP21LOONG64R_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREFR_PEIMAGEOFFR_INITORDERR_DWTXTADDR_U1R_DWTXTADDR_U2R_DWTXTADDR_U3R_DWTXTADDR_U4" const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USENAMEDMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_POWER_TLS_IE_PCREL34R_POWER_TLS_LE_TPREL34R_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_GOT_PCREL34R_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_ADDRPOWER_D34R_ADDRPOWER_PCREL34R_RISCV_JALR_RISCV_JAL_TRAMPR_RISCV_CALLR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IER_RISCV_TLS_LER_RISCV_GOT_HI20R_RISCV_GOT_PCREL_ITYPER_RISCV_PCREL_HI20R_RISCV_PCREL_LO12_IR_RISCV_PCREL_LO12_SR_RISCV_BRANCHR_RISCV_ADD32R_RISCV_SUB32R_RISCV_RVC_BRANCHR_RISCV_RVC_JUMPR_PCRELDBLR_LOONG64_ADDR_HIR_LOONG64_ADDR_LOR_LOONG64_TLS_LE_HIR_LOONG64_TLS_LE_LOR_CALLLOONG64R_LOONG64_TLS_IE_HIR_LOONG64_TLS_IE_LOR_LOONG64_GOT_HIR_LOONG64_GOT_LOR_LOONG64_ADD64R_LOONG64_SUB64R_JMP16LOONG64R_JMP21LOONG64R_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREFR_PEIMAGEOFFR_INITORDERR_DWTXTADDR_U1R_DWTXTADDR_U2R_DWTXTADDR_U3R_DWTXTADDR_U4"
var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 226, 237, 243, 254, 264, 273, 286, 300, 314, 330, 341, 354, 373, 393, 413, 433, 446, 460, 474, 488, 503, 517, 531, 542, 564, 586, 600, 615, 638, 655, 673, 694, 709, 728, 739, 756, 768, 787, 806, 820, 834, 850, 873, 891, 911, 931, 945, 963, 979, 989, 1006, 1023, 1042, 1061, 1074, 1093, 1112, 1128, 1144, 1159, 1174, 1188, 1202, 1214, 1225, 1238, 1249, 1261, 1271, 1283, 1294, 1308, 1322, 1336, 1350} var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 226, 237, 243, 254, 264, 273, 286, 300, 314, 330, 341, 354, 373, 393, 413, 433, 446, 460, 474, 488, 503, 517, 531, 542, 564, 586, 600, 615, 638, 655, 673, 694, 709, 728, 739, 756, 768, 787, 806, 820, 834, 850, 873, 891, 911, 931, 945, 958, 971, 989, 1005, 1015, 1032, 1049, 1068, 1087, 1100, 1119, 1138, 1154, 1170, 1185, 1200, 1214, 1228, 1240, 1251, 1264, 1275, 1287, 1297, 1309, 1320, 1334, 1348, 1362, 1376}
func (i RelocType) String() string { func (i RelocType) String() string {
i -= 1 i -= 1

View file

@ -1178,6 +1178,7 @@ func relSize(arch *sys.Arch, pn string, elftype uint32) (uint8, uint8, error) {
RISCV64 | uint32(elf.R_RISCV_SET32)<<16, RISCV64 | uint32(elf.R_RISCV_SET32)<<16,
RISCV64 | uint32(elf.R_RISCV_SUB32)<<16, RISCV64 | uint32(elf.R_RISCV_SUB32)<<16,
RISCV64 | uint32(elf.R_RISCV_32_PCREL)<<16, RISCV64 | uint32(elf.R_RISCV_32_PCREL)<<16,
RISCV64 | uint32(elf.R_RISCV_JAL)<<16,
RISCV64 | uint32(elf.R_RISCV_RELAX)<<16: RISCV64 | uint32(elf.R_RISCV_RELAX)<<16:
return 4, 4, nil return 4, 4, nil

View file

@ -2440,6 +2440,7 @@ var blockedLinknames = map[string][]string{
// Others // Others
"net.newWindowsFile": {"net"}, // pushed from os "net.newWindowsFile": {"net"}, // pushed from os
"testing/synctest.testingSynctestTest": {"testing/synctest"}, // pushed from testing "testing/synctest.testingSynctestTest": {"testing/synctest"}, // pushed from testing
"runtime.addmoduledata": {}, // disallow all package
} }
// check if a linkname reference to symbol s from pkg is allowed // check if a linkname reference to symbol s from pkg is allowed

View file

@ -118,6 +118,26 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_S) su.SetRelocType(rIdx, objabi.R_RISCV_PCREL_LO12_S)
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_32_PCREL):
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_PCREL)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_64):
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_ADDR)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_ADD32):
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_RISCV_ADD32)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_SUB32):
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_RISCV_SUB32)
return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_BRANCH): case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_RVC_BRANCH):
su := ldr.MakeSymbolUpdater(s) su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_RISCV_RVC_BRANCH) su.SetRelocType(rIdx, objabi.R_RISCV_RVC_BRANCH)
@ -137,6 +157,11 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
// Ignore relaxations, at least for now. // Ignore relaxations, at least for now.
return true return true
case objabi.ElfRelocOffset + objabi.RelocType(elf.R_RISCV_JAL):
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_RISCV_JAL)
return true
default: default:
if r.Type() >= objabi.ElfRelocOffset { if r.Type() >= objabi.ElfRelocOffset {
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type())) ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
@ -639,6 +664,14 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
second = (second &^ secondImmMask) | int64(uint32(secondImm)) second = (second &^ secondImmMask) | int64(uint32(secondImm))
return second<<32 | auipc, 0, true return second<<32 | auipc, 0, true
case objabi.R_RISCV_ADD32:
addr := val + ldr.SymValue(rs) + r.Add()
return int64(uint32(addr)), 0, true
case objabi.R_RISCV_SUB32:
addr := val - ldr.SymValue(rs) - r.Add()
return int64(uint32(addr)), 0, true
} }
return val, 0, false return val, 0, false

View file

@ -1613,6 +1613,7 @@ func TestCheckLinkname(t *testing.T) {
{"coro2.go", false}, {"coro2.go", false},
// pull linkname of a builtin symbol is not ok // pull linkname of a builtin symbol is not ok
{"builtin.go", false}, {"builtin.go", false},
{"addmoduledata.go", false},
// legacy bad linkname is ok, for now // legacy bad linkname is ok, for now
{"fastrand.go", true}, {"fastrand.go", true},
{"badlinkname.go", true}, {"badlinkname.go", true},

View file

@ -0,0 +1,18 @@
// Copyright 2025 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.
// Linkname runtime.addmoduledata is not allowed.
package main
import (
_ "unsafe"
)
//go:linkname addmoduledata runtime.addmoduledata
func addmoduledata()
func main() {
addmoduledata()
}

View file

@ -46,7 +46,6 @@ func Supported() error {
switch { switch {
case runtime.GOARCH == "wasm", case runtime.GOARCH == "wasm",
runtime.GOOS == "windows" && runtime.GOARCH == "386", runtime.GOOS == "windows" && runtime.GOARCH == "386",
runtime.GOOS == "windows" && runtime.GOARCH == "arm",
runtime.GOOS == "openbsd", // due to -fexecute-only, see #70880 runtime.GOOS == "openbsd", // due to -fexecute-only, see #70880
runtime.GOOS == "aix": runtime.GOOS == "aix":
return errors.New("FIPS 140-3 mode is not supported on " + runtime.GOOS + "-" + runtime.GOARCH) return errors.New("FIPS 140-3 mode is not supported on " + runtime.GOOS + "-" + runtime.GOARCH)

View file

@ -468,10 +468,17 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
return nil return nil
} }
// cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler // cloneHash uses [hash.Cloner] to clone in. If [hash.Cloner]
// is not implemented or not supported, then it falls back to the
// [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler]
// interfaces implemented by standard library hashes to clone the state of in // interfaces implemented by standard library hashes to clone the state of in
// to a new instance of h. It returns nil if the operation fails. // to a new instance of h. It returns nil if the operation fails.
func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash { func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash {
if cloner, ok := in.(hash.Cloner); ok {
if out, err := cloner.Clone(); err == nil {
return out
}
}
// Recreate the interface to avoid importing encoding. // Recreate the interface to avoid importing encoding.
type binaryMarshaler interface { type binaryMarshaler interface {
MarshalBinary() (data []byte, err error) MarshalBinary() (data []byte, err error)

View file

@ -221,7 +221,7 @@ func (q *QUICConn) NextEvent() QUICEvent {
qs := q.conn.quic qs := q.conn.quic
if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 { if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
// Write over some of the previous event's data, // Write over some of the previous event's data,
// to catch callers erroniously retaining it. // to catch callers erroneously retaining it.
qs.events[last].Data[0] = 0 qs.events[last].Data[0] = 0
} }
if qs.nextEvent >= len(qs.events) && qs.waitingForDrain { if qs.nextEvent >= len(qs.events) && qs.waitingForDrain {

View file

@ -692,6 +692,9 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
if len(data)%Sym64Size != 0 { if len(data)%Sym64Size != 0 {
return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size") return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
} }
if len(data) == 0 {
return nil, nil, ErrNoSymbols
}
strdata, err := f.stringTable(symtabSection.Link) strdata, err := f.stringTable(symtabSection.Link)
if err != nil { if err != nil {

View file

@ -1214,10 +1214,6 @@ func unquoteBytes(s []byte) (t []byte, ok bool) {
if c == '\\' || c == '"' || c < ' ' { if c == '\\' || c == '"' || c < ' ' {
break break
} }
if c < utf8.RuneSelf {
r++
continue
}
rr, size := utf8.DecodeRune(s[r:]) rr, size := utf8.DecodeRune(s[r:])
if rr == utf8.RuneError && size == 1 { if rr == utf8.RuneError && size == 1 {
break break

View file

@ -346,10 +346,7 @@ func (f *fmt) truncate(b []byte) []byte {
if n < 0 { if n < 0 {
return b[:i] return b[:i]
} }
wid := 1 _, wid := utf8.DecodeRune(b[i:])
if b[i] >= utf8.RuneSelf {
_, wid = utf8.DecodeRune(b[i:])
}
i += wid i += wid
} }
} }

View file

@ -1145,10 +1145,7 @@ formatLoop:
break break
} }
verb, size := rune(format[i]), 1 verb, size := utf8.DecodeRuneInString(format[i:])
if verb >= utf8.RuneSelf {
verb, size = utf8.DecodeRuneInString(format[i:])
}
i += size i += size
switch { switch {

View file

@ -1083,7 +1083,10 @@ func match0(x, y Value) (_, _ Value) {
return rtof(x1), y return rtof(x1), y
} }
case complexVal: case complexVal:
return vtoc(x), y switch x1 := x.(type) {
case int64Val, intVal, ratVal, floatVal:
return vtoc(x1), y
}
} }
// force unknown and invalid values into "x position" in callers of match // force unknown and invalid values into "x position" in callers of match

View file

@ -617,6 +617,9 @@ func TestUnknown(t *testing.T) {
if got := Compare(x, token.EQL, y); got { if got := Compare(x, token.EQL, y); got {
t.Errorf("%s == %s: got true; want false", x, y) t.Errorf("%s == %s: got true; want false", x, y)
} }
if got := Compare(x, token.NEQ, y); got {
t.Errorf("%s != %s: got true; want false", x, y)
}
} }
} }
} }

View file

@ -24,12 +24,12 @@ func TestComment(t *testing.T) {
pkg := New(pkgs["pkgdoc"], "testdata/pkgdoc", 0) pkg := New(pkgs["pkgdoc"], "testdata/pkgdoc", 0)
var ( var (
input = "[T] and [U] are types, and [T.M] is a method, but [V] is a broken link. [rand.Int] and [crand.Reader] are things. [G.M1] and [G.M2] are generic methods.\n" input = "[T] and [U] are types, and [T.M] is a method, but [V] is a broken link. [rand.Int] and [crand.Reader] are things. [G.M1] and [G.M2] are generic methods. [I.F] is an interface method and [I.V] is a broken link.\n"
wantHTML = `<p><a href="#T">T</a> and <a href="#U">U</a> are types, and <a href="#T.M">T.M</a> is a method, but [V] is a broken link. <a href="/math/rand#Int">rand.Int</a> and <a href="/crypto/rand#Reader">crand.Reader</a> are things. <a href="#G.M1">G.M1</a> and <a href="#G.M2">G.M2</a> are generic methods.` + "\n" wantHTML = `<p><a href="#T">T</a> and <a href="#U">U</a> are types, and <a href="#T.M">T.M</a> is a method, but [V] is a broken link. <a href="/math/rand#Int">rand.Int</a> and <a href="/crypto/rand#Reader">crand.Reader</a> are things. <a href="#G.M1">G.M1</a> and <a href="#G.M2">G.M2</a> are generic methods. <a href="#I.F">I.F</a> is an interface method and [I.V] is a broken link.` + "\n"
wantOldHTML = "<p>[T] and [U] are <i>types</i>, and [T.M] is a method, but [V] is a broken link. [rand.Int] and [crand.Reader] are things. [G.M1] and [G.M2] are generic methods.\n" wantOldHTML = "<p>[T] and [U] are <i>types</i>, and [T.M] is a method, but [V] is a broken link. [rand.Int] and [crand.Reader] are things. [G.M1] and [G.M2] are generic methods. [I.F] is an interface method and [I.V] is a broken link.\n"
wantMarkdown = "[T](#T) and [U](#U) are types, and [T.M](#T.M) is a method, but \\[V] is a broken link. [rand.Int](/math/rand#Int) and [crand.Reader](/crypto/rand#Reader) are things. [G.M1](#G.M1) and [G.M2](#G.M2) are generic methods.\n" wantMarkdown = "[T](#T) and [U](#U) are types, and [T.M](#T.M) is a method, but \\[V] is a broken link. [rand.Int](/math/rand#Int) and [crand.Reader](/crypto/rand#Reader) are things. [G.M1](#G.M1) and [G.M2](#G.M2) are generic methods. [I.F](#I.F) is an interface method and \\[I.V] is a broken link.\n"
wantText = "T and U are types, and T.M is a method, but [V] is a broken link. rand.Int and\ncrand.Reader are things. G.M1 and G.M2 are generic methods.\n" wantText = "T and U are types, and T.M is a method, but [V] is a broken link. rand.Int and\ncrand.Reader are things. G.M1 and G.M2 are generic methods. I.F is an interface\nmethod and [I.V] is a broken link.\n"
wantOldText = "[T] and [U] are types, and [T.M] is a method, but [V] is a broken link.\n[rand.Int] and [crand.Reader] are things. [G.M1] and [G.M2] are generic methods.\n" wantOldText = "[T] and [U] are types, and [T.M] is a method, but [V] is a broken link.\n[rand.Int] and [crand.Reader] are things. [G.M1] and [G.M2] are generic methods.\n[I.F] is an interface method and [I.V] is a broken link.\n"
wantSynopsis = "T and U are types, and T.M is a method, but [V] is a broken link." wantSynopsis = "T and U are types, and T.M is a method, but [V] is a broken link."
wantOldSynopsis = "[T] and [U] are types, and [T.M] is a method, but [V] is a broken link." wantOldSynopsis = "[T] and [U] are types, and [T.M] is a method, but [V] is a broken link."
) )

View file

@ -167,6 +167,7 @@ func (p *Package) collectTypes(types []*Type) {
p.collectValues(t.Vars) p.collectValues(t.Vars)
p.collectFuncs(t.Funcs) p.collectFuncs(t.Funcs)
p.collectFuncs(t.Methods) p.collectFuncs(t.Methods)
p.collectInterfaceMethods(t)
} }
} }
@ -184,6 +185,33 @@ func (p *Package) collectFuncs(funcs []*Func) {
} }
} }
// collectInterfaceMethods adds methods of interface types within t to p.syms.
// Note that t.Methods will contain methods of non-interface types, but not interface types.
// Adding interface methods to t.Methods might make sense, but would cause us to
// include those methods in the documentation index. Adding interface methods to p.syms
// here allows us to linkify references like [io.Reader.Read] without making any other
// changes to the documentation formatting at this time.
//
// If we do start adding interface methods to t.Methods in the future,
// collectInterfaceMethods can be dropped as redundant with collectFuncs(t.Methods).
func (p *Package) collectInterfaceMethods(t *Type) {
for _, s := range t.Decl.Specs {
spec, ok := s.(*ast.TypeSpec)
if !ok {
continue
}
list, isStruct := fields(spec.Type)
if isStruct {
continue
}
for _, field := range list {
for _, name := range field.Names {
p.syms[t.Name+"."+name.Name] = true
}
}
}
}
// NewFromFiles computes documentation for a package. // NewFromFiles computes documentation for a package.
// //
// The package is specified by a list of *ast.Files and corresponding // The package is specified by a list of *ast.Files and corresponding

View file

@ -20,5 +20,9 @@ var _ = crand.Reader
type G[T any] struct{ x T } type G[T any] struct{ x T }
func (g G[T]) M1() {} func (g G[T]) M1() {}
func (g *G[T]) M2() {} func (g *G[T]) M2() {}
type I interface {
F()
}

View file

@ -8,11 +8,6 @@ package cpu
import _ "unsafe" // for linkname import _ "unsafe" // for linkname
// DebugOptions is set to true by the runtime if the OS supports reading
// GODEBUG early in runtime startup.
// This should not be changed after it is initialized.
var DebugOptions bool
// CacheLinePad is used to pad structs to avoid false sharing. // CacheLinePad is used to pad structs to avoid false sharing.
type CacheLinePad struct{ _ [CacheLinePadSize]byte } type CacheLinePad struct{ _ [CacheLinePadSize]byte }

View file

@ -9,11 +9,14 @@ import (
"internal/godebug" "internal/godebug"
"internal/testenv" "internal/testenv"
"os/exec" "os/exec"
"runtime"
"testing" "testing"
) )
func MustHaveDebugOptionsSupport(t *testing.T) { func MustHaveDebugOptionsSupport(t *testing.T) {
if !DebugOptions { switch runtime.GOOS {
case "aix", "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "illumos", "solaris", "linux":
default:
t.Skipf("skipping test: cpu feature options not supported by OS") t.Skipf("skipping test: cpu feature options not supported by OS")
} }
} }

View file

@ -23,7 +23,7 @@ func (p OSArch) String() string {
func RaceDetectorSupported(goos, goarch string) bool { func RaceDetectorSupported(goos, goarch string) bool {
switch goos { switch goos {
case "linux": case "linux":
return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" || goarch == "s390x" || goarch == "loong64" return goarch == "amd64" || goarch == "arm64" || goarch == "loong64" || goarch == "ppc64le" || goarch == "riscv64" || goarch == "s390x"
case "darwin": case "darwin":
return goarch == "amd64" || goarch == "arm64" return goarch == "amd64" || goarch == "arm64"
case "freebsd", "netbsd", "windows": case "freebsd", "netbsd", "windows":

View file

@ -251,6 +251,23 @@ func (fd *FD) writeUnlock() {
} }
} }
// readWriteLock adds a reference to fd and locks fd for reading and writing.
// It returns an error when fd cannot be used for reading and writing.
func (fd *FD) readWriteLock() error {
if !fd.fdmu.rwlock(true) || !fd.fdmu.rwlock(false) {
return errClosing(fd.isFile)
}
return nil
}
// readWriteUnlock removes a reference from fd and unlocks fd for reading and writing.
// It also closes fd when the state of fd is set to closed and there
// is no remaining reference.
func (fd *FD) readWriteUnlock() {
fd.fdmu.rwunlock(true)
fd.fdmu.rwunlock(false)
}
// closing returns true if fd is closing. // closing returns true if fd is closing.
func (fd *FD) closing() bool { func (fd *FD) closing() bool {
return atomic.LoadUint64(&fd.fdmu.state)&mutexClosed != 0 return atomic.LoadUint64(&fd.fdmu.state)&mutexClosed != 0

View file

@ -77,9 +77,7 @@ type operation struct {
mode int32 mode int32
// fields used only by net package // fields used only by net package
buf syscall.WSABuf buf syscall.WSABuf
rsa *syscall.RawSockaddrAny
bufs []syscall.WSABuf
} }
func (o *operation) setEvent() { func (o *operation) setEvent() {
@ -114,49 +112,97 @@ func (o *operation) InitBuf(buf []byte) {
o.buf.Buf = unsafe.SliceData(buf) o.buf.Buf = unsafe.SliceData(buf)
} }
func (o *operation) InitBufs(buf *[][]byte) { var wsaBufsPool = sync.Pool{
if o.bufs == nil { New: func() any {
o.bufs = make([]syscall.WSABuf, 0, len(*buf)) buf := make([]syscall.WSABuf, 0, 16)
} else { return &buf
o.bufs = o.bufs[:0] },
} }
func newWSABufs(buf *[][]byte) *[]syscall.WSABuf {
bufsPtr := wsaBufsPool.Get().(*[]syscall.WSABuf)
*bufsPtr = (*bufsPtr)[:0]
for _, b := range *buf { for _, b := range *buf {
if len(b) == 0 { if len(b) == 0 {
o.bufs = append(o.bufs, syscall.WSABuf{}) *bufsPtr = append(*bufsPtr, syscall.WSABuf{})
continue continue
} }
for len(b) > maxRW { for len(b) > maxRW {
o.bufs = append(o.bufs, syscall.WSABuf{Len: maxRW, Buf: &b[0]}) *bufsPtr = append(*bufsPtr, syscall.WSABuf{Len: maxRW, Buf: &b[0]})
b = b[maxRW:] b = b[maxRW:]
} }
if len(b) > 0 { if len(b) > 0 {
o.bufs = append(o.bufs, syscall.WSABuf{Len: uint32(len(b)), Buf: &b[0]}) *bufsPtr = append(*bufsPtr, syscall.WSABuf{Len: uint32(len(b)), Buf: &b[0]})
} }
} }
return bufsPtr
} }
// ClearBufs clears all pointers to Buffers parameter captured func freeWSABufs(bufsPtr *[]syscall.WSABuf) {
// by InitBufs, so it can be released by garbage collector. // Clear pointers to buffers so they can be released by garbage collector.
func (o *operation) ClearBufs() { bufs := *bufsPtr
for i := range o.bufs { for i := range bufs {
o.bufs[i].Buf = nil bufs[i].Buf = nil
} }
o.bufs = o.bufs[:0] // Proper usage of a sync.Pool requires each entry to have approximately
// the same memory cost. To obtain this property when the stored type
// contains a variably-sized buffer, we add a hard limit on the maximum buffer
// to place back in the pool.
//
// See https://go.dev/issue/23199
if cap(*bufsPtr) > 128 {
*bufsPtr = nil
}
wsaBufsPool.Put(bufsPtr)
} }
func newWSAMsg(p []byte, oob []byte, flags int) windows.WSAMsg { // wsaMsgPool is a pool of WSAMsg structures that can only hold a single WSABuf.
return windows.WSAMsg{ var wsaMsgPool = sync.Pool{
Buffers: &syscall.WSABuf{ New: func() any {
Len: uint32(len(p)), return &windows.WSAMsg{
Buf: unsafe.SliceData(p), Buffers: &syscall.WSABuf{},
}, BufferCount: 1,
BufferCount: 1, }
Control: syscall.WSABuf{ },
Len: uint32(len(oob)), }
Buf: unsafe.SliceData(oob),
}, // newWSAMsg creates a new WSAMsg with the provided parameters.
Flags: uint32(flags), // Use [freeWSAMsg] to free it.
func newWSAMsg(p []byte, oob []byte, flags int, rsa *syscall.RawSockaddrAny) *windows.WSAMsg {
// The returned object can't be allocated in the stack because it is accessed asynchronously
// by Windows in between several system calls. If the stack frame is moved while that happens,
// then Windows may access invalid memory.
// TODO(qmuntal): investigate using runtime.Pinner keeping this path allocation-free.
// Use a pool to reuse allocations.
msg := wsaMsgPool.Get().(*windows.WSAMsg)
msg.Buffers.Len = uint32(len(p))
msg.Buffers.Buf = unsafe.SliceData(p)
msg.Control = syscall.WSABuf{
Len: uint32(len(oob)),
Buf: unsafe.SliceData(oob),
} }
msg.Flags = uint32(flags)
msg.Name = syscall.Pointer(unsafe.Pointer(rsa))
if rsa != nil {
msg.Namelen = int32(unsafe.Sizeof(*rsa))
} else {
msg.Namelen = 0
}
return msg
}
func freeWSAMsg(msg *windows.WSAMsg) {
// Clear pointers to buffers so they can be released by garbage collector.
msg.Buffers.Len = 0
msg.Buffers.Buf = nil
wsaMsgPool.Put(msg)
}
var wsaRsaPool = sync.Pool{
New: func() any {
return new(syscall.RawSockaddrAny)
},
} }
// waitIO waits for the IO operation o to complete. // waitIO waits for the IO operation o to complete.
@ -276,9 +322,6 @@ type FD struct {
// I/O poller. // I/O poller.
pd pollDesc pd pollDesc
// Used to implement pread/pwrite.
l sync.Mutex
// The file offset for the next read or write. // The file offset for the next read or write.
// Overlapped IO operations don't use the real file pointer, // Overlapped IO operations don't use the real file pointer,
// so we need to keep track of the offset ourselves. // so we need to keep track of the offset ourselves.
@ -316,7 +359,7 @@ type FD struct {
} }
// setOffset sets the offset fields of the overlapped object // setOffset sets the offset fields of the overlapped object
// to the given offset. The fd.l lock must be held. // to the given offset. The fd read/write lock must be held.
// //
// Overlapped IO operations don't update the offset fields // Overlapped IO operations don't update the offset fields
// of the overlapped object nor the file pointer automatically, // of the overlapped object nor the file pointer automatically,
@ -476,13 +519,16 @@ const maxRW = 1 << 30 // 1GB is large enough and keeps subsequent reads aligned
// Read implements io.Reader. // Read implements io.Reader.
func (fd *FD) Read(buf []byte) (int, error) { func (fd *FD) Read(buf []byte) (int, error) {
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
if fd.kind == kindFile { if fd.kind == kindFile {
fd.l.Lock() if err := fd.readWriteLock(); err != nil {
defer fd.l.Unlock() return 0, err
}
defer fd.readWriteUnlock()
} else {
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
} }
if len(buf) > maxRW { if len(buf) > maxRW {
@ -609,19 +655,16 @@ func (fd *FD) Pread(b []byte, off int64) (int, error) {
// Pread does not work with pipes // Pread does not work with pipes
return 0, syscall.ESPIPE return 0, syscall.ESPIPE
} }
// Call incref, not readLock, because since pread specifies the
// offset it is independent from other reads. if err := fd.readWriteLock(); err != nil {
if err := fd.incref(); err != nil {
return 0, err return 0, err
} }
defer fd.decref() defer fd.readWriteUnlock()
if len(b) > maxRW { if len(b) > maxRW {
b = b[:maxRW] b = b[:maxRW]
} }
fd.l.Lock()
defer fd.l.Unlock()
if fd.isBlocking { if fd.isBlocking {
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent) curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
if err != nil { if err != nil {
@ -668,20 +711,19 @@ func (fd *FD) ReadFrom(buf []byte) (int, syscall.Sockaddr, error) {
defer fd.readUnlock() defer fd.readUnlock()
o := &fd.rop o := &fd.rop
o.InitBuf(buf) o.InitBuf(buf)
rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
defer wsaRsaPool.Put(rsa)
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) { n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
if o.rsa == nil { rsan := int32(unsafe.Sizeof(*rsa))
o.rsa = new(syscall.RawSockaddrAny)
}
rsan := int32(unsafe.Sizeof(*o.rsa))
var flags uint32 var flags uint32
err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, o.rsa, &rsan, &o.o, nil) err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, rsa, &rsan, &o.o, nil)
return qty, err return qty, err
}) })
err = fd.eofError(n, err) err = fd.eofError(n, err)
if err != nil { if err != nil {
return n, nil, err return n, nil, err
} }
sa, _ := o.rsa.Sockaddr() sa, _ := rsa.Sockaddr()
return n, sa, nil return n, sa, nil
} }
@ -699,20 +741,19 @@ func (fd *FD) ReadFromInet4(buf []byte, sa4 *syscall.SockaddrInet4) (int, error)
defer fd.readUnlock() defer fd.readUnlock()
o := &fd.rop o := &fd.rop
o.InitBuf(buf) o.InitBuf(buf)
rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
defer wsaRsaPool.Put(rsa)
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) { n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
if o.rsa == nil { rsan := int32(unsafe.Sizeof(*rsa))
o.rsa = new(syscall.RawSockaddrAny)
}
rsan := int32(unsafe.Sizeof(*o.rsa))
var flags uint32 var flags uint32
err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, o.rsa, &rsan, &o.o, nil) err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, rsa, &rsan, &o.o, nil)
return qty, err return qty, err
}) })
err = fd.eofError(n, err) err = fd.eofError(n, err)
if err != nil { if err != nil {
return n, err return n, err
} }
rawToSockaddrInet4(o.rsa, sa4) rawToSockaddrInet4(rsa, sa4)
return n, err return n, err
} }
@ -730,32 +771,34 @@ func (fd *FD) ReadFromInet6(buf []byte, sa6 *syscall.SockaddrInet6) (int, error)
defer fd.readUnlock() defer fd.readUnlock()
o := &fd.rop o := &fd.rop
o.InitBuf(buf) o.InitBuf(buf)
rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
defer wsaRsaPool.Put(rsa)
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) { n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
if o.rsa == nil { rsan := int32(unsafe.Sizeof(*rsa))
o.rsa = new(syscall.RawSockaddrAny)
}
rsan := int32(unsafe.Sizeof(*o.rsa))
var flags uint32 var flags uint32
err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, o.rsa, &rsan, &o.o, nil) err = syscall.WSARecvFrom(fd.Sysfd, &o.buf, 1, &qty, &flags, rsa, &rsan, &o.o, nil)
return qty, err return qty, err
}) })
err = fd.eofError(n, err) err = fd.eofError(n, err)
if err != nil { if err != nil {
return n, err return n, err
} }
rawToSockaddrInet6(o.rsa, sa6) rawToSockaddrInet6(rsa, sa6)
return n, err return n, err
} }
// Write implements io.Writer. // Write implements io.Writer.
func (fd *FD) Write(buf []byte) (int, error) { func (fd *FD) Write(buf []byte) (int, error) {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
if fd.kind == kindFile { if fd.kind == kindFile {
fd.l.Lock() if err := fd.readWriteLock(); err != nil {
defer fd.l.Unlock() return 0, err
}
defer fd.readWriteUnlock()
} else {
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
} }
var ntotal int var ntotal int
@ -848,15 +891,12 @@ func (fd *FD) Pwrite(buf []byte, off int64) (int, error) {
// Pwrite does not work with pipes // Pwrite does not work with pipes
return 0, syscall.ESPIPE return 0, syscall.ESPIPE
} }
// Call incref, not writeLock, because since pwrite specifies the
// offset it is independent from other writes. if err := fd.readWriteLock(); err != nil {
if err := fd.incref(); err != nil {
return 0, err return 0, err
} }
defer fd.decref() defer fd.readWriteUnlock()
fd.l.Lock()
defer fd.l.Unlock()
if fd.isBlocking { if fd.isBlocking {
curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent) curoffset, err := syscall.Seek(fd.Sysfd, 0, io.SeekCurrent)
if err != nil { if err != nil {
@ -912,13 +952,12 @@ func (fd *FD) Writev(buf *[][]byte) (int64, error) {
if race.Enabled { if race.Enabled {
race.ReleaseMerge(unsafe.Pointer(&ioSync)) race.ReleaseMerge(unsafe.Pointer(&ioSync))
} }
o := &fd.wop bufs := newWSABufs(buf)
o.InitBufs(buf) defer freeWSABufs(bufs)
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) { n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
err = syscall.WSASend(fd.Sysfd, &o.bufs[0], uint32(len(o.bufs)), &qty, 0, &o.o, nil) err = syscall.WSASend(fd.Sysfd, &(*bufs)[0], uint32(len(*bufs)), &qty, 0, &o.o, nil)
return qty, err return qty, err
}) })
o.ClearBufs()
TestHookDidWritev(n) TestHookDidWritev(n)
consume(buf, int64(n)) consume(buf, int64(n))
return int64(n), err return int64(n), err
@ -1119,13 +1158,10 @@ func (fd *FD) Seek(offset int64, whence int) (int64, error) {
if fd.kind == kindPipe { if fd.kind == kindPipe {
return 0, syscall.ESPIPE return 0, syscall.ESPIPE
} }
if err := fd.incref(); err != nil { if err := fd.readWriteLock(); err != nil {
return 0, err return 0, err
} }
defer fd.decref() defer fd.readWriteUnlock()
fd.l.Lock()
defer fd.l.Unlock()
if !fd.isBlocking && whence == io.SeekCurrent { if !fd.isBlocking && whence == io.SeekCurrent {
// Windows doesn't keep the file pointer for overlapped file handles. // Windows doesn't keep the file pointer for overlapped file handles.
@ -1299,21 +1335,18 @@ func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.S
p = p[:maxRW] p = p[:maxRW]
} }
o := &fd.rop rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
if o.rsa == nil { defer wsaRsaPool.Put(rsa)
o.rsa = new(syscall.RawSockaddrAny) msg := newWSAMsg(p, oob, flags, rsa)
} defer freeWSAMsg(msg)
msg := newWSAMsg(p, oob, flags) n, err := fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) err = windows.WSARecvMsg(fd.Sysfd, msg, &qty, &o.o, nil)
msg.Namelen = int32(unsafe.Sizeof(*o.rsa))
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
err = windows.WSARecvMsg(fd.Sysfd, &msg, &qty, &o.o, nil)
return qty, err return qty, err
}) })
err = fd.eofError(n, err) err = fd.eofError(n, err)
var sa syscall.Sockaddr var sa syscall.Sockaddr
if err == nil { if err == nil {
sa, err = o.rsa.Sockaddr() sa, err = rsa.Sockaddr()
} }
return n, int(msg.Control.Len), int(msg.Flags), sa, err return n, int(msg.Control.Len), int(msg.Flags), sa, err
} }
@ -1329,20 +1362,17 @@ func (fd *FD) ReadMsgInet4(p []byte, oob []byte, flags int, sa4 *syscall.Sockadd
p = p[:maxRW] p = p[:maxRW]
} }
o := &fd.rop rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
if o.rsa == nil { defer wsaRsaPool.Put(rsa)
o.rsa = new(syscall.RawSockaddrAny) msg := newWSAMsg(p, oob, flags, rsa)
} defer freeWSAMsg(msg)
msg := newWSAMsg(p, oob, flags) n, err := fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) err = windows.WSARecvMsg(fd.Sysfd, msg, &qty, &o.o, nil)
msg.Namelen = int32(unsafe.Sizeof(*o.rsa))
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
err = windows.WSARecvMsg(fd.Sysfd, &msg, &qty, &o.o, nil)
return qty, err return qty, err
}) })
err = fd.eofError(n, err) err = fd.eofError(n, err)
if err == nil { if err == nil {
rawToSockaddrInet4(o.rsa, sa4) rawToSockaddrInet4(rsa, sa4)
} }
return n, int(msg.Control.Len), int(msg.Flags), err return n, int(msg.Control.Len), int(msg.Flags), err
} }
@ -1358,20 +1388,17 @@ func (fd *FD) ReadMsgInet6(p []byte, oob []byte, flags int, sa6 *syscall.Sockadd
p = p[:maxRW] p = p[:maxRW]
} }
o := &fd.rop rsa := wsaRsaPool.Get().(*syscall.RawSockaddrAny)
if o.rsa == nil { defer wsaRsaPool.Put(rsa)
o.rsa = new(syscall.RawSockaddrAny) msg := newWSAMsg(p, oob, flags, rsa)
} defer freeWSAMsg(msg)
msg := newWSAMsg(p, oob, flags) n, err := fd.execIO(&fd.rop, func(o *operation) (qty uint32, err error) {
msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) err = windows.WSARecvMsg(fd.Sysfd, msg, &qty, &o.o, nil)
msg.Namelen = int32(unsafe.Sizeof(*o.rsa))
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) {
err = windows.WSARecvMsg(fd.Sysfd, &msg, &qty, &o.o, nil)
return qty, err return qty, err
}) })
err = fd.eofError(n, err) err = fd.eofError(n, err)
if err == nil { if err == nil {
rawToSockaddrInet6(o.rsa, sa6) rawToSockaddrInet6(rsa, sa6)
} }
return n, int(msg.Control.Len), int(msg.Flags), err return n, int(msg.Control.Len), int(msg.Flags), err
} }
@ -1387,21 +1414,22 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err
} }
defer fd.writeUnlock() defer fd.writeUnlock()
o := &fd.wop var rsa *syscall.RawSockaddrAny
msg := newWSAMsg(p, oob, 0)
if sa != nil { if sa != nil {
if o.rsa == nil { rsa = wsaRsaPool.Get().(*syscall.RawSockaddrAny)
o.rsa = new(syscall.RawSockaddrAny) defer wsaRsaPool.Put(rsa)
} }
len, err := sockaddrToRaw(o.rsa, sa) msg := newWSAMsg(p, oob, 0, rsa)
defer freeWSAMsg(msg)
if sa != nil {
var err error
msg.Namelen, err = sockaddrToRaw(rsa, sa)
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa))
msg.Namelen = len
} }
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) { n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
err = windows.WSASendMsg(fd.Sysfd, &msg, 0, nil, &o.o, nil) err = windows.WSASendMsg(fd.Sysfd, msg, 0, nil, &o.o, nil)
return qty, err return qty, err
}) })
return n, int(msg.Control.Len), err return n, int(msg.Control.Len), err
@ -1418,16 +1446,18 @@ func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (in
} }
defer fd.writeUnlock() defer fd.writeUnlock()
o := &fd.wop var rsa *syscall.RawSockaddrAny
if o.rsa == nil { if sa != nil {
o.rsa = new(syscall.RawSockaddrAny) rsa = wsaRsaPool.Get().(*syscall.RawSockaddrAny)
defer wsaRsaPool.Put(rsa)
} }
len := sockaddrInet4ToRaw(o.rsa, sa) msg := newWSAMsg(p, oob, 0, rsa)
msg := newWSAMsg(p, oob, 0) defer freeWSAMsg(msg)
msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) if sa != nil {
msg.Namelen = len msg.Namelen = sockaddrInet4ToRaw(rsa, sa)
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) { }
err = windows.WSASendMsg(fd.Sysfd, &msg, 0, nil, &o.o, nil) n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
err = windows.WSASendMsg(fd.Sysfd, msg, 0, nil, &o.o, nil)
return qty, err return qty, err
}) })
return n, int(msg.Control.Len), err return n, int(msg.Control.Len), err
@ -1444,16 +1474,18 @@ func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (in
} }
defer fd.writeUnlock() defer fd.writeUnlock()
o := &fd.wop var rsa *syscall.RawSockaddrAny
if o.rsa == nil { if sa != nil {
o.rsa = new(syscall.RawSockaddrAny) rsa = wsaRsaPool.Get().(*syscall.RawSockaddrAny)
defer wsaRsaPool.Put(rsa)
} }
msg := newWSAMsg(p, oob, 0) msg := newWSAMsg(p, oob, 0, rsa)
len := sockaddrInet6ToRaw(o.rsa, sa) defer freeWSAMsg(msg)
msg.Name = (syscall.Pointer)(unsafe.Pointer(o.rsa)) if sa != nil {
msg.Namelen = len msg.Namelen = sockaddrInet6ToRaw(rsa, sa)
n, err := fd.execIO(o, func(o *operation) (qty uint32, err error) { }
err = windows.WSASendMsg(fd.Sysfd, &msg, 0, nil, &o.o, nil) n, err := fd.execIO(&fd.wop, func(o *operation) (qty uint32, err error) {
err = windows.WSASendMsg(fd.Sysfd, msg, 0, nil, &o.o, nil)
return qty, err return qty, err
}) })
return n, int(msg.Control.Len), err return n, int(msg.Control.Len), err

View file

@ -19,7 +19,7 @@ TEXT ·Cas(SB), NOSPLIT, $0-17
MOVW new+12(FP), R6 MOVW new+12(FP), R6
MOVBU internalcpu·Loong64+const_offsetLOONG64HasLAMCAS(SB), R8 MOVBU internalcpu·Loong64+const_offsetLOONG64HasLAMCAS(SB), R8
BEQ R8, cas_again BEQ R8, ll_sc
MOVV R5, R7 // backup old value MOVV R5, R7 // backup old value
AMCASDBW R6, (R4), R5 AMCASDBW R6, (R4), R5
BNE R7, R5, cas_fail0 BNE R7, R5, cas_fail0
@ -30,6 +30,7 @@ cas_fail0:
MOVB R0, ret+16(FP) MOVB R0, ret+16(FP)
RET RET
ll_sc:
// Implemented using the ll-sc instruction pair // Implemented using the ll-sc instruction pair
DBAR $0x14 // LoadAcquire barrier DBAR $0x14 // LoadAcquire barrier
cas_again: cas_again:
@ -60,7 +61,7 @@ TEXT ·Cas64(SB), NOSPLIT, $0-25
MOVV new+16(FP), R6 MOVV new+16(FP), R6
MOVBU internalcpu·Loong64+const_offsetLOONG64HasLAMCAS(SB), R8 MOVBU internalcpu·Loong64+const_offsetLOONG64HasLAMCAS(SB), R8
BEQ R8, cas64_again BEQ R8, ll_sc_64
MOVV R5, R7 // backup old value MOVV R5, R7 // backup old value
AMCASDBV R6, (R4), R5 AMCASDBV R6, (R4), R5
BNE R7, R5, cas64_fail0 BNE R7, R5, cas64_fail0
@ -71,6 +72,7 @@ cas64_fail0:
MOVB R0, ret+24(FP) MOVB R0, ret+24(FP)
RET RET
ll_sc_64:
// Implemented using the ll-sc instruction pair // Implemented using the ll-sc instruction pair
DBAR $0x14 DBAR $0x14
cas64_again: cas64_again:

View file

@ -1,77 +0,0 @@
// Copyright 2025 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.
#include "go_asm.h"
#include "go_tls.h"
#include "textflag.h"
#include "time_windows.h"
TEXT ·StdCall<ABIInternal>(SB),NOSPLIT,$0
B ·asmstdcall(SB)
TEXT ·asmstdcall(SB),NOSPLIT|NOFRAME,$0
MOVM.DB.W [R4, R5, R14], (R13) // push {r4, r5, lr}
MOVW R0, R4 // put fn * in r4
MOVW R13, R5 // save stack pointer in r5
// SetLastError(0)
MOVW $0, R0
MRC 15, 0, R1, C13, C0, 2
MOVW R0, 0x34(R1)
MOVW 8(R4), R12 // fn->Args
// Do we have more than 4 arguments?
MOVW 4(R4), R0 // fn->n
SUB.S $4, R0, R2
BLE loadregs
// Reserve stack space for remaining args
SUB R2<<2, R13
BIC $0x7, R13 // alignment for ABI
// R0: count of arguments
// R1:
// R2: loop counter, from 0 to (n-4)
// R3: scratch
// R4: pointer to StdCallInfo struct
// R12: fn->args
MOVW $0, R2
stackargs:
ADD $4, R2, R3 // r3 = args[4 + i]
MOVW R3<<2(R12), R3
MOVW R3, R2<<2(R13) // stack[i] = r3
ADD $1, R2 // i++
SUB $4, R0, R3 // while (i < (n - 4))
CMP R3, R2
BLT stackargs
loadregs:
CMP $3, R0
MOVW.GT 12(R12), R3
CMP $2, R0
MOVW.GT 8(R12), R2
CMP $1, R0
MOVW.GT 4(R12), R1
CMP $0, R0
MOVW.GT 0(R12), R0
BIC $0x7, R13 // alignment for ABI
MOVW 0(R4), R12 // branch to fn->fn
BL (R12)
MOVW R5, R13 // free stack space
MOVW R0, 12(R4) // save return value to fn->r1
MOVW R1, 16(R4)
// GetLastError
MRC 15, 0, R1, C13, C0, 2
MOVW 0x34(R1), R0
MOVW R0, 20(R4) // store in fn->err
MOVM.IA.W (R13), [R4, R5, R15]

View file

@ -11,18 +11,23 @@ import (
"unsafe" "unsafe"
) )
// Openat flags supported by syscall.Open.
const (
O_DIRECTORY = 0x04000 // target must be a directory
)
// Openat flags not supported by syscall.Open. // Openat flags not supported by syscall.Open.
// //
// These are invented values. // These are invented values, use values in the 33-63 bit range
// to avoid overlap with flags and attributes supported by [syscall.Open].
// //
// When adding a new flag here, add an unexported version to // When adding a new flag here, add an unexported version to
// the set of invented O_ values in syscall/types_windows.go // the set of invented O_ values in syscall/types_windows.go
// to avoid overlap. // to avoid overlap.
const ( const (
O_DIRECTORY = 0x100000 // target must be a directory O_NOFOLLOW_ANY = 0x200000000 // disallow symlinks anywhere in the path
O_NOFOLLOW_ANY = 0x20000000 // disallow symlinks anywhere in the path O_OPEN_REPARSE = 0x400000000 // FILE_OPEN_REPARSE_POINT, used by Lstat
O_OPEN_REPARSE = 0x40000000 // FILE_OPEN_REPARSE_POINT, used by Lstat O_WRITE_ATTRS = 0x800000000 // FILE_WRITE_ATTRIBUTES, used by Chmod
O_WRITE_ATTRS = 0x80000000 // FILE_WRITE_ATTRIBUTES, used by Chmod
) )
func Openat(dirfd syscall.Handle, name string, flag uint64, perm uint32) (_ syscall.Handle, e1 error) { func Openat(dirfd syscall.Handle, name string, flag uint64, perm uint32) (_ syscall.Handle, e1 error) {

View file

@ -10,7 +10,7 @@ import (
) )
// IsNonblock returns whether the file descriptor fd is opened // IsNonblock returns whether the file descriptor fd is opened
// in non-blocking mode, that is, the [syscall.FILE_FLAG_OVERLAPPED] flag // in non-blocking mode, that is, the [windows.O_FILE_FLAG_OVERLAPPED] flag
// was set when the file was opened. // was set when the file was opened.
func IsNonblock(fd syscall.Handle) (nonblocking bool, err error) { func IsNonblock(fd syscall.Handle) (nonblocking bool, err error) {
var info FILE_MODE_INFORMATION var info FILE_MODE_INFORMATION

View file

@ -164,6 +164,22 @@ type SECURITY_QUALITY_OF_SERVICE struct {
EffectiveOnly byte EffectiveOnly byte
} }
// File flags for [os.OpenFile]. The O_ prefix is used to indicate
// that these flags are specific to the OpenFile function.
const (
O_FILE_FLAG_OPEN_NO_RECALL = 0x00100000
O_FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
O_FILE_FLAG_SESSION_AWARE = 0x00800000
O_FILE_FLAG_POSIX_SEMANTICS = 0x01000000
O_FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
O_FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
O_FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000
O_FILE_FLAG_RANDOM_ACCESS = 0x10000000
O_FILE_FLAG_NO_BUFFERING = 0x20000000
O_FILE_FLAG_OVERLAPPED = 0x40000000
O_FILE_FLAG_WRITE_THROUGH = 0x80000000
)
const ( const (
// CreateDisposition flags for NtCreateFile and NtCreateNamedPipeFile. // CreateDisposition flags for NtCreateFile and NtCreateNamedPipeFile.
FILE_SUPERSEDE = 0x00000000 FILE_SUPERSEDE = 0x00000000

View file

@ -694,6 +694,9 @@ func testTraceProg(t *testing.T, progName string, extra func(t *testing.T, trace
runTest(t, false, "") runTest(t, false, "")
}) })
t.Run("AsyncPreemptOff", func(t *testing.T) { t.Run("AsyncPreemptOff", func(t *testing.T) {
if testing.Short() && runtime.NumCPU() < 2 {
t.Skip("skipping trace async preempt off tests in short mode")
}
runTest(t, false, "asyncpreemptoff=1") runTest(t, false, "asyncpreemptoff=1")
}) })
t.Run("Stress", func(t *testing.T) { t.Run("Stress", func(t *testing.T) {

View file

@ -48,7 +48,12 @@ func IsInf(f float64, sign int) bool {
// To avoid the floating-point hardware, could use: // To avoid the floating-point hardware, could use:
// x := Float64bits(f); // x := Float64bits(f);
// return sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf; // return sign >= 0 && x == uvinf || sign <= 0 && x == uvneginf;
return sign >= 0 && f > MaxFloat64 || sign <= 0 && f < -MaxFloat64 if sign == 0 {
f = Abs(f)
} else if sign < 0 {
f = -f
}
return f > MaxFloat64
} }
// normalize returns a normal number y and exponent exp // normalize returns a normal number y and exponent exp

View file

@ -66,11 +66,18 @@ func Trunc(x float64) float64 {
} }
func trunc(x float64) float64 { func trunc(x float64) float64 {
if x == 0 || IsNaN(x) || IsInf(x, 0) { if Abs(x) < 1 {
return x return Copysign(0, x)
} }
d, _ := Modf(x)
return d b := Float64bits(x)
e := uint(b>>shift)&mask - bias
// Keep the top 12+e bits, the integer part; clear the rest.
if e < 64-12 {
b &^= 1<<(64-12-e) - 1
}
return Float64frombits(b)
} }
// Round returns the nearest integer, rounding half away from zero. // Round returns the nearest integer, rounding half away from zero.

View file

@ -11,33 +11,8 @@ package math
// //
// Modf(±Inf) = ±Inf, NaN // Modf(±Inf) = ±Inf, NaN
// Modf(NaN) = NaN, NaN // Modf(NaN) = NaN, NaN
func Modf(f float64) (int float64, frac float64) { func Modf(f float64) (integer float64, fractional float64) {
if haveArchModf { integer = Trunc(f)
return archModf(f) fractional = Copysign(f-integer, f)
}
return modf(f)
}
func modf(f float64) (int float64, frac float64) {
if f < 1 {
switch {
case f < 0:
int, frac = Modf(-f)
return -int, -frac
case f == 0:
return f, f // Return -0, -0 when f == -0
}
return 0, f
}
x := Float64bits(f)
e := uint(x>>shift)&mask - bias
// Keep the top 12+e bits, the integer part; clear the rest.
if e < 64-12 {
x &^= 1<<(64-12-e) - 1
}
int = Float64frombits(x)
frac = f - int
return return
} }

View file

@ -1,18 +0,0 @@
// Copyright 2016 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.
#include "textflag.h"
// func archModf(f float64) (int float64, frac float64)
TEXT ·archModf(SB),NOSPLIT,$0
MOVD f+0(FP), R0
FMOVD R0, F0
FRINTZD F0, F1
FMOVD F1, int+8(FP)
FSUBD F1, F0
FMOVD F0, R1
AND $(1<<63), R0
ORR R0, R1 // must have same sign
MOVD R1, frac+16(FP)
RET

View file

@ -1,11 +0,0 @@
// Copyright 2021 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.
//go:build arm64 || ppc64 || ppc64le
package math
const haveArchModf = true
func archModf(f float64) (int float64, frac float64)

View file

@ -1,13 +0,0 @@
// Copyright 2021 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.
//go:build !arm64 && !ppc64 && !ppc64le
package math
const haveArchModf = false
func archModf(f float64) (int float64, frac float64) {
panic("not implemented")
}

View file

@ -1,17 +0,0 @@
// Copyright 2017 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.
//go:build ppc64 || ppc64le
#include "textflag.h"
// func archModf(f float64) (int float64, frac float64)
TEXT ·archModf(SB),NOSPLIT,$0
FMOVD f+0(FP), F0
FRIZ F0, F1
FMOVD F1, int+8(FP)
FSUB F1, F0, F2
FCPSGN F2, F0, F2
FMOVD F2, frac+16(FP)
RET

View file

@ -6,5 +6,5 @@ package math
// Signbit reports whether x is negative or negative zero. // Signbit reports whether x is negative or negative zero.
func Signbit(x float64) bool { func Signbit(x float64) bool {
return Float64bits(x)&(1<<63) != 0 return int64(Float64bits(x)) < 0
} }

View file

@ -31,7 +31,7 @@ func cgoLookupIP(ctx context.Context, network, name string) (addrs []IPAddr, err
panic("cgo stub: cgo not available") panic("cgo stub: cgo not available")
} }
func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) { func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error) {
panic("cgo stub: cgo not available") panic("cgo stub: cgo not available")
} }

View file

@ -297,16 +297,16 @@ func cgoSockaddr(ip IP, zone string) (*_C_struct_sockaddr, _C_socklen_t) {
return nil, 0 return nil, 0
} }
func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) { func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error) {
resources, err := resSearch(ctx, name, int(dnsmessage.TypeCNAME), int(dnsmessage.ClassINET)) resources, err := resSearch(ctx, name, int(dnsmessage.TypeCNAME), int(dnsmessage.ClassINET))
if err != nil { if err != nil {
return return "", err
} }
cname, err = parseCNAMEFromResources(resources) cname, err = parseCNAMEFromResources(resources)
if err != nil { if err != nil {
return "", err, false return "", err
} }
return cname, nil, true return cname, nil
} }
// resSearch will make a call to the 'res_nsearch' routine in the C library // resSearch will make a call to the 'res_nsearch' routine in the C library
@ -351,7 +351,7 @@ func cgoResSearch(hostname string, rtype, class int) ([]dnsmessage.Resource, err
var size int var size int
for { for {
size := _C_res_nsearch(state, (*_C_char)(unsafe.Pointer(s)), class, rtype, buf, bufSize) size = _C_res_nsearch(state, (*_C_char)(unsafe.Pointer(s)), class, rtype, buf, bufSize)
if size <= 0 || size > 0xffff { if size <= 0 || size > 0xffff {
return nil, errors.New("res_nsearch failure") return nil, errors.New("res_nsearch failure")
} }

View file

@ -8,6 +8,7 @@ package net
import ( import (
"context" "context"
"internal/testenv"
"testing" "testing"
) )
@ -67,3 +68,12 @@ func TestCgoLookupPTRWithCancel(t *testing.T) {
t.Error(err) t.Error(err)
} }
} }
func TestCgoLookupCNAME(t *testing.T) {
mustHaveExternalNetwork(t)
testenv.SkipFlakyNet(t)
defer dnsWaitGroup.Wait()
if _, err := cgoLookupCNAME(t.Context(), "www.iana.org."); err != nil {
t.Error(err)
}
}

View file

@ -1227,7 +1227,7 @@ func testClientTimeout(t *testing.T, mode testMode) {
t.Logf("timeout before response received") t.Logf("timeout before response received")
continue continue
} }
if runtime.GOOS == "windows" && strings.HasPrefix(runtime.GOARCH, "arm") { if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
testenv.SkipFlaky(t, 43120) testenv.SkipFlaky(t, 43120)
} }
t.Fatal(err) t.Fatal(err)
@ -1256,7 +1256,7 @@ func testClientTimeout(t *testing.T, mode testMode) {
t.Errorf("ReadAll error = %q; expected some context.DeadlineExceeded", err) t.Errorf("ReadAll error = %q; expected some context.DeadlineExceeded", err)
} }
if got := ne.Error(); !strings.Contains(got, "(Client.Timeout") { if got := ne.Error(); !strings.Contains(got, "(Client.Timeout") {
if runtime.GOOS == "windows" && strings.HasPrefix(runtime.GOARCH, "arm") { if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
testenv.SkipFlaky(t, 43120) testenv.SkipFlaky(t, 43120)
} }
t.Errorf("error string = %q; missing timeout substring", got) t.Errorf("error string = %q; missing timeout substring", got)
@ -1302,7 +1302,7 @@ func testClientTimeout_Headers(t *testing.T, mode testMode) {
t.Errorf("ReadAll error = %q; expected some context.DeadlineExceeded", err) t.Errorf("ReadAll error = %q; expected some context.DeadlineExceeded", err)
} }
if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") { if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") {
if runtime.GOOS == "windows" && strings.HasPrefix(runtime.GOARCH, "arm") { if runtime.GOOS == "windows" && runtime.GOARCH == "arm64" {
testenv.SkipFlaky(t, 43120) testenv.SkipFlaky(t, 43120)
} }
t.Errorf("error string = %q; missing timeout substring", got) t.Errorf("error string = %q; missing timeout substring", got)

View file

@ -77,13 +77,21 @@ func (c *CrossOriginProtection) AddTrustedOrigin(origin string) error {
return nil return nil
} }
var noopHandler = HandlerFunc(func(w ResponseWriter, r *Request) {}) type noopHandler struct{}
func (noopHandler) ServeHTTP(ResponseWriter, *Request) {}
var sentinelHandler Handler = &noopHandler{}
// AddInsecureBypassPattern permits all requests that match the given pattern. // AddInsecureBypassPattern permits all requests that match the given pattern.
// The pattern syntax and precedence rules are the same as [ServeMux].
// //
// AddInsecureBypassPattern can be called concurrently with other methods // The pattern syntax and precedence rules are the same as [ServeMux]. Only
// or request handling, and applies to future requests. // requests that match the pattern directly are permitted. Those that ServeMux
// would redirect to a pattern (e.g. after cleaning the path or adding a
// trailing slash) are not.
//
// AddInsecureBypassPattern can be called concurrently with other methods or
// request handling, and applies to future requests.
func (c *CrossOriginProtection) AddInsecureBypassPattern(pattern string) { func (c *CrossOriginProtection) AddInsecureBypassPattern(pattern string) {
var bypass *ServeMux var bypass *ServeMux
@ -99,7 +107,7 @@ func (c *CrossOriginProtection) AddInsecureBypassPattern(pattern string) {
} }
} }
bypass.Handle(pattern, noopHandler) bypass.Handle(pattern, sentinelHandler)
} }
// SetDenyHandler sets a handler to invoke when a request is rejected. // SetDenyHandler sets a handler to invoke when a request is rejected.
@ -172,7 +180,7 @@ var (
// be deferred until the last moment. // be deferred until the last moment.
func (c *CrossOriginProtection) isRequestExempt(req *Request) bool { func (c *CrossOriginProtection) isRequestExempt(req *Request) bool {
if bypass := c.bypass.Load(); bypass != nil { if bypass := c.bypass.Load(); bypass != nil {
if _, pattern := bypass.Handler(req); pattern != "" { if h, _ := bypass.Handler(req); h == sentinelHandler {
// The request matches a bypass pattern. // The request matches a bypass pattern.
return true return true
} }

View file

@ -113,6 +113,11 @@ func TestCrossOriginProtectionPatternBypass(t *testing.T) {
protection := http.NewCrossOriginProtection() protection := http.NewCrossOriginProtection()
protection.AddInsecureBypassPattern("/bypass/") protection.AddInsecureBypassPattern("/bypass/")
protection.AddInsecureBypassPattern("/only/{foo}") protection.AddInsecureBypassPattern("/only/{foo}")
protection.AddInsecureBypassPattern("/no-trailing")
protection.AddInsecureBypassPattern("/yes-trailing/")
protection.AddInsecureBypassPattern("PUT /put-only/")
protection.AddInsecureBypassPattern("GET /get-only/")
protection.AddInsecureBypassPattern("POST /post-only/")
handler := protection.Handler(okHandler) handler := protection.Handler(okHandler)
tests := []struct { tests := []struct {
@ -126,13 +131,23 @@ func TestCrossOriginProtectionPatternBypass(t *testing.T) {
{"non-bypass path without sec-fetch-site", "/api/", "", http.StatusForbidden}, {"non-bypass path without sec-fetch-site", "/api/", "", http.StatusForbidden},
{"non-bypass path with cross-site", "/api/", "cross-site", http.StatusForbidden}, {"non-bypass path with cross-site", "/api/", "cross-site", http.StatusForbidden},
{"redirect to bypass path without ..", "/foo/../bypass/bar", "", http.StatusOK}, {"redirect to bypass path without ..", "/foo/../bypass/bar", "", http.StatusForbidden},
{"redirect to bypass path with trailing slash", "/bypass", "", http.StatusOK}, {"redirect to bypass path with trailing slash", "/bypass", "", http.StatusForbidden},
{"redirect to non-bypass path with ..", "/foo/../api/bar", "", http.StatusForbidden}, {"redirect to non-bypass path with ..", "/foo/../api/bar", "", http.StatusForbidden},
{"redirect to non-bypass path with trailing slash", "/api", "", http.StatusForbidden}, {"redirect to non-bypass path with trailing slash", "/api", "", http.StatusForbidden},
{"wildcard bypass", "/only/123", "", http.StatusOK}, {"wildcard bypass", "/only/123", "", http.StatusOK},
{"non-wildcard", "/only/123/foo", "", http.StatusForbidden}, {"non-wildcard", "/only/123/foo", "", http.StatusForbidden},
// https://go.dev/issue/75054
{"no trailing slash exact match", "/no-trailing", "", http.StatusOK},
{"no trailing slash with slash", "/no-trailing/", "", http.StatusForbidden},
{"yes trailing slash exact match", "/yes-trailing/", "", http.StatusOK},
{"yes trailing slash without slash", "/yes-trailing", "", http.StatusForbidden},
{"method-specific hit", "/post-only/", "", http.StatusOK},
{"method-specific miss (PUT)", "/put-only/", "", http.StatusForbidden},
{"method-specific miss (GET)", "/get-only/", "", http.StatusForbidden},
} }
for _, tc := range tests { for _, tc := range tests {

View file

@ -7,6 +7,7 @@
package httptest package httptest
import ( import (
"context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"flag" "flag"
@ -126,8 +127,24 @@ func (s *Server) Start() {
if s.URL != "" { if s.URL != "" {
panic("Server already started") panic("Server already started")
} }
if s.client == nil { if s.client == nil {
s.client = &http.Client{Transport: &http.Transport{}} tr := &http.Transport{}
dialer := net.Dialer{}
// User code may set either of Dial or DialContext, with DialContext taking precedence.
// We set DialContext here to preserve any context values that are passed in,
// but fall back to Dial if the user has set it.
tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
if tr.Dial != nil {
return tr.Dial(network, addr)
}
if addr == "example.com:80" || strings.HasSuffix(addr, ".example.com:80") {
addr = s.Listener.Addr().String()
}
return dialer.DialContext(ctx, network, addr)
}
s.client = &http.Client{Transport: tr}
} }
s.URL = "http://" + s.Listener.Addr().String() s.URL = "http://" + s.Listener.Addr().String()
s.wrap() s.wrap()
@ -173,12 +190,23 @@ func (s *Server) StartTLS() {
} }
certpool := x509.NewCertPool() certpool := x509.NewCertPool()
certpool.AddCert(s.certificate) certpool.AddCert(s.certificate)
s.client.Transport = &http.Transport{ tr := &http.Transport{
TLSClientConfig: &tls.Config{ TLSClientConfig: &tls.Config{
RootCAs: certpool, RootCAs: certpool,
}, },
ForceAttemptHTTP2: s.EnableHTTP2, ForceAttemptHTTP2: s.EnableHTTP2,
} }
dialer := net.Dialer{}
tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
if tr.Dial != nil {
return tr.Dial(network, addr)
}
if addr == "example.com:443" || strings.HasSuffix(addr, ".example.com:443") {
addr = s.Listener.Addr().String()
}
return dialer.DialContext(ctx, network, addr)
}
s.client.Transport = tr
s.Listener = tls.NewListener(s.Listener, s.TLS) s.Listener = tls.NewListener(s.Listener, s.TLS)
s.URL = "https://" + s.Listener.Addr().String() s.URL = "https://" + s.Listener.Addr().String()
s.wrap() s.wrap()
@ -300,6 +328,8 @@ func (s *Server) Certificate() *x509.Certificate {
// It is configured to trust the server's TLS test certificate and will // It is configured to trust the server's TLS test certificate and will
// close its idle connections on [Server.Close]. // close its idle connections on [Server.Close].
// Use Server.URL as the base URL to send requests to the server. // Use Server.URL as the base URL to send requests to the server.
// The returned client will also redirect any requests to "example.com"
// or its subdomains to the server.
func (s *Server) Client() *http.Client { func (s *Server) Client() *http.Client {
return s.client return s.client
} }

View file

@ -293,3 +293,40 @@ func TestTLSServerWithHTTP2(t *testing.T) {
}) })
} }
} }
func TestClientExampleCom(t *testing.T) {
modes := []struct {
proto string
host string
}{
{"http", "example.com"},
{"http", "foo.example.com"},
{"https", "example.com"},
{"https", "foo.example.com"},
}
for _, tt := range modes {
t.Run(tt.proto+" "+tt.host, func(t *testing.T) {
cst := NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("requested-hostname", r.Host)
}))
switch tt.proto {
case "https":
cst.EnableHTTP2 = true
cst.StartTLS()
default:
cst.Start()
}
defer cst.Close()
res, err := cst.Client().Get(tt.proto + "://" + tt.host)
if err != nil {
t.Fatalf("Failed to make request: %v", err)
}
if got, want := res.Header.Get("requested-hostname"), tt.host; got != want {
t.Fatalf("Requested hostname mismatch\ngot: %q\nwant: %q", got, want)
}
})
}
}

View file

@ -147,7 +147,6 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
req.Body = save req.Body = save
if err != nil { if err != nil {
pw.Close()
dr.err = err dr.err = err
close(quitReadCh) close(quitReadCh)
return nil, err return nil, err

View file

@ -2759,9 +2759,12 @@ func (mux *ServeMux) matchOrRedirect(host, method, path string, u *url.URL) (_ *
defer mux.mu.RUnlock() defer mux.mu.RUnlock()
n, matches := mux.tree.match(host, method, path) n, matches := mux.tree.match(host, method, path)
// If we have an exact match, or we were asked not to try trailing-slash redirection, // We can terminate here if any of the following is true:
// or the URL already has a trailing slash, then we're done. // - We have an exact match already.
if !exactMatch(n, path) && u != nil && !strings.HasSuffix(path, "/") { // - We were asked not to try trailing slash redirection.
// - The URL already has a trailing slash.
// - The URL is an empty string.
if !exactMatch(n, path) && u != nil && !strings.HasSuffix(path, "/") && path != "" {
// If there is an exact match with a trailing slash, then redirect. // If there is an exact match with a trailing slash, then redirect.
path += "/" path += "/"
n2, _ := mux.tree.match(host, method, path) n2, _ := mux.tree.match(host, method, path)

View file

@ -97,6 +97,7 @@ func TestFindHandler(t *testing.T) {
{"GET", "/foo/x", "&http.handler{i:2}"}, {"GET", "/foo/x", "&http.handler{i:2}"},
{"GET", "/bar/x", "&http.handler{i:4}"}, {"GET", "/bar/x", "&http.handler{i:4}"},
{"GET", "/bar", `&http.redirectHandler{url:"/bar/", code:301}`}, {"GET", "/bar", `&http.redirectHandler{url:"/bar/", code:301}`},
{"CONNECT", "", "(http.HandlerFunc)(.*)"},
{"CONNECT", "/", "&http.handler{i:1}"}, {"CONNECT", "/", "&http.handler{i:1}"},
{"CONNECT", "//", "&http.handler{i:1}"}, {"CONNECT", "//", "&http.handler{i:1}"},
{"CONNECT", "//foo", "&http.handler{i:5}"}, {"CONNECT", "//foo", "&http.handler{i:5}"},
@ -112,7 +113,7 @@ func TestFindHandler(t *testing.T) {
r.URL = &url.URL{Path: test.path} r.URL = &url.URL{Path: test.path}
gotH, _, _, _ := mux.findHandler(&r) gotH, _, _, _ := mux.findHandler(&r)
got := fmt.Sprintf("%#v", gotH) got := fmt.Sprintf("%#v", gotH)
if got != test.wantHandler { if !regexp.MustCompile(test.wantHandler).MatchString(got) {
t.Errorf("%s %q: got %q, want %q", test.method, test.path, got, test.wantHandler) t.Errorf("%s %q: got %q, want %q", test.method, test.path, got, test.wantHandler)
} }
} }

View file

@ -325,6 +325,13 @@ func (t *Transport) readBufferSize() int {
return 4 << 10 return 4 << 10
} }
func (t *Transport) maxHeaderResponseSize() int64 {
if t.MaxResponseHeaderBytes > 0 {
return t.MaxResponseHeaderBytes
}
return 10 << 20 // conservative default; same as http2
}
// Clone returns a deep copy of t's exported fields. // Clone returns a deep copy of t's exported fields.
func (t *Transport) Clone() *Transport { func (t *Transport) Clone() *Transport {
t.nextProtoOnce.Do(t.onceSetNextProtoDefaults) t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
@ -1871,7 +1878,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers
} }
// Okay to use and discard buffered reader here, because // Okay to use and discard buffered reader here, because
// TLS server will not speak until spoken to. // TLS server will not speak until spoken to.
br := bufio.NewReader(conn) br := bufio.NewReader(&io.LimitedReader{R: conn, N: t.maxHeaderResponseSize()})
resp, err = ReadResponse(br, connectReq) resp, err = ReadResponse(br, connectReq)
}() }()
select { select {
@ -2108,10 +2115,7 @@ type persistConn struct {
} }
func (pc *persistConn) maxHeaderResponseSize() int64 { func (pc *persistConn) maxHeaderResponseSize() int64 {
if v := pc.t.MaxResponseHeaderBytes; v != 0 { return pc.t.maxHeaderResponseSize()
return v
}
return 10 << 20 // conservative default; same as http2
} }
func (pc *persistConn) Read(p []byte) (n int, err error) { func (pc *persistConn) Read(p []byte) (n int, err error) {

View file

@ -1550,6 +1550,72 @@ func TestTransportProxy(t *testing.T) {
} }
} }
// Issue 74633: verify that a client will not indefinitely read a response from
// a proxy server that writes an infinite byte of stream, rather than
// responding with 200 OK.
func TestProxyWithInfiniteHeader(t *testing.T) {
defer afterTest(t)
ln := newLocalListener(t)
defer ln.Close()
cancelc := make(chan struct{})
defer close(cancelc)
// Simulate a malicious / misbehaving proxy that writes an unlimited number
// of bytes rather than responding with 200 OK.
go func() {
c, err := ln.Accept()
if err != nil {
t.Errorf("Accept: %v", err)
return
}
defer c.Close()
// Read the CONNECT request
br := bufio.NewReader(c)
cr, err := ReadRequest(br)
if err != nil {
t.Errorf("proxy server failed to read CONNECT request")
return
}
if cr.Method != "CONNECT" {
t.Errorf("unexpected method %q", cr.Method)
return
}
// Keep writing bytes until the test exits.
for {
// runtime.Gosched() is needed here. Otherwise, this test might
// livelock in environments like WASM, where the one single thread
// we have could be hogged by the infinite loop of writing bytes.
runtime.Gosched()
select {
case <-cancelc:
return
default:
c.Write([]byte("infinite stream of bytes"))
}
}
}()
c := &Client{
Transport: &Transport{
Proxy: func(*Request) (*url.URL, error) {
return url.Parse("http://" + ln.Addr().String())
},
// Limit MaxResponseHeaderBytes so the test returns quicker.
MaxResponseHeaderBytes: 1024,
},
}
req, err := NewRequest("GET", "https://golang.fake.tld/", nil)
if err != nil {
t.Fatal(err)
}
_, err = c.Do(req)
if err == nil {
t.Errorf("unexpected Get success")
}
}
func TestOnProxyConnectResponse(t *testing.T) { func TestOnProxyConnectResponse(t *testing.T) {
var tcases = []struct { var tcases = []struct {

View file

@ -25,6 +25,12 @@ import (
// BUG(mikio): On JS and Plan 9, methods and functions related // BUG(mikio): On JS and Plan 9, methods and functions related
// to IPConn are not implemented. // to IPConn are not implemented.
// BUG: On Windows, raw IP sockets are restricted by the operating system.
// Sending TCP data, sending UDP data with invalid source addresses,
// and calling bind with TCP protocol don't work.
//
// See Winsock reference for details.
func ipAddrFromAddr(addr netip.Addr) *IPAddr { func ipAddrFromAddr(addr netip.Addr) *IPAddr {
return &IPAddr{ return &IPAddr{
IP: addr.AsSlice(), IP: addr.AsSlice(),

View file

@ -260,9 +260,6 @@ func addrPortToSockaddrInet6(ap netip.AddrPort) (syscall.SockaddrInet6, error) {
// to an IPv4-mapped IPv6 address. // to an IPv4-mapped IPv6 address.
// The error message is kept consistent with ipToSockaddrInet6. // The error message is kept consistent with ipToSockaddrInet6.
addr := ap.Addr() addr := ap.Addr()
if !addr.IsValid() {
return syscall.SockaddrInet6{}, &AddrError{Err: "non-IPv6 address", Addr: addr.String()}
}
sa := syscall.SockaddrInet6{ sa := syscall.SockaddrInet6{
Addr: addr.As16(), Addr: addr.As16(),
Port: int(ap.Port()), Port: int(ap.Port()),

View file

@ -87,8 +87,8 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int
func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) { func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
order, conf := systemConf().hostLookupOrder(r, name) order, conf := systemConf().hostLookupOrder(r, name)
if order == hostLookupCgo { if order == hostLookupCgo {
if cname, err, ok := cgoLookupCNAME(ctx, name); ok { if cname, err := cgoLookupCNAME(ctx, name); err == nil {
return cname, err return cname, nil
} }
} }
return r.goLookupCNAME(ctx, name, order, conf) return r.goLookupCNAME(ctx, name, order, conf)

View file

@ -1082,11 +1082,19 @@ func (ffd *fakeNetFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int
return n, 0, err return n, 0, err
} }
func (ffd *fakeNetFD) writeMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (n int, oobn int, err error) { func (ffd *fakeNetFD) writeMsgInet4(p []byte, oob []byte, sa4 *syscall.SockaddrInet4) (n int, oobn int, err error) {
var sa syscall.Sockaddr
if sa4 != nil {
sa = sa4
}
return ffd.writeMsg(p, oob, sa) return ffd.writeMsg(p, oob, sa)
} }
func (ffd *fakeNetFD) writeMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (n int, oobn int, err error) { func (ffd *fakeNetFD) writeMsgInet6(p []byte, oob []byte, sa6 *syscall.SockaddrInet6) (n int, oobn int, err error) {
var sa syscall.Sockaddr
if sa6 != nil {
sa = sa6
}
return ffd.writeMsg(p, oob, sa) return ffd.writeMsg(p, oob, sa)
} }

View file

@ -110,11 +110,12 @@ func trim(s []byte) []byte {
for i < len(s) && (s[i] == ' ' || s[i] == '\t') { for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
i++ i++
} }
n := len(s) s = s[i:]
for n > i && (s[n-1] == ' ' || s[n-1] == '\t') { n := len(s) - 1
for n >= 0 && (s[n] == ' ' || s[n] == '\t') {
n-- n--
} }
return s[i:n] return s[:n+1]
} }
// ReadContinuedLineBytes is like [Reader.ReadContinuedLine] but // ReadContinuedLineBytes is like [Reader.ReadContinuedLine] but

View file

@ -186,17 +186,25 @@ func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn
switch c.fd.family { switch c.fd.family {
case syscall.AF_INET: case syscall.AF_INET:
sa, err := addrPortToSockaddrInet4(addr) var sap *syscall.SockaddrInet4
if err != nil { if addr.IsValid() {
return 0, 0, err sa, err := addrPortToSockaddrInet4(addr)
if err != nil {
return 0, 0, err
}
sap = &sa
} }
return c.fd.writeMsgInet4(b, oob, &sa) return c.fd.writeMsgInet4(b, oob, sap)
case syscall.AF_INET6: case syscall.AF_INET6:
sa, err := addrPortToSockaddrInet6(addr) var sap *syscall.SockaddrInet6
if err != nil { if addr.IsValid() {
return 0, 0, err sa, err := addrPortToSockaddrInet6(addr)
if err != nil {
return 0, 0, err
}
sap = &sa
} }
return c.fd.writeMsgInet6(b, oob, &sa) return c.fd.writeMsgInet6(b, oob, sap)
default: default:
return 0, 0, &AddrError{Err: "invalid address family", Addr: addr.Addr().String()} return 0, 0, &AddrError{Err: "invalid address family", Addr: addr.Addr().String()}
} }

View file

@ -141,36 +141,37 @@ func testWriteToConn(t *testing.T, raddr string) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
rap := ra.AddrPort()
assertErrWriteToConnected := func(t *testing.T, err error) {
t.Helper()
if e, ok := err.(*OpError); !ok || e.Err != ErrWriteToConnected {
t.Errorf("got %v; want ErrWriteToConnected", err)
}
}
b := []byte("CONNECTED-MODE SOCKET") b := []byte("CONNECTED-MODE SOCKET")
_, err = c.(*UDPConn).WriteToUDPAddrPort(b, rap)
assertErrWriteToConnected(t, err)
_, err = c.(*UDPConn).WriteToUDP(b, ra) _, err = c.(*UDPConn).WriteToUDP(b, ra)
if err == nil { assertErrWriteToConnected(t, err)
t.Fatal("should fail")
}
if err != nil && err.(*OpError).Err != ErrWriteToConnected {
t.Fatalf("should fail as ErrWriteToConnected: %v", err)
}
_, err = c.(*UDPConn).WriteTo(b, ra) _, err = c.(*UDPConn).WriteTo(b, ra)
if err == nil { assertErrWriteToConnected(t, err)
t.Fatal("should fail")
}
if err != nil && err.(*OpError).Err != ErrWriteToConnected {
t.Fatalf("should fail as ErrWriteToConnected: %v", err)
}
_, err = c.Write(b) _, err = c.Write(b)
if err != nil { if err != nil {
t.Fatal(err) t.Errorf("c.Write(b) = %v; want nil", err)
} }
_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra) _, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
if err == nil { assertErrWriteToConnected(t, err)
t.Fatal("should fail")
}
if err != nil && err.(*OpError).Err != ErrWriteToConnected {
t.Fatalf("should fail as ErrWriteToConnected: %v", err)
}
_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil) _, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Errorf("c.WriteMsgUDP(b, nil, nil) = %v; want nil", err)
}
_, _, err = c.(*UDPConn).WriteMsgUDPAddrPort(b, nil, rap)
assertErrWriteToConnected(t, err)
_, _, err = c.(*UDPConn).WriteMsgUDPAddrPort(b, nil, netip.AddrPort{})
if err != nil {
t.Errorf("c.WriteMsgUDPAddrPort(b, nil, netip.AddrPort{}) = %v; want nil", err)
} }
} }

View file

@ -120,12 +120,12 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
if err != nil { if err != nil {
return nil, &PathError{Op: "open", Path: name, Err: err} return nil, &PathError{Op: "open", Path: name, Err: err}
} }
// syscall.Open always returns a non-blocking handle. nonblocking := flag&windows.O_FILE_FLAG_OVERLAPPED != 0
return newFile(r, name, "file", false), nil return newFile(r, name, "file", nonblocking), nil
} }
func openDirNolog(name string) (*File, error) { func openDirNolog(name string) (*File, error) {
return openFileNolog(name, O_RDONLY, 0) return openFileNolog(name, O_RDONLY|windows.O_DIRECTORY, 0)
} }
func (file *file) close() error { func (file *file) close() error {

Some files were not shown because too many files have changed in this diff Show more