[dev.simd] all: merge master (57362e9) into dev.simd

Conflicts:

- src/cmd/compile/internal/ir/symtab.go
- src/cmd/compile/internal/ssa/prove.go
- src/cmd/compile/internal/ssa/rewriteAMD64.go
- src/cmd/compile/internal/ssagen/intrinsics.go
- src/cmd/compile/internal/typecheck/builtin.go
- src/internal/buildcfg/exp.go
- src/internal/strconv/ftoa.go
- test/codegen/stack.go

Manually resolved some conflicts:

- Use internal/strconv for simd.String, remove internal/ftoa
- prove.go is just copied from the one on the main branch. We
  have cherry-picked the changes to prove.go to main branch, so
  our copy is identical to an old version of the one on the main
  branch. There are CLs landed after our cherry-picks. Just copy
  it over to adopt the new code.

Merge List:

+ 2025-11-13 57362e9814 go/types, types2: check for direct cycles as a separate phase
+ 2025-11-13 099e0027bd cmd/go/internal/modfetch: consolidate global vars
+ 2025-11-13 028375323f cmd/go/internal/modfetch/codehost: fix flaky TestReadZip
+ 2025-11-13 4ebf295b0b runtime: prefer to restart Ps on the same M after STW
+ 2025-11-13 625d8e9b9c runtime/pprof: fix goroutine leak profile tests for noopt
+ 2025-11-13 4684a26c26 spec: remove cycle restriction for type parameters
+ 2025-11-13 0f9c8fb29d cmd/asm,cmd/internal/obj/riscv: add support for riscv compressed instructions
+ 2025-11-13 a15d036ce2 cmd/internal/obj/riscv: implement better bit pattern encoding
+ 2025-11-12 abb241a789 cmd/internal/obj/loong64: add {,X}VS{ADD,SUB}.{B/H/W/V}{,U} instructions support
+ 2025-11-12 0929d21978 cmd/go: keep objects alive while stopping cleanups
+ 2025-11-12 f03d06ec1a runtime: fix list test memory management for mayMoreStack
+ 2025-11-12 48127f656b crypto/internal/fips140/sha3: remove outdated TODO
+ 2025-11-12 c3d1d42764 sync/atomic: amend comments for Value.{Swap,CompareAndSwap}
+ 2025-11-12 e0807ba470 cmd/compile: don't clear ptrmask in fillptrmask
+ 2025-11-12 66318d2b4b internal/abi: correctly describe result in Name.Name doc comment
+ 2025-11-12 34aef89366 cmd/compile: use FCLASSD for subnormal checks on riscv64
+ 2025-11-12 0c28789bd7 net/url: disallow raw IPv6 addresses in host
+ 2025-11-12 4e761b9a18 cmd/compile: optimize liveness in stackalloc
+ 2025-11-12 956909ff84 crypto/x509: move BetterTLS suite from crypto/tls
+ 2025-11-12 6525f46707 cmd/link: change shdr and phdr from arrays to slices
+ 2025-11-12 d3aeba1670 runtime: switch p.gcFractionalMarkTime to atomic.Int64
+ 2025-11-12 8873e8bea2 runtime,runtime/pprof: clean up goroutine leak profile writing
+ 2025-11-12 b8b84b789e cmd/go: clarify the -o testflag is only for copying the binary
+ 2025-11-12 c761b26b56 mime: parse media types that contain braces
+ 2025-11-12 65858a146e os/exec: include Cmd.Start in the list of methods that run Cmd
+ 2025-11-11 4bfc3a9d14 std,cmd: go fix -any std cmd
+ 2025-11-11 2263d4aabd runtime: doubly-linked sched.midle list
+ 2025-11-11 046dce0e54 runtime: use new list type for spanSPMCs
+ 2025-11-11 5f11275457 runtime: reusable intrusive doubly-linked list
+ 2025-11-11 951cf0501b internal/trace/testtrace: fix flag name typos
+ 2025-11-11 2750f95291 cmd/go: implement accurate pseudo-versions for Mercurial
+ 2025-11-11 b709a3e8b4 cmd/go/internal/vcweb: cache hg servers
+ 2025-11-11 426ef30ecf cmd/go: implement -reuse for Mercurial repos
+ 2025-11-10 5241d114f5 spec: more precise prose for special case of append
+ 2025-11-10 cdf64106f6 go/types, types2: first argument to append must never be be nil
+ 2025-11-10 a0eb4548cf .gitignore: ignore go test artifacts
+ 2025-11-10 bf58e7845e internal/trace: add "command" to convert text traces to raw
+ 2025-11-10 052c192a4c runtime: fix lock rank for work.spanSPMCs.lock
+ 2025-11-10 bc5ffe5c79 internal/runtime/sys,math/bits: eliminate bounds checks on len8tab
+ 2025-11-10 32f8d6486f runtime: document that tracefpunwindoff applies to some profilers
+ 2025-11-10 1c1c1942ba cmd/go: remove redundant AVX regex in security flag checks
+ 2025-11-10 3b3d6b9e5d cmd/internal/obj/arm64: shorten constant integer loads
+ 2025-11-10 5f4b5f1a19 runtime/msan: use different msan routine for copying
+ 2025-11-10 0fe6c8e8c8 runtime: tweak wording for comment of mcache.flushGen
+ 2025-11-10 95a0e5adc1 sync: don't call Done when f() panics in WaitGroup.Go
+ 2025-11-08 e8ed85d6c2 cmd/go: update goSum if necessary
+ 2025-11-08 b76103c08e cmd/go: output missing GoDebug entries
+ 2025-11-07 47a63a331d cmd/go: rewrite hgrepo1 test repo to be deterministic
+ 2025-11-07 7995751d3a cmd/go: copy git reuse and support repos to hg
+ 2025-11-07 66c7ca7fb3 cmd/go: improve TestScript/reuse_git
+ 2025-11-07 de84ac55c6 cmd/link: clean up some comments to Go standards
+ 2025-11-07 5cd1b73772 runtime: correctly print panics before fatal-ing on defer
+ 2025-11-07 91ca80f970 runtime/cgo: improve error messages after pointer panic
+ 2025-11-07 d36e88f21f runtime: tweak wording for doc
+ 2025-11-06 ad3ccd92e4 cmd/link: move pclntab out of relro section
+ 2025-11-06 43b91e7abd iter: fix a tiny doc comment bug
+ 2025-11-06 48c7fa13c6 Revert "runtime: remove the pc field of _defer struct"
+ 2025-11-05 8111104a21 cmd/internal/obj/loong64: add {,X}VSHUF.{B/H/W/V} instructions support
+ 2025-11-05 2e2072561c cmd/internal/obj/loong64: add {,X}VEXTRINS.{B,H,W,V} instruction support
+ 2025-11-05 01c29d1f0b internal/chacha8rand: replace VORV with instruction VMOVQ on loong64
+ 2025-11-05 f01a1841fd cmd/compile: fix error message on loong64
+ 2025-11-05 8cf7a0b4c9 cmd/link: support weak binding on darwin
+ 2025-11-05 2dd7e94e16 cmd/go: use go.dev instead of golang.org in flag errors
+ 2025-11-05 28f1ad5782 cmd/go: fix TestScript/govcs
+ 2025-11-05 daa220a1c9 cmd/go: silence TLS handshake errors during test
+ 2025-11-05 3ae9e95002 cmd/go: fix TestCgoPkgConfig on darwin with pkg-config installed
+ 2025-11-05 a494a26bc2 cmd/go: fix TestScript/vet_flags
+ 2025-11-05 a8fb94969c cmd/go: fix TestScript/tool_build_as_needed
+ 2025-11-05 04f05219c4 cmd/cgo: skip escape checks if call site has no argument
+ 2025-11-04 9f3a108ee0 os: ignore O_TRUNC errors on named pipes and terminal devices on Windows
+ 2025-11-04 0e1bd8b5f1 cmd/link, runtime: don't store text start in pcHeader
+ 2025-11-04 7347b54727 cmd/link: don't generate .gosymtab section
+ 2025-11-04 6914dd11c0 cmd/link: add and use new SymKind SFirstUnallocated
+ 2025-11-04 f5f14262d0 cmd/link: remove misleading comment
+ 2025-11-04 61de3a9dae cmd/link: remove unused SFILEPATH symbol kind
+ 2025-11-04 8e2bd267b5 cmd/link: add comments for SymKind values
+ 2025-11-04 16705b962e cmd/compile: faster liveness analysis in regalloc
+ 2025-11-04 a5fe6791d7 internal/syscall/windows: fix ReOpenFile sentinel error value
+ 2025-11-04 a7d174ccaa cmd/compile/internal/ssa: simplify riscv64 FCLASSD rewrite rules
+ 2025-11-04 856238615d runtime: amend doc for setPinned
+ 2025-11-04 c7ccbddf22 cmd/compile/internal/ssa: more aggressive on dead auto elim
+ 2025-11-04 75b2bb1d1a cmd/cgo: drop pre-1.18 support
+ 2025-11-04 dd839f1d00 internal/strconv: handle %f with fixedFtoa when possible
+ 2025-11-04 6e165b4d17 cmd/compile: implement Avg64u, Hmul64, Hmul64u for wasm
+ 2025-11-04 9f6590f333 encoding/pem: don't reslice in failure modes
+ 2025-11-03 34fec512ce internal/strconv: extract fixed-precision ftoa from ftoaryu.go
+ 2025-11-03 162ba6cc40 internal/strconv: add tests and benchmarks for ftoaFixed
+ 2025-11-03 9795c7ba22 internal/strconv: fix pow10 off-by-one in exponent result
+ 2025-11-03 ad5e941a45 cmd/internal/obj/loong64: using {xv,v}slli.d to perform copying between vector registers
+ 2025-11-03 dadbac0c9e cmd/internal/obj/loong64: add VPERMI.W, XVPERMI.{W,V,Q} instruction support
+ 2025-11-03 e2c6a2024c runtime: avoid append in printint, printuint
+ 2025-11-03 c93cc603cd runtime: allow Stack to traceback goroutines in syscall _Grunning window
+ 2025-11-03 b5353fd90a runtime: don't panic in castogscanstatus
+ 2025-11-03 43491f8d52 cmd/cgo: use the export'ed file/line in error messages
+ 2025-11-03 aa94fdf0cc cmd/go: link to go.dev/doc/godebug for removed GODEBUG settings
+ 2025-11-03 4d2b03d2fc crypto/tls: add BetterTLS test coverage
+ 2025-11-03 0c4444e13d cmd/internal/obj: support arm64 FMOVQ large offset encoding
+ 2025-11-03 85bec791a0 cmd/go/testdata/script: loosen list_empty_importpath for freebsd
+ 2025-11-03 17b57078ab internal/runtime/cgobench: add cgo callback benchmark
+ 2025-11-03 5f8fdb720c cmd/go: move functions to methods
+ 2025-11-03 0a95856b95 cmd/go: eliminate additional global variable
+ 2025-11-03 f93186fb44 cmd/go/internal/telemetrystats: count cgo usage
+ 2025-11-03 eaf28a27fd runtime: update outdated comments for deferprocStack
+ 2025-11-03 e12d8a90bf all: remove extra space in the comments
+ 2025-11-03 c5559344ac internal/profile: optimize Parse allocs
+ 2025-11-03 5132158ac2 bytes: add Buffer.Peek
+ 2025-11-03 361d51a6b5 runtime: remove the pc field of _defer struct
+ 2025-11-03 00ee1860ce crypto/internal/constanttime: expose intrinsics to the FIPS 140-3 packages
+ 2025-11-02 388c41c412 cmd/go: skip git sha256 tests if git < 2.29
+ 2025-11-01 385dc33250 runtime: prevent time.Timer.Reset(0) from deadlocking testing/synctest tests
+ 2025-10-31 99b724f454 cmd/go: document purego convention
+ 2025-10-31 27937289dc runtime: avoid zeroing scavenged memory
+ 2025-10-30 89dee70484 runtime: prioritize panic output over racefini
+ 2025-10-30 8683bb846d runtime: optimistically CAS atomicstatus directly in enter/exitsyscall
+ 2025-10-30 5b8e850340 runtime: don't track scheduling latency for _Grunning <-> _Gsyscall
+ 2025-10-30 251814e580 runtime: document tracer invariants explicitly
+ 2025-10-30 7244e9221f runtime: eliminate _Psyscall
+ 2025-10-30 5ef19c0d0c strconv: delete divmod1e9
+ 2025-10-30 d32b1f02c3 runtime: delete timediv
+ 2025-10-30 cbbd385cb8 strconv: remove arch-specific decision in formatBase10
+ 2025-10-30 6aca04a73a reflect: correct internal docs for uncommonType
+ 2025-10-30 235b4e729d cmd/compile/internal/ssa: model right shift more precisely
+ 2025-10-30 d44db293f9 go/token: fix a typo in a comment
+ 2025-10-30 cdc6b559ca strconv: remove hand-written divide on 32-bit systems
+ 2025-10-30 1e5bb416d8 cmd/compile: implement bits.Mul64 on 32-bit systems
+ 2025-10-30 38317c44e7 crypto/internal/fips140/aes: fix CTR generator
+ 2025-10-29 3be9a0e014 go/types, types: proceed with correct (invalid) type in case of a selector error
+ 2025-10-29 d2c5fa0814 strconv: remove &0xFF trick in formatBase10
+ 2025-10-29 9bbda7c99d cmd/compile: make prove understand div, mod better
+ 2025-10-29 915c1839fe test/codegen: simplify asmcheck pattern matching
+ 2025-10-29 32ee3f3f73 runtime: tweak example code for gorecover
+ 2025-10-29 da3fb90b23 crypto/internal/fips140/bigmod: fix extendedGCD comment
+ 2025-10-29 9035f7aea5 runtime: use internal/strconv
+ 2025-10-29 49c1da474d internal/itoa, internal/runtime/strconv: delete
+ 2025-10-29 b2a346bbd1 strconv: move all but Quote to internal/strconv
+ 2025-10-28 041f564b3e internal/runtime/gc/scan: avoid memory destination on VPCOMPRESSQ
+ 2025-10-28 81afd3a59b cmd/compile: extend ppc64 MADDLD to match const ADDconst & MULLDconst
+ 2025-10-28 ea50d61b66 cmd/compile: name change isDirect -> isDirectAndComparable
+ 2025-10-28 bd4dc413cd cmd/compile: don't optimize away a panicing interface comparison
+ 2025-10-28 30c047d0d0 cmd/compile: extend loong MOV*idx rules to match ADDshiftLLV
+ 2025-10-28 46e5e2b09a runtime: define PanicBounds in funcdata.h
+ 2025-10-28 3da0356685 crypto/internal/fips140test: collect 300M entropy samples for ESV
+ 2025-10-28 d5953185d5 runtime: amend comments a bit
+ 2025-10-28 12c8d14d94 errors: document that the target of Is must be comparable
+ 2025-10-28 1f4d14e493 go/types, types2: pull up package-level object sort to a separate phase
+ 2025-10-28 b8aa1ee442 go/types, types2: reduce locks held at once in resolveUnderlying
+ 2025-10-28 24af441437 cmd/compile: rewrite proved multiplies by 0 or 1 into CondSelect
+ 2025-10-28 2d33a456c6 cmd/compile: move branchelim supported arches to Config
+ 2025-10-27 2c91c33e88 crypto/subtle,cmd/compile: add intrinsics for ConstantTimeSelect and *Eq
+ 2025-10-27 73d7635fae cmd/compile: add generic rules to remove bool → int → bool roundtrips
+ 2025-10-27 1662d55247 cmd/compile: do not Zext bools to 64bits in amd64 CMOV generation rules
+ 2025-10-27 b8468d8c4e cmd/compile: introduce bytesizeToConst to cleanup switches in prove
+ 2025-10-27 9e25c2f6de cmd/link: internal linking support for windows/arm64
+ 2025-10-27 ff2ebf69c4 internal/runtime/gc/scan: correct size class size check
+ 2025-10-27 9a77aa4f08 cmd/compile: add position info to sccp debug messages
+ 2025-10-27 77dc138030 cmd/compile: teach prove about unsigned rounding-up divide
+ 2025-10-27 a0f33b2887 cmd/compile: change !l.nonzero() into l.maybezero()
+ 2025-10-27 5453b788fd cmd/compile: optimize Add64carry with unused carries into plain Add64
+ 2025-10-27 2ce5aab79e cmd/compile: remove 68857 ModU flowLimit workaround in prove
+ 2025-10-27 a50de4bda7 cmd/compile: remove 68857 min & max flowLimit workaround in prove
+ 2025-10-27 53be78630a cmd/compile: use topo-sort in prove to correctly learn facts while walking once
+ 2025-10-27 dec2b4c83d runtime: avoid bound check in freebsd binuptime
+ 2025-10-27 916e682d51 cmd/internal/obj, cmd/asm: reclassify the offset of memory access operations on loong64
+ 2025-10-27 2835b994fb cmd/go: remove global loader state variable
+ 2025-10-27 139f89226f cmd/go: use local state for telemetry
+ 2025-10-27 8239156571 cmd/go: use tagged switch
+ 2025-10-27 d741483a1f cmd/go: increase stmt threshold on amd64
+ 2025-10-27 a6929cf4a7 cmd/go: removed unused code in toolchain.Exec
+ 2025-10-27 180c07e2c1 go/types, types2: clarify docs for resolveUnderlying
+ 2025-10-27 d8a32f3d4b go/types, types2: wrap Named.fromRHS into Named.rhs
+ 2025-10-27 b2af92270f go/types, types2: verify stateMask transitions in debug mode
+ 2025-10-27 92decdcbaa net/url: further speed up escape and unescape
+ 2025-10-27 5f4ec3541f runtime: remove unused cgoCheckUsingType function
+ 2025-10-27 189f2c08cc time: rewrite IsZero method to use wall and ext fields
+ 2025-10-27 f619b4a00d cmd/go: reorder parameters so that context is first
+ 2025-10-27 f527994c61 sync: update comments for Once.done
+ 2025-10-26 5dcaf9a01b runtime: add GOEXPERIMENT=runtimefree
+ 2025-10-26 d7a52f9369 cmd/compile: use MOV(D|F) with const for Const(64|32)F on riscv64
+ 2025-10-26 6f04a92be3 internal/chacha8rand: provide vector implementation for riscv64
+ 2025-10-26 54e3adc533 cmd/go: use local loader state in test
+ 2025-10-26 ca379b1c56 cmd/go: remove loaderstate dependency
+ 2025-10-26 83a44bde64 cmd/go: remove unused loader state
+ 2025-10-26 7e7cd9de68 cmd/go: remove temporary rf cleanup script
+ 2025-10-26 53ad68de4b cmd/compile: allow unaligned load/store on Wasm
+ 2025-10-25 12ec09f434 cmd/go: use local state object in work.runBuild and work.runInstall
+ 2025-10-24 643f80a11f runtime: add ppc and s390 to 32 build constraints for gccgo
+ 2025-10-24 0afbeb5102 runtime: add ppc and s390 to linux 32 bits syscall build constraints for gccgo
+ 2025-10-24 7b506d106f cmd/go: use local state object in `generate.runGenerate`
+ 2025-10-24 26a8a21d7f cmd/go: use local state object in `env.runEnv`
+ 2025-10-24 f2dd3d7e31 cmd/go: use local state object in `vet.runVet`
+ 2025-10-24 784700439a cmd/go: use local state object in pkg `workcmd`
+ 2025-10-24 69673e9be2 cmd/go: use local state object in `tool.runTool`
+ 2025-10-24 2e12c5db11 cmd/go: use local state object in `test.runTest`
+ 2025-10-24 fe345ff2ae cmd/go: use local state object in `modget.runGet`
+ 2025-10-24 d312e27e8b cmd/go: use local state object in pkg `modcmd`
+ 2025-10-24 ea9cf26aa1 cmd/go: use local state object in `list.runList`
+ 2025-10-24 9926e1124e cmd/go: use local state object in `bug.runBug`
+ 2025-10-24 2c4fd7b2cd cmd/go: use local state object in `run.runRun`
+ 2025-10-24 ade9f33e1f cmd/go: add loaderstate as field on `mvsReqs`
+ 2025-10-24 ccf4192a31 cmd/go: make ImportMissingError work with local state
+ 2025-10-24 f5403f15f0 debug/pe: check for zdebug_gdb_scripts section in testDWARF
+ 2025-10-24 a26f860fa4 runtime: use 32-bit hash for maps on Wasm
+ 2025-10-24 747fe2efed encoding/json/v2: fix typo in documentation about errors.AsType
+ 2025-10-24 94f47fc03f cmd/link: remove pointless assignment in SetSymAlign
+ 2025-10-24 e6cff69051 crypto/x509: move constraint checking after chain building
+ 2025-10-24 f5f69a3de9 encoding/json/jsontext: avoid pinning application data in pools
+ 2025-10-24 a6a59f0762 encoding/json/v2: use slices.Sort directly
+ 2025-10-24 0d3dab9b1d crypto/x509: simplify candidate chain filtering
+ 2025-10-24 29046398bb cmd/go: refactor injection of modload.LoaderState
+ 2025-10-24 c18fa69e52 cmd/go: make ErrNoModRoot work with local state
+ 2025-10-24 296ecc918d cmd/go: add modload.State parameter to AllowedFunc
+ 2025-10-24 c445a61e52 cmd/go: add loaderstate as field on `QueryMatchesMainModulesError`
+ 2025-10-24 6ac40051d3 cmd/go: remove module loader state from ccompile
+ 2025-10-24 6a5a452528 cmd/go: inject vendor dir into builder struct
+ 2025-10-23 dfac972233 crypto/pbkdf2: add missing error return value in example
+ 2025-10-23 47bf8f073e unique: fix inconsistent panic prefix in canonmap cleanup path
+ 2025-10-23 03bd43e8bb go/types, types2: rename Named.resolve to unpack
+ 2025-10-23 9fcdc814b2 go/types, types2: rename loaded namedState to lazyLoaded
+ 2025-10-23 8401512a9b go/types, types2: rename complete namedState to hasMethods
+ 2025-10-23 cf826bfcb4 go/types, types2: set t.underlying exactly once in resolveUnderlying
+ 2025-10-23 c4e910895b net/url: speed up escape and unescape
+ 2025-10-23 3f6ac3a10f go/build: use slices.Equal
+ 2025-10-23 839da71f89 encoding/pem: properly calculate end indexes
+ 2025-10-23 39ed968832 cmd: update golang.org/x/arch for riscv64 disassembler
+ 2025-10-23 ca448191c9 all: replace Split in loops with more efficient SplitSeq
+ 2025-10-23 107fcb70de internal/goroot: replace HasPrefix+TrimPrefix with CutPrefix
+ 2025-10-23 8378276d66 strconv: optimize int-to-decimal and use consistently
+ 2025-10-23 e5688d0bdd cmd/internal/obj/riscv: simplify validation and encoding of raw instructions
+ 2025-10-22 77fc27972a doc/next: improve new(expr) release note
+ 2025-10-22 d94a8c56ad runtime: cleanup pagetrace
+ 2025-10-22 02728a2846 crypto/internal/fips140test: add entropy SHA2-384 testing
+ 2025-10-22 f92e01c117 runtime/cgo: fix cgoCheckArg description
+ 2025-10-22 50586182ab runtime: use backoff and ISB instruction to reduce contention in (*lfstack).pop and (*spanSet).pop on arm64
+ 2025-10-22 1ff59f3dd3 strconv: clean up powers-of-10 table, tests
+ 2025-10-22 7c9fa4d5e9 cmd/go: check if build output should overwrite files with renames
+ 2025-10-22 557b4d6e0f comment: change slice to string in function comment/help
+ 2025-10-22 d09a8c8ef4 go/types, types2: simplify locking in Named.resolveUnderlying
+ 2025-10-22 5a42af7f6c go/types, types2: in resolveUnderlying, only compute path when needed
+ 2025-10-22 4bdb55b5b8 go/types, types2: rename Named.under to Named.resolveUnderlying
+ 2025-10-21 29d43df8ab go/build, cmd/go: use ast.ParseDirective for go:embed
+ 2025-10-21 4e695dd634 go/ast: add ParseDirective for parsing directive comments
+ 2025-10-21 06e57e60a7 go/types, types2: only report version errors if new(expr) is ok otherwise
+ 2025-10-21 6c3d0d259f path/filepath: reword documentation for Rel
+ 2025-10-21 39fd61ddb0 go/types, types2: guard Named.underlying with Named.mu
+ 2025-10-21 4a0115c886 runtime,syscall: implement and use syscalln on darwin
+ 2025-10-21 261c561f5a all: gofmt -w
+ 2025-10-21 c9c78c06ef strconv: embed testdata in test
+ 2025-10-21 8f74f9daf4 sync: re-enable race even when panicking
+ 2025-10-21 8a6c64f4fe syscall: use rawSyscall6 to call ptrace in forkAndExecInChild
+ 2025-10-21 4620db72d2 runtime: use timer_settime64 on 32-bit Linux
+ 2025-10-21 b31dc77cea os: support deleting read-only files in RemoveAll on older Windows versions
+ 2025-10-21 46cc532900 cmd/compile/internal/ssa: fix typo in comment
+ 2025-10-21 2163a58021 crypto/internal/fips140/entropy: increase AllocsPerRun iterations
+ 2025-10-21 306eacbc11 cmd/go/testdata/script: disable list_empty_importpath test on Windows
+ 2025-10-21 a5a249d6a6 all: eliminate unnecessary type conversions
+ 2025-10-21 694182d77b cmd/internal/obj/ppc64: improve large prologue generation
+ 2025-10-21 b0dcb95542 cmd/compile: leave the horses alone
+ 2025-10-21 9a5a1202f4 runtime: clean dead architectures from go:build constraint
+ 2025-10-21 8539691d0c crypto/internal/fips140/entropy: move to crypto/internal/entropy/v1.0.0
+ 2025-10-20 99cf4d671c runtime: save lasx and lsx registers in loong64 async preemption
+ 2025-10-20 79ae97fe9b runtime: make procyieldAsm no longer loop infinitely if passed 0
+ 2025-10-20 f838faffe2 runtime: wrap procyield assembly and check for 0
+ 2025-10-20 ee4d2c312d runtime/trace: dump test traces on validation failure
+ 2025-10-20 7b81a1e107 net/url: reduce allocs in Encode
+ 2025-10-20 e425176843 cmd/asm: fix typo in comment
+ 2025-10-20 dc9a3e2a65 runtime: fix generation skew with trace reentrancy
+ 2025-10-20 df33c17091 runtime: add _Gdeadextra status
+ 2025-10-20 7503856d40 cmd/go: inject loaderstate into matcher function
+ 2025-10-20 d57c3fd743 cmd/go: inject State parameter into `work.runInstall`
+ 2025-10-20 e94a5008f6 cmd/go: inject State parameter into `work.runBuild`
+ 2025-10-20 d9e6f95450 cmd/go: inject State parameter into `workcmd.runSync`
+ 2025-10-20 9769a61e64 cmd/go: inject State parameter into `modget.runGet`
+ 2025-10-20 f859799ccf cmd/go: inject State parameter into `modcmd.runVerify`
+ 2025-10-20 0f820aca29 cmd/go: inject State parameter into `modcmd.runVendor`
+ 2025-10-20 92aa3e9e98 cmd/go: inject State parameter into `modcmd.runInit`
+ 2025-10-20 e176dff41c cmd/go: inject State parameter into `modcmd.runDownload`
+ 2025-10-20 e7c66a58d5 cmd/go: inject State parameter into `toolchain.Select`
+ 2025-10-20 4dc3dd9a86 cmd/go: add loaderstate to Switcher
+ 2025-10-20 bcf7da1595 cmd/go: convert functions to methods
+ 2025-10-20 0d3044f965 cmd/go: make Reset work with any State instance
+ 2025-10-20 386d81151d cmd/go: make setState work with any State instance
+ 2025-10-20 a420aa221e cmd/go: inject State parameter into `tool.runTool`
+ 2025-10-20 441e7194a4 cmd/go: inject State parameter into `test.runTest`
+ 2025-10-20 35e8309be2 cmd/go: inject State parameter into `list.runList`
+ 2025-10-20 29a81624f7 cmd/go: inject state parameter into `fmtcmd.runFmt`
+ 2025-10-20 f7eaea02fd cmd/go: inject state parameter into `clean.runClean`
+ 2025-10-20 58a8fdb6cf cmd/go: inject State parameter into `bug.runBug`
+ 2025-10-20 8d0bef7ffe runtime: add linkname documentation and guidance
+ 2025-10-20 3e43f48cb6 encoding/asn1: use reflect.TypeAssert to improve performance
+ 2025-10-20 4ad5585c2c runtime: fix _rt0_ppc64x_lib on aix
+ 2025-10-17 a5f55a441e cmd/fix: add modernize and inline analyzers
+ 2025-10-17 80876f4b42 cmd/go/internal/vet: tweak help doc
+ 2025-10-17 b5aefe07e5 all: remove unnecessary loop variable copies in tests
+ 2025-10-17 5137c473b6 go/types, types2: remove references to under function in comments
+ 2025-10-17 dbbb1bfc91 all: correct name for comments
+ 2025-10-17 0983090171 encoding/pem: properly decode strange PEM data
+ 2025-10-17 36863d6194 runtime: unify riscv64 library entry point
+ 2025-10-16 0c14000f87 go/types, types2: remove under(Type) in favor of Type.Underlying()
+ 2025-10-16 1099436f1b go/types, types2: change and enforce lifecycle of Named.fromRHS and Named.underlying fields
+ 2025-10-16 41f5659347 go/types, types2: remove superfluous unalias call (minor cleanup)
+ 2025-10-16 e7351c03c8 runtime: use DC ZVA instead of its encoding in WORD in arm64 memclr
+ 2025-10-16 6cbe0920c4 cmd: update to x/tools@7d9453cc
+ 2025-10-15 45eee553e2 cmd/internal/obj: move ARM64RegisterExtension from cmd/asm/internal/arch
+ 2025-10-15 27f9a6705c runtime: increase repeat count for alloc test
+ 2025-10-15 b68cebd809 net/http/httptest: record failed ResponseWriter writes
+ 2025-10-15 f1fed742eb cmd: fix three printf problems reported by newest vet
+ 2025-10-15 0984dcd757 cmd/compile: fix an error in comments
+ 2025-10-15 31f82877e8 go/types, types2: fix misleading internal comment
+ 2025-10-15 6346349f56 cmd/compile: replace angle brackets with square
+ 2025-10-15 284379cdfc cmd/compile: remove rematerializable values from live set across calls
+ 2025-10-15 519ae514ab cmd/compile: eliminate bound check for slices of the same length
+ 2025-10-15 b5a29cca48 cmd/distpack: add fix tool to inventory
+ 2025-10-15 bb5eb51715 runtime/pprof: fix errors in pprof_test
+ 2025-10-15 5c9a26c7f8 cmd/compile: use arm64 neon in LoweredMemmove/LoweredMemmoveLoop
+ 2025-10-15 61d1ff61ad cmd/compile: use block starting position for phi line number
+ 2025-10-15 5b29875c8e cmd/go: inject State parameter into `run.runRun`
+ 2025-10-15 5113496805 runtime/pprof: skip flaky test TestProfilerStackDepth/heap for now
+ 2025-10-15 36086e85f8 cmd/go: create temporary cleanup script
+ 2025-10-14 7056c71d32 cmd/compile: disable use of new saturating float-to-int conversions
+ 2025-10-14 6d5b13793f Revert "cmd/compile: make 386 float-to-int conversions match amd64"
+ 2025-10-14 bb2a14252b Revert "runtime: adjust softfloat corner cases to match amd64/arm64"
+ 2025-10-14 3bc9d9fa83 Revert "cmd/compile: make wasm match other platforms for FP->int32/64 conversions"
+ 2025-10-14 ee5af46172 encoding/json: avoid misleading errors under goexperiment.jsonv2
+ 2025-10-14 11d3d2f77d cmd/internal/obj/arm64: add support for PAC instructions
+ 2025-10-14 4dbf1a5a4c cmd/compile/internal/devirtualize: do not track assignments to non-PAUTO
+ 2025-10-14 0ddb5ed465 cmd/compile/internal/devirtualize: use FatalfAt instead of Fatalf where possible
+ 2025-10-14 0a239bcc99 Revert "net/url: disallow raw IPv6 addresses in host"
+ 2025-10-14 5a9ef44bc0 cmd/compile/internal/devirtualize: fix OCONVNOP assertion
+ 2025-10-14 3765758b96 go/types, types2: minor cleanup (remove TODO)
+ 2025-10-14 f6b9d56aff crypto/internal/fips140/entropy: fix benign race
+ 2025-10-14 60f6d2f623 crypto/internal/fips140/entropy: support SHA-384 sizes for ACVP tests
+ 2025-10-13 6fd8e88d07 encoding/json/v2: restrict presence of default options
+ 2025-10-13 1abc6b0204 go/types, types2: permit type cycles through type parameter lists
+ 2025-10-13 9fdd6904da strconv: add tests that Java once mishandled
+ 2025-10-13 9b8742f2e7 cmd/compile: don't depend on arch-dependent conversions in the compiler
+ 2025-10-13 0e64ee1286 encoding/json/v2: report EOF for top-level values in UnmarshalDecode
+ 2025-10-13 6bcd97d9f4 all: replace calls to errors.As with errors.AsType
+ 2025-10-11 1cd71689f2 crypto/x509: rework fix for CVE-2025-58187
+ 2025-10-11 8aa1efa223 cmd/link: in TestFallocate, only check number of blocks on Darwin
+ 2025-10-10 b497a29d25 encoding/json: fix regression in quoted numbers under goexperiment.jsonv2
+ 2025-10-10 48bb7a6114 cmd/compile: repair bisection behavior for float-to-unsigned conversion
+ 2025-10-10 e8a53538b4 runtime: fail TestGoroutineLeakProfile on data race
+ 2025-10-10 e3be2d1b2b net/url: disallow raw IPv6 addresses in host
+ 2025-10-10 aced4c79a2 net/http: strip request body headers on POST to GET redirects
+ 2025-10-10 584a89fe74 all: omit unnecessary reassignment
+ 2025-10-10 69e8279632 net/http: set cookie host to Request.Host when available
+ 2025-10-10 6f4c63ba63 cmd/go: unify "go fix" and "go vet"
+ 2025-10-10 955a5a0dc5 runtime: support arm64 Neon in async preemption
+ 2025-10-10 5368e77429 net/http: run TestRequestWriteTransport with fake time to avoid flakes
+ 2025-10-09 c53cb642de internal/buildcfg: enable greenteagc experiment for loong64
+ 2025-10-09 954fdcc51a cmd/compile: declare no output register for loong64 LoweredAtomic{And,Or}32 ops
+ 2025-10-09 19a30ea3f2 cmd/compile: call generated size-specialized malloc functions directly
+ 2025-10-09 80f3bb5516 reflect: remove timeout in TestChanOfGC
+ 2025-10-09 9db7e30bb4 net/url: allow IP-literals with IPv4-mapped IPv6 addresses
+ 2025-10-09 8d810286b3 cmd/compile: make wasm match other platforms for FP->int32/64 conversions
+ 2025-10-09 b9f3accdcf runtime: adjust softfloat corner cases to match amd64/arm64
+ 2025-10-09 78d75b3799 cmd/compile: make 386 float-to-int conversions match amd64
+ 2025-10-09 0e466a8d1d cmd/compile: modify float-to-[u]int so that amd64 and arm64 match
+ 2025-10-08 4837fbe414 net/http/httptest: check whether response bodies are allowed
+ 2025-10-08 ee163197a8 path/filepath: return cleaned path from Rel
+ 2025-10-08 de9da0de30 cmd/compile/internal/devirtualize: improve concrete type analysis
+ 2025-10-08 ae094a1397 crypto/internal/fips140test: make entropy file pair names match
+ 2025-10-08 941e5917c1 runtime: cleanup comments from asm_ppc64x.s improvements
+ 2025-10-08 d945600d06 cmd/gofmt: change -d to exit 1 if diffs exist
+ 2025-10-08 d4830c6130 cmd/internal/obj: fix Link.Diag printf errors
+ 2025-10-08 e1ca1de123 net/http: format pprof.go
+ 2025-10-08 e5d004c7a8 net/http: update HTTP/2 documentation to reference new config features
+ 2025-10-08 97fd6bdecc cmd/compile: fuse NaN checks with other comparisons
+ 2025-10-07 78b43037dc cmd/go: refactor usage of `workFilePath`
+ 2025-10-07 bb1ca7ae81 cmd/go, testing: add TB.ArtifactDir and -artifacts flag
+ 2025-10-07 1623927730 cmd/go: refactor usage of `requirements`
+ 2025-10-07 a1661e776f Revert "crypto/internal/fips140/subtle: add assembly implementation of xorBytes for mips64x"
+ 2025-10-07 cb81270113 Revert "crypto/internal/fips140/subtle: add assembly implementation of xorBytes for mipsx"
+ 2025-10-07 f2d0d05d28 cmd/go: refactor usage of `MainModules`
+ 2025-10-07 f7a68d3804 archive/tar: set a limit on the size of GNU sparse file 1.0 regions
+ 2025-10-07 463165699d net/mail: avoid quadratic behavior in mail address parsing
+ 2025-10-07 5ede095649 net/textproto: avoid quadratic complexity in Reader.ReadResponse
+ 2025-10-07 5ce8cd16f3 encoding/pem: make Decode complexity linear
+ 2025-10-07 f6f4e8b3ef net/url: enforce stricter parsing of bracketed IPv6 hostnames
+ 2025-10-07 7dd54e1fd7 runtime: make work.spanSPMCs.all doubly-linked
+ 2025-10-07 3ee761739b runtime: free spanQueue on P destroy
+ 2025-10-07 8709a41d5e encoding/asn1: prevent memory exhaustion when parsing using internal/saferio
+ 2025-10-07 9b9d02c5a0 net/http: add httpcookiemaxnum GODEBUG option to limit number of cookies parsed
+ 2025-10-07 3fc4c79fdb crypto/x509: improve domain name verification
+ 2025-10-07 6e4007e8cf crypto/x509: mitigate DoS vector when intermediate certificate contains DSA public key
+ 2025-10-07 6f7926589d cmd/go: refactor usage of `modRoots`
+ 2025-10-07 11d5484190 runtime: fix self-deadlock on sbrk platforms
+ 2025-10-07 2e52060084 cmd/go: refactor usage of `RootMode`
+ 2025-10-07 f86ddb54b5 cmd/go: refactor usage of `ForceUseModules`
+ 2025-10-07 c938051dd0 Revert "cmd/compile: redo arm64 LR/FP save and restore"
+ 2025-10-07 6469954203 runtime: assert p.destroy runs with GC not running
+ 2025-10-06 4c0fd3a2b4 internal/goexperiment: remove the synctest GOEXPERIMENT
+ 2025-10-06 c1e6e49d5d fmt: reduce Errorf("x") allocations to match errors.New("x")
+ 2025-10-06 7fbf54bfeb internal/buildcfg: enable greenteagc experiment by default
+ 2025-10-06 7bfeb43509 cmd/go: refactor usage of `initialized`
+ 2025-10-06 1d62e92567 test/codegen: make sure assignment results are used.
+ 2025-10-06 4fca79833f runtime: delete redundant code in the page allocator
+ 2025-10-06 719dfcf8a8 cmd/compile: redo arm64 LR/FP save and restore
+ 2025-10-06 f3312124c2 runtime: remove batching from spanSPMC free
+ 2025-10-06 24416458c2 cmd/go: export type State
+ 2025-10-06 c2fb15164b testing/synctest: remove Run
+ 2025-10-06 ac2ec82172 runtime: bump thread count slack for TestReadMetricsSched
+ 2025-10-06 e74b224b7c crypto/tls: streamline BoGo testing w/ -bogo-local-dir
+ 2025-10-06 3a05e7b032 spec: close tag
+ 2025-10-03 2a71af11fc net/url: improve URL docs
+ 2025-10-03 ee5369b003 cmd/link: add LIBRARY statement only with -buildmode=cshared
+ 2025-10-03 1bca4c1673 cmd/compile: improve slicemask removal
+ 2025-10-03 38b26f29f1 cmd/compile: remove stores to unread parameters
+ 2025-10-03 003b5ce1bc cmd/compile: fix SIMD const rematerialization condition
+ 2025-10-03 d91148c7a8 cmd/compile: enhance prove to infer bounds in slice len/cap calculations
+ 2025-10-03 20c9377e47 cmd/compile: enhance the chunked indexing case to include reslicing
+ 2025-10-03 ad3db2562e cmd/compile: handle rematerialized op for incompatible reg constraint
+ 2025-10-03 18cd4a1fc7 cmd/compile: use the right type for spill slot
+ 2025-10-03 1caa95acfa cmd/compile: enhance prove to deal with double-offset IsInBounds checks
+ 2025-10-03 ec70d19023 cmd/compile: rewrite to elide Slicemask from len==c>0 slicing
+ 2025-10-03 10e7968849 cmd/compile: accounts rematerialize ops's output reginfo
+ 2025-10-03 ab043953cb cmd/compile: minor tweak for race detector
+ 2025-10-03 ebb72bef44 cmd/compile: don't treat devel compiler as a released compiler
+ 2025-10-03 c54dc1418b runtime: support valgrind (but not asan) in specialized malloc functions
+ 2025-10-03 a7917eed70 internal/buildcfg: enable specializedmalloc experiment
+ 2025-10-03 630799c6c9 crypto/tls: add flag to render HTML BoGo report

Change-Id: I6bf904c523a77ee7d3dea9c8ae72292f8a5f2ba5
This commit is contained in:
Cherry Mui 2025-11-13 16:43:45 -05:00
commit d7a0c45642
1155 changed files with 57745 additions and 19718 deletions

1
.gitignore vendored
View file

@ -30,6 +30,7 @@ _testmain.go
/misc/cgo/testso/main
/pkg/
/src/*.*/
/src/_artifacts/
/src/cmd/cgo/zdefaultcc.go
/src/cmd/dist/dist
/src/cmd/go/internal/cfg/zdefaultcc.go

13
api/next/68021.txt Normal file
View file

@ -0,0 +1,13 @@
pkg go/ast, func ParseDirective(token.Pos, string) (Directive, bool) #68021
pkg go/ast, method (*Directive) End() token.Pos #68021
pkg go/ast, method (*Directive) ParseArgs() ([]DirectiveArg, error) #68021
pkg go/ast, method (*Directive) Pos() token.Pos #68021
pkg go/ast, type Directive struct #68021
pkg go/ast, type Directive struct, Args string #68021
pkg go/ast, type Directive struct, ArgsPos token.Pos #68021
pkg go/ast, type Directive struct, Name string #68021
pkg go/ast, type Directive struct, Slash token.Pos #68021
pkg go/ast, type Directive struct, Tool string #68021
pkg go/ast, type DirectiveArg struct #68021
pkg go/ast, type DirectiveArg struct, Arg string #68021
pkg go/ast, type DirectiveArg struct, Pos token.Pos #68021

4
api/next/71287.txt Normal file
View file

@ -0,0 +1,4 @@
pkg testing, method (*B) ArtifactDir() string #71287
pkg testing, method (*F) ArtifactDir() string #71287
pkg testing, method (*T) ArtifactDir() string #71287
pkg testing, type TB interface, ArtifactDir() string #71287

1
api/next/73794.txt Normal file
View file

@ -0,0 +1 @@
pkg bytes, method (*Buffer) Peek(int) ([]uint8, error) #73794

View file

@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
"Subtitle": "Language version go1.26 (Oct 1, 2025)",
"Subtitle": "Language version go1.26 (Nov 12, 2025)",
"Path": "/ref/spec"
}-->
@ -2686,22 +2686,6 @@ of a <a href="#Method_declarations">method declaration</a> associated
with a generic type.
</p>
<p>
Within a type parameter list of a generic type <code>T</code>, a type constraint
may not (directly, or indirectly through the type parameter list of another
generic type) refer to <code>T</code>.
</p>
<pre>
type T1[P T1[P]] … // illegal: T1 refers to itself
type T2[P interface{ T2[int] }] … // illegal: T2 refers to itself
type T3[P interface{ m(T3[int])}] … // illegal: T3 refers to itself
type T4[P T5[P]] … // illegal: T4 refers to T5 and
type T5[P T4[P]] … // T5 refers to T4
type T6[P int] struct{ f *T6[P] } // ok: reference to T6 is not in type parameter list
</pre>
<h4 id="Type_constraints">Type constraints</h4>
<p>
@ -3173,7 +3157,7 @@ Element = Expression | LiteralValue .
<p>
Unless the LiteralType is a type parameter,
its <a href="#Underlying_types">underlying type
its <a href="#Underlying_types">underlying type</a>
must be a struct, array, slice, or map type
(the syntax enforces this constraint except when the type is given
as a TypeName).
@ -4873,7 +4857,7 @@ For instance, <code>x / y * z</code> is the same as <code>(x / y) * z</code>.
x &lt;= f() // x &lt;= f()
^a &gt;&gt; b // (^a) >> b
f() || g() // f() || g()
x == y+1 &amp;&amp; &lt;-chanInt &gt; 0 // (x == (y+1)) && ((<-chanInt) > 0)
x == y+1 &amp;&amp; &lt;-chanInt &gt; 0 // (x == (y+1)) && ((&lt;-chanInt) > 0)
</pre>
@ -6635,7 +6619,7 @@ iteration's variable at that moment.
<pre>
var prints []func()
for i := 0; i < 5; i++ {
for i := 0; i &lt; 5; i++ {
prints = append(prints, func() { println(i) })
i++
}
@ -6772,7 +6756,7 @@ if the iteration variable is preexisting, the type of the iteration values is th
variable, which must be of integer type.
Otherwise, if the iteration variable is declared by the "range" clause or is absent,
the type of the iteration values is the <a href="#Constants">default type</a> for <code>n</code>.
If <code>n</code> &lt= 0, the loop does not run any iterations.
If <code>n</code> &lt;= 0, the loop does not run any iterations.
</li>
<li>
@ -7383,8 +7367,8 @@ The values <code>x</code> are passed to a parameter of type <code>...E</code>
where <code>E</code> is the element type of <code>S</code>
and the respective <a href="#Passing_arguments_to_..._parameters">parameter
passing rules</a> apply.
As a special case, <code>append</code> also accepts a first argument assignable
to type <code>[]byte</code> with a second argument of string type followed by
As a special case, <code>append</code> also accepts a slice whose type is assignable to
type <code>[]byte</code> with a second argument of <code>string</code> type followed by
<code>...</code>.
This form appends the bytes of the string.
</p>
@ -7799,7 +7783,7 @@ compared lexically byte-wise:
</p>
<pre>
min(x, y) == if x <= y then x else y
min(x, y) == if x &lt;= y then x else y
min(x, y, z) == min(min(x, y), z)
</pre>

View file

@ -153,6 +153,21 @@ for example,
see the [runtime documentation](/pkg/runtime#hdr-Environment_Variables)
and the [go command documentation](/cmd/go#hdr-Build_and_test_caching).
### Go 1.26
Go 1.26 added a new `httpcookiemaxnum` setting that controls the maximum number
of cookies that net/http will accept when parsing HTTP headers. If the number of
cookie in a header exceeds the number set in `httpcookiemaxnum`, cookie parsing
will fail early. The default value is `httpcookiemaxnum=3000`. Setting
`httpcookiemaxnum=0` will allow the cookie parsing to accept an indefinite
number of cookies. To avoid denial of service attacks, this setting and default
was backported to Go 1.25.2 and Go 1.24.8.
Go 1.26 added a new `urlstrictcolons` setting that controls whether `net/url.Parse`
allows malformed hostnames containing colons outside of a bracketed IPv6 address.
The default `urlstrictcolons=1` rejects URLs such as `http://localhost:1:2` or `http://::1/`.
Colons are permitted as part of a bracketed IPv6 address, such as `http://[::1]/`.
### Go 1.25
Go 1.25 added a new `decoratemappings` setting that controls whether the Go

View file

@ -19,10 +19,14 @@ type Person struct {
Age *int `json:"age"` // age if known; nil otherwise
}
func personJSON(name string, age int) ([]byte, error) {
func personJSON(name string, born time.Time) ([]byte, error) {
return json.Marshal(Person{
Name: name,
Age: new(age),
Age: new(yearsSince(born)),
})
}
func yearsSince(t time.Time) int {
return int(time.Since(t).Hours() / (365.25 * 24)) // approximately
}
```

View file

@ -7,5 +7,15 @@
a replacement for `go tool doc`: it takes the same flags and arguments and
has the same behavior.
<!-- go.dev/issue/75432 -->
The `go fix` command, following the pattern of `go vet` in Go 1.10,
now uses the Go analysis framework (`golang.org/x/tools/go/analysis`).
This means the same analyzers that provide diagnostics in `go vet`
can be used to suggest and apply fixes in `go fix`.
The `go fix` command's historical fixers, all of which were obsolete,
have been removed and replaced by a suite of new analyzers that
offer fixes to use newer features of the language and library.
<!-- I'll write a blog post that discusses this at length. --adonovan -->
### Cgo {#cgo}

View file

@ -4,6 +4,10 @@
## Linker {#linker}
On 64-bit ARM-based Windows (the `windows/arm64` port), the linker now supports internal
linking mode of cgo programs, which can be requested with the
`-ldflags=-linkmode=internal` flag.
## Bootstrap {#bootstrap}
<!-- go.dev/issue/69315 -->

View file

@ -0,0 +1,2 @@
The new [Buffer.Peek] method returns the next n bytes from the buffer without
advancing it.

View file

@ -0,0 +1,4 @@
The new [ParseDirective] function parses [directive
comments](/doc/comment#Syntax), which are comments such as `//go:generate`.
Source code tools can support their own directive comments and this new API
should help them implement the conventional syntax.

View file

@ -0,0 +1,4 @@
[Parse] now rejects malformed URLs containing colons in the host subcomponent,
such as `http://::1/` or `http://localhost:80:80/`.
URLs containing bracketed IPv6 addresses, such as `http://[::1]/` are still accepted.
The new GODEBUG=urlstrictcolons=0 setting restores the old behavior.

View file

@ -0,0 +1,18 @@
The new methods [T.ArtifactDir], [B.ArtifactDir], and [F.ArtifactDir]
return a directory in which to write test output files (artifacts).
When the `-artifacts` flag is provided to `go test`,
this directory will be located under the output directory
(specified with `-outputdir`, or the current directory by default).
Otherwise, artifacts are stored in a temporary directory
which is removed after the test completes.
The first call to `ArtifactDir` when `-artifacts` is provided
writes the location of the directory to the test log.
For example, in a test named `TestArtifacts`,
`t.ArtifactDir()` emits:
```
=== ARTIFACTS Test /path/to/artifact/dir
```

64
lib/hg/goreposum.py Normal file
View file

@ -0,0 +1,64 @@
# 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.
# Mercurial extension to add a 'goreposum' command that
# computes a hash of a remote repo's tag state.
# Tag definitions can come from the .hgtags file stored in
# any head of any branch, and the server protocol does not
# expose the tags directly. However, the protocol does expose
# the hashes of all the branch heads, so we can use a hash of
# all those branch names and heads as a conservative snapshot
# of the entire remote repo state, and use that as the tag sum.
# Any change on the server then invalidates the tag sum,
# even if it didn't have anything to do with tags, but at least
# we will avoid re-cloning a server when there have been no
# changes at all.
#
# Separately, this extension also adds a 'golookup' command that
# returns the hash of a specific reference, like 'default' or a tag.
# And golookup of a hash confirms that it still exists on the server.
# We can use that to revalidate that specific versions still exist and
# have the same meaning they did the last time we checked.
#
# Usage:
#
# hg --config "extensions.goreposum=$GOROOT/lib/hg/goreposum.py" goreposum REPOURL
import base64, hashlib, sys
from mercurial import registrar, ui, hg, node
from mercurial.i18n import _
cmdtable = {}
command = registrar.command(cmdtable)
@command(b'goreposum', [], _('url'), norepo=True)
def goreposum(ui, url):
"""
goreposum computes a checksum of all the named state in the remote repo.
It hashes together all the branch names and hashes
and then all the bookmark names and hashes.
Tags are stored in .hgtags files in any of the branches,
so the branch metadata includes the tags as well.
"""
h = hashlib.sha256()
peer = hg.peer(ui, {}, url)
for name, revs in peer.branchmap().items():
h.update(name)
for r in revs:
h.update(b' ')
h.update(r)
h.update(b'\n')
if (b'bookmarks' in peer.listkeys(b'namespaces')):
for name, rev in peer.listkeys(b'bookmarks').items():
h.update(name)
h.update(b'=')
h.update(rev)
h.update(b'\n')
print('r1:'+base64.standard_b64encode(h.digest()).decode('utf-8'))
@command(b'golookup', [], _('url rev'), norepo=True)
def golookup(ui, url, rev):
"""
golookup looks up a single identifier in the repo,
printing its hash.
"""
print(node.hex(hg.peer(ui, {}, url).lookup(rev)).decode('utf-8'))

View file

@ -39,6 +39,7 @@ var (
errMissData = errors.New("archive/tar: sparse file references non-existent data")
errUnrefData = errors.New("archive/tar: sparse file contains unreferenced data")
errWriteHole = errors.New("archive/tar: write non-NUL byte in sparse hole")
errSparseTooLong = errors.New("archive/tar: sparse map too long")
)
type headerError []string

View file

@ -531,12 +531,17 @@ func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
cntNewline int64
buf bytes.Buffer
blk block
totalSize int
)
// feedTokens copies data in blocks from r into buf until there are
// at least cnt newlines in buf. It will not read more blocks than needed.
feedTokens := func(n int64) error {
for cntNewline < n {
totalSize += len(blk)
if totalSize > maxSpecialFileSize {
return errSparseTooLong
}
if _, err := mustReadFull(r, blk[:]); err != nil {
return err
}
@ -569,8 +574,8 @@ func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
}
// Parse for all member entries.
// numEntries is trusted after this since a potential attacker must have
// committed resources proportional to what this library used.
// numEntries is trusted after this since feedTokens limits the number of
// tokens based on maxSpecialFileSize.
if err := feedTokens(2 * numEntries); err != nil {
return nil, err
}

View file

@ -621,6 +621,11 @@ func TestReader(t *testing.T) {
},
Format: FormatPAX,
}},
}, {
// Small compressed file that uncompresses to
// a file with a very large GNU 1.0 sparse map.
file: "testdata/gnu-sparse-many-zeros.tar.bz2",
err: errSparseTooLong,
}}
for _, v := range vectors {

Binary file not shown.

View file

@ -1213,7 +1213,6 @@ func TestFS(t *testing.T) {
[]string{"a/b/c"},
},
} {
test := test
t.Run(test.file, func(t *testing.T) {
t.Parallel()
z, err := OpenReader(test.file)
@ -1247,7 +1246,6 @@ func TestFSWalk(t *testing.T) {
wantErr: true,
},
} {
test := test
t.Run(test.file, func(t *testing.T) {
t.Parallel()
z, err := OpenReader(test.file)

View file

@ -77,6 +77,18 @@ func (b *Buffer) String() string {
return string(b.buf[b.off:])
}
// Peek returns the next n bytes without advancing the buffer.
// If Peek returns fewer than n bytes, it also returns [io.EOF].
// The slice is only valid until the next call to a read or write method.
// The slice aliases the buffer content at least until the next buffer modification,
// so immediate changes to the slice will affect the result of future reads.
func (b *Buffer) Peek(n int) ([]byte, error) {
if b.Len() < n {
return b.buf[b.off:], io.EOF
}
return b.buf[b.off:n], nil
}
// empty reports whether the unread portion of the buffer is empty.
func (b *Buffer) empty() bool { return len(b.buf) <= b.off }

View file

@ -531,6 +531,34 @@ func TestReadString(t *testing.T) {
}
}
var peekTests = []struct {
buffer string
n int
expected string
err error
}{
{"", 0, "", nil},
{"aaa", 3, "aaa", nil},
{"foobar", 2, "fo", nil},
{"a", 2, "a", io.EOF},
}
func TestPeek(t *testing.T) {
for _, test := range peekTests {
buf := NewBufferString(test.buffer)
bytes, err := buf.Peek(test.n)
if string(bytes) != test.expected {
t.Errorf("expected %q, got %q", test.expected, bytes)
}
if err != test.err {
t.Errorf("expected error %v, got %v", test.err, err)
}
if buf.Len() != len(test.buffer) {
t.Errorf("bad length after peek: %d, want %d", buf.Len(), len(test.buffer))
}
}
}
func BenchmarkReadString(b *testing.B) {
const n = 32 << 10

View file

@ -1224,7 +1224,7 @@ func TestMap(t *testing.T) {
// Run a couple of awful growth/shrinkage tests
a := tenRunes('a')
// 1. Grow. This triggers two reallocations in Map.
// 1. Grow. This triggers two reallocations in Map.
maxRune := func(r rune) rune { return unicode.MaxRune }
m := Map(maxRune, []byte(a))
expect := tenRunes(unicode.MaxRune)

View file

@ -92,7 +92,8 @@ func jumpX86(word string) bool {
func jumpRISCV(word string) bool {
switch word {
case "BEQ", "BEQZ", "BGE", "BGEU", "BGEZ", "BGT", "BGTU", "BGTZ", "BLE", "BLEU", "BLEZ",
"BLT", "BLTU", "BLTZ", "BNE", "BNEZ", "CALL", "JAL", "JALR", "JMP":
"BLT", "BLTU", "BLTZ", "BNE", "BNEZ", "CALL", "CBEQZ", "CBNEZ", "CJ", "CJALR", "CJR",
"JAL", "JALR", "JMP":
return true
}
return false

View file

@ -195,149 +195,6 @@ func ARM64RegisterShift(reg, op, count int16) (int64, error) {
return int64(reg&31)<<16 | int64(op)<<22 | int64(uint16(count)), nil
}
// ARM64RegisterExtension constructs an ARM64 register with extension or arrangement.
func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
Rnum := (reg & 31) + int16(num<<5)
if isAmount {
if num < 0 || num > 7 {
return errors.New("index shift amount is out of range")
}
}
if reg <= arm64.REG_R31 && reg >= arm64.REG_R0 {
if !isAmount {
return errors.New("invalid register extension")
}
switch ext {
case "UXTB":
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTB + Rnum
case "UXTH":
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTH + Rnum
case "UXTW":
// effective address of memory is a base register value and an offset register value.
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_UXTW + Rnum
} else {
a.Reg = arm64.REG_UXTW + Rnum
}
case "UXTX":
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_UXTX + Rnum
case "SXTB":
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_SXTB + Rnum
case "SXTH":
if a.Type == obj.TYPE_MEM {
return errors.New("invalid shift for the register offset addressing mode")
}
a.Reg = arm64.REG_SXTH + Rnum
case "SXTW":
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_SXTW + Rnum
} else {
a.Reg = arm64.REG_SXTW + Rnum
}
case "SXTX":
if a.Type == obj.TYPE_MEM {
a.Index = arm64.REG_SXTX + Rnum
} else {
a.Reg = arm64.REG_SXTX + Rnum
}
case "LSL":
a.Index = arm64.REG_LSL + Rnum
default:
return errors.New("unsupported general register extension type: " + ext)
}
} else if reg <= arm64.REG_V31 && reg >= arm64.REG_V0 {
switch ext {
case "B8":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8B & 15) << 5)
case "B16":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_16B & 15) << 5)
case "H4":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4H & 15) << 5)
case "H8":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_8H & 15) << 5)
case "S2":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2S & 15) << 5)
case "S4":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_4S & 15) << 5)
case "D1":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1D & 15) << 5)
case "D2":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_2D & 15) << 5)
case "Q1":
if isIndex {
return errors.New("invalid register extension")
}
a.Reg = arm64.REG_ARNG + (reg & 31) + ((arm64.ARNG_1Q & 15) << 5)
case "B":
if !isIndex {
return nil
}
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_B & 15) << 5)
a.Index = num
case "H":
if !isIndex {
return nil
}
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_H & 15) << 5)
a.Index = num
case "S":
if !isIndex {
return nil
}
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_S & 15) << 5)
a.Index = num
case "D":
if !isIndex {
return nil
}
a.Reg = arm64.REG_ELEM + (reg & 31) + ((arm64.ARNG_D & 15) << 5)
a.Index = num
default:
return errors.New("unsupported simd register extension type: " + ext)
}
} else {
return errors.New("invalid register and extension combination")
}
return nil
}
// ARM64RegisterArrangement constructs an ARM64 vector register arrangement.
func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) {
var curQ, curSize uint16

View file

@ -248,7 +248,7 @@ func (p *Parser) asmData(operands [][]lex.Token) {
case obj.TYPE_CONST:
switch sz {
case 1, 2, 4, 8:
nameAddr.Sym.WriteInt(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Offset)
nameAddr.Sym.WriteInt(p.ctxt, nameAddr.Offset, sz, valueAddr.Offset)
default:
p.errorf("bad int size for DATA argument: %d", sz)
}
@ -262,10 +262,10 @@ func (p *Parser) asmData(operands [][]lex.Token) {
p.errorf("bad float size for DATA argument: %d", sz)
}
case obj.TYPE_SCONST:
nameAddr.Sym.WriteString(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Val.(string))
nameAddr.Sym.WriteString(p.ctxt, nameAddr.Offset, sz, valueAddr.Val.(string))
case obj.TYPE_ADDR:
if sz == p.arch.PtrSize {
nameAddr.Sym.WriteAddr(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Sym, valueAddr.Offset)
nameAddr.Sym.WriteAddr(p.ctxt, nameAddr.Offset, sz, valueAddr.Sym, valueAddr.Offset)
} else {
p.errorf("bad addr size for DATA argument: %d", sz)
}

View file

@ -38,7 +38,7 @@ func testEndToEnd(t *testing.T, goarch, file string) {
ctxt.IsAsm = true
defer ctxt.Bso.Flush()
failed := false
ctxt.DiagFunc = func(format string, args ...interface{}) {
ctxt.DiagFunc = func(format string, args ...any) {
failed = true
t.Errorf(format, args...)
}
@ -193,7 +193,7 @@ Diff:
top := pList.Firstpc
var text *obj.LSym
ok = true
ctxt.DiagFunc = func(format string, args ...interface{}) {
ctxt.DiagFunc = func(format string, args ...any) {
t.Errorf(format, args...)
ok = false
}
@ -294,7 +294,7 @@ func testErrors(t *testing.T, goarch, file string, flags ...string) {
failed := false
var errBuf bytes.Buffer
parser.errorWriter = &errBuf
ctxt.DiagFunc = func(format string, args ...interface{}) {
ctxt.DiagFunc = func(format string, args ...any) {
failed = true
s := fmt.Sprintf(format, args...)
if !strings.HasSuffix(s, "\n") {
@ -467,6 +467,7 @@ func TestLOONG64Encoder(t *testing.T) {
testEndToEnd(t, "loong64", "loong64enc3")
testEndToEnd(t, "loong64", "loong64enc4")
testEndToEnd(t, "loong64", "loong64enc5")
testEndToEnd(t, "loong64", "loong64enc6")
testEndToEnd(t, "loong64", "loong64")
}

View file

@ -78,7 +78,7 @@ func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
// and turn it into a recoverable panic.
var panicOnError bool
func (p *Parser) errorf(format string, args ...interface{}) {
func (p *Parser) errorf(format string, args ...any) {
if panicOnError {
panic(fmt.Errorf(format, args...))
}
@ -90,7 +90,7 @@ func (p *Parser) errorf(format string, args ...interface{}) {
if p.lex != nil {
// Put file and line information on head of message.
format = "%s:%d: " + format + "\n"
args = append([]interface{}{p.lex.File(), p.lineNum}, args...)
args = append([]any{p.lex.File(), p.lineNum}, args...)
}
fmt.Fprintf(p.errorWriter, format, args...)
p.errorCount++
@ -775,7 +775,7 @@ func (p *Parser) registerExtension(a *obj.Addr, name string, prefix rune) {
switch p.arch.Family {
case sys.ARM64:
err := arch.ARM64RegisterExtension(a, ext, reg, num, isAmount, isIndex)
err := arm64.ARM64RegisterExtension(a, ext, reg, num, isAmount, isIndex)
if err != nil {
p.errorf("%v", err)
}

View file

@ -400,6 +400,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
MOVD $0x11110000, R1 // MOVD $286326784, R1 // 2122a2d2
MOVD $0xaaaa0000aaaa1111, R1 // MOVD $-6149102338357718767, R1 // 212282d24155b5f24155f5f2
MOVD $0x1111ffff1111aaaa, R1 // MOVD $1230045644216969898, R1 // a1aa8a922122a2f22122e2f2
MOVD $0xaaaaaaaaaaaaaaab, R1 // MOVD $-6148914691236517205, R1 // e1f301b2615595f2
MOVD $0x0ff019940ff00ff0, R1 // MOVD $1148446028692721648, R1 // e19f0cb28132c3f2
MOVD $0, R1 // e1031faa
MOVD $-1, R1 // 01008092
MOVD $0x210000, R0 // MOVD $2162688, R0 // 2004a0d2
@ -630,6 +632,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
FMOVS F1, 0x44332211(R2) // FMOVS F1, 1144201745(R2)
FMOVD F1, 0x1007000(R2) // FMOVD F1, 16805888(R2)
FMOVD F1, 0x44332211(R2) // FMOVD F1, 1144201745(R2)
FMOVQ F1, 0x1003000(R2) // FMOVQ F1, 16789504(R2)
FMOVQ F1, 0x44332211(R2) // FMOVQ F1, 1144201745(R2)
MOVB 0x1000000(R1), R2 // MOVB 16777216(R1), R2
MOVB 0x44332211(R1), R2 // MOVB 1144201745(R1), R2
@ -643,6 +647,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
FMOVS 0x44332211(R1), F2 // FMOVS 1144201745(R1), F2
FMOVD 0x1000000(R1), F2 // FMOVD 16777216(R1), F2
FMOVD 0x44332211(R1), F2 // FMOVD 1144201745(R1), F2
FMOVQ 0x1000000(R1), F2 // FMOVQ 16777216(R1), F2
FMOVQ 0x44332211(R1), F2 // FMOVQ 1144201745(R1), F2
// shifted or extended register offset.
MOVD (R2)(R6.SXTW), R4 // 44c866f8
@ -1894,4 +1900,12 @@ next:
BTI J // 9f2403d5
BTI JC // df2403d5
// Pointer Authentication Codes (PAC)
PACIASP // 3f2303d5
AUTIASP // bf2303d5
PACIBSP // 7f2303d5
AUTIBSP // ff2303d5
AUTIA1716 // 9f2103d5
AUTIB1716 // df2103d5
END

View file

@ -422,4 +422,10 @@ TEXT errors(SB),$0
SHA1H V1.B16, V2.B16 // ERROR "invalid operands"
BTI // ERROR "missing operand"
BTI PLDL1KEEP // ERROR "illegal argument"
PACIASP C // ERROR "illegal combination"
AUTIASP R2 // ERROR "illegal combination"
PACIBSP R0 // ERROR "illegal combination"
AUTIBSP C // ERROR "illegal combination"
AUTIA1716 $45 // ERROR "illegal combination"
AUTIB1716 R0 // ERROR "illegal combination"
RET

View file

@ -93,8 +93,8 @@ lable2:
MOVV R4, 1(R5) // a404c029
MOVB R4, 1(R5) // a4040029
MOVBU R4, 1(R5) // a4040029
SC R4, 1(R5) // a4040021
SCV R4, 1(R5) // a4040023
SC R4, 4096(R5) // a4001021
SCV R4, 4096(R5) // a4001023
MOVW y+8(FP), R4 // 64408028
MOVWU y+8(FP), R4 // 6440802a
MOVV y+8(FP), R4 // 6440c028
@ -105,8 +105,8 @@ lable2:
MOVV 1(R5), R4 // a404c028
MOVB 1(R5), R4 // a4040028
MOVBU 1(R5), R4 // a404002a
LL 1(R5), R4 // a4040020
LLV 1(R5), R4 // a4040022
LL 4096(R5), R4 // a4001020
LLV 4096(R5), R4 // a4001022
MOVW $4(R4), R5 // 8510c002
MOVV $4(R4), R5 // 8510c002
MOVW $-1, R4 // 04fcff02
@ -261,22 +261,18 @@ lable2:
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
@ -537,12 +533,18 @@ lable2:
XVMOVQ X28.V[3], X8 // 88ef0377
XVMOVQ X27.V[0], X9 // 69e30377
//Move vector element to vector.
// Move vector element to vector.
VMOVQ V1.B[3], V9.B16 // 298cf772
VMOVQ V2.H[2], V8.H8 // 48c8f772
VMOVQ V3.W[1], V7.W4 // 67e4f772
VMOVQ V4.V[0], V6.V2 // 86f0f772
// Move vector register to vector register.
VMOVQ V1, V9 // 29002d73
VMOVQ V2, V8 // 48002d73
XVMOVQ X3, X7 // 67002d77
XVMOVQ X4, X6 // 86002d77
// Load data from memory and broadcast to each element of a vector register: VMOVQ offset(Rj), <Vd>.<T>
VMOVQ (R4), V0.B16 // 80008030
VMOVQ 1(R4), V0.B16 // 80048030
@ -841,6 +843,42 @@ lable2:
XVSUBWU $15, X1, X2 // 223c8d76
XVSUBVU $16, X1, X2 // 22c08d76
// [X]VSADD{B,H,W,V}, [X]VSSUB{B,H,W,V} instructions
VSADDB V1, V2, V3 // 43044670
VSADDH V1, V2, V3 // 43844670
VSADDW V1, V2, V3 // 43044770
VSADDV V1, V2, V3 // 43844770
VSSUBB V1, V2, V3 // 43044870
VSSUBH V1, V2, V3 // 43844870
VSSUBW V1, V2, V3 // 43044970
VSSUBV V1, V2, V3 // 43844970
XVSADDB X3, X2, X1 // 410c4674
XVSADDH X3, X2, X1 // 418c4674
XVSADDW X3, X2, X1 // 410c4774
XVSADDV X3, X2, X1 // 418c4774
XVSSUBB X3, X2, X1 // 410c4874
XVSSUBH X3, X2, X1 // 418c4874
XVSSUBW X3, X2, X1 // 410c4974
XVSSUBV X3, X2, X1 // 418c4974
// [X]VSADD{B,H,W,V}U, [X]VSSUB{B,H,W,V}U instructions
VSADDBU V1, V2, V3 // 43044a70
VSADDHU V1, V2, V3 // 43844a70
VSADDWU V1, V2, V3 // 43044b70
VSADDVU V1, V2, V3 // 43844b70
VSSUBBU V1, V2, V3 // 43044c70
VSSUBHU V1, V2, V3 // 43844c70
VSSUBWU V1, V2, V3 // 43044d70
VSSUBVU V1, V2, V3 // 43844d70
XVSADDBU X1, X2, X3 // 43044a74
XVSADDHU X1, X2, X3 // 43044b74
XVSADDWU X1, X2, X3 // 43044b74
XVSADDVU X1, X2, X3 // 43844b74
XVSSUBBU X1, X2, X3 // 43044c74
XVSSUBHU X1, X2, X3 // 43844c74
XVSSUBWU X1, X2, X3 // 43044d74
XVSSUBVU X1, X2, X3 // 43844d74
// [X]VILV{L/H}{B,H,W,V} instructions
VILVLB V1, V2, V3 // 43041a71
VILVLH V1, V2, V3 // 43841a71
@ -1021,6 +1059,32 @@ lable2:
XVSHUF4IV $8, X1, X2 // 22209c77
XVSHUF4IV $15, X1, X2 // 223c9c77
// [X]VSHUF.{B/H/W/V} instructions
VSHUFH V1, V2, V3 // 43847a71
VSHUFW V1, V2, V3 // 43047b71
VSHUFV V1, V2, V3 // 43847b71
XVSHUFH X1, X2, X3 // 43847a75
XVSHUFW X1, X2, X3 // 43047b75
XVSHUFV X1, X2, X3 // 43847b75
VSHUFB V1, V2, V3, V4 // 6488500d
XVSHUFB X1, X2, X3, X4 // 6488600d
// VPERMIW, XVPERMI{W,V,Q} instructions
VPERMIW $0x1B, V1, V2 // VPERMIW $27, V1, V2 // 226ce473
XVPERMIW $0x2B, X1, X2 // XVPERMIW $43, X1, X2 // 22ace477
XVPERMIV $0x3B, X1, X2 // XVPERMIV $59, X1, X2 // 22ece877
XVPERMIQ $0x4B, X1, X2 // XVPERMIQ $75, X1, X2 // 222ced77
// A{,X}VEXTRINS.{B,H,W,V} instructions
VEXTRINSB $0x18, V1, V2 // VEXTRINSB $24, V1, V2 // 22608c73
VEXTRINSH $0x27, V1, V2 // VEXTRINSH $39, V1, V2 // 229c8873
VEXTRINSW $0x36, V1, V2 // VEXTRINSW $54, V1, V2 // 22d88473
VEXTRINSV $0x45, V1, V2 // VEXTRINSV $69, V1, V2 // 22148173
XVEXTRINSB $0x54, X1, X2 // XVEXTRINSB $84, X1, X2 // 22508d77
XVEXTRINSH $0x63, X1, X2 // XVEXTRINSH $99, X1, X2 // 228c8977
XVEXTRINSW $0x72, X1, X2 // XVEXTRINSW $114, X1, X2 // 22c88577
XVEXTRINSV $0x81, X1, X2 // XVEXTRINSV $129, X1, X2 // 22048277
// [X]VSETEQZ.V, [X]VSETNEZ.V
VSETEQV V1, FCC0 // 20989c72
VSETNEV V1, FCC0 // 209c9c72

View file

@ -42,8 +42,10 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
MOVB R4, 4096(R5) // 3e000014de971000c4030029
MOVBU R4, 65536(R5) // 1e020014de971000c4030029
MOVBU R4, 4096(R5) // 3e000014de971000c4030029
SC R4, 65536(R5) // 1e020014de971000c4030021
SC R4, 4096(R5) // 3e000014de971000c4030021
SC R4, 65536(R5) // 1e040010de971000c4030021
SCV R4, 65536(R5) // 1e040010de971000c4030023
LL 65536(R5), R4 // 1e040010de971000c4030020
LLV 65536(R5), R4 // 1e040010de971000c4030022
MOVW y+65540(FP), R4 // 1e020014de8f1000c4338028
MOVWU y+65540(FP), R4 // 1e020014de8f1000c433802a
MOVV y+65540(FP), R4 // 1e020014de8f1000c433c028
@ -122,6 +124,21 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
XOR $4097, R4 // 3e000014de07800384f81500
XOR $4097, R4, R5 // 3e000014de07800385f81500
MOVWP R5, -32768(R4) // 1efcff13de931000c5038025
MOVWP R5, 32768(R4) // 1e000010de931000c5038025
MOVWP R5, 65536(R4) // 1e040010de931000c5030025
MOVWP R5, 1048576(R4) // 1e400010de931000c5030025
MOVVP R5, -32768(R4) // 1efcff13de931000c5038027
MOVVP R5, 65536(R4) // 1e040010de931000c5030027
MOVVP R5, 1048576(R4) // 1e400010de931000c5030027
MOVWP -32768(R5), R4 // 1efcff13de971000c4038024
MOVWP 2229248(R5), R4 // 1e880010de971000c4030424
MOVWP -2145518592(R5), R4 // 1e740012de971000c403fc24
MOVVP -32768(R5), R4 // 1efcff13de971000c4038026
MOVVP 2229248(R5), R4 // 1e880010de971000c4030426
MOVVP -2145518592(R5), R4 // 1e740012de971000c403fc26
// MOVV C_DCON32_12S, r
MOVV $0x27312345fffff800, R4 // MOVV $2824077224892692480, R4 // 0400a002a468241684cc0903
MOVV $0xf7312345fffff800, R4 // MOVV $-634687288927848448, R4 // 0400a002a468241684cc3d03

View file

@ -0,0 +1,12 @@
// 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 "../../../../../runtime/textflag.h"
TEXT asmtest(SB),DUPOK|NOSPLIT,$0
// MOVWP LOREG_64(Rx), Ry
MOVWP 81985529216486896(R4), R5 // 9e571315dec3b703feac6816de4b000384f8100085000025
MOVWP -81985529216486896(R4), R5 // 7ea8ec14de4388031e539717deb73f0384f8100085000025
MOVWP R4, 81985529216486896(R5) // 9e571315dec3b703feac6816de4b0003a5f81000a4000025
MOVWP R4, -81985529216486896(R5) // 7ea8ec14de4388031e539717deb73f03a5f81000a4000025

View file

@ -7,3 +7,8 @@ TEXT errors(SB),$0
XVSHUF4IV $16, X1, X2 // ERROR "operand out of range 0 to 15"
ADDV16 $1, R4, R5 // ERROR "the constant must be a multiple of 65536."
ADDV16 $65535, R4, R5 // ERROR "the constant must be a multiple of 65536."
SC R4, 1(R5) // ERROR "offset must be a multiple of 4."
SCV R4, 1(R5) // ERROR "offset must be a multiple of 4."
LL 1(R5), R4 // ERROR "offset must be a multiple of 4."
LLV 1(R5), R4 // ERROR "offset must be a multiple of 4."

View file

@ -372,6 +372,76 @@ start:
// 21.7: Double-Precision Floating-Point Classify Instruction
FCLASSD F0, X5 // d31200e2
//
// "C" Extension for Compressed Instructions, Version 2.0
//
// 26.3.1: Compressed Stack-Pointer-Based Loads and Stores
CLWSP 20(SP), X10 // 5245
CLDSP 24(SP), X10 // 6265
CFLDSP 32(SP), F10 // 0235
CSWSP X10, 20(SP) // 2aca
CSDSP X10, 24(SP) // 2aec
CFSDSP F10, 32(SP) // 2ab0
// 26.3.2: Compressed Register-Based Loads and Stores
CLW 20(X10), X11 // 4c49
CLD 24(X10), X11 // 0c6d
CFLD 32(X10), F11 // 0c31
CSW X11, 20(X10) // 4cc9
CSD X11, 24(X10) // 0ced
CFSD F11, 32(X10) // 0cb1
// 26.4: Compressed Control Transfer Instructions
CJ 1(PC) // 09a0
CJR X5 // 8282
CJALR X5 // 8292
CBEQZ X10, 1(PC) // 09c1
CBNEZ X10, 1(PC) // 09e1
// 26.5.1: Compressed Integer Constant-Generation Instructions
CLI $-32, X5 // 8152
CLI $31, X5 // fd42
CLUI $-32, X5 // 8172
CLUI $31, X5 // fd62
// 26.5.2: Compressed Integer Register-Immediate Operations
CADD $-32, X5 // 8112
CADD $31, X5 // fd02
CADDI $-32, X5 // 8112
CADDI $31, X5 // fd02
CADDW $-32, X5 // 8132
CADDW $31, X5 // fd22
CADDIW $-32, X5 // 8132
CADDIW $31, X5 // fd22
CADDI16SP $-512, SP // 0171
CADDI16SP $496, SP // 7d61
CADDI4SPN $4, SP, X10 // 4800
CADDI4SPN $1020, SP, X10 // e81f
CSLLI $63, X5 // fe12
CSRLI $63, X10 // 7d91
CSRAI $63, X10 // 7d95
CAND $-32, X10 // 0199
CAND $31, X10 // 7d89
CANDI $-32, X10 // 0199
CANDI $31, X10 // 7d89
// 26.5.3: Compressed Integer Register-Register Operations
CMV X6, X5 // 9a82
CADD X9, X8 // 2694
CAND X9, X8 // 658c
COR X9, X8 // 458c
CXOR X9, X8 // 258c
CSUB X9, X8 // 058c
CADDW X9, X8 // 259c
CSUBW X9, X8 // 059c
// 26.5.5: Compressed NOP Instruction
CNOP // 0100
// 26.5.6: Compressed Breakpoint Instruction
CEBREAK // 0290
// 28.4.1: Address Generation Instructions (Zba)
ADDUW X10, X11, X12 // 3b86a508
ADDUW X10, X11 // bb85a508

View file

@ -12,6 +12,147 @@ TEXT validation(SB),$0
SRLI $1, X5, F1 // ERROR "expected integer register in rd position but got non-integer register F1"
SRLI $1, F1, X5 // ERROR "expected integer register in rs1 position but got non-integer register F1"
WORD $-1 // ERROR "must be in range [0x0, 0xffffffff]"
WORD $0x100000000 // ERROR "must be in range [0x0, 0xffffffff]"
//
// "C" Extension for Compressed Instructions, Version 2.0
//
CLWSP 20(X5), X10 // ERROR "rs2 must be SP/X2"
CLWSP 20(SP), X0 // ERROR "cannot use register X0"
CLWSP 20(SP), F10 // ERROR "expected integer register in rd position"
CLWSP 22(SP), X10 // ERROR "must be a multiple of 4"
CLDSP 24(X5), X10 // ERROR "rs2 must be SP/X2"
CLDSP 24(SP), X0 // ERROR "cannot use register X0"
CLDSP 24(SP), F10 // ERROR "expected integer register in rd position"
CLDSP 28(SP), X10 // ERROR "must be a multiple of 8"
CFLDSP 32(X5), F10 // ERROR "rs2 must be SP/X2"
CFLDSP 32(SP), X10 // ERROR "expected float register in rd position"
CFLDSP 36(SP), F10 // ERROR "must be a multiple of 8"
CSWSP X10, 20(X5) // ERROR "rd must be SP/X2"
CSWSP F10, 20(SP) // ERROR "expected integer register in rs2 position"
CSWSP X10, 22(SP) // ERROR "must be a multiple of 4"
CSDSP X10, 24(X5) // ERROR "rd must be SP/X2"
CSDSP F10, 24(SP) // ERROR "expected integer register in rs2 position"
CSDSP X10, 28(SP) // ERROR "must be a multiple of 8"
CFSDSP F10, 32(X5) // ERROR "rd must be SP/X2"
CFSDSP X10, 32(SP) // ERROR "expected float register in rs2 position"
CFSDSP F10, 36(SP) // ERROR "must be a multiple of 8"
CLW 20(X10), F11 // ERROR "expected integer prime register in rd position"
CLW 20(X5), X11 // ERROR "expected integer prime register in rs1 position"
CLW 20(X10), X5 // ERROR "expected integer prime register in rd position"
CLW -1(X10), X11 // ERROR "must be in range [0, 127]"
CLW 22(X10), X11 // ERROR "must be a multiple of 4"
CLW 128(X10), X11 // ERROR "must be in range [0, 127]"
CLD 24(X10), F11 // ERROR "expected integer prime register in rd position"
CLD 24(X5), X11 // ERROR "expected integer prime register in rs1 position"
CLD -1(X10), X11 // ERROR "must be in range [0, 255]"
CLD 30(X10), X11 // ERROR "must be a multiple of 8"
CLD 256(X10), X11 // ERROR "must be in range [0, 255]"
CFLD 32(X10), X11 // ERROR "expected float prime register in rd position"
CFLD 32(X5), F11 // ERROR "expected integer prime register in rs1 position"
CFLD -1(X10), F11 // ERROR "must be in range [0, 255]"
CFLD 34(X10), F11 // ERROR "must be a multiple of 8"
CFLD 256(X10), F11 // ERROR "must be in range [0, 255]"
CSW F11, 20(X10) // ERROR "expected integer prime register in rs2 position"
CSW X11, -1(X10) // ERROR "must be in range [0, 127]"
CSW X11, 22(X10) // ERROR "must be a multiple of 4"
CSW X11, 128(X10) // ERROR "must be in range [0, 127]"
CSD F11, 24(X10) // ERROR "expected integer prime register in rs2 position"
CSD X11, -1(X10) // ERROR "must be in range [0, 255]"
CSD X11, 28(X10) // ERROR "must be a multiple of 8"
CSD X11, 256(X10) // ERROR "must be in range [0, 255]"
CFSD X11, 32(X10) // ERROR "expected float prime register in rs2 position"
CFSD F11, -1(X10) // ERROR "must be in range [0, 255]"
CFSD F11, 36(X10) // ERROR "must be a multiple of 8"
CFSD F11, 256(X10) // ERROR "must be in range [0, 255]"
CJR X0 // ERROR "cannot use register X0 in rs1"
CJR X10, X11 // ERROR "expected no register in rs2"
CJALR X0 // ERROR "cannot use register X0 in rs1"
CJALR X10, X11 // ERROR "expected no register in rd"
CBEQZ X5, 1(PC) // ERROR "expected integer prime register in rs1"
CBNEZ X5, 1(PC) // ERROR "expected integer prime register in rs1"
CLI $3, X0 // ERROR "cannot use register X0 in rd"
CLI $-33, X5 // ERROR "must be in range [-32, 31]"
CLI $32, X5 // ERROR "must be in range [-32, 31]"
CLUI $0, X5 // ERROR "immediate cannot be zero"
CLUI $3, X0 // ERROR "cannot use register X0 in rd"
CLUI $3, X2 // ERROR "cannot use register SP/X2 in rd"
CLUI $-33, X5 // ERROR "must be in range [-32, 31]"
CLUI $32, X5 // ERROR "must be in range [-32, 31]"
CADD $31, X5, X6 // ERROR "rd must be the same as rs1"
CADD $-33, X5 // ERROR "must be in range [-32, 31]"
CADD $32, X5 // ERROR "must be in range [-32, 31]"
CADDI $0, X5 // ERROR "immediate cannot be zero"
CADDI $31, X5, X6 // ERROR "rd must be the same as rs1"
CADDI $-33, X5 // ERROR "must be in range [-32, 31]"
CADDI $32, X5 // ERROR "must be in range [-32, 31]"
CADDW $-33, X5 // ERROR "must be in range [-32, 31]"
CADDW $32, X5 // ERROR "must be in range [-32, 31]"
CADDIW $-33, X5 // ERROR "must be in range [-32, 31]"
CADDIW $32, X5 // ERROR "must be in range [-32, 31]"
CADDI16SP $0, SP // ERROR "immediate cannot be zero"
CADDI16SP $16, X5 // ERROR "rd must be SP/X2"
CADDI16SP $-513, SP // ERROR "must be in range [-512, 511]"
CADDI16SP $20, SP // ERROR "must be a multiple of 16"
CADDI16SP $512, SP // ERROR "must be in range [-512, 511]"
CADDI4SPN $4, SP, X5 // ERROR "expected integer prime register in rd"
CADDI4SPN $4, X5, X10 // ERROR "SP/X2 must be in rs1"
CADDI4SPN $-1, SP, X10 // ERROR "must be in range [0, 1023]"
CADDI4SPN $0, SP, X10 // ERROR "immediate cannot be zero"
CADDI4SPN $6, SP, X10 // ERROR "must be a multiple of 4"
CADDI4SPN $1024, SP, X10 // ERROR "must be in range [0, 1023]"
CSLLI $63, X5, X6 // ERROR "rd must be the same as rs1"
CSLLI $-1, X5 // ERROR "must be in range [0, 63]"
CSLLI $0, X5 // ERROR "immediate cannot be zero"
CSLLI $64, X5 // ERROR "must be in range [0, 63]"
CSRLI $63, X10, X11 // ERROR "rd must be the same as rs1"
CSRLI $63, X5 // ERROR "expected integer prime register in rd"
CSRLI $-1, X10 // ERROR "must be in range [0, 63]"
CSRLI $0, X10 // ERROR "immediate cannot be zero"
CSRLI $64, X10 // ERROR "must be in range [0, 63]"
CSRAI $63, X10, X11 // ERROR "rd must be the same as rs1"
CSRAI $63, X5 // ERROR "expected integer prime register in rd"
CSRAI $-1, X10 // ERROR "must be in range [0, 63]"
CSRAI $0, X10 // ERROR "immediate cannot be zero"
CSRAI $64, X10 // ERROR "must be in range [0, 63]"
CAND $1, X10, X11 // ERROR "rd must be the same as rs1"
CAND $1, X5 // ERROR "expected integer prime register in rd"
CAND $-64, X10 // ERROR "must be in range [-32, 31]"
CAND $63, X10 // ERROR "must be in range [-32, 31]"
CANDI $1, X10, X11 // ERROR "rd must be the same as rs1"
CANDI $1, X5 // ERROR "expected integer prime register in rd"
CANDI $-64, X10 // ERROR "must be in range [-32, 31]"
CANDI $63, X10 // ERROR "must be in range [-32, 31]"
CMV X0, X5 // ERROR "cannot use register X0 in rs2"
CMV X5, X6, X7 // ERROR "expected no register in rs1"
CMV X5, X0 // ERROR "cannot use register X0 in rd"
CMV F1, X5 // ERROR "expected integer register in rs2"
CMV X5, F1 // ERROR "expected integer register in rd"
CADD X5, X6, X7 // ERROR "rd must be the same as rs1"
CADD X0, X8 // ERROR "cannot use register X0 in rs2"
CADD X8, X0 // ERROR "cannot use register X0 in rd"
CAND X10, X11, X12 // ERROR "rd must be the same as rs1"
CAND X5, X11 // ERROR "expected integer prime register in rs2"
CAND X10, X5 // ERROR "expected integer prime register in rd"
COR X10, X11, X12 // ERROR "rd must be the same as rs1"
COR X5, X11 // ERROR "expected integer prime register in rs2"
COR X10, X5 // ERROR "expected integer prime register in rd"
CXOR X10, X11, X12 // ERROR "rd must be the same as rs1"
CXOR X5, X11 // ERROR "expected integer prime register in rs2"
CXOR X10, X5 // ERROR "expected integer prime register in rd"
CSUB X10, X11, X12 // ERROR "rd must be the same as rs1"
CSUB X5, X11 // ERROR "expected integer prime register in rs2"
CSUB X10, X5 // ERROR "expected integer prime register in rd"
CADDW X10, X11, X12 // ERROR "rd must be the same as rs1"
CADDW X5, X11 // ERROR "expected integer prime register in rs2"
CADDW X10, X5 // ERROR "expected integer prime register in rd"
CSUBW X10, X11, X12 // ERROR "rd must be the same as rs1"
CSUBW X5, X11 // ERROR "expected integer prime register in rs2"
CSUBW X10, X5 // ERROR "expected integer prime register in rd"
CNOP X10 // ERROR "expected no register in rs2"
CEBREAK X10 // ERROR "expected no register in rs2"
//
// "V" Standard Extension for Vector Operations, Version 1.0
//

View file

@ -68,7 +68,7 @@ func predefine(defines flags.MultiFlag) map[string]*Macro {
var panicOnError bool // For testing.
func (in *Input) Error(args ...interface{}) {
func (in *Input) Error(args ...any) {
if panicOnError {
panic(fmt.Errorf("%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...)))
}
@ -77,7 +77,7 @@ func (in *Input) Error(args ...interface{}) {
}
// expectText is like Error but adds "got XXX" where XXX is a quoted representation of the most recent token.
func (in *Input) expectText(args ...interface{}) {
func (in *Input) expectText(args ...any) {
in.Error(append(args, "; got", strconv.Quote(in.Stack.Text()))...)
}

View file

@ -58,7 +58,7 @@ func main() {
// nothing
case "index":
// known to compiler; ignore here so people can use
// the same list with -gcflags=-spectre=LIST and -asmflags=-spectrre=LIST
// the same list with -gcflags=-spectre=LIST and -asmflags=-spectre=LIST
case "all", "ret":
ctxt.Retpoline = true
}
@ -93,7 +93,7 @@ func main() {
for _, f := range flag.Args() {
lexer := lex.NewLexer(f)
parser := asm.NewParser(ctxt, architecture, lexer)
ctxt.DiagFunc = func(format string, args ...interface{}) {
ctxt.DiagFunc = func(format string, args ...any) {
diag = true
log.Printf(format, args...)
}

View file

@ -199,7 +199,7 @@ func commentText(g *ast.CommentGroup) string {
return strings.Join(pieces, "")
}
func (f *File) validateIdents(x interface{}, context astContext) {
func (f *File) validateIdents(x any, context astContext) {
if x, ok := x.(*ast.Ident); ok {
if f.isMangledName(x.Name) {
error_(x.Pos(), "identifier %q may conflict with identifiers generated by cgo", x.Name)
@ -208,7 +208,7 @@ func (f *File) validateIdents(x interface{}, context astContext) {
}
// Save various references we are going to need later.
func (f *File) saveExprs(x interface{}, context astContext) {
func (f *File) saveExprs(x any, context astContext) {
switch x := x.(type) {
case *ast.Expr:
switch (*x).(type) {
@ -278,7 +278,7 @@ func (f *File) saveCall(call *ast.CallExpr, context astContext) {
}
// If a function should be exported add it to ExpFunc.
func (f *File) saveExport(x interface{}, context astContext) {
func (f *File) saveExport(x any, context astContext) {
n, ok := x.(*ast.FuncDecl)
if !ok {
return
@ -318,7 +318,7 @@ func (f *File) saveExport(x interface{}, context astContext) {
}
// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
func (f *File) saveExport2(x interface{}, context astContext) {
func (f *File) saveExport2(x any, context astContext) {
n, ok := x.(*ast.FuncDecl)
if !ok {
return
@ -355,7 +355,7 @@ const (
)
// walk walks the AST x, calling visit(f, x, context) for each node.
func (f *File) walk(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
func (f *File) walk(x any, context astContext, visit func(*File, any, astContext)) {
visit(f, x, context)
switch n := x.(type) {
case *ast.Expr:
@ -363,7 +363,8 @@ func (f *File) walk(x interface{}, context astContext, visit func(*File, interfa
// everything else just recurs
default:
f.walkUnexpected(x, context, visit)
error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
case nil:
@ -396,6 +397,9 @@ func (f *File) walk(x interface{}, context astContext, visit func(*File, interfa
case *ast.IndexExpr:
f.walk(&n.X, ctxExpr, visit)
f.walk(&n.Index, ctxExpr, visit)
case *ast.IndexListExpr:
f.walk(&n.X, ctxExpr, visit)
f.walk(n.Indices, ctxExpr, visit)
case *ast.SliceExpr:
f.walk(&n.X, ctxExpr, visit)
if n.Low != nil {
@ -434,8 +438,8 @@ func (f *File) walk(x interface{}, context astContext, visit func(*File, interfa
case *ast.StructType:
f.walk(n.Fields, ctxField, visit)
case *ast.FuncType:
if tparams := funcTypeTypeParams(n); tparams != nil {
f.walk(tparams, ctxParam, visit)
if n.TypeParams != nil {
f.walk(n.TypeParams, ctxParam, visit)
}
f.walk(n.Params, ctxParam, visit)
if n.Results != nil {
@ -524,8 +528,8 @@ func (f *File) walk(x interface{}, context astContext, visit func(*File, interfa
f.walk(n.Values, ctxExpr, visit)
}
case *ast.TypeSpec:
if tparams := typeSpecTypeParams(n); tparams != nil {
f.walk(tparams, ctxParam, visit)
if n.TypeParams != nil {
f.walk(n.TypeParams, ctxParam, visit)
}
f.walk(&n.Type, ctxType, visit)

View file

@ -1,25 +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 compiler_bootstrap
package main
import (
"go/ast"
"go/token"
)
func (f *File) walkUnexpected(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
}
func funcTypeTypeParams(n *ast.FuncType) *ast.FieldList {
return nil
}
func typeSpecTypeParams(n *ast.TypeSpec) *ast.FieldList {
return nil
}

View file

@ -1,32 +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 !compiler_bootstrap
package main
import (
"go/ast"
"go/token"
)
func (f *File) walkUnexpected(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
switch n := x.(type) {
default:
error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
case *ast.IndexListExpr:
f.walk(&n.X, ctxExpr, visit)
f.walk(n.Indices, ctxExpr, visit)
}
}
func funcTypeTypeParams(n *ast.FuncType) *ast.FieldList {
return n.TypeParams
}
func typeSpecTypeParams(n *ast.TypeSpec) *ast.FieldList {
return n.TypeParams
}

View file

@ -127,7 +127,7 @@ environment variable when running the go tool: set it to 1 to enable
the use of cgo, and to 0 to disable it. The go tool will set the
build constraint "cgo" if cgo is enabled. The special import "C"
implies the "cgo" build constraint, as though the file also said
"//go:build cgo". Therefore, if cgo is disabled, files that import
"//go:build cgo". Therefore, if cgo is disabled, files that import
"C" will not be built by the go tool. (For more about build constraints
see https://golang.org/pkg/go/build/#hdr-Build_Constraints).

View file

@ -1056,7 +1056,7 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
// An untyped nil does not need a pointer check, and when
// _cgoCheckPointer returns the untyped nil the type assertion we
// are going to insert will fail. Easier to just skip nil arguments.
// are going to insert will fail. Easier to just skip nil arguments.
// TODO: Note that this fails if nil is shadowed.
if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" {
return false
@ -1158,7 +1158,7 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
// If addPosition is true, add position info to the idents of C names in arg.
func (p *Package) mangle(f *File, arg *ast.Expr, addPosition bool) (ast.Expr, bool) {
needsUnsafe := false
f.walk(arg, ctxExpr, func(f *File, arg interface{}, context astContext) {
f.walk(arg, ctxExpr, func(f *File, arg any, context astContext) {
px, ok := arg.(*ast.Expr)
if !ok {
return
@ -2154,7 +2154,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
for _, s := range f.Symbols {
switch {
case isDebugInts(s.Name):
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
if i := s.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
@ -2167,7 +2167,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
}
}
case isDebugFloats(s.Name):
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
if i := s.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
@ -2181,7 +2181,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
}
default:
if n := indexOfDebugStr(s.Name); n != -1 {
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
if i := s.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
@ -2193,7 +2193,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
break
}
if n := indexOfDebugStrlen(s.Name); n != -1 {
if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
if i := s.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
sect := f.Sections[i]
if s.Value < sect.Size {
if sdat, err := sect.Data(); err == nil {
@ -2439,7 +2439,7 @@ func (tr *TypeRepr) Empty() bool {
// Set modifies the type representation.
// If fargs are provided, repr is used as a format for fmt.Sprintf.
// Otherwise, repr is used unprocessed as the type representation.
func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
func (tr *TypeRepr) Set(repr string, fargs ...any) {
tr.Repr = repr
tr.FormatArgs = fargs
}
@ -2713,7 +2713,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
// so execute the basic things that the struct case would do
// other than try to determine a Go representation.
tt := *t
tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
tt.C = &TypeRepr{"%s %s", []any{dt.Kind, tag}}
// We don't know what the representation of this struct is, so don't let
// anyone allocate one on the Go side. As a side effect of this annotation,
// pointers to this type will not be considered pointers in Go. They won't
@ -2743,7 +2743,7 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
t.Align = align
tt := *t
if tag != "" {
tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
tt.C = &TypeRepr{"struct %s", []any{tag}}
}
tt.Go = g
if c.incompleteStructs[tag] {
@ -3010,7 +3010,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
for i, f := range dtype.ParamType {
// gcc's DWARF generator outputs a single DotDotDotType parameter for
// function pointers that specify no parameters (e.g. void
// (*__cgo_0)()). Treat this special case as void. This case is
// (*__cgo_0)()). Treat this special case as void. This case is
// invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
// legal).
if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
@ -3081,7 +3081,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
off := int64(0)
// Rename struct fields that happen to be named Go keywords into
// _{keyword}. Create a map from C ident -> Go ident. The Go ident will
// _{keyword}. Create a map from C ident -> Go ident. The Go ident will
// be mangled. Any existing identifier that already has the same name on
// the C-side will cause the Go-mangled version to be prefixed with _.
// (e.g. in a struct with fields '_type' and 'type', the latter would be
@ -3309,7 +3309,7 @@ func godefsFields(fld []*ast.Field) {
// fieldPrefix returns the prefix that should be removed from all the
// field names when generating the C or Go code. For generated
// C, we leave the names as is (tv_sec, tv_usec), since that's what
// people are used to seeing in C. For generated Go code, such as
// people are used to seeing in C. For generated Go code, such as
// package syscall's data structures, we drop a common prefix
// (so sec, usec, which will get turned into Sec, Usec for exporting).
func fieldPrefix(fld []*ast.Field) string {
@ -3456,7 +3456,7 @@ func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
// Tagged pointer support
// Low-bit set means tagged object, next 3 bits (currently)
// define the tagged object class, next 4 bits are for type
// information for the specific tagged object class. Thus,
// information for the specific tagged object class. Thus,
// the low byte is for type info, and the rest of a pointer
// (32 or 64-bit) is for payload, whatever the tagged class.
//

View file

@ -117,7 +117,7 @@ func (p *Package) godefs(f *File, args []string) string {
var gofmtBuf strings.Builder
// gofmt returns the gofmt-formatted string for an AST node.
func gofmt(n interface{}) string {
func gofmt(n any) string {
gofmtBuf.Reset()
err := printer.Fprint(&gofmtBuf, fset, n)
if err != nil {

View file

@ -80,7 +80,7 @@ func mustHaveCxx(t *testing.T) {
if len(args) == 0 {
t.Skip("no C++ compiler")
}
testenv.MustHaveExecPath(t, string(args[0]))
testenv.MustHaveExecPath(t, args[0])
}
var (

View file

@ -4,9 +4,9 @@
package cgotest
// Test that we have no more than one build ID. In the past we used
// Test that we have no more than one build ID. In the past we used
// to generate a separate build ID for each package using cgo, and the
// linker concatenated them all. We don't want that--we only want
// linker concatenated them all. We don't want that--we only want
// one.
import (
@ -42,7 +42,7 @@ sections:
for len(d) > 0 {
// ELF standards differ as to the sizes in
// note sections. Both the GNU linker and
// note sections. Both the GNU linker and
// gold always generate 32-bit sizes, so that
// is what we assume here.

View file

@ -40,7 +40,7 @@ func nestedCall(f func()) {
callbackMutex.Unlock()
// Pass the address of i because the C function was written to
// take a pointer. We could pass an int if we felt like
// take a pointer. We could pass an int if we felt like
// rewriting the C code.
C.callback(unsafe.Pointer(&i))

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.
//go:build cgo && darwin
package cgotest
import "testing"
func TestIssue76023(t *testing.T) { issue76023(t) }

View file

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Test that it's OK to have C code that does nothing other than
// initialize a global variable. This used to fail with gccgo.
// initialize a global variable. This used to fail with gccgo.
package gcc68255

View file

@ -0,0 +1,27 @@
// 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.
//go:build darwin
package cgotest
/*
#cgo LDFLAGS: -Wl,-undefined,dynamic_lookup
extern void __gotest_cgo_null_api(void) __attribute__((weak_import));
int issue76023(void) {
if (__gotest_cgo_null_api) return 1;
return 0;
}
*/
import "C"
import "testing"
func issue76023(t *testing.T) {
r := C.issue76023()
if r != 0 {
t.Error("found __gotest_cgo_null_api")
}
}

View file

@ -102,14 +102,14 @@ func testMain(m *testing.M) int {
bin = cmdToRun("./testp")
ccOut := goEnv("CC")
cc = []string{string(ccOut)}
cc = []string{ccOut}
out := goEnv("GOGCCFLAGS")
quote := '\000'
start := 0
lastSpace := true
backslash := false
s := string(out)
s := out
for i, c := range s {
if quote == '\000' && unicode.IsSpace(c) {
if !lastSpace {

View file

@ -76,7 +76,7 @@ func testMain(m *testing.M) int {
start := 0
lastSpace := true
backslash := false
s := string(out)
s := out
for i, c := range s {
if quote == '\000' && unicode.IsSpace(c) {
if !lastSpace {

View file

@ -186,7 +186,7 @@ func cCompilerCmd(t *testing.T) []string {
start := 0
lastSpace := true
backslash := false
s := string(out)
s := out
for i, c := range s {
if quote == '\000' && unicode.IsSpace(c) {
if !lastSpace {

View file

@ -14,6 +14,7 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"slices"
"strings"
"sync/atomic"
@ -24,15 +25,16 @@ var tmp = flag.String("tmp", "", "use `dir` for temporary files and do not clean
// ptrTest is the tests without the boilerplate.
type ptrTest struct {
name string // for reporting
c string // the cgo comment
c1 string // cgo comment forced into non-export cgo file
imports []string // a list of imports
support string // supporting functions
body string // the body of the main function
extra []extra // extra files
fail bool // whether the test should fail
expensive bool // whether the test requires the expensive check
name string // for reporting
c string // the cgo comment
c1 string // cgo comment forced into non-export cgo file
imports []string // a list of imports
support string // supporting functions
body string // the body of the main function
extra []extra // extra files
fail bool // whether the test should fail
expensive bool // whether the test requires the expensive check
errTextRegexp string // error text regexp; if empty, use the pattern `.*unpinned Go.*`
}
type extra struct {
@ -489,6 +491,27 @@ var ptrTests = []ptrTest{
body: `i := 0; a := &[2]unsafe.Pointer{nil, unsafe.Pointer(&i)}; C.f45(&a[0])`,
fail: true,
},
{
// Passing a Go map as argument to C.
name: "argmap",
c: `void f46(void* p) {}`,
imports: []string{"unsafe"},
body: `m := map[int]int{0: 1,}; C.f46(unsafe.Pointer(&m))`,
fail: true,
errTextRegexp: `.*argument of cgo function has Go pointer to unpinned Go map`,
},
{
// Returning a Go map to C.
name: "retmap",
c: `extern void f47();`,
support: `//export GoMap47
func GoMap47() map[int]int { return map[int]int{0: 1,} }`,
body: `C.f47()`,
c1: `extern void* GoMap47();
void f47() { GoMap47(); }`,
fail: true,
errTextRegexp: `.*result of Go function GoMap47 called from cgo is unpinned Go map or points to unpinned Go map.*`,
},
}
func TestPointerChecks(t *testing.T) {
@ -519,7 +542,6 @@ func TestPointerChecks(t *testing.T) {
// after testOne finishes.
var pending int32
for _, pt := range ptrTests {
pt := pt
t.Run(pt.name, func(t *testing.T) {
atomic.AddInt32(&pending, +1)
defer func() {
@ -690,11 +712,17 @@ func testOne(t *testing.T, pt ptrTest, exe, exe2 string) {
}
buf, err := runcmd(cgocheck)
var pattern string = pt.errTextRegexp
if pt.errTextRegexp == "" {
pattern = `.*unpinned Go.*`
}
if pt.fail {
if err == nil {
t.Logf("%s", buf)
t.Fatalf("did not fail as expected")
} else if !bytes.Contains(buf, []byte("Go pointer")) {
} else if ok, _ := regexp.Match(pattern, buf); !ok {
t.Logf("%s", buf)
t.Fatalf("did not print expected error (failed with %v)", err)
}

View file

@ -8,8 +8,8 @@ import (
"bufio"
"bytes"
"fmt"
"internal/testenv"
"internal/goarch"
"internal/testenv"
"os"
"path/filepath"
"regexp"

View file

@ -37,7 +37,7 @@ func TestMain(m *testing.M) {
var tmpDir string
// prettyPrintf prints lines with tmpDir sanitized.
func prettyPrintf(format string, args ...interface{}) {
func prettyPrintf(format string, args ...any) {
s := fmt.Sprintf(format, args...)
if tmpDir != "" {
s = strings.ReplaceAll(s, tmpDir, "$TMPDIR")

View file

@ -5,7 +5,7 @@
//go:build test_run
// Compute Fibonacci numbers with two goroutines
// that pass integers back and forth. No actual
// that pass integers back and forth. No actual
// concurrency, just threads and synchronization
// and foreign code on multiple pthreads.

View file

@ -72,8 +72,8 @@ type File struct {
ExpFunc []*ExpFunc // exported functions for this file
Name map[string]*Name // map from Go name to Name
NamePos map[*Name]token.Pos // map from Name to position of the first reference
NoCallbacks map[string]bool // C function names that with #cgo nocallback directive
NoEscapes map[string]bool // C function names that with #cgo noescape directive
NoCallbacks map[string]bool // C function names with #cgo nocallback directive
NoEscapes map[string]bool // C function names with #cgo noescape directive
Edit *edit.Buffer
debugs []*debug // debug data from iterations of gccDebug. Initialized by File.loadDebug.
@ -148,7 +148,7 @@ type ExpFunc struct {
// A TypeRepr contains the string representation of a type.
type TypeRepr struct {
Repr string
FormatArgs []interface{}
FormatArgs []any
}
// A Type collects information about a type in both the C and Go worlds.

View file

@ -649,13 +649,15 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) {
if p.noEscapes[n.C] && p.noCallbacks[n.C] {
touchFunc = "_Cgo_keepalive"
}
fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
if d.Type.Params != nil {
if len(paramnames) > 0 {
fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
for _, name := range paramnames {
fmt.Fprintf(fgo2, "\t\t%s(%s)\n", touchFunc, name)
}
fmt.Fprintf(fgo2, "\t}\n")
}
fmt.Fprintf(fgo2, "\t}\n")
fmt.Fprintf(fgo2, "\treturn\n")
fmt.Fprintf(fgo2, "}\n")
}
@ -951,7 +953,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
npad := 0
// the align is at least 1 (for char)
maxAlign := int64(1)
argField := func(typ ast.Expr, namePat string, args ...interface{}) {
argField := func(typ ast.Expr, namePat string, args ...any) {
name := fmt.Sprintf(namePat, args...)
t := p.cgoType(typ)
if off%t.Align != 0 {
@ -1144,6 +1146,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
if !p.hasPointer(nil, atype, false) {
return
}
// Use the export'ed file/line in error messages.
pos := fset.Position(exp.Func.Pos())
fmt.Fprintf(fgo2, "//line %s:%d\n", pos.Filename, pos.Line)
fmt.Fprintf(fgo2, "\t_cgoCheckResult(a.r%d)\n", i)
})
}
@ -1406,7 +1412,7 @@ func forFieldList(fl *ast.FieldList, fn func(int, string, ast.Expr)) {
}
}
func c(repr string, args ...interface{}) *TypeRepr {
func c(repr string, args ...any) *TypeRepr {
return &TypeRepr{repr, args}
}

View file

@ -75,7 +75,7 @@ func lineno(pos token.Pos) string {
}
// Die with an error message.
func fatalf(msg string, args ...interface{}) {
func fatalf(msg string, args ...any) {
// If we've already printed other errors, they might have
// caused the fatal condition. Assume they're enough.
if nerrors == 0 {
@ -86,7 +86,7 @@ func fatalf(msg string, args ...interface{}) {
var nerrors int
func error_(pos token.Pos, msg string, args ...interface{}) {
func error_(pos token.Pos, msg string, args ...any) {
nerrors++
if pos.IsValid() {
fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())

View file

@ -289,9 +289,9 @@ dependencies, so is not suitable for distributed build systems.)
```
After that, your edit/compile/test cycle can be similar to:
```
<... make edits to cmd/compile source ...>
[... make edits to cmd/compile source ...]
$ toolstash restore && go install cmd/compile # restore known good tools to build compiler
<... 'go build', 'go test', etc. ...> # use freshly built compiler
[... 'go build', 'go test', etc. ...] # use freshly built compiler
```
* toolstash also allows comparing the installed vs. stashed copy of

View file

@ -28,7 +28,7 @@ type T struct {
type node32 struct {
// Standard conventions hold for left = smaller, right = larger
left, right *node32
data interface{}
data any
key int32
height_ int8
}
@ -49,21 +49,21 @@ func (t *T) IsSingle() bool {
// VisitInOrder applies f to the key and data pairs in t,
// with keys ordered from smallest to largest.
func (t *T) VisitInOrder(f func(int32, interface{})) {
func (t *T) VisitInOrder(f func(int32, any)) {
if t.root == nil {
return
}
t.root.visitInOrder(f)
}
func (n *node32) nilOrData() interface{} {
func (n *node32) nilOrData() any {
if n == nil {
return nil
}
return n.data
}
func (n *node32) nilOrKeyAndData() (k int32, d interface{}) {
func (n *node32) nilOrKeyAndData() (k int32, d any) {
if n == nil {
k = NOT_KEY32
d = nil
@ -83,7 +83,7 @@ func (n *node32) height() int8 {
// Find returns the data associated with x in the tree, or
// nil if x is not in the tree.
func (t *T) Find(x int32) interface{} {
func (t *T) Find(x int32) any {
return t.root.find(x).nilOrData()
}
@ -92,7 +92,7 @@ func (t *T) Find(x int32) interface{} {
// x was already a key in the tree. The previous data associated
// with x is returned, and is nil if x was not previously a
// key in the tree.
func (t *T) Insert(x int32, data interface{}) interface{} {
func (t *T) Insert(x int32, data any) any {
if x == NOT_KEY32 {
panic("Cannot use sentinel value -0x80000000 as key")
}
@ -105,7 +105,7 @@ func (t *T) Insert(x int32, data interface{}) interface{} {
} else {
newroot, n, o = n.aInsert(x)
}
var r interface{}
var r any
if o != nil {
r = o.data
} else {
@ -121,7 +121,7 @@ func (t *T) Copy() *T {
return &u
}
func (t *T) Delete(x int32) interface{} {
func (t *T) Delete(x int32) any {
n := t.root
if n == nil {
return nil
@ -135,7 +135,7 @@ func (t *T) Delete(x int32) interface{} {
return d.data
}
func (t *T) DeleteMin() (int32, interface{}) {
func (t *T) DeleteMin() (int32, any) {
n := t.root
if n == nil {
return NOT_KEY32, nil
@ -149,7 +149,7 @@ func (t *T) DeleteMin() (int32, interface{}) {
return d.key, d.data
}
func (t *T) DeleteMax() (int32, interface{}) {
func (t *T) DeleteMax() (int32, any) {
n := t.root
if n == nil {
return NOT_KEY32, nil
@ -172,7 +172,7 @@ func (t *T) Size() int {
// not be symmetric. If f returns nil, then the key and data are not
// added to the result. If f itself is nil, then whatever value was
// already present in the smaller set is used.
func (t *T) Intersection(u *T, f func(x, y interface{}) interface{}) *T {
func (t *T) Intersection(u *T, f func(x, y any) any) *T {
if t.Size() == 0 || u.Size() == 0 {
return &T{}
}
@ -227,7 +227,7 @@ func (t *T) Intersection(u *T, f func(x, y interface{}) interface{}) *T {
// is given by f(t's data, u's data) -- f need not be symmetric. If f returns nil,
// then the key and data are not added to the result. If f itself is nil, then
// whatever value was already present in the larger set is used.
func (t *T) Union(u *T, f func(x, y interface{}) interface{}) *T {
func (t *T) Union(u *T, f func(x, y any) any) *T {
if t.Size() == 0 {
return u
}
@ -284,7 +284,7 @@ func (t *T) Union(u *T, f func(x, y interface{}) interface{}) *T {
// of f applied to data corresponding to equal keys. If f returns nil
// (or if f is nil) then the key+data are excluded, as usual. If f
// returns not-nil, then that key+data pair is inserted. instead.
func (t *T) Difference(u *T, f func(x, y interface{}) interface{}) *T {
func (t *T) Difference(u *T, f func(x, y any) any) *T {
if t.Size() == 0 {
return &T{}
}
@ -365,7 +365,7 @@ func (t *node32) equals(u *node32) bool {
return it.done() == iu.done()
}
func (t *T) Equiv(u *T, eqv func(x, y interface{}) bool) bool {
func (t *T) Equiv(u *T, eqv func(x, y any) bool) bool {
if t == u {
return true
}
@ -375,7 +375,7 @@ func (t *T) Equiv(u *T, eqv func(x, y interface{}) bool) bool {
return t.root.equiv(u.root, eqv)
}
func (t *node32) equiv(u *node32, eqv func(x, y interface{}) bool) bool {
func (t *node32) equiv(u *node32, eqv func(x, y any) bool) bool {
if t == u {
return true
}
@ -404,7 +404,7 @@ type Iterator struct {
it iterator
}
func (it *Iterator) Next() (int32, interface{}) {
func (it *Iterator) Next() (int32, any) {
x := it.it.next()
if x == nil {
return NOT_KEY32, nil
@ -461,37 +461,37 @@ func (it *iterator) next() *node32 {
// Min returns the minimum element of t.
// If t is empty, then (NOT_KEY32, nil) is returned.
func (t *T) Min() (k int32, d interface{}) {
func (t *T) Min() (k int32, d any) {
return t.root.min().nilOrKeyAndData()
}
// Max returns the maximum element of t.
// If t is empty, then (NOT_KEY32, nil) is returned.
func (t *T) Max() (k int32, d interface{}) {
func (t *T) Max() (k int32, d any) {
return t.root.max().nilOrKeyAndData()
}
// Glb returns the greatest-lower-bound-exclusive of x and the associated
// data. If x has no glb in the tree, then (NOT_KEY32, nil) is returned.
func (t *T) Glb(x int32) (k int32, d interface{}) {
func (t *T) Glb(x int32) (k int32, d any) {
return t.root.glb(x, false).nilOrKeyAndData()
}
// GlbEq returns the greatest-lower-bound-inclusive of x and the associated
// data. If x has no glbEQ in the tree, then (NOT_KEY32, nil) is returned.
func (t *T) GlbEq(x int32) (k int32, d interface{}) {
func (t *T) GlbEq(x int32) (k int32, d any) {
return t.root.glb(x, true).nilOrKeyAndData()
}
// Lub returns the least-upper-bound-exclusive of x and the associated
// data. If x has no lub in the tree, then (NOT_KEY32, nil) is returned.
func (t *T) Lub(x int32) (k int32, d interface{}) {
func (t *T) Lub(x int32) (k int32, d any) {
return t.root.lub(x, false).nilOrKeyAndData()
}
// LubEq returns the least-upper-bound-inclusive of x and the associated
// data. If x has no lubEq in the tree, then (NOT_KEY32, nil) is returned.
func (t *T) LubEq(x int32) (k int32, d interface{}) {
func (t *T) LubEq(x int32) (k int32, d any) {
return t.root.lub(x, true).nilOrKeyAndData()
}
@ -499,7 +499,7 @@ func (t *node32) isLeaf() bool {
return t.left == nil && t.right == nil && t.height_ == LEAF_HEIGHT
}
func (t *node32) visitInOrder(f func(int32, interface{})) {
func (t *node32) visitInOrder(f func(int32, any)) {
if t.left != nil {
t.left.visitInOrder(f)
}

View file

@ -317,7 +317,7 @@ func applicIterator(te *testing.T, x []int32) {
}
}
func equiv(a, b interface{}) bool {
func equiv(a, b any) bool {
sa, sb := a.(*sstring), b.(*sstring)
return *sa == *sb
}
@ -450,16 +450,16 @@ func TestEquals(t *testing.T) {
[]int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2})
}
func first(x, y interface{}) interface{} {
func first(x, y any) any {
return x
}
func second(x, y interface{}) interface{} {
func second(x, y any) any {
return y
}
func alwaysNil(x, y interface{}) interface{} {
func alwaysNil(x, y any) any {
return nil
}
func smaller(x, y interface{}) interface{} {
func smaller(x, y any) any {
xi, _ := strconv.Atoi(fmt.Sprint(x))
yi, _ := strconv.Atoi(fmt.Sprint(y))
if xi < yi {
@ -560,7 +560,7 @@ func (s *sstring) String() string {
return s.s
}
func stringer(s string) interface{} {
func stringer(s string) any {
return &sstring{s}
}

View file

@ -245,6 +245,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpARMADDS,
ssa.OpARMADCS,
ssa.OpARMSUBS:
r := v.Reg0()
r1 := v.Args[0].Reg()

View file

@ -1189,8 +1189,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
if dstReg == srcReg {
break
}
tmpReg1 := int16(arm64.REG_R24)
tmpReg2 := int16(arm64.REG_R25)
tmpReg1 := int16(arm64.REG_R25)
tmpFReg1 := int16(arm64.REG_F16)
tmpFReg2 := int16(arm64.REG_F17)
n := v.AuxInt
if n < 16 {
v.Fatalf("Move too small %d", n)
@ -1198,10 +1199,17 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
// Generate copying instructions.
var off int64
for n >= 32 {
// FLDPQ off(srcReg), (tmpFReg1, tmpFReg2)
// FSTPQ (tmpFReg1, tmpFReg2), off(dstReg)
move32(s, srcReg, dstReg, tmpFReg1, tmpFReg2, off, false)
off += 32
n -= 32
}
for n >= 16 {
// LDP off(srcReg), (tmpReg1, tmpReg2)
// STP (tmpReg1, tmpReg2), off(dstReg)
move16(s, srcReg, dstReg, tmpReg1, tmpReg2, off, false)
// FMOVQ off(src), tmpFReg1
// FMOVQ tmpFReg1, off(dst)
move16(s, srcReg, dstReg, tmpFReg1, off, false)
off += 16
n -= 16
}
@ -1223,9 +1231,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
if dstReg == srcReg {
break
}
countReg := int16(arm64.REG_R23)
tmpReg1 := int16(arm64.REG_R24)
tmpReg2 := int16(arm64.REG_R25)
countReg := int16(arm64.REG_R24)
tmpReg1 := int16(arm64.REG_R25)
tmpFReg1 := int16(arm64.REG_F16)
tmpFReg2 := int16(arm64.REG_F17)
n := v.AuxInt
loopSize := int64(64)
if n < 3*loopSize {
@ -1251,10 +1260,10 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
// Move loopSize bytes starting at srcReg to dstReg.
// Increment srcReg and destReg by loopSize as a side effect.
for range loopSize / 16 {
// LDP.P 16(srcReg), (tmpReg1, tmpReg2)
// STP.P (tmpReg1, tmpReg2), 16(dstReg)
move16(s, srcReg, dstReg, tmpReg1, tmpReg2, 0, true)
for range loopSize / 32 {
// FLDPQ.P 32(srcReg), (tmpFReg1, tmpFReg2)
// FSTPQ.P (tmpFReg1, tmpFReg2), 32(dstReg)
move32(s, srcReg, dstReg, tmpFReg1, tmpFReg2, 0, true)
}
// Decrement loop count.
// SUB $1, countReg
@ -1276,10 +1285,17 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
// Copy any fractional portion.
var off int64
for n >= 32 {
// FLDPQ off(srcReg), (tmpFReg1, tmpFReg2)
// FSTPQ (tmpFReg1, tmpFReg2), off(dstReg)
move32(s, srcReg, dstReg, tmpFReg1, tmpFReg2, off, false)
off += 32
n -= 32
}
for n >= 16 {
// LDP off(srcReg), (tmpReg1, tmpReg2)
// STP (tmpReg1, tmpReg2), off(dstReg)
move16(s, srcReg, dstReg, tmpReg1, tmpReg2, off, false)
// FMOVQ off(src), tmpFReg1
// FMOVQ tmpFReg1, off(dst)
move16(s, srcReg, dstReg, tmpFReg1, off, false)
off += 16
n -= 16
}
@ -1699,26 +1715,55 @@ func zero8(s *ssagen.State, reg int16, off int64) {
p.To.Offset = off
}
// move16 copies 16 bytes at src+off to dst+off.
// move32 copies 32 bytes at src+off to dst+off.
// Uses registers tmp1 and tmp2.
// If postInc is true, increment src and dst by 16.
func move16(s *ssagen.State, src, dst, tmp1, tmp2 int16, off int64, postInc bool) {
// LDP off(src), (tmp1, tmp2)
ld := s.Prog(arm64.ALDP)
// If postInc is true, increment src and dst by 32.
func move32(s *ssagen.State, src, dst, tmp1, tmp2 int16, off int64, postInc bool) {
// FLDPQ off(src), (tmp1, tmp2)
ld := s.Prog(arm64.AFLDPQ)
ld.From.Type = obj.TYPE_MEM
ld.From.Reg = src
ld.From.Offset = off
ld.To.Type = obj.TYPE_REGREG
ld.To.Reg = tmp1
ld.To.Offset = int64(tmp2)
// STP (tmp1, tmp2), off(dst)
st := s.Prog(arm64.ASTP)
// FSTPQ (tmp1, tmp2), off(dst)
st := s.Prog(arm64.AFSTPQ)
st.From.Type = obj.TYPE_REGREG
st.From.Reg = tmp1
st.From.Offset = int64(tmp2)
st.To.Type = obj.TYPE_MEM
st.To.Reg = dst
st.To.Offset = off
if postInc {
if off != 0 {
panic("can't postinc with non-zero offset")
}
ld.Scond = arm64.C_XPOST
st.Scond = arm64.C_XPOST
ld.From.Offset = 32
st.To.Offset = 32
}
}
// move16 copies 16 bytes at src+off to dst+off.
// Uses register tmp1
// If postInc is true, increment src and dst by 16.
func move16(s *ssagen.State, src, dst, tmp1 int16, off int64, postInc bool) {
// FMOVQ off(src), tmp1
ld := s.Prog(arm64.AFMOVQ)
ld.From.Type = obj.TYPE_MEM
ld.From.Reg = src
ld.From.Offset = off
ld.To.Type = obj.TYPE_REG
ld.To.Reg = tmp1
// FMOVQ tmp1, off(dst)
st := s.Prog(arm64.AFMOVQ)
st.From.Type = obj.TYPE_REG
st.From.Reg = tmp1
st.To.Type = obj.TYPE_MEM
st.To.Reg = dst
st.To.Offset = off
if postInc {
if off != 0 {
panic("can't postinc with non-zero offset")

View file

@ -20,6 +20,7 @@ type DebugFlags struct {
Append int `help:"print information about append compilation"`
Checkptr int `help:"instrument unsafe pointer conversions\n0: instrumentation disabled\n1: conversions involving unsafe.Pointer are instrumented\n2: conversions to unsafe.Pointer force heap allocation" concurrent:"ok"`
Closure int `help:"print information about closure compilation"`
Converthash string `help:"hash value for use in debugging changes to platform-dependent float-to-[u]int conversion" concurrent:"ok"`
Defer int `help:"print information about defer compilation"`
DisableNil int `help:"disable nil checks" concurrent:"ok"`
DumpInlFuncProps string `help:"dump function properties from inl heuristics to specified file"`

View file

@ -262,6 +262,12 @@ func ParseFlags() {
Debug.LoopVar = 1
}
if Debug.Converthash != "" {
ConvertHash = NewHashDebug("converthash", Debug.Converthash, nil)
} else {
// quietly disable the convert hash changes
ConvertHash = NewHashDebug("converthash", "qn", nil)
}
if Debug.Fmahash != "" {
FmaHash = NewHashDebug("fmahash", Debug.Fmahash, nil)
}

View file

@ -53,6 +53,7 @@ func (d *HashDebug) SetInlineSuffixOnly(b bool) *HashDebug {
// The default compiler-debugging HashDebug, for "-d=gossahash=..."
var hashDebug *HashDebug
var ConvertHash *HashDebug // for debugging float-to-[u]int conversion changes
var FmaHash *HashDebug // for debugging fused-multiply-add floating point changes
var LoopVarHash *HashDebug // for debugging shared/private loop variable changes
var PGOHash *HashDebug // for debugging PGO optimization decisions

View file

@ -45,7 +45,7 @@ func SyntaxErrors() int {
}
// addErrorMsg adds a new errorMsg (which may be a warning) to errorMsgs.
func addErrorMsg(pos src.XPos, code errors.Code, format string, args ...interface{}) {
func addErrorMsg(pos src.XPos, code errors.Code, format string, args ...any) {
msg := fmt.Sprintf(format, args...)
// Only add the position if know the position.
// See issue golang.org/issue/11361.
@ -108,12 +108,12 @@ func sameline(a, b src.XPos) bool {
}
// Errorf reports a formatted error at the current line.
func Errorf(format string, args ...interface{}) {
func Errorf(format string, args ...any) {
ErrorfAt(Pos, 0, format, args...)
}
// ErrorfAt reports a formatted error message at pos.
func ErrorfAt(pos src.XPos, code errors.Code, format string, args ...interface{}) {
func ErrorfAt(pos src.XPos, code errors.Code, format string, args ...any) {
msg := fmt.Sprintf(format, args...)
if strings.HasPrefix(msg, "syntax error") {
@ -164,7 +164,7 @@ func UpdateErrorDot(line string, name, expr string) {
// In general the Go compiler does NOT generate warnings,
// so this should be used only when the user has opted in
// to additional output by setting a particular flag.
func Warn(format string, args ...interface{}) {
func Warn(format string, args ...any) {
WarnfAt(Pos, format, args...)
}
@ -172,7 +172,7 @@ func Warn(format string, args ...interface{}) {
// In general the Go compiler does NOT generate warnings,
// so this should be used only when the user has opted in
// to additional output by setting a particular flag.
func WarnfAt(pos src.XPos, format string, args ...interface{}) {
func WarnfAt(pos src.XPos, format string, args ...any) {
addErrorMsg(pos, 0, format, args...)
if Flag.LowerM != 0 {
FlushErrors()
@ -191,7 +191,7 @@ func WarnfAt(pos src.XPos, format string, args ...interface{}) {
// prints a stack trace.
//
// If -h has been specified, Fatalf panics to force the usual runtime info dump.
func Fatalf(format string, args ...interface{}) {
func Fatalf(format string, args ...any) {
FatalfAt(Pos, format, args...)
}
@ -209,7 +209,7 @@ var bugStack = counter.NewStack("compile/bug", 16) // 16 is arbitrary; used by g
// prints a stack trace.
//
// If -h has been specified, FatalfAt panics to force the usual runtime info dump.
func FatalfAt(pos src.XPos, format string, args ...interface{}) {
func FatalfAt(pos src.XPos, format string, args ...any) {
FlushErrors()
bugStack.Inc()
@ -244,14 +244,14 @@ func Assert(b bool) {
}
// Assertf reports a fatal error with Fatalf, unless b is true.
func Assertf(b bool, format string, args ...interface{}) {
func Assertf(b bool, format string, args ...any) {
if !b {
Fatalf(format, args...)
}
}
// AssertfAt reports a fatal error with FatalfAt, unless b is true.
func AssertfAt(b bool, pos src.XPos, format string, args ...interface{}) {
func AssertfAt(b bool, pos src.XPos, format string, args ...any) {
if !b {
FatalfAt(pos, format, args...)
}

View file

@ -168,7 +168,7 @@ type lines [][]string
func (lines *lines) add(label string, n int, dt, tot time.Duration, events []*event) {
var line []string
add := func(format string, args ...interface{}) {
add := func(format string, args ...any) {
line = append(line, fmt.Sprintf(format, args...))
}

View file

@ -93,7 +93,7 @@ func (bv BitVec) Unset(i int32) {
bv.B[i/wordBits] &^= mask
}
// bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
// Next returns the smallest index >= i for which bvget(bv, i) == 1.
// If there is no such index, bvnext returns -1.
func (bv BitVec) Next(i int32) int32 {
if i >= bv.N {

View file

@ -131,7 +131,7 @@ func metaHashAndLen() ([16]byte, int) {
}
var hv [16]byte
for i := 0; i < 16; i++ {
nib := string(mhash[i*2 : i*2+2])
nib := mhash[i*2 : i*2+2]
x, err := strconv.ParseInt(nib, 16, 32)
if err != nil {
base.Fatalf("metahash bad byte %q", nib)

View file

@ -18,9 +18,11 @@ import (
"cmd/compile/internal/types"
)
const go126ImprovedConcreteTypeAnalysis = true
// StaticCall devirtualizes the given call if possible when the concrete callee
// is available statically.
func StaticCall(call *ir.CallExpr) {
func StaticCall(s *State, call *ir.CallExpr) {
// For promoted methods (including value-receiver methods promoted
// to pointer-receivers), the interface method wrapper may contain
// expressions that can panic (e.g., ODEREF, ODOTPTR,
@ -40,15 +42,31 @@ func StaticCall(call *ir.CallExpr) {
}
sel := call.Fun.(*ir.SelectorExpr)
r := ir.StaticValue(sel.X)
if r.Op() != ir.OCONVIFACE {
return
}
recv := r.(*ir.ConvExpr)
var typ *types.Type
if go126ImprovedConcreteTypeAnalysis {
typ = concreteType(s, sel.X)
if typ == nil {
return
}
typ := recv.X.Type()
if typ.IsInterface() {
return
// Don't create type-assertions that would be impossible at compile-time.
// This can happen in such case: any(0).(interface {A()}).A(), this typechecks without
// any errors, but will cause a runtime panic. We statically know that int(0) does not
// implement that interface, thus we skip the devirtualization, as it is not possible
// to make an assertion: any(0).(interface{A()}).(int) (int does not implement interface{A()}).
if !typecheck.Implements(typ, sel.X.Type()) {
return
}
} else {
r := ir.StaticValue(sel.X)
if r.Op() != ir.OCONVIFACE {
return
}
recv := r.(*ir.ConvExpr)
typ = recv.X.Type()
if typ.IsInterface() {
return
}
}
// If typ is a shape type, then it was a type argument originally
@ -99,8 +117,27 @@ func StaticCall(call *ir.CallExpr) {
return
}
dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
dt.SetType(typ)
dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, typ)
if go126ImprovedConcreteTypeAnalysis {
// Consider:
//
// var v Iface
// v.A()
// v = &Impl{}
//
// Here in the devirtualizer, we determine the concrete type of v as being an *Impl,
// but it can still be a nil interface, we have not detected that. The v.(*Impl)
// type assertion that we make here would also have failed, but with a different
// panic "pkg.Iface is nil, not *pkg.Impl", where previously we would get a nil panic.
// We fix this, by introducing an additional nilcheck on the itab.
// Calling a method on an nil interface (in most cases) is a bug in a program, so it is fine
// to devirtualize and further (possibly) inline them, even though we would never reach
// the called function.
dt.UseNilPanic = true
dt.SetPos(call.Pos())
}
x := typecheck.XDotMethod(sel.Pos(), dt, sel.Sel, true)
switch x.Op() {
case ir.ODOTMETH:
@ -138,3 +175,413 @@ func StaticCall(call *ir.CallExpr) {
// Desugar OCALLMETH, if we created one (#57309).
typecheck.FixMethodCall(call)
}
const concreteTypeDebug = false
// concreteType determines the concrete type of n, following OCONVIFACEs and type asserts.
// Returns nil when the concrete type could not be determined, or when there are multiple
// (different) types assigned to an interface.
func concreteType(s *State, n ir.Node) (typ *types.Type) {
typ = concreteType1(s, n, make(map[*ir.Name]struct{}))
if typ == &noType {
return nil
}
if typ != nil && typ.IsInterface() {
base.FatalfAt(n.Pos(), "typ.IsInterface() = true; want = false; typ = %v", typ)
}
return typ
}
// noType is a sentinel value returned by [concreteType1].
var noType types.Type
// concreteType1 analyzes the node n and returns its concrete type if it is statically known.
// Otherwise, it returns a nil Type, indicating that a concrete type was not determined.
// When n is known to be statically nil or a self-assignment is detected, in returns a sentinel [noType] type instead.
func concreteType1(s *State, n ir.Node, seen map[*ir.Name]struct{}) (outT *types.Type) {
nn := n // for debug messages
if concreteTypeDebug {
defer func() {
t := "&noType"
if outT != &noType {
t = outT.String()
}
base.Warn("concreteType1(%v) -> %v", nn, t)
}()
}
for {
if concreteTypeDebug {
base.Warn("concreteType1(%v): analyzing %v", nn, n)
}
if !n.Type().IsInterface() {
return n.Type()
}
switch n1 := n.(type) {
case *ir.ConvExpr:
if n1.Op() == ir.OCONVNOP {
if !n1.Type().IsInterface() || !types.Identical(n1.Type().Underlying(), n1.X.Type().Underlying()) {
// As we check (directly before this switch) whether n is an interface, thus we should only reach
// here for iface conversions where both operands are the same.
base.FatalfAt(n1.Pos(), "not identical/interface types found n1.Type = %v; n1.X.Type = %v", n1.Type(), n1.X.Type())
}
n = n1.X
continue
}
if n1.Op() == ir.OCONVIFACE {
n = n1.X
continue
}
case *ir.InlinedCallExpr:
if n1.Op() == ir.OINLCALL {
n = n1.SingleResult()
continue
}
case *ir.ParenExpr:
n = n1.X
continue
case *ir.TypeAssertExpr:
n = n1.X
continue
}
break
}
if n.Op() != ir.ONAME {
return nil
}
name := n.(*ir.Name).Canonical()
if name.Class != ir.PAUTO {
return nil
}
if name.Op() != ir.ONAME {
base.FatalfAt(name.Pos(), "name.Op = %v; want = ONAME", n.Op())
}
// name.Curfn must be set, as we checked name.Class != ir.PAUTO before.
if name.Curfn == nil {
base.FatalfAt(name.Pos(), "name.Curfn = nil; want not nil")
}
if name.Addrtaken() {
return nil // conservatively assume it's reassigned with a different type indirectly
}
if _, ok := seen[name]; ok {
return &noType // Already analyzed assignments to name, no need to do that twice.
}
seen[name] = struct{}{}
if concreteTypeDebug {
base.Warn("concreteType1(%v): analyzing assignments to %v", nn, name)
}
var typ *types.Type
for _, v := range s.assignments(name) {
var t *types.Type
switch v := v.(type) {
case *types.Type:
t = v
case ir.Node:
t = concreteType1(s, v, seen)
if t == &noType {
continue
}
}
if t == nil || (typ != nil && !types.Identical(typ, t)) {
return nil
}
typ = t
}
if typ == nil {
// Variable either declared with zero value, or only assigned with nil.
return &noType
}
return typ
}
// assignment can be one of:
// - nil - assignment from an interface type.
// - *types.Type - assignment from a concrete type (non-interface).
// - ir.Node - assignment from a ir.Node.
//
// In most cases assignment should be an [ir.Node], but in cases where we
// do not follow the data-flow, we return either a concrete type (*types.Type) or a nil.
// For example in range over a slice, if the slice elem is of an interface type, then we return
// a nil, otherwise the elem's concrete type (We do so because we do not analyze assignment to the
// slice being ranged-over).
type assignment any
// State holds precomputed state for use in [StaticCall].
type State struct {
// ifaceAssignments maps interface variables to all their assignments
// defined inside functions stored in the analyzedFuncs set.
// Note: it does not include direct assignments to nil.
ifaceAssignments map[*ir.Name][]assignment
// ifaceCallExprAssigns stores every [*ir.CallExpr], which has an interface
// result, that is assigned to a variable.
ifaceCallExprAssigns map[*ir.CallExpr][]ifaceAssignRef
// analyzedFuncs is a set of Funcs that were analyzed for iface assignments.
analyzedFuncs map[*ir.Func]struct{}
}
type ifaceAssignRef struct {
name *ir.Name // ifaceAssignments[name]
assignmentIndex int // ifaceAssignments[name][assignmentIndex]
returnIndex int // (*ir.CallExpr).Result(returnIndex)
}
// InlinedCall updates the [State] to take into account a newly inlined call.
func (s *State) InlinedCall(fun *ir.Func, origCall *ir.CallExpr, inlinedCall *ir.InlinedCallExpr) {
if _, ok := s.analyzedFuncs[fun]; !ok {
// Full analyze has not been yet executed for the provided function, so we can skip it for now.
// When no devirtualization happens in a function, it is unnecessary to analyze it.
return
}
// Analyze assignments in the newly inlined function.
s.analyze(inlinedCall.Init())
s.analyze(inlinedCall.Body)
refs, ok := s.ifaceCallExprAssigns[origCall]
if !ok {
return
}
delete(s.ifaceCallExprAssigns, origCall)
// Update assignments to reference the new ReturnVars of the inlined call.
for _, ref := range refs {
vt := &s.ifaceAssignments[ref.name][ref.assignmentIndex]
if *vt != nil {
base.Fatalf("unexpected non-nil assignment")
}
if concreteTypeDebug {
base.Warn(
"InlinedCall(%v, %v): replacing interface node in (%v,%v) to %v (typ %v)",
origCall, inlinedCall, ref.name, ref.assignmentIndex,
inlinedCall.ReturnVars[ref.returnIndex],
inlinedCall.ReturnVars[ref.returnIndex].Type(),
)
}
// Update ifaceAssignments with an ir.Node from the inlined functions ReturnVars.
// This may enable future devirtualization of calls that reference ref.name.
// We will get calls to [StaticCall] from the interleaved package,
// to try devirtualize such calls afterwards.
*vt = inlinedCall.ReturnVars[ref.returnIndex]
}
}
// assignments returns all assignments to n.
func (s *State) assignments(n *ir.Name) []assignment {
fun := n.Curfn
if fun == nil {
base.FatalfAt(n.Pos(), "n.Curfn = <nil>")
}
if n.Class != ir.PAUTO {
base.FatalfAt(n.Pos(), "n.Class = %v; want = PAUTO", n.Class)
}
if !n.Type().IsInterface() {
base.FatalfAt(n.Pos(), "name passed to assignments is not of an interface type: %v", n.Type())
}
// Analyze assignments in func, if not analyzed before.
if _, ok := s.analyzedFuncs[fun]; !ok {
if concreteTypeDebug {
base.Warn("assignments(): analyzing assignments in %v func", fun)
}
if s.analyzedFuncs == nil {
s.ifaceAssignments = make(map[*ir.Name][]assignment)
s.ifaceCallExprAssigns = make(map[*ir.CallExpr][]ifaceAssignRef)
s.analyzedFuncs = make(map[*ir.Func]struct{})
}
s.analyzedFuncs[fun] = struct{}{}
s.analyze(fun.Init())
s.analyze(fun.Body)
}
return s.ifaceAssignments[n]
}
// analyze analyzes every assignment to interface variables in nodes, updating [State].
func (s *State) analyze(nodes ir.Nodes) {
assign := func(name ir.Node, assignment assignment) (*ir.Name, int) {
if name == nil || name.Op() != ir.ONAME || ir.IsBlank(name) {
return nil, -1
}
n, ok := ir.OuterValue(name).(*ir.Name)
if !ok || n.Curfn == nil {
return nil, -1
}
// Do not track variables that are not of interface types.
// For devirtualization they are unnecessary, we will not even look them up.
if !n.Type().IsInterface() {
return nil, -1
}
n = n.Canonical()
if n.Op() != ir.ONAME {
base.FatalfAt(n.Pos(), "n.Op = %v; want = ONAME", n.Op())
}
if n.Class != ir.PAUTO {
return nil, -1
}
switch a := assignment.(type) {
case nil:
case *types.Type:
if a != nil && a.IsInterface() {
assignment = nil // non-concrete type
}
case ir.Node:
// nil assignment, we can safely ignore them, see [StaticCall].
if ir.IsNil(a) {
return nil, -1
}
default:
base.Fatalf("unexpected type: %v", assignment)
}
if concreteTypeDebug {
base.Warn("analyze(): assignment found %v = %v", name, assignment)
}
s.ifaceAssignments[n] = append(s.ifaceAssignments[n], assignment)
return n, len(s.ifaceAssignments[n]) - 1
}
var do func(n ir.Node)
do = func(n ir.Node) {
switch n.Op() {
case ir.OAS:
n := n.(*ir.AssignStmt)
if rhs := n.Y; rhs != nil {
for {
if r, ok := rhs.(*ir.ParenExpr); ok {
rhs = r.X
continue
}
break
}
if call, ok := rhs.(*ir.CallExpr); ok && call.Fun != nil {
retTyp := call.Fun.Type().Results()[0].Type
n, idx := assign(n.X, retTyp)
if n != nil && retTyp.IsInterface() {
// We have a call expression, that returns an interface, store it for later evaluation.
// In case this func gets inlined later, we will update the assignment (added before)
// with a reference to ReturnVars, see [State.InlinedCall], which might allow for future devirtualizing of n.X.
s.ifaceCallExprAssigns[call] = append(s.ifaceCallExprAssigns[call], ifaceAssignRef{n, idx, 0})
}
} else {
assign(n.X, rhs)
}
}
case ir.OAS2:
n := n.(*ir.AssignListStmt)
for i, p := range n.Lhs {
if n.Rhs[i] != nil {
assign(p, n.Rhs[i])
}
}
case ir.OAS2DOTTYPE:
n := n.(*ir.AssignListStmt)
if n.Rhs[0] == nil {
base.FatalfAt(n.Pos(), "n.Rhs[0] == nil; n = %v", n)
}
assign(n.Lhs[0], n.Rhs[0])
assign(n.Lhs[1], nil) // boolean does not have methods to devirtualize
case ir.OAS2MAPR, ir.OAS2RECV, ir.OSELRECV2:
n := n.(*ir.AssignListStmt)
if n.Rhs[0] == nil {
base.FatalfAt(n.Pos(), "n.Rhs[0] == nil; n = %v", n)
}
assign(n.Lhs[0], n.Rhs[0].Type())
assign(n.Lhs[1], nil) // boolean does not have methods to devirtualize
case ir.OAS2FUNC:
n := n.(*ir.AssignListStmt)
rhs := n.Rhs[0]
for {
if r, ok := rhs.(*ir.ParenExpr); ok {
rhs = r.X
continue
}
break
}
if call, ok := rhs.(*ir.CallExpr); ok {
for i, p := range n.Lhs {
retTyp := call.Fun.Type().Results()[i].Type
n, idx := assign(p, retTyp)
if n != nil && retTyp.IsInterface() {
// We have a call expression, that returns an interface, store it for later evaluation.
// In case this func gets inlined later, we will update the assignment (added before)
// with a reference to ReturnVars, see [State.InlinedCall], which might allow for future devirtualizing of n.X.
s.ifaceCallExprAssigns[call] = append(s.ifaceCallExprAssigns[call], ifaceAssignRef{n, idx, i})
}
}
} else if call, ok := rhs.(*ir.InlinedCallExpr); ok {
for i, p := range n.Lhs {
assign(p, call.ReturnVars[i])
}
} else {
base.FatalfAt(n.Pos(), "unexpected type %T in OAS2FUNC Rhs[0]", call)
}
case ir.ORANGE:
n := n.(*ir.RangeStmt)
xTyp := n.X.Type()
// Range over an array pointer.
if xTyp.IsPtr() && xTyp.Elem().IsArray() {
xTyp = xTyp.Elem()
}
if xTyp.IsArray() || xTyp.IsSlice() {
assign(n.Key, nil) // integer does not have methods to devirtualize
assign(n.Value, xTyp.Elem())
} else if xTyp.IsChan() {
assign(n.Key, xTyp.Elem())
base.AssertfAt(n.Value == nil, n.Pos(), "n.Value != nil in range over chan")
} else if xTyp.IsMap() {
assign(n.Key, xTyp.Key())
assign(n.Value, xTyp.Elem())
} else if xTyp.IsInteger() || xTyp.IsString() {
// Range over int/string, results do not have methods, so nothing to devirtualize.
assign(n.Key, nil)
assign(n.Value, nil)
} else {
// We will not reach here in case of an range-over-func, as it is
// rewrtten to function calls in the noder package.
base.FatalfAt(n.Pos(), "range over unexpected type %v", n.X.Type())
}
case ir.OSWITCH:
n := n.(*ir.SwitchStmt)
if guard, ok := n.Tag.(*ir.TypeSwitchGuard); ok {
for _, v := range n.Cases {
if v.Var == nil {
base.Assert(guard.Tag == nil)
continue
}
assign(v.Var, guard.X)
}
}
case ir.OCLOSURE:
n := n.(*ir.ClosureExpr)
if _, ok := s.analyzedFuncs[n.Func]; !ok {
s.analyzedFuncs[n.Func] = struct{}{}
ir.Visit(n.Func, do)
}
}
}
ir.VisitList(nodes, do)
}

View file

@ -315,7 +315,7 @@ func CanInline(fn *ir.Func, profile *pgoir.Profile) {
// function is inlinable.
func noteInlinableFunc(n *ir.Name, fn *ir.Func, cost int32) {
if base.Flag.LowerM > 1 {
fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, cost, fn.Type(), ir.Nodes(fn.Body))
fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, cost, fn.Type(), fn.Body)
} else if base.Flag.LowerM != 0 {
fmt.Printf("%v: can inline %v\n", ir.Line(fn), n)
}

View file

@ -45,6 +45,8 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {
inlState := make(map[*ir.Func]*inlClosureState)
calleeUseCounts := make(map[*ir.Func]int)
var state devirtualize.State
// Pre-process all the functions, adding parentheses around call sites and starting their "inl state".
for _, fn := range typecheck.Target.Funcs {
bigCaller := base.Flag.LowerL != 0 && inline.IsBigFunc(fn)
@ -58,7 +60,7 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {
// Do a first pass at counting call sites.
for i := range s.parens {
s.resolve(i)
s.resolve(&state, i)
}
}
@ -102,10 +104,11 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {
for {
for i := l0; i < l1; i++ { // can't use "range parens" here
paren := s.parens[i]
if new := s.edit(i); new != nil {
if origCall, inlinedCall := s.edit(&state, i); inlinedCall != nil {
// Update AST and recursively mark nodes.
paren.X = new
ir.EditChildren(new, s.mark) // mark may append to parens
paren.X = inlinedCall
ir.EditChildren(inlinedCall, s.mark) // mark may append to parens
state.InlinedCall(s.fn, origCall, inlinedCall)
done = false
}
}
@ -114,7 +117,7 @@ func DevirtualizeAndInlinePackage(pkg *ir.Package, profile *pgoir.Profile) {
break
}
for i := l0; i < l1; i++ {
s.resolve(i)
s.resolve(&state, i)
}
}
@ -188,7 +191,7 @@ type inlClosureState struct {
// resolve attempts to resolve a call to a potentially inlineable callee
// and updates use counts on the callees. Returns the call site count
// for that callee.
func (s *inlClosureState) resolve(i int) (*ir.Func, int) {
func (s *inlClosureState) resolve(state *devirtualize.State, i int) (*ir.Func, int) {
p := s.parens[i]
if i < len(s.resolved) {
if callee := s.resolved[i]; callee != nil {
@ -200,7 +203,7 @@ func (s *inlClosureState) resolve(i int) (*ir.Func, int) {
if !ok { // previously inlined
return nil, -1
}
devirtualize.StaticCall(call)
devirtualize.StaticCall(state, call)
if callee := inline.InlineCallTarget(s.fn, call, s.profile); callee != nil {
for len(s.resolved) <= i {
s.resolved = append(s.resolved, nil)
@ -213,23 +216,23 @@ func (s *inlClosureState) resolve(i int) (*ir.Func, int) {
return nil, 0
}
func (s *inlClosureState) edit(i int) ir.Node {
func (s *inlClosureState) edit(state *devirtualize.State, i int) (*ir.CallExpr, *ir.InlinedCallExpr) {
n := s.parens[i].X
call, ok := n.(*ir.CallExpr)
if !ok {
return nil
return nil, nil
}
// This is redundant with earlier calls to
// resolve, but because things can change it
// must be re-checked.
callee, count := s.resolve(i)
callee, count := s.resolve(state, i)
if count <= 0 {
return nil
return nil, nil
}
if inlCall := inline.TryInlineCall(s.fn, call, s.bigCaller, s.profile, count == 1 && callee.ClosureParent != nil); inlCall != nil {
return inlCall
return call, inlCall
}
return nil
return nil, nil
}
// Mark inserts parentheses, and is called repeatedly.
@ -338,16 +341,18 @@ func (s *inlClosureState) unparenthesize() {
// returns.
func (s *inlClosureState) fixpoint() bool {
changed := false
var state devirtualize.State
ir.WithFunc(s.fn, func() {
done := false
for !done {
done = true
for i := 0; i < len(s.parens); i++ { // can't use "range parens" here
paren := s.parens[i]
if new := s.edit(i); new != nil {
if origCall, inlinedCall := s.edit(&state, i); inlinedCall != nil {
// Update AST and recursively mark nodes.
paren.X = new
ir.EditChildren(new, s.mark) // mark may append to parens
paren.X = inlinedCall
ir.EditChildren(inlinedCall, s.mark) // mark may append to parens
state.InlinedCall(s.fn, origCall, inlinedCall)
done = false
changed = true
}

View file

@ -23,7 +23,7 @@ func (f *bitset8) set2(shift uint8, b uint8) {
// Clear old bits.
*(*uint8)(f) &^= 3 << shift
// Set new bits.
*(*uint8)(f) |= uint8(b&3) << shift
*(*uint8)(f) |= (b & 3) << shift
}
type bitset16 uint16

View file

@ -21,7 +21,7 @@ import (
)
// DumpAny is like FDumpAny but prints to stderr.
func DumpAny(root interface{}, filter string, depth int) {
func DumpAny(root any, filter string, depth int) {
FDumpAny(os.Stderr, root, filter, depth)
}
@ -42,7 +42,7 @@ func DumpAny(root interface{}, filter string, depth int) {
// rather than their type; struct fields with zero values or
// non-matching field names are omitted, and "…" means recursion
// depth has been reached or struct fields have been omitted.
func FDumpAny(w io.Writer, root interface{}, filter string, depth int) {
func FDumpAny(w io.Writer, root any, filter string, depth int) {
if root == nil {
fmt.Fprintln(w, "nil")
return
@ -110,7 +110,7 @@ func (p *dumper) Write(data []byte) (n int, err error) {
}
// printf is a convenience wrapper.
func (p *dumper) printf(format string, args ...interface{}) {
func (p *dumper) printf(format string, args ...any) {
if _, err := fmt.Fprintf(p, format, args...); err != nil {
panic(err)
}

View file

@ -617,7 +617,7 @@ func (o Op) IsSlice3() bool {
return false
}
// A SliceHeader expression constructs a slice header from its parts.
// A SliceHeaderExpr constructs a slice header from its parts.
type SliceHeaderExpr struct {
miniExpr
Ptr Node
@ -665,7 +665,7 @@ func NewStarExpr(pos src.XPos, x Node) *StarExpr {
func (n *StarExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }
func (n *StarExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
// A TypeAssertionExpr is a selector expression X.(Type).
// A TypeAssertExpr is a selector expression X.(Type).
// Before type-checking, the type is Ntype.
type TypeAssertExpr struct {
miniExpr
@ -677,6 +677,11 @@ type TypeAssertExpr struct {
// An internal/abi.TypeAssert descriptor to pass to the runtime.
Descriptor *obj.LSym
// When set to true, if this assert would panic, then use a nil pointer panic
// instead of an interface conversion panic.
// It must not be set for type asserts using the commaok form.
UseNilPanic bool
}
func NewTypeAssertExpr(pos src.XPos, x Node, typ *types.Type) *TypeAssertExpr {

View file

@ -90,7 +90,7 @@ type Func struct {
Marks []Mark
FieldTrack map[*obj.LSym]struct{}
DebugInfo interface{}
DebugInfo any
LSym *obj.LSym // Linker object in this function's native ABI (Func.ABI)
Inl *Inline

View file

@ -43,8 +43,8 @@ type Name struct {
Func *Func // TODO(austin): nil for I.M
Offset_ int64
val constant.Value
Opt interface{} // for use by escape analysis
Embed *[]Embed // list of embedded files, for ONAME var
Opt any // for use by escape analysis
Embed *[]Embed // list of embedded files, for ONAME var
// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
// For a closure var, the ONAME node of the original (outermost) captured variable.

View file

@ -16,9 +16,9 @@ func TestSizeof(t *testing.T) {
const _64bit = unsafe.Sizeof(uintptr(0)) == 8
var tests = []struct {
val interface{} // type as a value
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
val any // type as a value
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
{Func{}, 184, 312},
{Name{}, 96, 160},

View file

@ -13,48 +13,51 @@ import (
var Syms symsStruct
type symsStruct struct {
AssertE2I *obj.LSym
AssertE2I2 *obj.LSym
Asanread *obj.LSym
Asanwrite *obj.LSym
CgoCheckMemmove *obj.LSym
CgoCheckPtrWrite *obj.LSym
CheckPtrAlignment *obj.LSym
Deferproc *obj.LSym
Deferprocat *obj.LSym
DeferprocStack *obj.LSym
Deferreturn *obj.LSym
Duffcopy *obj.LSym
Duffzero *obj.LSym
GCWriteBarrier [8]*obj.LSym
Goschedguarded *obj.LSym
Growslice *obj.LSym
InterfaceSwitch *obj.LSym
MallocGC *obj.LSym
Memmove *obj.LSym
Msanread *obj.LSym
Msanwrite *obj.LSym
Msanmove *obj.LSym
Newobject *obj.LSym
Newproc *obj.LSym
PanicBounds *obj.LSym
PanicExtend *obj.LSym
Panicdivide *obj.LSym
Panicshift *obj.LSym
PanicdottypeE *obj.LSym
PanicdottypeI *obj.LSym
Panicnildottype *obj.LSym
Panicoverflow *obj.LSym
PanicSimdImm *obj.LSym
Racefuncenter *obj.LSym
Racefuncexit *obj.LSym
Raceread *obj.LSym
Racereadrange *obj.LSym
Racewrite *obj.LSym
Racewriterange *obj.LSym
TypeAssert *obj.LSym
WBZero *obj.LSym
WBMove *obj.LSym
AssertE2I *obj.LSym
AssertE2I2 *obj.LSym
Asanread *obj.LSym
Asanwrite *obj.LSym
CgoCheckMemmove *obj.LSym
CgoCheckPtrWrite *obj.LSym
CheckPtrAlignment *obj.LSym
Deferproc *obj.LSym
Deferprocat *obj.LSym
DeferprocStack *obj.LSym
Deferreturn *obj.LSym
Duffcopy *obj.LSym
Duffzero *obj.LSym
GCWriteBarrier [8]*obj.LSym
Goschedguarded *obj.LSym
Growslice *obj.LSym
InterfaceSwitch *obj.LSym
MallocGC *obj.LSym
MallocGCSmallNoScan [27]*obj.LSym
MallocGCSmallScanNoHeader [27]*obj.LSym
MallocGCTiny [16]*obj.LSym
Memmove *obj.LSym
Msanread *obj.LSym
Msanwrite *obj.LSym
Msanmove *obj.LSym
Newobject *obj.LSym
Newproc *obj.LSym
PanicBounds *obj.LSym
PanicExtend *obj.LSym
Panicdivide *obj.LSym
Panicshift *obj.LSym
PanicdottypeE *obj.LSym
PanicdottypeI *obj.LSym
Panicnildottype *obj.LSym
Panicoverflow *obj.LSym
PanicSimdImm *obj.LSym
Racefuncenter *obj.LSym
Racefuncexit *obj.LSym
Raceread *obj.LSym
Racereadrange *obj.LSym
Racewrite *obj.LSym
Racewriterange *obj.LSym
TypeAssert *obj.LSym
WBZero *obj.LSym
WBMove *obj.LSym
// Wasm
SigPanic *obj.LSym
Staticuint64s *obj.LSym

View file

@ -224,12 +224,12 @@ type Diagnostic struct {
// A LoggedOpt is what the compiler produces and accumulates,
// to be converted to JSON for human or IDE consumption.
type LoggedOpt struct {
pos src.XPos // Source code position at which the event occurred. If it is inlined, outer and all inlined locations will appear in JSON.
lastPos src.XPos // Usually the same as pos; current exception is for reporting entire range of transformed loops
compilerPass string // Compiler pass. For human/adhoc consumption; does not appear in JSON (yet)
functionName string // Function name. For human/adhoc consumption; does not appear in JSON (yet)
what string // The (non) optimization; "nilcheck", "boundsCheck", "inline", "noInline"
target []interface{} // Optional target(s) or parameter(s) of "what" -- what was inlined, why it was not, size of copy, etc. 1st is most important/relevant.
pos src.XPos // Source code position at which the event occurred. If it is inlined, outer and all inlined locations will appear in JSON.
lastPos src.XPos // Usually the same as pos; current exception is for reporting entire range of transformed loops
compilerPass string // Compiler pass. For human/adhoc consumption; does not appear in JSON (yet)
functionName string // Function name. For human/adhoc consumption; does not appear in JSON (yet)
what string // The (non) optimization; "nilcheck", "boundsCheck", "inline", "noInline"
target []any // Optional target(s) or parameter(s) of "what" -- what was inlined, why it was not, size of copy, etc. 1st is most important/relevant.
}
type logFormat uint8
@ -325,7 +325,7 @@ var mu = sync.Mutex{} // mu protects loggedOpts.
// Pos is the source position (including inlining), what is the message, pass is which pass created the message,
// funcName is the name of the function
// A typical use for this to accumulate an explanation for a missed optimization, for example, why did something escape?
func NewLoggedOpt(pos, lastPos src.XPos, what, pass, funcName string, args ...interface{}) *LoggedOpt {
func NewLoggedOpt(pos, lastPos src.XPos, what, pass, funcName string, args ...any) *LoggedOpt {
pass = strings.ReplaceAll(pass, " ", "_")
return &LoggedOpt{pos, lastPos, pass, funcName, what, args}
}
@ -333,7 +333,7 @@ func NewLoggedOpt(pos, lastPos src.XPos, what, pass, funcName string, args ...in
// LogOpt logs information about a (usually missed) optimization performed by the compiler.
// Pos is the source position (including inlining), what is the message, pass is which pass created the message,
// funcName is the name of the function.
func LogOpt(pos src.XPos, what, pass, funcName string, args ...interface{}) {
func LogOpt(pos src.XPos, what, pass, funcName string, args ...any) {
if Format == None {
return
}
@ -346,7 +346,7 @@ func LogOpt(pos src.XPos, what, pass, funcName string, args ...interface{}) {
// LogOptRange is the same as LogOpt, but includes the ability to express a range of positions,
// not just a point.
func LogOptRange(pos, lastPos src.XPos, what, pass, funcName string, args ...interface{}) {
func LogOptRange(pos, lastPos src.XPos, what, pass, funcName string, args ...any) {
if Format == None {
return
}

View file

@ -692,7 +692,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
// vs
// 16 instructions in the straightline code
// Might as well use straightline code.
v.Fatalf("ZeroLoop size too small %d", n)
v.Fatalf("MoveLoop size too small %d", n)
}
// Put iteration count in a register.
@ -1175,8 +1175,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.From.Type = obj.TYPE_MEM
p.From.Reg = v.Args[0].Reg()
p.AddRestSourceArgs([]obj.Addr{
{Type: obj.TYPE_CONST, Offset: int64((v.AuxInt >> 5) & 0x1fffffffff)},
{Type: obj.TYPE_CONST, Offset: int64((v.AuxInt >> 0) & 0x1f)},
{Type: obj.TYPE_CONST, Offset: (v.AuxInt >> 5) & 0x1fffffffff},
{Type: obj.TYPE_CONST, Offset: (v.AuxInt >> 0) & 0x1f},
})
case ssa.OpLOONG64ADDshiftLLV:

View file

@ -557,7 +557,7 @@ func LogTransformations(transformed []VarAndLoop) {
if logopt.Enabled() {
// For automated checking of coverage of this transformation, include this in the JSON information.
var nString interface{} = n
var nString any = n
if inner != outer {
nString = fmt.Sprintf("%v (from inline)", n)
}

View file

@ -2961,6 +2961,7 @@ func (r *reader) multiExpr() []ir.Node {
as.Def = true
for i := range results {
tmp := r.temp(pos, r.typ())
tmp.Defn = as
as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, tmp))
as.Lhs.Append(tmp)
@ -3576,7 +3577,7 @@ func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlInd
edit(r.curfn)
})
body := ir.Nodes(r.curfn.Body)
body := r.curfn.Body
// Reparent any declarations into the caller function.
for _, name := range r.curfn.Dcl {

View file

@ -120,12 +120,12 @@ func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info, otherInfo ma
}
// errorf reports a user error about thing p.
func (pw *pkgWriter) errorf(p poser, msg string, args ...interface{}) {
func (pw *pkgWriter) errorf(p poser, msg string, args ...any) {
base.ErrorfAt(pw.m.pos(p), 0, msg, args...)
}
// fatalf reports an internal compiler error about thing p.
func (pw *pkgWriter) fatalf(p poser, msg string, args ...interface{}) {
func (pw *pkgWriter) fatalf(p poser, msg string, args ...any) {
base.FatalfAt(pw.m.pos(p), msg, args...)
}

View file

@ -631,7 +631,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p := s.Prog(v.Op.Asm())
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()}
p.Reg = v.Args[0].Reg()
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(sh)}
p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: sh}
p.AddRestSourceArgs([]obj.Addr{{Type: obj.TYPE_CONST, Offset: mb}, {Type: obj.TYPE_CONST, Offset: me}})
// Auxint holds mask

View file

@ -1282,7 +1282,6 @@ func dgcptrmask(t *types.Type, write bool) *obj.LSym {
// word offsets in t that hold pointers.
// ptrmask is assumed to fit at least types.PtrDataSize(t)/PtrSize bits.
func fillptrmask(t *types.Type, ptrmask []byte) {
clear(ptrmask)
if !t.HasPointers() {
return
}

View file

@ -446,6 +446,14 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
case ssa.OpRISCV64FMOVDconst, ssa.OpRISCV64FMOVFconst:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_FCONST
p.From.Val = v.AuxFloat()
p.From.Name = obj.NAME_NONE
p.From.Reg = obj.REG_NONE
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
case ssa.OpRISCV64MOVaddr:
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_ADDR

View file

@ -11,7 +11,7 @@ import (
"cmd/internal/obj/s390x"
)
// clearLoopCutOff is the (somewhat arbitrary) value above which it is better
// clearLoopCutoff is the (somewhat arbitrary) value above which it is better
// to have a loop of clear instructions (e.g. XCs) rather than just generating
// multiple instructions (i.e. loop unrolling).
// Must be between 256 and 4096.

View file

@ -7,6 +7,7 @@
(Add(32|64)F ...) => (ADDS(S|D) ...)
(Add32carry ...) => (ADDLcarry ...)
(Add32withcarry ...) => (ADCL ...)
(Add32carrywithcarry ...) => (ADCLcarry ...)
(Sub(Ptr|32|16|8) ...) => (SUBL ...)
(Sub(32|64)F ...) => (SUBS(S|D) ...)

View file

@ -90,22 +90,23 @@ func init() {
// Common regInfo
var (
gp01 = regInfo{inputs: nil, outputs: gponly}
gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly}
gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
gp11carry = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}}
gp21carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
gp1carry1 = regInfo{inputs: []regMask{gp}, outputs: gponly}
gp2carry1 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}}
gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax}, clobbers: dx}
gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax}
gp11mod = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{dx}, clobbers: ax}
gp21mul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}
gp01 = regInfo{inputs: nil, outputs: gponly}
gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly}
gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
gp11carry = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}}
gp21carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
gp1carry1 = regInfo{inputs: []regMask{gp}, outputs: gponly}
gp2carry1 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
gp2carry1carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}}
gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax}, clobbers: dx}
gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax}
gp11mod = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{dx}, clobbers: ax}
gp21mul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}
gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}}
gp1flags = regInfo{inputs: []regMask{gpsp}}
@ -181,10 +182,11 @@ func init() {
{name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true}, // arg0 + arg1
{name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32", typ: "UInt32", clobberFlags: true}, // arg0 + auxint
{name: "ADDLcarry", argLength: 2, reg: gp21carry, asm: "ADDL", commutative: true, resultInArg0: true}, // arg0 + arg1, generates <carry,result> pair
{name: "ADDLconstcarry", argLength: 1, reg: gp11carry, asm: "ADDL", aux: "Int32", resultInArg0: true}, // arg0 + auxint, generates <carry,result> pair
{name: "ADCL", argLength: 3, reg: gp2carry1, asm: "ADCL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0+arg1+carry(arg2), where arg2 is flags
{name: "ADCLconst", argLength: 2, reg: gp1carry1, asm: "ADCL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0+auxint+carry(arg1), where arg1 is flags
{name: "ADDLcarry", argLength: 2, reg: gp21carry, asm: "ADDL", commutative: true, resultInArg0: true}, // arg0 + arg1, generates <carry,result> pair
{name: "ADDLconstcarry", argLength: 1, reg: gp11carry, asm: "ADDL", aux: "Int32", resultInArg0: true}, // arg0 + auxint, generates <carry,result> pair
{name: "ADCL", argLength: 3, reg: gp2carry1, asm: "ADCL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0+arg1+carry(arg2), where arg2 is flags
{name: "ADCLcarry", argLength: 3, reg: gp2carry1carry, asm: "ADCL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0+arg1+carry(arg2), where arg2 is flags, generates <carry,result> pair
{name: "ADCLconst", argLength: 2, reg: gp1carry1, asm: "ADCL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0+auxint+carry(arg1), where arg1 is flags
{name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true}, // arg0 - arg1
{name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 - auxint

View file

@ -162,10 +162,19 @@
(Cvt64to32F ...) => (CVTSQ2SS ...)
(Cvt64to64F ...) => (CVTSQ2SD ...)
(Cvt32Fto32 ...) => (CVTTSS2SL ...)
(Cvt32Fto64 ...) => (CVTTSS2SQ ...)
(Cvt64Fto32 ...) => (CVTTSD2SL ...)
(Cvt64Fto64 ...) => (CVTTSD2SQ ...)
// Float, to int.
// To make AMD64 "overflow" return max positive instead of max negative, compute
// y and not x, smear the sign bit, and xor.
(Cvt32Fto32 <t> x) && base.ConvertHash.MatchPos(v.Pos, nil) => (XORL <t> y (SARLconst <t> [31] (ANDL <t> y:(CVTTSS2SL <t> x) (NOTL <typ.Int32> (MOVLf2i x)))))
(Cvt64Fto32 <t> x) && base.ConvertHash.MatchPos(v.Pos, nil) => (XORL <t> y (SARLconst <t> [31] (ANDL <t> y:(CVTTSD2SL <t> x) (NOTL <typ.Int32> (MOVLf2i (CVTSD2SS <typ.Float32> x))))))
(Cvt32Fto64 <t> x) && base.ConvertHash.MatchPos(v.Pos, nil) => (XORQ <t> y (SARQconst <t> [63] (ANDQ <t> y:(CVTTSS2SQ <t> x) (NOTQ <typ.Int64> (MOVQf2i (CVTSS2SD <typ.Float64> x))) )))
(Cvt64Fto64 <t> x) && base.ConvertHash.MatchPos(v.Pos, nil) => (XORQ <t> y (SARQconst <t> [63] (ANDQ <t> y:(CVTTSD2SQ <t> x) (NOTQ <typ.Int64> (MOVQf2i x)))))
(Cvt32Fto32 <t> x) && !base.ConvertHash.MatchPos(v.Pos, nil) => (CVTTSS2SL <t> x)
(Cvt32Fto64 <t> x) && !base.ConvertHash.MatchPos(v.Pos, nil) => (CVTTSS2SQ <t> x)
(Cvt64Fto32 <t> x) && !base.ConvertHash.MatchPos(v.Pos, nil) => (CVTTSD2SL <t> x)
(Cvt64Fto64 <t> x) && !base.ConvertHash.MatchPos(v.Pos, nil) => (CVTTSD2SQ <t> x)
(Cvt32Fto64F ...) => (CVTSS2SD ...)
(Cvt64Fto32F ...) => (CVTSD2SS ...)
@ -388,20 +397,30 @@
(CondSelect <t> x y (SET(EQ|NE|L|G|LE|GE|A|B|AE|BE|EQF|NEF|GF|GEF) cond)) && is16BitInt(t)
=> (CMOVW(EQ|NE|LT|GT|LE|GE|HI|CS|CC|LS|EQF|NEF|GTF|GEF) y x cond)
// If the condition does not set the flags, we need to generate a comparison.
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 1
=> (CondSelect <t> x y (MOVBQZX <typ.UInt64> check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 2
=> (CondSelect <t> x y (MOVWQZX <typ.UInt64> check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 4
=> (CondSelect <t> x y (MOVLQZX <typ.UInt64> check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 8 && (is64BitInt(t) || isPtr(t))
=> (CMOVQNE y x (CMPQconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 8 && is32BitInt(t)
=> (CMOVLNE y x (CMPQconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 8 && is16BitInt(t)
=> (CMOVWNE y x (CMPQconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 4 && (is64BitInt(t) || isPtr(t))
=> (CMOVQNE y x (CMPLconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 4 && is32BitInt(t)
=> (CMOVLNE y x (CMPLconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 4 && is16BitInt(t)
=> (CMOVWNE y x (CMPLconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 2 && (is64BitInt(t) || isPtr(t))
=> (CMOVQNE y x (CMPWconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 2 && is32BitInt(t)
=> (CMOVLNE y x (CMPWconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 2 && is16BitInt(t)
=> (CMOVWNE y x (CMPWconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 1 && (is64BitInt(t) || isPtr(t))
=> (CMOVQNE y x (CMPBconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 1 && is32BitInt(t)
=> (CMOVLNE y x (CMPBconst [0] check))
(CondSelect <t> x y check) && !check.Type.IsFlags() && check.Type.Size() == 1 && is16BitInt(t)
=> (CMOVWNE y x (CMPBconst [0] check))
// Absorb InvertFlags
(CMOVQ(EQ|NE|LT|GT|LE|GE|HI|CS|CC|LS) x y (InvertFlags cond))

View file

@ -6,6 +6,7 @@
(Add(32|64)F ...) => (ADD(F|D) ...)
(Add32carry ...) => (ADDS ...)
(Add32withcarry ...) => (ADC ...)
(Add32carrywithcarry ...) => (ADCS ...)
(Sub(Ptr|32|16|8) ...) => (SUB ...)
(Sub(32|64)F ...) => (SUB(F|D) ...)

View file

@ -144,8 +144,9 @@ func init() {
gpspsbg = gpspg | buildReg("SB")
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
r25 = buildReg("R25")
r24to25 = buildReg("R24 R25")
r23to25 = buildReg("R23 R24 R25")
f16to17 = buildReg("F16 F17")
rz = buildReg("ZERO")
first16 = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15")
)
@ -599,8 +600,8 @@ func init() {
aux: "Int64",
argLength: 3,
reg: regInfo{
inputs: []regMask{gp &^ r24to25, gp &^ r24to25},
clobbers: r24to25, // TODO: figure out needIntTemp x2
inputs: []regMask{gp &^ r25, gp &^ r25},
clobbers: r25 | f16to17, // TODO: figure out needIntTemp + x2 for floats
},
faultOnNilArg0: true,
faultOnNilArg1: true,
@ -617,8 +618,8 @@ func init() {
aux: "Int64",
argLength: 3,
reg: regInfo{
inputs: []regMask{gp &^ r23to25, gp &^ r23to25},
clobbers: r23to25, // TODO: figure out needIntTemp x3
inputs: []regMask{gp &^ r24to25, gp &^ r24to25},
clobbers: r24to25 | f16to17, // TODO: figure out needIntTemp x2 + x2 for floats
clobbersArg0: true,
clobbersArg1: true,
},

View file

@ -102,36 +102,37 @@ func init() {
)
// Common regInfo
var (
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
gp11carry = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp, 0}}
gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
gp1flags = regInfo{inputs: []regMask{gpg}}
gp1flags1 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
gp21carry = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, 0}}
gp2flags = regInfo{inputs: []regMask{gpg, gpg}}
gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
gp22 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, gp}}
gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
gp31carry = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp, 0}}
gp3flags = regInfo{inputs: []regMask{gp, gp, gp}}
gp3flags1 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
gp2store = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}}
fp01 = regInfo{inputs: nil, outputs: []regMask{fp}}
fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
fp1flags = regInfo{inputs: []regMask{fp}}
fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}, clobbers: buildReg("F15")} // int-float conversion uses F15 as tmp
gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}, clobbers: buildReg("F15")}
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
fp31 = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}}
fp2flags = regInfo{inputs: []regMask{fp, fp}}
fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
fpstore = regInfo{inputs: []regMask{gpspsbg, fp}}
readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
gp11carry = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp, 0}}
gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
gp1flags = regInfo{inputs: []regMask{gpg}}
gp1flags1 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
gp21carry = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, 0}}
gp2flags = regInfo{inputs: []regMask{gpg, gpg}}
gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
gp2flags1carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
gp22 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, gp}}
gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
gp31carry = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp, 0}}
gp3flags = regInfo{inputs: []regMask{gp, gp, gp}}
gp3flags1 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
gp2store = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}}
fp01 = regInfo{inputs: nil, outputs: []regMask{fp}}
fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
fp1flags = regInfo{inputs: []regMask{fp}}
fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}, clobbers: buildReg("F15")} // int-float conversion uses F15 as tmp
gpfp = regInfo{inputs: []regMask{gp}, outputs: []regMask{fp}, clobbers: buildReg("F15")}
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
fp31 = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}}
fp2flags = regInfo{inputs: []regMask{fp, fp}}
fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
fpstore = regInfo{inputs: []regMask{gpspsbg, fp}}
readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
)
ops := []opData{
// binary ops
@ -161,16 +162,17 @@ func init() {
call: false, // TODO(mdempsky): Should this be true?
},
{name: "ADDS", argLength: 2, reg: gp21carry, asm: "ADD", commutative: true}, // arg0 + arg1, set carry flag
{name: "ADDSconst", argLength: 1, reg: gp11carry, asm: "ADD", aux: "Int32"}, // arg0 + auxInt, set carry flag
{name: "ADC", argLength: 3, reg: gp2flags1, asm: "ADC", commutative: true}, // arg0 + arg1 + carry, arg2=flags
{name: "ADCconst", argLength: 2, reg: gp1flags1, asm: "ADC", aux: "Int32"}, // arg0 + auxInt + carry, arg1=flags
{name: "SUBS", argLength: 2, reg: gp21carry, asm: "SUB"}, // arg0 - arg1, set carry flag
{name: "SUBSconst", argLength: 1, reg: gp11carry, asm: "SUB", aux: "Int32"}, // arg0 - auxInt, set carry flag
{name: "RSBSconst", argLength: 1, reg: gp11carry, asm: "RSB", aux: "Int32"}, // auxInt - arg0, set carry flag
{name: "SBC", argLength: 3, reg: gp2flags1, asm: "SBC"}, // arg0 - arg1 - carry, arg2=flags
{name: "SBCconst", argLength: 2, reg: gp1flags1, asm: "SBC", aux: "Int32"}, // arg0 - auxInt - carry, arg1=flags
{name: "RSCconst", argLength: 2, reg: gp1flags1, asm: "RSC", aux: "Int32"}, // auxInt - arg0 - carry, arg1=flags
{name: "ADDS", argLength: 2, reg: gp21carry, asm: "ADD", commutative: true}, // arg0 + arg1, set carry flag
{name: "ADDSconst", argLength: 1, reg: gp11carry, asm: "ADD", aux: "Int32"}, // arg0 + auxInt, set carry flag
{name: "ADC", argLength: 3, reg: gp2flags1, asm: "ADC", commutative: true}, // arg0 + arg1 + carry, arg2=flags
{name: "ADCconst", argLength: 2, reg: gp1flags1, asm: "ADC", aux: "Int32"}, // arg0 + auxInt + carry, arg1=flags
{name: "ADCS", argLength: 3, reg: gp2flags1carry, asm: "ADC", commutative: true}, // arg0 + arg1 + carrry, sets carry
{name: "SUBS", argLength: 2, reg: gp21carry, asm: "SUB"}, // arg0 - arg1, set carry flag
{name: "SUBSconst", argLength: 1, reg: gp11carry, asm: "SUB", aux: "Int32"}, // arg0 - auxInt, set carry flag
{name: "RSBSconst", argLength: 1, reg: gp11carry, asm: "RSB", aux: "Int32"}, // auxInt - arg0, set carry flag
{name: "SBC", argLength: 3, reg: gp2flags1, asm: "SBC"}, // arg0 - arg1 - carry, arg2=flags
{name: "SBCconst", argLength: 2, reg: gp1flags1, asm: "SBC", aux: "Int32"}, // arg0 - auxInt - carry, arg1=flags
{name: "RSCconst", argLength: 2, reg: gp1flags1, asm: "RSC", aux: "Int32"}, // auxInt - arg0 - carry, arg1=flags
{name: "MULLU", argLength: 2, reg: gp22, asm: "MULLU", commutative: true}, // arg0 * arg1, high 32 bits in out0, low 32 bits in out1
{name: "MULA", argLength: 3, reg: gp31, asm: "MULA"}, // arg0 * arg1 + arg2

View file

@ -611,15 +611,24 @@
(MOVWstore [off] {sym} ptr (MOVWUreg x) mem) => (MOVWstore [off] {sym} ptr x mem)
// register indexed load
(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)
(MOVWload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVWloadidx ptr idx mem)
(MOVHUload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVHUloadidx ptr idx mem)
(MOVHload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVHloadidx ptr idx mem)
(MOVBUload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVBUloadidx ptr idx mem)
(MOVBload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVBloadidx ptr idx mem)
(MOVFload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVFloadidx ptr idx mem)
(MOVDload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVDloadidx ptr idx mem)
(MOVVload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVVloadidx ptr idx mem)
(MOVVload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVVloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVWUload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVWUloadidx ptr idx mem)
(MOVWUload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVWUloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVWload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVWloadidx ptr idx mem)
(MOVWload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVWloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVHUload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVHUloadidx ptr idx mem)
(MOVHUload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVHUloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVHload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVHloadidx ptr idx mem)
(MOVHload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVHloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVBUload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVBUloadidx ptr idx mem)
(MOVBUload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVBUloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVBload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVBloadidx ptr idx mem)
(MOVBload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVBloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVFload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVFloadidx ptr idx mem)
(MOVFload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVFloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVDload [off] {sym} (ADDV ptr idx) mem) && off == 0 && sym == nil => (MOVDloadidx ptr idx mem)
(MOVDload [off] {sym} (ADDshiftLLV [shift] ptr idx) mem) && off == 0 && sym == nil => (MOVDloadidx ptr (SLLVconst <typ.Int64> [shift] idx) mem)
(MOVVloadidx ptr (MOVVconst [c]) mem) && is32Bit(c) => (MOVVload [int32(c)] ptr mem)
(MOVVloadidx (MOVVconst [c]) ptr mem) && is32Bit(c) => (MOVVload [int32(c)] ptr mem)
(MOVWUloadidx ptr (MOVVconst [c]) mem) && is32Bit(c) => (MOVWUload [int32(c)] ptr mem)
@ -640,12 +649,18 @@
(MOVDloadidx (MOVVconst [c]) ptr mem) && is32Bit(c) => (MOVDload [int32(c)] ptr mem)
// register indexed store
(MOVVstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVVstoreidx ptr idx val mem)
(MOVWstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVWstoreidx ptr idx val mem)
(MOVHstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVHstoreidx ptr idx val mem)
(MOVBstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVBstoreidx ptr idx val mem)
(MOVFstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVFstoreidx ptr idx val mem)
(MOVDstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVDstoreidx ptr idx val mem)
(MOVVstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVVstoreidx ptr idx val mem)
(MOVVstore [off] {sym} (ADDshiftLLV [shift] ptr idx) val mem) && off == 0 && sym == nil => (MOVVstoreidx ptr (SLLVconst <typ.Int64> [shift] idx) val mem)
(MOVWstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVWstoreidx ptr idx val mem)
(MOVWstore [off] {sym} (ADDshiftLLV [shift] ptr idx) val mem) && off == 0 && sym == nil => (MOVWstoreidx ptr (SLLVconst <typ.Int64> [shift] idx) val mem)
(MOVHstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVHstoreidx ptr idx val mem)
(MOVHstore [off] {sym} (ADDshiftLLV [shift] ptr idx) val mem) && off == 0 && sym == nil => (MOVHstoreidx ptr (SLLVconst <typ.Int64> [shift] idx) val mem)
(MOVBstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVBstoreidx ptr idx val mem)
(MOVBstore [off] {sym} (ADDshiftLLV [shift] ptr idx) val mem) && off == 0 && sym == nil => (MOVBstoreidx ptr (SLLVconst <typ.Int64> [shift] idx) val mem)
(MOVFstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVFstoreidx ptr idx val mem)
(MOVFstore [off] {sym} (ADDshiftLLV [shift] ptr idx) val mem) && off == 0 && sym == nil => (MOVFstoreidx ptr (SLLVconst <typ.Int64> [shift] idx) val mem)
(MOVDstore [off] {sym} (ADDV ptr idx) val mem) && off == 0 && sym == nil => (MOVDstoreidx ptr idx val mem)
(MOVDstore [off] {sym} (ADDshiftLLV [shift] ptr idx) val mem) && off == 0 && sym == nil => (MOVDstoreidx ptr (SLLVconst <typ.Int64> [shift] idx) val mem)
(MOVVstoreidx ptr (MOVVconst [c]) val mem) && is32Bit(c) => (MOVVstore [int32(c)] ptr val mem)
(MOVVstoreidx (MOVVconst [c]) idx val mem) && is32Bit(c) => (MOVVstore [int32(c)] idx val mem)
(MOVWstoreidx ptr (MOVVconst [c]) val mem) && is32Bit(c) => (MOVWstore [int32(c)] ptr val mem)

View file

@ -143,6 +143,7 @@ func init() {
gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
gpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg, gpg | rz}}
gpoldatom = regInfo{inputs: []regMask{gpspsbg, gpg}}
gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
preldreg = regInfo{inputs: []regMask{gpspg}}
@ -431,6 +432,12 @@ func init() {
faultOnNilArg1: true,
},
// Atomic operations.
//
// resultNotInArgs is needed by all ops lowering to LoongArch
// atomic memory access instructions, because these instructions
// are defined to require rd != rj && rd != rk per the ISA spec.
// atomic loads.
// load from arg0. arg1=mem.
// returns <value,memory> so they can be properly ordered with other loads.
@ -500,8 +507,8 @@ func init() {
// Atomic 32 bit AND/OR.
// *arg0 &= (|=) arg1. arg2=mem. returns nil.
{name: "LoweredAtomicAnd32", argLength: 3, reg: gpxchg, asm: "AMANDDBW", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicOr32", argLength: 3, reg: gpxchg, asm: "AMORDBW", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicAnd32", argLength: 3, reg: gpoldatom, asm: "AMANDDBW", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicOr32", argLength: 3, reg: gpoldatom, asm: "AMORDBW", resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
// Atomic 32,64 bit AND/OR.
// *arg0 &= (|=) arg1. arg2=mem. returns <old content of *arg0, memory>. auxint must be zero.

View file

@ -9,6 +9,12 @@
(Select1 (Add32carry <t> x y)) => (SGTU <typ.Bool> x (ADD <t.FieldType(0)> x y))
(Add32withcarry <t> x y c) => (ADD c (ADD <t> x y))
(Select0 (Add32carrywithcarry <t> x y c)) => (ADD <t.FieldType(0)> c (ADD <t.FieldType(0)> x y))
(Select1 (Add32carrywithcarry <t> x y c)) =>
(OR <typ.Bool>
(SGTU <typ.Bool> x xy:(ADD <t.FieldType(0)> x y))
(SGTU <typ.Bool> xy (ADD <t.FieldType(0)> c xy)))
(Sub(Ptr|32|16|8) ...) => (SUB ...)
(Sub(32|64)F ...) => (SUB(F|D) ...)

View file

@ -18,7 +18,10 @@
(Max(32|64)F x y) && buildcfg.GOPPC64 >= 9 => (XSMAXJDP x y)
// Combine 64 bit integer multiply and adds
(ADD l:(MULLD x y) z) && buildcfg.GOPPC64 >= 9 && l.Uses == 1 && clobber(l) => (MADDLD x y z)
(ADD z l:(MULLD x y)) && buildcfg.GOPPC64 >= 9 && l.Uses == 1 && clobber(l) => (MADDLD x y z )
(ADD z l:(MULLDconst <mt> [x] y)) && buildcfg.GOPPC64 >= 9 && l.Uses == 1 && clobber(l) => (MADDLD (MOVDconst <mt> [int64(x)]) y z )
(ADDconst <at> [z] l:(MULLD x y)) && buildcfg.GOPPC64 >= 9 && l.Uses == 1 && clobber(l) => (MADDLD x y (MOVDconst <at> [int64(z)]))
(ADDconst <at> [z] l:(MULLDconst <mt> [x] y)) && buildcfg.GOPPC64 >= 9 && l.Uses == 1 && clobber(l) => (MADDLD (MOVDconst <mt> [int64(x)]) y (MOVDconst <at> [int64(z)]))
(Mod16 x y) => (Mod32 (SignExt16to32 x) (SignExt16to32 y))
(Mod16u x y) => (Mod32u (ZeroExt16to32 x) (ZeroExt16to32 y))

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