aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/api/goapi.go20
-rw-r--r--src/cmd/asm/internal/asm/asm.go2
-rw-r--r--src/cmd/asm/internal/asm/endtoend_test.go26
-rw-r--r--src/cmd/asm/internal/asm/expr_test.go4
-rw-r--r--src/cmd/asm/internal/asm/line_test.go2
-rw-r--r--src/cmd/asm/internal/asm/operand_test.go24
-rw-r--r--src/cmd/asm/internal/asm/parse.go177
-rw-r--r--src/cmd/asm/internal/asm/pseudo_test.go1
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm64.s4
-rw-r--r--src/cmd/asm/internal/asm/testdata/buildtagerror.s8
-rw-r--r--src/cmd/asm/internal/asm/testdata/ppc64.s2006
-rw-r--r--src/cmd/asm/internal/asm/testdata/ppc64enc.s638
-rw-r--r--src/cmd/asm/internal/asm/testdata/riscvenc.s29
-rw-r--r--src/cmd/asm/internal/flags/flags.go19
-rw-r--r--src/cmd/asm/internal/lex/input.go3
-rw-r--r--src/cmd/asm/internal/lex/lex.go12
-rw-r--r--src/cmd/asm/internal/lex/lex_test.go3
-rw-r--r--src/cmd/asm/internal/lex/tokenizer.go11
-rw-r--r--src/cmd/asm/main.go3
-rw-r--r--src/cmd/cgo/doc.go2
-rw-r--r--src/cmd/cgo/main.go19
-rw-r--r--src/cmd/cgo/out.go286
-rw-r--r--src/cmd/compile/fmtmap_test.go1
-rw-r--r--src/cmd/compile/internal/amd64/ssa.go2
-rw-r--r--src/cmd/compile/internal/arm64/ssa.go18
-rw-r--r--src/cmd/compile/internal/gc/alg.go152
-rw-r--r--src/cmd/compile/internal/gc/align.go12
-rw-r--r--src/cmd/compile/internal/gc/bench_test.go12
-rw-r--r--src/cmd/compile/internal/gc/bexport.go43
-rw-r--r--src/cmd/compile/internal/gc/builtin.go431
-rw-r--r--src/cmd/compile/internal/gc/builtin/runtime.go1
-rw-r--r--src/cmd/compile/internal/gc/closure.go8
-rw-r--r--src/cmd/compile/internal/gc/const.go71
-rw-r--r--src/cmd/compile/internal/gc/dcl.go2
-rw-r--r--src/cmd/compile/internal/gc/dwinl.go4
-rw-r--r--src/cmd/compile/internal/gc/embed.go273
-rw-r--r--src/cmd/compile/internal/gc/esc.go47
-rw-r--r--src/cmd/compile/internal/gc/escape.go47
-rw-r--r--src/cmd/compile/internal/gc/export.go12
-rw-r--r--src/cmd/compile/internal/gc/float_test.go19
-rw-r--r--src/cmd/compile/internal/gc/fmt.go27
-rw-r--r--src/cmd/compile/internal/gc/go.go21
-rw-r--r--src/cmd/compile/internal/gc/gsubr.go4
-rw-r--r--src/cmd/compile/internal/gc/iexport.go21
-rw-r--r--src/cmd/compile/internal/gc/iimport.go10
-rw-r--r--src/cmd/compile/internal/gc/inl.go273
-rw-r--r--src/cmd/compile/internal/gc/inl_test.go3
-rw-r--r--src/cmd/compile/internal/gc/lex.go7
-rw-r--r--src/cmd/compile/internal/gc/main.go119
-rw-r--r--src/cmd/compile/internal/gc/noder.go157
-rw-r--r--src/cmd/compile/internal/gc/obj.go143
-rw-r--r--src/cmd/compile/internal/gc/order.go13
-rw-r--r--src/cmd/compile/internal/gc/pgen.go18
-rw-r--r--src/cmd/compile/internal/gc/plive.go9
-rw-r--r--src/cmd/compile/internal/gc/range.go17
-rw-r--r--src/cmd/compile/internal/gc/reflect.go3
-rw-r--r--src/cmd/compile/internal/gc/scope.go4
-rw-r--r--src/cmd/compile/internal/gc/sinit.go27
-rw-r--r--src/cmd/compile/internal/gc/ssa.go400
-rw-r--r--src/cmd/compile/internal/gc/subr.go189
-rw-r--r--src/cmd/compile/internal/gc/swt.go29
-rw-r--r--src/cmd/compile/internal/gc/syntax.go98
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go71
-rw-r--r--src/cmd/compile/internal/gc/universe.go10
-rw-r--r--src/cmd/compile/internal/gc/walk.go179
-rw-r--r--src/cmd/compile/internal/logopt/logopt_test.go3
-rw-r--r--src/cmd/compile/internal/ppc64/ssa.go55
-rw-r--r--src/cmd/compile/internal/riscv64/ggen.go10
-rw-r--r--src/cmd/compile/internal/riscv64/ssa.go52
-rw-r--r--src/cmd/compile/internal/s390x/ssa.go8
-rw-r--r--src/cmd/compile/internal/ssa/addressingmodes.go8
-rw-r--r--src/cmd/compile/internal/ssa/branchelim.go2
-rw-r--r--src/cmd/compile/internal/ssa/compile.go12
-rw-r--r--src/cmd/compile/internal/ssa/config.go15
-rw-r--r--src/cmd/compile/internal/ssa/decompose.go87
-rw-r--r--src/cmd/compile/internal/ssa/expand_calls.go786
-rw-r--r--src/cmd/compile/internal/ssa/export_test.go4
-rw-r--r--src/cmd/compile/internal/ssa/flagalloc.go5
-rw-r--r--src/cmd/compile/internal/ssa/func.go2
-rw-r--r--src/cmd/compile/internal/ssa/gen/386.rules12
-rw-r--r--src/cmd/compile/internal/ssa/gen/386Ops.go14
-rw-r--r--src/cmd/compile/internal/ssa/gen/AMD64.rules14
-rw-r--r--src/cmd/compile/internal/ssa/gen/AMD64Ops.go2
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM.rules34
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64.rules182
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64Ops.go6
-rw-r--r--src/cmd/compile/internal/ssa/gen/MIPS.rules11
-rw-r--r--src/cmd/compile/internal/ssa/gen/MIPS64.rules6
-rw-r--r--src/cmd/compile/internal/ssa/gen/PPC64.rules46
-rw-r--r--src/cmd/compile/internal/ssa/gen/PPC64Ops.go23
-rw-r--r--src/cmd/compile/internal/ssa/gen/RISCV64.rules127
-rw-r--r--src/cmd/compile/internal/ssa/gen/RISCV64Ops.go56
-rw-r--r--src/cmd/compile/internal/ssa/gen/S390X.rules3
-rw-r--r--src/cmd/compile/internal/ssa/gen/S390XOps.go4
-rw-r--r--src/cmd/compile/internal/ssa/gen/dec64.rules137
-rw-r--r--src/cmd/compile/internal/ssa/gen/generic.rules44
-rw-r--r--src/cmd/compile/internal/ssa/gen/genericOps.go22
-rw-r--r--src/cmd/compile/internal/ssa/gen/rulegen.go109
-rw-r--r--src/cmd/compile/internal/ssa/html.go13
-rw-r--r--src/cmd/compile/internal/ssa/op.go47
-rw-r--r--src/cmd/compile/internal/ssa/opGen.go818
-rw-r--r--src/cmd/compile/internal/ssa/regalloc.go69
-rw-r--r--src/cmd/compile/internal/ssa/rewrite.go181
-rw-r--r--src/cmd/compile/internal/ssa/rewrite386.go88
-rw-r--r--src/cmd/compile/internal/ssa/rewriteAMD64.go54
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM.go421
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM64.go394
-rw-r--r--src/cmd/compile/internal/ssa/rewriteMIPS.go22
-rw-r--r--src/cmd/compile/internal/ssa/rewriteMIPS64.go12
-rw-r--r--src/cmd/compile/internal/ssa/rewritePPC64.go496
-rw-r--r--src/cmd/compile/internal/ssa/rewriteRISCV64.go1043
-rw-r--r--src/cmd/compile/internal/ssa/rewriteS390X.go6
-rw-r--r--src/cmd/compile/internal/ssa/rewrite_test.go181
-rw-r--r--src/cmd/compile/internal/ssa/rewritedec64.go796
-rw-r--r--src/cmd/compile/internal/ssa/rewritegeneric.go220
-rw-r--r--src/cmd/compile/internal/ssa/shortcircuit.go5
-rw-r--r--src/cmd/compile/internal/ssa/value.go3
-rw-r--r--src/cmd/compile/internal/ssa/writebarrier.go6
-rw-r--r--src/cmd/compile/internal/syntax/parser.go10
-rw-r--r--src/cmd/compile/internal/types/type.go14
-rw-r--r--src/cmd/compile/internal/x86/387.go403
-rw-r--r--src/cmd/compile/internal/x86/galign.go16
-rw-r--r--src/cmd/compile/internal/x86/ssa.go2
-rw-r--r--src/cmd/dist/build.go52
-rw-r--r--src/cmd/dist/buildtool.go1
-rw-r--r--src/cmd/dist/cpuid_386.s16
-rw-r--r--src/cmd/dist/cpuid_amd64.s16
-rw-r--r--src/cmd/dist/cpuid_default.s10
-rw-r--r--src/cmd/dist/main.go6
-rw-r--r--src/cmd/dist/test.go63
-rw-r--r--src/cmd/dist/util_gc.go12
-rw-r--r--src/cmd/dist/util_gccgo.go13
-rw-r--r--src/cmd/doc/doc_test.go2
-rw-r--r--src/cmd/doc/pkg.go10
-rw-r--r--src/cmd/fix/gotypes.go6
-rw-r--r--src/cmd/fix/main.go25
-rw-r--r--src/cmd/fix/typecheck.go2
-rw-r--r--src/cmd/go.mod6
-rw-r--r--src/cmd/go.sum12
-rw-r--r--src/cmd/go/alldocs.go51
-rw-r--r--src/cmd/go/go_test.go30
-rw-r--r--src/cmd/go/go_windows_test.go9
-rw-r--r--src/cmd/go/internal/base/goflags.go6
-rw-r--r--src/cmd/go/internal/cache/cache.go3
-rw-r--r--src/cmd/go/internal/cfg/cfg.go12
-rw-r--r--src/cmd/go/internal/clean/clean.go21
-rw-r--r--src/cmd/go/internal/envcmd/env.go41
-rw-r--r--src/cmd/go/internal/fsys/fsys.go679
-rw-r--r--src/cmd/go/internal/fsys/fsys_test.go1095
-rw-r--r--src/cmd/go/internal/get/get.go4
-rw-r--r--src/cmd/go/internal/help/helpdoc.go4
-rw-r--r--src/cmd/go/internal/imports/read.go4
-rw-r--r--src/cmd/go/internal/imports/scan.go15
-rw-r--r--src/cmd/go/internal/imports/tags.go23
-rw-r--r--src/cmd/go/internal/imports/testdata/android/.h.go3
-rw-r--r--src/cmd/go/internal/imports/testdata/illumos/.h.go3
-rw-r--r--src/cmd/go/internal/list/list.go34
-rw-r--r--src/cmd/go/internal/load/pkg.go94
-rw-r--r--src/cmd/go/internal/lockedfile/internal/filelock/filelock.go5
-rw-r--r--src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go6
-rw-r--r--src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go6
-rw-r--r--src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go8
-rw-r--r--src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go4
-rw-r--r--src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go6
-rw-r--r--src/cmd/go/internal/lockedfile/lockedfile.go14
-rw-r--r--src/cmd/go/internal/lockedfile/lockedfile_filelock.go3
-rw-r--r--src/cmd/go/internal/lockedfile/lockedfile_plan9.go9
-rw-r--r--src/cmd/go/internal/modcmd/download.go2
-rw-r--r--src/cmd/go/internal/modcmd/init.go17
-rw-r--r--src/cmd/go/internal/modcmd/vendor.go7
-rw-r--r--src/cmd/go/internal/modcmd/verify.go9
-rw-r--r--src/cmd/go/internal/modfetch/cache.go77
-rw-r--r--src/cmd/go/internal/modfetch/codehost/codehost.go14
-rw-r--r--src/cmd/go/internal/modfetch/codehost/git.go27
-rw-r--r--src/cmd/go/internal/modfetch/codehost/git_test.go6
-rw-r--r--src/cmd/go/internal/modfetch/codehost/shell.go3
-rw-r--r--src/cmd/go/internal/modfetch/codehost/vcs.go5
-rw-r--r--src/cmd/go/internal/modfetch/coderepo.go87
-rw-r--r--src/cmd/go/internal/modfetch/coderepo_test.go30
-rw-r--r--src/cmd/go/internal/modfetch/fetch.go162
-rw-r--r--src/cmd/go/internal/modfetch/proxy.go11
-rw-r--r--src/cmd/go/internal/modfetch/pseudo.go12
-rw-r--r--src/cmd/go/internal/modfetch/repo.go52
-rw-r--r--src/cmd/go/internal/modfetch/sumdb.go11
-rw-r--r--src/cmd/go/internal/modget/get.go30
-rw-r--r--src/cmd/go/internal/modget/mvs.go2
-rw-r--r--src/cmd/go/internal/modload/build.go4
-rw-r--r--src/cmd/go/internal/modload/buildlist.go21
-rw-r--r--src/cmd/go/internal/modload/import.go268
-rw-r--r--src/cmd/go/internal/modload/init.go251
-rw-r--r--src/cmd/go/internal/modload/load.go59
-rw-r--r--src/cmd/go/internal/modload/modfile.go70
-rw-r--r--src/cmd/go/internal/modload/mvs.go48
-rw-r--r--src/cmd/go/internal/modload/query.go587
-rw-r--r--src/cmd/go/internal/modload/query_test.go22
-rw-r--r--src/cmd/go/internal/modload/search.go11
-rw-r--r--src/cmd/go/internal/modload/stat_openfile.go5
-rw-r--r--src/cmd/go/internal/modload/stat_unix.go5
-rw-r--r--src/cmd/go/internal/modload/stat_windows.go6
-rw-r--r--src/cmd/go/internal/modload/testgo.go11
-rw-r--r--src/cmd/go/internal/modload/vendor.go4
-rw-r--r--src/cmd/go/internal/renameio/renameio.go7
-rw-r--r--src/cmd/go/internal/renameio/renameio_test.go10
-rw-r--r--src/cmd/go/internal/renameio/umask_test.go5
-rw-r--r--src/cmd/go/internal/search/search.go12
-rw-r--r--src/cmd/go/internal/test/test.go3
-rw-r--r--src/cmd/go/internal/vcs/vcs.go5
-rw-r--r--src/cmd/go/internal/version/version.go11
-rw-r--r--src/cmd/go/internal/web/api.go11
-rw-r--r--src/cmd/go/internal/web/file_test.go5
-rw-r--r--src/cmd/go/internal/work/build.go5
-rw-r--r--src/cmd/go/internal/work/build_test.go9
-rw-r--r--src/cmd/go/internal/work/buildid.go1
-rw-r--r--src/cmd/go/internal/work/exec.go78
-rw-r--r--src/cmd/go/internal/work/gc.go74
-rw-r--r--src/cmd/go/internal/work/gccgo.go62
-rw-r--r--src/cmd/go/internal/work/init.go16
-rw-r--r--src/cmd/go/internal/work/security.go1
-rw-r--r--src/cmd/go/internal/work/security_test.go3
-rw-r--r--src/cmd/go/proxy_test.go9
-rw-r--r--src/cmd/go/script_test.go7
-rw-r--r--src/cmd/go/testdata/addmod.go3
-rw-r--r--src/cmd/go/testdata/mod/example.com_ambiguous_a_b_v0.0.0-empty.txt12
-rw-r--r--src/cmd/go/testdata/mod/example.com_ambiguous_a_v1.0.0.txt18
-rw-r--r--src/cmd/go/testdata/savedir.go3
-rw-r--r--src/cmd/go/testdata/script/build_cache_arch_mode.txt10
-rw-r--r--src/cmd/go/testdata/script/build_overlay.txt130
-rw-r--r--src/cmd/go/testdata/script/build_trimpath.txt28
-rw-r--r--src/cmd/go/testdata/script/clean_binary.txt78
-rw-r--r--src/cmd/go/testdata/script/env_write.txt54
-rw-r--r--src/cmd/go/testdata/script/gcflags_patterns.txt4
-rw-r--r--src/cmd/go/testdata/script/import_ignore.txt11
-rw-r--r--src/cmd/go/testdata/script/link_syso_issue33139.txt4
-rw-r--r--src/cmd/go/testdata/script/list_overlay.txt63
-rw-r--r--src/cmd/go/testdata/script/mod_bad_domain.txt16
-rw-r--r--src/cmd/go/testdata/script/mod_build_info_err.txt4
-rw-r--r--src/cmd/go/testdata/script/mod_concurrent_unzipinplace.txt17
-rw-r--r--src/cmd/go/testdata/script/mod_download_concurrent_read.txt23
-rw-r--r--src/cmd/go/testdata/script/mod_download_partial.txt1
-rw-r--r--src/cmd/go/testdata/script/mod_get_downgrade_missing.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_get_errors.txt4
-rw-r--r--src/cmd/go/testdata/script/mod_get_replaced.txt111
-rw-r--r--src/cmd/go/testdata/script/mod_gobuild_import.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_indirect.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_init_path.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_init_tidy.txt30
-rw-r--r--src/cmd/go/testdata/script/mod_install_pkg_version.txt6
-rw-r--r--src/cmd/go/testdata/script/mod_list_bad_import.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_list_retract.txt4
-rw-r--r--src/cmd/go/testdata/script/mod_load_badchain.txt13
-rw-r--r--src/cmd/go/testdata/script/mod_load_replace_mismatch.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_outside.txt19
-rw-r--r--src/cmd/go/testdata/script/mod_proxy_invalid.txt4
-rw-r--r--src/cmd/go/testdata/script/mod_query_empty.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_readonly.txt30
-rw-r--r--src/cmd/go/testdata/script/mod_replace_import.txt7
-rw-r--r--src/cmd/go/testdata/script/mod_replace_readonly.txt62
-rw-r--r--src/cmd/go/testdata/script/mod_retract_pseudo_base.txt62
-rw-r--r--src/cmd/go/testdata/script/mod_retract_replace.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_sum_ambiguous.txt48
-rw-r--r--src/cmd/go/testdata/script/mod_sum_readonly.txt87
-rw-r--r--src/cmd/go/testdata/script/mod_sumdb.txt2
-rw-r--r--src/cmd/go/testdata/script/mod_vendor_auto.txt2
-rw-r--r--src/cmd/go/testdata/script/sum_readonly.txt29
-rw-r--r--src/cmd/go/testdata/script/test_cache_inputs.txt4
-rw-r--r--src/cmd/go/testdata/script/toolexec.txt85
-rw-r--r--src/cmd/go/testdata/script/vet_flags.txt16
-rw-r--r--src/cmd/gofmt/gofmt.go11
-rw-r--r--src/cmd/gofmt/long_test.go3
-rw-r--r--src/cmd/internal/buildid/buildid.go9
-rw-r--r--src/cmd/internal/buildid/note.go7
-rw-r--r--src/cmd/internal/moddeps/moddeps_test.go3
-rw-r--r--src/cmd/internal/obj/arm/asm5.go8
-rw-r--r--src/cmd/internal/obj/arm/obj5.go36
-rw-r--r--src/cmd/internal/obj/arm64/a.out.go4
-rw-r--r--src/cmd/internal/obj/arm64/anames.go4
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go96
-rw-r--r--src/cmd/internal/obj/arm64/obj7.go38
-rw-r--r--src/cmd/internal/obj/dwarf.go31
-rw-r--r--src/cmd/internal/obj/ld.go2
-rw-r--r--src/cmd/internal/obj/link.go67
-rw-r--r--src/cmd/internal/obj/mips/asm0.go10
-rw-r--r--src/cmd/internal/obj/mips/obj0.go42
-rw-r--r--src/cmd/internal/obj/objfile.go146
-rw-r--r--src/cmd/internal/obj/objfile_test.go36
-rw-r--r--src/cmd/internal/obj/pass.go6
-rw-r--r--src/cmd/internal/obj/pcln.go28
-rw-r--r--src/cmd/internal/obj/plist.go14
-rw-r--r--src/cmd/internal/obj/ppc64/asm9.go56
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go28
-rw-r--r--src/cmd/internal/obj/riscv/cpu.go12
-rw-r--r--src/cmd/internal/obj/riscv/obj.go109
-rw-r--r--src/cmd/internal/obj/s390x/asmz.go6
-rw-r--r--src/cmd/internal/obj/s390x/objz.go34
-rw-r--r--src/cmd/internal/obj/sizeof_test.go2
-rw-r--r--src/cmd/internal/obj/sym.go8
-rw-r--r--src/cmd/internal/obj/util.go39
-rw-r--r--src/cmd/internal/obj/wasm/wasmobj.go34
-rw-r--r--src/cmd/internal/obj/x86/asm6.go8
-rw-r--r--src/cmd/internal/obj/x86/obj6.go26
-rw-r--r--src/cmd/internal/objabi/funcid.go6
-rw-r--r--src/cmd/internal/objabi/path.go22
-rw-r--r--src/cmd/internal/objabi/reloctype.go8
-rw-r--r--src/cmd/internal/objabi/reloctype_string.go18
-rw-r--r--src/cmd/internal/objfile/goobj.go4
-rw-r--r--src/cmd/internal/pkgpath/pkgpath.go114
-rw-r--r--src/cmd/internal/pkgpath/pkgpath_test.go121
-rw-r--r--src/cmd/internal/sys/supported.go25
-rw-r--r--src/cmd/internal/sys/supported_test.go18
-rw-r--r--src/cmd/link/dwarf_test.go10
-rw-r--r--src/cmd/link/internal/amd64/asm.go69
-rw-r--r--src/cmd/link/internal/arm/asm.go4
-rw-r--r--src/cmd/link/internal/arm64/asm.go165
-rw-r--r--src/cmd/link/internal/arm64/obj.go2
-rw-r--r--src/cmd/link/internal/ld/config.go25
-rw-r--r--src/cmd/link/internal/ld/data.go7
-rw-r--r--src/cmd/link/internal/ld/deadcode.go6
-rw-r--r--src/cmd/link/internal/ld/dwarf_test.go17
-rw-r--r--src/cmd/link/internal/ld/elf.go1143
-rw-r--r--src/cmd/link/internal/ld/go.go3
-rw-r--r--src/cmd/link/internal/ld/ld_test.go77
-rw-r--r--src/cmd/link/internal/ld/lib.go55
-rw-r--r--src/cmd/link/internal/ld/macho.go340
-rw-r--r--src/cmd/link/internal/ld/main.go26
-rw-r--r--src/cmd/link/internal/ld/pcln.go17
-rw-r--r--src/cmd/link/internal/ld/symtab.go75
-rw-r--r--src/cmd/link/internal/loader/loader.go13
-rw-r--r--src/cmd/link/internal/loader/symbolbuilder.go18
-rw-r--r--src/cmd/link/internal/loadmacho/ldmacho.go57
-rw-r--r--src/cmd/link/internal/mips64/obj.go5
-rw-r--r--src/cmd/link/internal/ppc64/asm.go7
-rw-r--r--src/cmd/link/internal/riscv64/asm.go163
-rw-r--r--src/cmd/link/internal/riscv64/obj.go3
-rw-r--r--src/cmd/link/internal/s390x/asm.go2
-rw-r--r--src/cmd/link/internal/x86/asm.go4
-rw-r--r--src/cmd/link/link_test.go56
-rw-r--r--src/cmd/nm/nm_cgo_test.go5
-rw-r--r--src/cmd/nm/nm_test.go3
-rw-r--r--src/cmd/objdump/objdump_test.go94
-rw-r--r--src/cmd/objdump/testdata/testfilenum/a.go7
-rw-r--r--src/cmd/objdump/testdata/testfilenum/b.go7
-rw-r--r--src/cmd/objdump/testdata/testfilenum/c.go7
-rw-r--r--src/cmd/objdump/testdata/testfilenum/go.mod3
-rw-r--r--src/cmd/pack/pack.go3
-rw-r--r--src/cmd/pack/pack_test.go11
-rw-r--r--src/cmd/pprof/pprof.go9
-rw-r--r--src/cmd/trace/trace_test.go10
-rw-r--r--src/cmd/trace/trace_unix_test.go4
-rw-r--r--src/cmd/vendor/github.com/google/pprof/driver/driver.go6
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go132
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go14
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go129
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go281
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/config.go367
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go110
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.go24
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go7
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go177
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go157
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/tempfile.go18
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go238
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go143
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go13
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go2
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/report/report.go11
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/report/source.go6
-rw-r--r--src/cmd/vendor/github.com/google/pprof/profile/profile.go10
-rw-r--r--src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go5
-rw-r--r--src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go32
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go13
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go21
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go10
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go22
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go2
-rw-r--r--src/cmd/vendor/modules.txt6
375 files changed, 16526 insertions, 8622 deletions
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 6a80ed269b..b14d57c236 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -326,6 +326,18 @@ func compareAPI(w io.Writer, features, required, optional, exception []string, a
return
}
+// aliasReplacer applies type aliases to earlier API files,
+// to avoid misleading negative results.
+// This makes all the references to os.FileInfo in go1.txt
+// be read as if they said fs.FileInfo, since os.FileInfo is now an alias.
+// If there are many of these, we could do a more general solution,
+// but for now the replacer is fine.
+var aliasReplacer = strings.NewReplacer(
+ "os.FileInfo", "fs.FileInfo",
+ "os.FileMode", "fs.FileMode",
+ "os.PathError", "fs.PathError",
+)
+
func fileFeatures(filename string) []string {
if filename == "" {
return nil
@@ -334,7 +346,9 @@ func fileFeatures(filename string) []string {
if err != nil {
log.Fatalf("Error reading file %s: %v", filename, err)
}
- lines := strings.Split(string(bs), "\n")
+ s := string(bs)
+ s = aliasReplacer.Replace(s)
+ lines := strings.Split(s, "\n")
var nonblank []string
for _, line := range lines {
line = strings.TrimSpace(line)
@@ -856,6 +870,10 @@ func (w *Walker) emitObj(obj types.Object) {
func (w *Walker) emitType(obj *types.TypeName) {
name := obj.Name()
typ := obj.Type()
+ if obj.IsAlias() {
+ w.emitf("type %s = %s", name, w.typeString(typ))
+ return
+ }
switch typ := typ.Underlying().(type) {
case *types.Struct:
w.emitStructType(name, typ)
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 7878d74549..b9efa454ed 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -181,7 +181,7 @@ func (p *Parser) asmText(operands [][]lex.Token) {
// Argsize set below.
},
}
- nameAddr.Sym.Func.Text = prog
+ nameAddr.Sym.Func().Text = prog
prog.To.Val = int32(argSize)
p.append(prog, "", true)
}
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index 0759b7d10f..989b7a5405 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -31,7 +31,7 @@ func testEndToEnd(t *testing.T, goarch, file string) {
architecture, ctxt := setArch(goarch)
architecture.Init(ctxt)
lexer := lex.NewLexer(input)
- parser := NewParser(ctxt, architecture, lexer)
+ parser := NewParser(ctxt, architecture, lexer, false)
pList := new(obj.Plist)
var ok bool
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
@@ -257,11 +257,11 @@ func isHexes(s string) bool {
return true
}
-// It would be nice if the error messages began with
+// It would be nice if the error messages always began with
// the standard file:line: prefix,
// but that's not where we are today.
// It might be at the beginning but it might be in the middle of the printed instruction.
-var fileLineRE = regexp.MustCompile(`(?:^|\()(testdata[/\\][0-9a-z]+\.s:[0-9]+)(?:$|\))`)
+var fileLineRE = regexp.MustCompile(`(?:^|\()(testdata[/\\][0-9a-z]+\.s:[0-9]+)(?:$|\)|:)`)
// Same as in test/run.go
var (
@@ -273,7 +273,7 @@ func testErrors(t *testing.T, goarch, file string) {
input := filepath.Join("testdata", file+".s")
architecture, ctxt := setArch(goarch)
lexer := lex.NewLexer(input)
- parser := NewParser(ctxt, architecture, lexer)
+ parser := NewParser(ctxt, architecture, lexer, false)
pList := new(obj.Plist)
var ok bool
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
@@ -281,6 +281,7 @@ func testErrors(t *testing.T, goarch, file string) {
defer ctxt.Bso.Flush()
failed := false
var errBuf bytes.Buffer
+ parser.errorWriter = &errBuf
ctxt.DiagFunc = func(format string, args ...interface{}) {
failed = true
s := fmt.Sprintf(format, args...)
@@ -292,7 +293,7 @@ func testErrors(t *testing.T, goarch, file string) {
pList.Firstpc, ok = parser.Parse()
obj.Flushplist(ctxt, pList, nil, "")
if ok && !failed {
- t.Errorf("asm: %s had no errors", goarch)
+ t.Errorf("asm: %s had no errors", file)
}
errors := map[string]string{}
@@ -353,12 +354,7 @@ func testErrors(t *testing.T, goarch, file string) {
}
func Test386EndToEnd(t *testing.T) {
- defer func(old string) { objabi.GO386 = old }(objabi.GO386)
- for _, go386 := range []string{"387", "sse2"} {
- t.Logf("GO386=%v", go386)
- objabi.GO386 = go386
- testEndToEnd(t, "386", "386")
- }
+ testEndToEnd(t, "386", "386")
}
func TestARMEndToEnd(t *testing.T) {
@@ -373,6 +369,10 @@ func TestARMEndToEnd(t *testing.T) {
}
}
+func TestGoBuildErrors(t *testing.T) {
+ testErrors(t, "amd64", "buildtagerror")
+}
+
func TestARMErrors(t *testing.T) {
testErrors(t, "arm", "armerror")
}
@@ -442,10 +442,6 @@ func TestPPC64EndToEnd(t *testing.T) {
testEndToEnd(t, "ppc64", "ppc64")
}
-func TestPPC64Encoder(t *testing.T) {
- testEndToEnd(t, "ppc64", "ppc64enc")
-}
-
func TestRISCVEncoder(t *testing.T) {
testEndToEnd(t, "riscv64", "riscvenc")
}
diff --git a/src/cmd/asm/internal/asm/expr_test.go b/src/cmd/asm/internal/asm/expr_test.go
index 1251594349..e9c92df1f3 100644
--- a/src/cmd/asm/internal/asm/expr_test.go
+++ b/src/cmd/asm/internal/asm/expr_test.go
@@ -57,7 +57,7 @@ var exprTests = []exprTest{
}
func TestExpr(t *testing.T) {
- p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
+ p := NewParser(nil, nil, nil, false) // Expression evaluation uses none of these fields of the parser.
for i, test := range exprTests {
p.start(lex.Tokenize(test.input))
result := int64(p.expr())
@@ -113,7 +113,7 @@ func TestBadExpr(t *testing.T) {
}
func runBadTest(i int, test badExprTest, t *testing.T) (err error) {
- p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
+ p := NewParser(nil, nil, nil, false) // Expression evaluation uses none of these fields of the parser.
p.start(lex.Tokenize(test.input))
return tryParse(t, func() {
p.expr()
diff --git a/src/cmd/asm/internal/asm/line_test.go b/src/cmd/asm/internal/asm/line_test.go
index 01b058bd95..da857ced3a 100644
--- a/src/cmd/asm/internal/asm/line_test.go
+++ b/src/cmd/asm/internal/asm/line_test.go
@@ -39,7 +39,7 @@ func testBadInstParser(t *testing.T, goarch string, tests []badInstTest) {
for i, test := range tests {
arch, ctxt := setArch(goarch)
tokenizer := lex.NewTokenizer("", strings.NewReader(test.input+"\n"), nil)
- parser := NewParser(ctxt, arch, tokenizer)
+ parser := NewParser(ctxt, arch, tokenizer, false)
err := tryParse(t, func() {
parser.Parse()
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index f187d0b166..2e83e176b2 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -28,7 +28,7 @@ func setArch(goarch string) (*arch.Arch, *obj.Link) {
func newParser(goarch string) *Parser {
architecture, ctxt := setArch(goarch)
- return NewParser(ctxt, architecture, nil)
+ return NewParser(ctxt, architecture, nil, false)
}
// tryParse executes parse func in panicOnError=true context.
@@ -75,7 +75,12 @@ func testOperandParser(t *testing.T, parser *Parser, tests []operandTest) {
parser.start(lex.Tokenize(test.input))
addr := obj.Addr{}
parser.operand(&addr)
- result := obj.Dconv(&emptyProg, &addr)
+ var result string
+ if parser.compilingRuntime {
+ result = obj.DconvWithABIDetail(&emptyProg, &addr)
+ } else {
+ result = obj.Dconv(&emptyProg, &addr)
+ }
if result != test.output {
t.Errorf("fail at %s: got %s; expected %s\n", test.input, result, test.output)
}
@@ -86,6 +91,9 @@ func TestAMD64OperandParser(t *testing.T) {
parser := newParser("amd64")
testOperandParser(t, parser, amd64OperandTests)
testBadOperandParser(t, parser, amd64BadOperandTests)
+ parser.compilingRuntime = true
+ testOperandParser(t, parser, amd64RuntimeOperandTests)
+ testBadOperandParser(t, parser, amd64BadOperandRuntimeTests)
}
func Test386OperandParser(t *testing.T) {
@@ -141,7 +149,7 @@ func TestFuncAddress(t *testing.T) {
parser := newParser(sub.arch)
for _, test := range sub.tests {
parser.start(lex.Tokenize(test.input))
- name, ok := parser.funcAddress()
+ name, _, ok := parser.funcAddress()
isFuncSym := strings.HasSuffix(test.input, "(SB)") &&
// Ignore static symbols.
@@ -298,6 +306,11 @@ var amd64OperandTests = []operandTest{
{"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
}
+var amd64RuntimeOperandTests = []operandTest{
+ {"$bar<ABI0>(SB)", "$bar<ABI0>(SB)"},
+ {"$foo<ABIInternal>(SB)", "$foo<ABIInternal>(SB)"},
+}
+
var amd64BadOperandTests = []badOperandTest{
{"[", "register list: expected ']', found EOF"},
{"[4", "register list: bad low register in `[4`"},
@@ -311,6 +324,11 @@ var amd64BadOperandTests = []badOperandTest{
{"[X0-X1-X2]", "register list: expected ']' after `[X0-X1`, found '-'"},
{"[X0,X3]", "register list: expected '-' after `[X0`, found ','"},
{"[X0,X1,X2,X3]", "register list: expected '-' after `[X0`, found ','"},
+ {"$foo<ABI0>", "ABI selector only permitted when compiling runtime, reference was to \"foo\""},
+}
+
+var amd64BadOperandRuntimeTests = []badOperandTest{
+ {"$foo<bletch>", "malformed ABI selector \"bletch\" in reference to \"foo\""},
}
var x86OperandTests = []operandTest{
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index 17d40ee415..154cf9c7a7 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -25,24 +25,26 @@ import (
)
type Parser struct {
- lex lex.TokenReader
- lineNum int // Line number in source file.
- errorLine int // Line number of last error.
- errorCount int // Number of errors.
- pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
- input []lex.Token
- inputPos int
- pendingLabels []string // Labels to attach to next instruction.
- labels map[string]*obj.Prog
- toPatch []Patch
- addr []obj.Addr
- arch *arch.Arch
- ctxt *obj.Link
- firstProg *obj.Prog
- lastProg *obj.Prog
- dataAddr map[string]int64 // Most recent address for DATA for this symbol.
- isJump bool // Instruction being assembled is a jump.
- errorWriter io.Writer
+ lex lex.TokenReader
+ lineNum int // Line number in source file.
+ errorLine int // Line number of last error.
+ errorCount int // Number of errors.
+ sawCode bool // saw code in this file (as opposed to comments and blank lines)
+ pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
+ input []lex.Token
+ inputPos int
+ pendingLabels []string // Labels to attach to next instruction.
+ labels map[string]*obj.Prog
+ toPatch []Patch
+ addr []obj.Addr
+ arch *arch.Arch
+ ctxt *obj.Link
+ firstProg *obj.Prog
+ lastProg *obj.Prog
+ dataAddr map[string]int64 // Most recent address for DATA for this symbol.
+ isJump bool // Instruction being assembled is a jump.
+ compilingRuntime bool
+ errorWriter io.Writer
}
type Patch struct {
@@ -50,14 +52,15 @@ type Patch struct {
label string
}
-func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
+func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader, compilingRuntime bool) *Parser {
return &Parser{
- ctxt: ctxt,
- arch: ar,
- lex: lexer,
- labels: make(map[string]*obj.Prog),
- dataAddr: make(map[string]int64),
- errorWriter: os.Stderr,
+ ctxt: ctxt,
+ arch: ar,
+ lex: lexer,
+ labels: make(map[string]*obj.Prog),
+ dataAddr: make(map[string]int64),
+ errorWriter: os.Stderr,
+ compilingRuntime: compilingRuntime,
}
}
@@ -132,6 +135,30 @@ func (p *Parser) ParseSymABIs(w io.Writer) bool {
return p.errorCount == 0
}
+// nextToken returns the next non-build-comment token from the lexer.
+// It reports misplaced //go:build comments but otherwise discards them.
+func (p *Parser) nextToken() lex.ScanToken {
+ for {
+ tok := p.lex.Next()
+ if tok == lex.BuildComment {
+ if p.sawCode {
+ p.errorf("misplaced //go:build comment")
+ }
+ continue
+ }
+ if tok != '\n' {
+ p.sawCode = true
+ }
+ if tok == '#' {
+ // A leftover wisp of a #include/#define/etc,
+ // to let us know that p.sawCode should be true now.
+ // Otherwise ignored.
+ continue
+ }
+ return tok
+ }
+}
+
// line consumes a single assembly line from p.lex of the form
//
// {label:} WORD[.cond] [ arg {, arg} ] (';' | '\n')
@@ -146,7 +173,7 @@ next:
// Skip newlines.
var tok lex.ScanToken
for {
- tok = p.lex.Next()
+ tok = p.nextToken()
// We save the line number here so error messages from this instruction
// are labeled with this line. Otherwise we complain after we've absorbed
// the terminating newline and the line numbers are off by one in errors.
@@ -179,11 +206,11 @@ next:
items = make([]lex.Token, 0, 3)
}
for {
- tok = p.lex.Next()
+ tok = p.nextToken()
if len(operands) == 0 && len(items) == 0 {
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' {
// Suffixes: ARM conditionals or x86 modifiers.
- tok = p.lex.Next()
+ tok = p.nextToken()
str := p.lex.Text()
if tok != scanner.Ident {
p.errorf("instruction suffix expected identifier, found %s", str)
@@ -285,8 +312,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
// Defines text symbol in operands[0].
if len(operands) > 0 {
p.start(operands[0])
- if name, ok := p.funcAddress(); ok {
- fmt.Fprintf(w, "def %s ABI0\n", name)
+ if name, abi, ok := p.funcAddress(); ok {
+ fmt.Fprintf(w, "def %s %s\n", name, abi)
}
}
return
@@ -304,8 +331,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
// Search for symbol references.
for _, op := range operands {
p.start(op)
- if name, ok := p.funcAddress(); ok {
- fmt.Fprintf(w, "ref %s ABI0\n", name)
+ if name, abi, ok := p.funcAddress(); ok {
+ fmt.Fprintf(w, "ref %s %s\n", name, abi)
}
}
}
@@ -740,20 +767,19 @@ func (p *Parser) symbolReference(a *obj.Addr, name string, prefix rune) {
case '*':
a.Type = obj.TYPE_INDIR
}
- // Weirdness with statics: Might now have "<>".
- isStatic := false
- if p.peek() == '<' {
- isStatic = true
- p.next()
- p.get('>')
- }
+
+ // Parse optional <> (indicates a static symbol) or
+ // <ABIxxx> (selecting text symbol with specific ABI).
+ doIssueError := true
+ isStatic, abi := p.symRefAttrs(name, doIssueError)
+
if p.peek() == '+' || p.peek() == '-' {
a.Offset = int64(p.expr())
}
if isStatic {
a.Sym = p.ctxt.LookupStatic(name)
} else {
- a.Sym = p.ctxt.Lookup(name)
+ a.Sym = p.ctxt.LookupABI(name, abi)
}
if p.peek() == scanner.EOF {
if prefix == 0 && p.isJump {
@@ -798,12 +824,60 @@ func (p *Parser) setPseudoRegister(addr *obj.Addr, reg string, isStatic bool, pr
}
}
+// symRefAttrs parses an optional function symbol attribute clause for
+// the function symbol 'name', logging an error for a malformed
+// attribute clause if 'issueError' is true. The return value is a
+// (boolean, ABI) pair indicating that the named symbol is either
+// static or a particular ABI specification.
+//
+// The expected form of the attribute clause is:
+//
+// empty, yielding (false, obj.ABI0)
+// "<>", yielding (true, obj.ABI0)
+// "<ABI0>" yielding (false, obj.ABI0)
+// "<ABIInternal>" yielding (false, obj.ABIInternal)
+//
+// Anything else beginning with "<" logs an error if issueError is
+// true, otherwise returns (false, obj.ABI0).
+//
+func (p *Parser) symRefAttrs(name string, issueError bool) (bool, obj.ABI) {
+ abi := obj.ABI0
+ isStatic := false
+ if p.peek() != '<' {
+ return isStatic, abi
+ }
+ p.next()
+ tok := p.peek()
+ if tok == '>' {
+ isStatic = true
+ } else if tok == scanner.Ident {
+ abistr := p.get(scanner.Ident).String()
+ if !p.compilingRuntime {
+ if issueError {
+ p.errorf("ABI selector only permitted when compiling runtime, reference was to %q", name)
+ }
+ } else {
+ theabi, valid := obj.ParseABI(abistr)
+ if !valid {
+ if issueError {
+ p.errorf("malformed ABI selector %q in reference to %q",
+ abistr, name)
+ }
+ } else {
+ abi = theabi
+ }
+ }
+ }
+ p.get('>')
+ return isStatic, abi
+}
+
// funcAddress parses an external function address. This is a
// constrained form of the operand syntax that's always SB-based,
// non-static, and has at most a simple integer offset:
//
-// [$|*]sym[+Int](SB)
-func (p *Parser) funcAddress() (string, bool) {
+// [$|*]sym[<abi>][+Int](SB)
+func (p *Parser) funcAddress() (string, obj.ABI, bool) {
switch p.peek() {
case '$', '*':
// Skip prefix.
@@ -813,25 +887,32 @@ func (p *Parser) funcAddress() (string, bool) {
tok := p.next()
name := tok.String()
if tok.ScanToken != scanner.Ident || p.atStartOfRegister(name) {
- return "", false
+ return "", obj.ABI0, false
+ }
+ // Parse optional <> (indicates a static symbol) or
+ // <ABIxxx> (selecting text symbol with specific ABI).
+ noErrMsg := false
+ isStatic, abi := p.symRefAttrs(name, noErrMsg)
+ if isStatic {
+ return "", obj.ABI0, false // This function rejects static symbols.
}
tok = p.next()
if tok.ScanToken == '+' {
if p.next().ScanToken != scanner.Int {
- return "", false
+ return "", obj.ABI0, false
}
tok = p.next()
}
if tok.ScanToken != '(' {
- return "", false
+ return "", obj.ABI0, false
}
if reg := p.next(); reg.ScanToken != scanner.Ident || reg.String() != "SB" {
- return "", false
+ return "", obj.ABI0, false
}
if p.next().ScanToken != ')' || p.peek() != scanner.EOF {
- return "", false
+ return "", obj.ABI0, false
}
- return name, true
+ return name, abi, true
}
// registerIndirect parses the general form of a register indirection.
diff --git a/src/cmd/asm/internal/asm/pseudo_test.go b/src/cmd/asm/internal/asm/pseudo_test.go
index 100bef91cf..622ee25ce7 100644
--- a/src/cmd/asm/internal/asm/pseudo_test.go
+++ b/src/cmd/asm/internal/asm/pseudo_test.go
@@ -37,6 +37,7 @@ func TestErroneous(t *testing.T) {
{"TEXT", "$0É:0, 0, $1", "expected end of operand, found É"}, // Issue #12467.
{"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468.
{"TEXT", "@B(SB),0,$0", "expected '(', found B"}, // Issue 23580.
+ {"TEXT", "foo<ABIInternal>(SB),0", "ABI selector only permitted when compiling runtime, reference was to \"foo\""},
{"FUNCDATA", "", "expect two operands for FUNCDATA"},
{"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"},
{"DATA", "", "expect two operands for DATA"},
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index e277c04b7c..7f495b90bb 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -81,6 +81,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
SHA512H2 V4.D2, V3, V2 // 628464ce
SHA512SU0 V9.D2, V8.D2 // 2881c0ce
SHA512SU1 V7.D2, V6.D2, V5.D2 // c58867ce
+ VRAX1 V26.D2, V29.D2, V30.D2 // be8f7ace
+ VXAR $63, V27.D2, V21.D2, V26.D2 // bafe9bce
VADDV V0.S4, V0 // 00b8b14e
VMOVI $82, V0.B16 // 40e6024f
VUADDLV V6.B16, V6 // c638306e
@@ -139,6 +141,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
VTBL V14.B16, [V3.B16, V4.B16, V5.B16], V17.B16 // 71400e4e
VTBL V13.B16, [V29.B16, V30.B16, V31.B16, V0.B16], V28.B16 // bc630d4e
VTBL V3.B8, [V27.B16], V8.B8 // 6803030e
+ VEOR3 V2.B16, V7.B16, V12.B16, V25.B16 // 990907ce
+ VBCAX V1.B16, V2.B16, V26.B16, V31.B16 // 5f0722ce
VZIP1 V16.H8, V3.H8, V19.H8 // 7338504e
VZIP2 V22.D2, V25.D2, V21.D2 // 357bd64e
VZIP1 V6.D2, V9.D2, V11.D2 // 2b39c64e
diff --git a/src/cmd/asm/internal/asm/testdata/buildtagerror.s b/src/cmd/asm/internal/asm/testdata/buildtagerror.s
new file mode 100644
index 0000000000..5a2d65b978
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/buildtagerror.s
@@ -0,0 +1,8 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define X 1
+
+//go:build x // ERROR "misplaced //go:build comment"
+
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
index ba64d84a35..2b1191c44b 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64.s
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -2,1311 +2,717 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This input was created by taking the instruction productions in
-// the old assembler's (9a's) grammar and hand-writing complete
-// instructions for each rule, to guarantee we cover the same space.
+// This contains the majority of valid opcode combinations
+// available in cmd/internal/obj/ppc64/asm9.go with
+// their valid instruction encodings.
#include "../../../../../runtime/textflag.h"
-TEXT foo(SB),DUPOK|NOSPLIT,$0
+TEXT asmtest(SB),DUPOK|NOSPLIT,$0
+ // move constants
+ MOVD $1, R3 // 38600001
+ MOVD $-1, R4 // 3880ffff
+ MOVD $65535, R5 // 6005ffff
+ MOVD $65536, R6 // 64060001
+ MOVD $-32767, R5 // 38a08001
+ MOVD $-32768, R6 // 38c08000
+ MOVD $1234567, R5 // 6405001260a5d687
+ MOVW $1, R3 // 38600001
+ MOVW $-1, R4 // 3880ffff
+ MOVW $65535, R5 // 6005ffff
+ MOVW $65536, R6 // 64060001
+ MOVW $-32767, R5 // 38a08001
+ MOVW $-32768, R6 // 38c08000
+ MOVW $1234567, R5 // 6405001260a5d687
+ MOVD 8(R3), R4 // e8830008
+ MOVD (R3)(R4), R5 // 7ca4182a
+ MOVW 4(R3), R4 // e8830006
+ MOVW (R3)(R4), R5 // 7ca41aaa
+ MOVWZ 4(R3), R4 // 80830004
+ MOVWZ (R3)(R4), R5 // 7ca4182e
+ MOVH 4(R3), R4 // a8830004
+ MOVH (R3)(R4), R5 // 7ca41aae
+ MOVHZ 2(R3), R4 // a0830002
+ MOVHZ (R3)(R4), R5 // 7ca41a2e
+ MOVB 1(R3), R4 // 888300017c840774
+ MOVB (R3)(R4), R5 // 7ca418ae7ca50774
+ MOVBZ 1(R3), R4 // 88830001
+ MOVBZ (R3)(R4), R5 // 7ca418ae
+ MOVDBR (R3)(R4), R5 // 7ca41c28
+ MOVWBR (R3)(R4), R5 // 7ca41c2c
+ MOVHBR (R3)(R4), R5 // 7ca41e2c
+
+ MOVDU 8(R3), R4 // e8830009
+ MOVDU (R3)(R4), R5 // 7ca4186a
+ MOVWU (R3)(R4), R5 // 7ca41aea
+ MOVWZU 4(R3), R4 // 84830004
+ MOVWZU (R3)(R4), R5 // 7ca4186e
+ MOVHU 2(R3), R4 // ac830002
+ MOVHU (R3)(R4), R5 // 7ca41aee
+ MOVHZU 2(R3), R4 // a4830002
+ MOVHZU (R3)(R4), R5 // 7ca41a6e
+ MOVBU 1(R3), R4 // 8c8300017c840774
+ MOVBU (R3)(R4), R5 // 7ca418ee7ca50774
+ MOVBZU 1(R3), R4 // 8c830001
+ MOVBZU (R3)(R4), R5 // 7ca418ee
+
+ MOVD R4, 8(R3) // f8830008
+ MOVD R5, (R3)(R4) // 7ca4192a
+ MOVW R4, 4(R3) // 90830004
+ MOVW R5, (R3)(R4) // 7ca4192e
+ MOVH R4, 2(R3) // b0830002
+ MOVH R5, (R3)(R4) // 7ca41b2e
+ MOVB R4, 1(R3) // 98830001
+ MOVB R5, (R3)(R4) // 7ca419ae
+ MOVDBR R5, (R3)(R4) // 7ca41d28
+ MOVWBR R5, (R3)(R4) // 7ca41d2c
+ MOVHBR R5, (R3)(R4) // 7ca41f2c
+
+ MOVDU R4, 8(R3) // f8830009
+ MOVDU R5, (R3)(R4) // 7ca4196a
+ MOVWU R4, 4(R3) // 94830004
+ MOVWU R5, (R3)(R4) // 7ca4196e
+ MOVHU R4, 2(R3) // b4830002
+ MOVHU R5, (R3)(R4) // 7ca41b6e
+ MOVBU R4, 1(R3) // 9c830001
+ MOVBU R5, (R3)(R4) // 7ca419ee
+
+ ADD $1, R3 // 38630001
+ ADD $1, R3, R4 // 38830001
+ ADD $-1, R4 // 3884ffff
+ ADD $-1, R4, R5 // 38a4ffff
+ ADD $65535, R5 // 601fffff7cbf2a14
+ ADD $65535, R5, R6 // 601fffff7cdf2a14
+ ADD $65536, R6 // 3cc60001
+ ADD $65536, R6, R7 // 3ce60001
+ ADD $-32767, R5 // 38a58001
+ ADD $-32767, R5, R4 // 38858001
+ ADD $-32768, R6 // 38c68000
+ ADD $-32768, R6, R5 // 38a68000
+ ADD $1234567, R5 // 641f001263ffd6877cbf2a14
+ ADD $1234567, R5, R6 // 641f001263ffd6877cdf2a14
+ ADDEX R3, R5, $3, R6 // 7cc32f54
+ ADDIS $8, R3 // 3c630008
+ ADDIS $1000, R3, R4 // 3c8303e8
+
+ ANDCC $1, R3 // 70630001
+ ANDCC $1, R3, R4 // 70640001
+ ANDCC $-1, R4 // 3be0ffff7fe42039
+ ANDCC $-1, R4, R5 // 3be0ffff7fe52039
+ ANDCC $65535, R5 // 70a5ffff
+ ANDCC $65535, R5, R6 // 70a6ffff
+ ANDCC $65536, R6 // 74c60001
+ ANDCC $65536, R6, R7 // 74c70001
+ ANDCC $-32767, R5 // 3be080017fe52839
+ ANDCC $-32767, R5, R4 // 3be080017fe42839
+ ANDCC $-32768, R6 // 3be080007fe63039
+ ANDCC $-32768, R5, R6 // 3be080007fe62839
+ ANDCC $1234567, R5 // 641f001263ffd6877fe52839
+ ANDCC $1234567, R5, R6 // 641f001263ffd6877fe62839
+ ANDISCC $1, R3 // 74630001
+ ANDISCC $1000, R3, R4 // 746403e8
+
+ OR $1, R3 // 60630001
+ OR $1, R3, R4 // 60640001
+ OR $-1, R4 // 3be0ffff7fe42378
+ OR $-1, R4, R5 // 3be0ffff7fe52378
+ OR $65535, R5 // 60a5ffff
+ OR $65535, R5, R6 // 60a6ffff
+ OR $65536, R6 // 64c60001
+ OR $65536, R6, R7 // 64c70001
+ OR $-32767, R5 // 3be080017fe52b78
+ OR $-32767, R5, R6 // 3be080017fe62b78
+ OR $-32768, R6 // 3be080007fe63378
+ OR $-32768, R6, R7 // 3be080007fe73378
+ OR $1234567, R5 // 641f001263ffd6877fe52b78
+ OR $1234567, R5, R3 // 641f001263ffd6877fe32b78
+ ORIS $255, R3, R4
+
+ XOR $1, R3 // 68630001
+ XOR $1, R3, R4 // 68640001
+ XOR $-1, R4 // 3be0ffff7fe42278
+ XOR $-1, R4, R5 // 3be0ffff7fe52278
+ XOR $65535, R5 // 68a5ffff
+ XOR $65535, R5, R6 // 68a6ffff
+ XOR $65536, R6 // 6cc60001
+ XOR $65536, R6, R7 // 6cc70001
+ XOR $-32767, R5 // 3be080017fe52a78
+ XOR $-32767, R5, R6 // 3be080017fe62a78
+ XOR $-32768, R6 // 3be080007fe63278
+ XOR $-32768, R6, R7 // 3be080007fe73278
+ XOR $1234567, R5 // 641f001263ffd6877fe52a78
+ XOR $1234567, R5, R3 // 641f001263ffd6877fe32a78
+ XORIS $15, R3, R4
+
+ // TODO: the order of CR operands don't match
+ CMP R3, R4 // 7c232000
+ CMPU R3, R4 // 7c232040
+ CMPW R3, R4 // 7c032000
+ CMPWU R3, R4 // 7c032040
+ CMPB R3,R4,R4 // 7c6423f8
+ CMPEQB R3,R4,CR6 // 7f0321c0
+
+ // TODO: constants for ADDC?
+ ADD R3, R4 // 7c841a14
+ ADD R3, R4, R5 // 7ca41a14
+ ADDC R3, R4 // 7c841814
+ ADDC R3, R4, R5 // 7ca41814
+ ADDE R3, R4 // 7c841914
+ ADDECC R3, R4 // 7c841915
+ ADDEV R3, R4 // 7c841d14
+ ADDEVCC R3, R4 // 7c841d15
+ ADDV R3, R4 // 7c841e14
+ ADDVCC R3, R4 // 7c841e15
+ ADDCCC R3, R4, R5 // 7ca41815
+ ADDME R3, R4 // 7c8301d4
+ ADDMECC R3, R4 // 7c8301d5
+ ADDMEV R3, R4 // 7c8305d4
+ ADDMEVCC R3, R4 // 7c8305d5
+ ADDCV R3, R4 // 7c841c14
+ ADDCVCC R3, R4 // 7c841c15
+ ADDZE R3, R4 // 7c830194
+ ADDZECC R3, R4 // 7c830195
+ ADDZEV R3, R4 // 7c830594
+ ADDZEVCC R3, R4 // 7c830595
+ SUBME R3, R4 // 7c8301d0
+ SUBMECC R3, R4 // 7c8301d1
+ SUBMEV R3, R4 // 7c8305d0
+ SUBZE R3, R4 // 7c830190
+ SUBZECC R3, R4 // 7c830191
+ SUBZEV R3, R4 // 7c830590
+ SUBZEVCC R3, R4 // 7c830591
+
+ AND R3, R4 // 7c841838
+ AND R3, R4, R5 // 7c851838
+ ANDN R3, R4, R5 // 7c851878
+ ANDCC R3, R4, R5 // 7c851839
+ OR R3, R4 // 7c841b78
+ OR R3, R4, R5 // 7c851b78
+ ORN R3, R4, R5 // 7c851b38
+ ORCC R3, R4, R5 // 7c851b79
+ XOR R3, R4 // 7c841a78
+ XOR R3, R4, R5 // 7c851a78
+ XORCC R3, R4, R5 // 7c851a79
+ NAND R3, R4, R5 // 7c851bb8
+ NANDCC R3, R4, R5 // 7c851bb9
+ EQV R3, R4, R5 // 7c851a38
+ EQVCC R3, R4, R5 // 7c851a39
+ NOR R3, R4, R5 // 7c8518f8
+ NORCC R3, R4, R5 // 7c8518f9
+
+ SUB R3, R4 // 7c832050
+ SUB R3, R4, R5 // 7ca32050
+ SUBC R3, R4 // 7c832010
+ SUBC R3, R4, R5 // 7ca32010
+
+ MULLW R3, R4 // 7c8419d6
+ MULLW R3, R4, R5 // 7ca419d6
+ MULLW $10, R3 // 1c63000a
+ MULLW $10000000, R3 // 641f009863ff96807c7f19d6
+
+ MULLWCC R3, R4, R5 // 7ca419d7
+ MULHW R3, R4, R5 // 7ca41896
+
+ MULHWU R3, R4, R5 // 7ca41816
+ MULLD R3, R4 // 7c8419d2
+ MULLD R4, R4, R5 // 7ca421d2
+ MULLD $20, R4 // 1c840014
+ MULLD $200000000, R4 // 641f0beb63ffc2007c9f21d2
+
+ MULLDCC R3, R4, R5 // 7ca419d3
+ MULHD R3, R4, R5 // 7ca41892
+ MULHDCC R3, R4, R5 // 7ca41893
+
+ MULLWV R3, R4 // 7c841dd6
+ MULLWV R3, R4, R5 // 7ca41dd6
+ MULLWVCC R3, R4, R5 // 7ca41dd7
+ MULHWUCC R3, R4, R5 // 7ca41817
+ MULLDV R3, R4, R5 // 7ca41dd2
+ MULLDVCC R3, R4, R5 // 7ca41dd3
+
+ DIVD R3,R4 // 7c841bd2
+ DIVD R3, R4, R5 // 7ca41bd2
+ DIVDCC R3,R4, R5 // 7ca41bd3
+ DIVDU R3, R4, R5 // 7ca41b92
+ DIVDV R3, R4, R5 // 7ca41fd2
+ DIVDUCC R3, R4, R5 // 7ca41b93
+ DIVDVCC R3, R4, R5 // 7ca41fd3
+ DIVDUV R3, R4, R5 // 7ca41f92
+ DIVDUVCC R3, R4, R5 // 7ca41f93
+ DIVDE R3, R4, R5 // 7ca41b52
+ DIVDECC R3, R4, R5 // 7ca41b53
+ DIVDEU R3, R4, R5 // 7ca41b12
+ DIVDEUCC R3, R4, R5 // 7ca41b13
+
+ REM R3, R4, R5 // 7fe41bd67fff19d67cbf2050
+ REMU R3, R4, R5 // 7fe41b967fff19d67bff00287cbf2050
+ REMD R3, R4, R5 // 7fe41bd27fff19d27cbf2050
+ REMDU R3, R4, R5 // 7fe41b927fff19d27cbf2050
+
+ MADDHD R3,R4,R5,R6 // 10c32170
+ MADDHDU R3,R4,R5,R6 // 10c32171
+
+ MODUD R3, R4, R5 // 7ca41a12
+ MODUW R3, R4, R5 // 7ca41a16
+ MODSD R3, R4, R5 // 7ca41e12
+ MODSW R3, R4, R5 // 7ca41e16
+
+ SLW $8, R3, R4 // 5464402e
+ SLW R3, R4, R5 // 7c851830
+ SLWCC R3, R4 // 7c841831
+ SLD $16, R3, R4 // 786483e4
+ SLD R3, R4, R5 // 7c851836
+ SLDCC R3, R4 // 7c841837
+
+ SRW $8, R3, R4 // 5464c23e
+ SRW R3, R4, R5 // 7c851c30
+ SRWCC R3, R4 // 7c841c31
+ SRAW $8, R3, R4 // 7c644670
+ SRAW R3, R4, R5 // 7c851e30
+ SRAWCC R3, R4 // 7c841e31
+ SRD $16, R3, R4 // 78648402
+ SRD R3, R4, R5 // 7c851c36
+ SRDCC R3, R4 // 7c841c37
+ SRAD $16, R3, R4 // 7c648674
+ SRAD R3, R4, R5 // 7c851e34
+ SRDCC R3, R4 // 7c841c37
+ ROTLW $16, R3, R4 // 5464803e
+ ROTLW R3, R4, R5 // 5c85183e
+ EXTSWSLI $3, R4, R5 // 7c851ef4
+ RLWMI $7, R3, $65535, R6 // 50663c3e
+ RLWMICC $7, R3, $65535, R6 // 50663c3f
+ RLWNM $3, R4, $7, R6 // 54861f7e
+ RLWNMCC $3, R4, $7, R6 // 54861f7f
+ RLDMI $0, R4, $7, R6 // 7886076c
+ RLDMICC $0, R4, $7, R6 // 7886076d
+ RLDIMI $0, R4, $7, R6 // 788601cc
+ RLDIMICC $0, R4, $7, R6 // 788601cd
+ RLDC $0, R4, $15, R6 // 78860728
+ RLDCCC $0, R4, $15, R6 // 78860729
+ RLDCL $0, R4, $7, R6 // 78860770
+ RLDCLCC $0, R4, $15, R6 // 78860721
+ RLDCR $0, R4, $-16, R6 // 788606f2
+ RLDCRCC $0, R4, $-16, R6 // 788606f3
+ RLDICL $0, R4, $15, R6 // 788603c0
+ RLDICLCC $0, R4, $15, R6 // 788603c1
+ RLDICR $0, R4, $15, R6 // 788603c4
+ RLDICRCC $0, R4, $15, R6 // 788603c5
+ RLDIC $0, R4, $15, R6 // 788603c8
+ RLDICCC $0, R4, $15, R6 // 788603c9
+ CLRLSLWI $16, R5, $8, R4 // 54a4422e
+ CLRLSLDI $24, R4, $2, R3 // 78831588
+
+ BEQ 0(PC) // 41820000
+ BEQ CR1,0(PC) // 41860000
+ BGE 0(PC) // 40800000
+ BGE CR2,0(PC) // 40880000
+ BGT 4(PC) // 41810010
+ BGT CR3,4(PC) // 418d0010
+ BLE 0(PC) // 40810000
+ BLE CR4,0(PC) // 40910000
+ BLT 0(PC) // 41800000
+ BLT CR5,0(PC) // 41940000
+ BNE 0(PC) // 40820000
+ BLT CR6,0(PC) // 41980000
+ JMP 8(PC) // 48000010
-//inst:
-//
-// load ints and bytes
-//
-// LMOVW rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, R2
-
-// LMOVW addr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW foo<>+4(SB), R2
- MOVW 16(R1), R2
-
-// LMOVW regaddr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW (R1), R2
- MOVW (R1+R2), R3 // MOVW (R1)(R2*1), R3
-
-// LMOVB rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, R2
-
-// LMOVB addr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVB foo<>+3(SB), R2
- MOVB 16(R1), R2
-
-// LMOVB regaddr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVB (R1), R2
- MOVB (R1+R2), R3 // MOVB (R1)(R2*1), R3
-
-//
-// load floats
-//
-// LFMOV addr ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD foo<>+4(SB), F2
- FMOVD 16(R1), F2
-
-// LFMOV regaddr ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD (R1), F2
-
-// LFMOV fimm ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD $0.1, F2 // FMOVD $(0.10000000000000001), F2
-
-// LFMOV freg ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F1, F2
-
-// LFMOV freg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F2, foo<>+4(SB)
- FMOVD F2, 16(R1)
-
-// LFMOV freg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F2, (R1)
-
-//
-// store ints and bytes
-//
-// LMOVW rreg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, foo<>+3(SB)
- MOVW R1, 16(R2)
-
-// LMOVW rreg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, (R1)
- MOVW R1, (R2+R3) // MOVW R1, (R2)(R3*1)
-
-// LMOVB rreg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVB R1, foo<>+3(SB)
- MOVB R1, 16(R2)
-
-// LMOVB rreg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVB R1, (R1)
- MOVB R1, (R2+R3) // MOVB R1, (R2)(R3*1)
-//
-// store floats
-//
-// LMOVW freg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F1, foo<>+4(SB)
- FMOVD F1, 16(R2)
-
-// LMOVW freg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FMOVD F1, (R1)
-
-//
-// floating point status
-//
-// LMOVW fpscr ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVFL FPSCR, F1
-
-// LMOVW freg ',' fpscr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVFL F1, FPSCR
-
-// LMOVW freg ',' imm ',' fpscr
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
- MOVFL F1, $4, FPSCR
-
-// LMOVW fpscr ',' creg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVFL FPSCR, CR0
-
-// LMTFSB imm ',' con
-// {
-// outcode(int($1), &$2, int($4), &nullgen);
-// }
-//TODO 9a doesn't work MTFSB0 $4, 4
-
-//
-// field moves (mtcrf)
-//
-// LMOVW rreg ',' imm ',' lcr
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
-// TODO 9a doesn't work MOVFL R1,$4,CR
-
-// LMOVW rreg ',' creg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, CR1
-
-// LMOVW rreg ',' lcr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, CR
-
-//
-// integer operations
-// logical instructions
-// shift instructions
-// unary instructions
-//
-// LADDW rreg ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- ADD R1, R2, R3
-
-// LADDW imm ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- ADD $1, R2, R3
-
-// LADDW rreg ',' imm ',' rreg
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
-//TODO 9a trouble ADD R1, $2, R3 maybe swap rreg and imm
-
-// LADDW rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- ADD R1, R2
-
-// LADDW imm ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- ADD $4, R1
-
-// LLOGW rreg ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- ADDE R1, R2, R3
-
-// LLOGW rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- ADDE R1, R2
-
-// LSHW rreg ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- SLW R1, R2, R3
-
-// LSHW rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- SLW R1, R2
-
-// LSHW imm ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
- SLW $4, R1, R2
-
-// LSHW imm ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- SLW $4, R1
-
-// LABS rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- SLW $4, R1
-
-// LABS rreg
-// {
-// outcode(int($1), &$2, 0, &$2);
-// }
- SUBME R1 // SUBME R1, R1
-
-//
-// multiply-accumulate
-//
-// LMA rreg ',' sreg ',' rreg
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
-//TODO this instruction is undefined in lex.go LMA R1, R2, R3 NOT SUPPORTED (called MAC)
-
-//
-// move immediate: macro for cau+or, addi, addis, and other combinations
-//
-// LMOVW imm ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW $1, R1
-
-// LMOVW ximm ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW $1, R1
- MOVW $foo(SB), R1
-
-// condition register operations
-//
-// LCROP cbit ',' cbit
-// {
-// outcode(int($1), &$2, int($4.Reg), &$4);
-// }
-//TODO 9a trouble CREQV 1, 2 delete? liblink encodes like a divide (maybe wrong too)
-
-// LCROP cbit ',' con ',' cbit
-// {
-// outcode(int($1), &$2, int($4), &$6);
-// }
-//TODO 9a trouble CREQV 1, 2, 3
-
-//
-// condition register moves
-// move from machine state register
-//
-// LMOVW creg ',' creg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVFL CR0, CR1
-
-// LMOVW psr ',' creg // TODO: should psr should be fpscr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-//TODO 9a trouble MOVW FPSCR, CR1
-
-// LMOVW lcr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW CR, R1
-
-// LMOVW psr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW SPR(0), R1
- MOVW SPR(7), R1
-
-// LMOVW xlreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW LR, R1
- MOVW CTR, R1
-
-// LMOVW rreg ',' xlreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, LR
- MOVW R1, CTR
-
-// LMOVW creg ',' psr // TODO doesn't exist
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-//TODO 9a trouble MOVW CR1, SPR(7)
-
-// LMOVW rreg ',' psr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVW R1, SPR(7)
-
-//
-// branch, branch conditional
-// branch conditional register
-// branch conditional to count register
-//
-// LBRA rel
-// {
-// outcode(int($1), &nullgen, 0, &$2);
-// }
- BEQ CR1, 2(PC)
-label0:
- BR 1(PC) // JMP 1(PC)
- BEQ CR1, 2(PC)
- BR label0+0 // JMP 62
-
-// LBRA addr
-// {
-// outcode(int($1), &nullgen, 0, &$2);
-// }
- BEQ CR1, 2(PC)
- BR LR // JMP LR
- BEQ CR1, 2(PC)
-// BR 0(R1) // TODO should work
- BEQ CR1, 2(PC)
- BR foo+0(SB) // JMP foo(SB)
-
-// LBRA '(' xlreg ')'
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
- BEQ CR1, 2(PC)
- BR (CTR) // JMP CTR
-
-// LBRA ',' rel // asm doesn't support the leading comma
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
-// LBRA ',' addr // asm doesn't support the leading comma
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
-// LBRA ',' '(' xlreg ')' // asm doesn't support the leading comma
-// {
-// outcode(int($1), &nullgen, 0, &$4);
-// }
-// LBRA creg ',' rel
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-label1:
- BEQ CR1, 1(PC)
- BEQ CR1, label1 // BEQ CR1, 72
-
-// LBRA creg ',' addr // TODO DOES NOT WORK in 9a
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-
-// LBRA creg ',' '(' xlreg ')' // TODO DOES NOT WORK in 9a
-// {
-// outcode(int($1), &$2, 0, &$5);
-// }
-
-// LBRA con ',' rel // TODO DOES NOT WORK in 9a
-// {
-// outcode(int($1), &nullgen, int($2), &$4);
-// }
-
-// LBRA con ',' addr // TODO DOES NOT WORK in 9a
-// {
-// outcode(int($1), &nullgen, int($2), &$4);
-// }
-
-// LBRA con ',' '(' xlreg ')'
-// {
-// outcode(int($1), &nullgen, int($2), &$5);
-// }
-// BC 4, (CTR) // TODO - should work
-
-// LBRA con ',' con ',' rel
-// {
-// var g obj.Addr
-// g = nullgen;
-// g.Type = obj.TYPE_CONST;
-// g.Offset = $2;
-// outcode(int($1), &g, int(REG_R0+$4), &$6);
-// }
-// BC 3, 4, label1 // TODO - should work
-
-// LBRA con ',' con ',' addr // TODO mystery
-// {
-// var g obj.Addr
-// g = nullgen;
-// g.Type = obj.TYPE_CONST;
-// g.Offset = $2;
-// outcode(int($1), &g, int(REG_R0+$4), &$6);
-// }
-//TODO 9a trouble BC 3, 3, 4(R1)
-
-// LBRA con ',' con ',' '(' xlreg ')'
-// {
-// var g obj.Addr
-// g = nullgen;
-// g.Type = obj.TYPE_CONST;
-// g.Offset = $2;
-// outcode(int($1), &g, int(REG_R0+$4), &$7);
-// }
- BC 3, 3, (LR) // BC $3, R3, LR
-
-//
-// conditional trap // TODO NOT DEFINED
-// TODO these instructions are not in lex.go
-//
-// LTRAP rreg ',' sreg
-// {
-// outcode(int($1), &$2, int($4), &nullgen);
-// }
-// LTRAP imm ',' sreg
-// {
-// outcode(int($1), &$2, int($4), &nullgen);
-// }
-// LTRAP rreg comma
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
-// LTRAP comma
-// {
-// outcode(int($1), &nullgen, 0, &nullgen);
-// }
-
-//
-// floating point operate
-//
-// LFCONV freg ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FABS F1, F2
-
-// LFADD freg ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FADD F1, F2
-
-// LFADD freg ',' freg ',' freg
-// {
-// outcode(int($1), &$2, int($4.Reg), &$6);
-// }
- FADD F1, F2, F3
-
-// LFMA freg ',' freg ',' freg ',' freg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- FMADD F1, F2, F3, F4
-
-// LFCMP freg ',' freg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- FCMPU F1, F2
-
-// LFCMP freg ',' freg ',' creg
-// {
-// outcode(int($1), &$2, int($6.Reg), &$4);
-// }
-// FCMPU F1, F2, CR0
-
-// FTDIV FRA, FRB, BF produces
-// ftdiv BF, FRA, FRB
- FTDIV F1,F2,$7
-
-// FTSQRT FRB, BF produces
-// ftsqrt BF, FRB
- FTSQRT F2,$7
-
-// FCFID
-// FCFIDS
-
- FCFID F2,F3
- FCFIDCC F3,F3
- FCFIDS F2,F3
- FCFIDSCC F2,F3
-
-//
-// CMP
-//
-// LCMP rreg ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- CMP R1, R2
-
-// LCMP rreg ',' imm
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- CMP R1, $4
-
-// LCMP rreg ',' rreg ',' creg
-// {
-// outcode(int($1), &$2, int($6.Reg), &$4);
-// }
- CMP R1, R2, CR0 // CMP R1, CR0, R2
-
-// LCMP rreg ',' imm ',' creg
-// {
-// outcode(int($1), &$2, int($6.Reg), &$4);
-// }
- CMP R1, $4, CR0 // CMP R1, CR0, $4
-
-// CMPB RS,RB,RA produces
-// cmpb RA,RS,RB
- CMPB R2,R2,R1
-
-// CMPEQB RA,RB,BF produces
-// cmpeqb BF,RA,RB
- CMPEQB R1, R2, CR0
-
-//
-// rotate extended mnemonics map onto other shift instructions
-//
-
- ROTL $12,R2,R3
- ROTL R2,R3,R4
- ROTLW $9,R2,R3
- ROTLW R2,R3,R4
-
-//
-// rotate and mask
-//
-// LRLWM imm ',' rreg ',' imm ',' rreg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- RLDC $4, R1, $16, R2
-
-// LRLWM imm ',' rreg ',' mask ',' rreg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- RLDC $26, R1, 4, 5, R2 // RLDC $26, R1, $201326592, R2
-
-// LRLWM rreg ',' rreg ',' imm ',' rreg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- RLDCL R1, R2, $7, R3
-
-// LRLWM rreg ',' rreg ',' mask ',' rreg
-// {
-// outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
-// }
- RLWMI R1, R2, 4, 5, R3 // RLWMI R1, R2, $201326592, R3
-
-
-// opcodes added with constant shift counts, not masks
-
- RLDICR $3, R2, $24, R4
-
- RLDICL $1, R2, $61, R6
-
- RLDIMI $7, R2, $52, R7
-
-// opcodes for right and left shifts, const and reg shift counts
-
- SLD $4, R3, R4
- SLD R2, R3, R4
- SLW $4, R3, R4
- SLW R2, R3, R4
- SRD $8, R3, R4
- SRD R2, R3, R4
- SRW $8, R3, R4
- SRW R2, R3, R4
-
-//
-// load/store multiple
-//
-// LMOVMW addr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-// MOVMW foo+0(SB), R2 // TODO TLS broke this!
- MOVMW 4(R1), R2
-
-// LMOVMW rreg ',' addr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
-// MOVMW R1, foo+0(SB) // TODO TLS broke this!
- MOVMW R1, 4(R2)
-
-//
-// various indexed load/store
-// indexed unary (eg, cache clear)
-//
-// LXLD regaddr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- LSW (R1), R2
- LSW (R1+R2), R3 // LSW (R1)(R2*1), R3
-
-// LXLD regaddr ',' imm ',' rreg
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
- LSW (R1), $1, R2
- LSW (R1+R2), $1, R3 // LSW (R1)(R2*1), $1, R3
-
-// LXST rreg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- STSW R1, (R2)
- STSW R1, (R2+R3) // STSW R1, (R2)(R3*1)
-
-// LXST rreg ',' imm ',' regaddr
-// {
-// outgcode(int($1), &$2, 0, &$4, &$6);
-// }
- STSW R1, $1, (R2)
- STSW R1, $1, (R2+R3) // STSW R1, $1, (R2)(R3*1)
-
-// LXMV regaddr ',' rreg
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVHBR (R1), R2
- MOVHBR (R1+R2), R3 // MOVHBR (R1)(R2*1), R3
-
-// LXMV rreg ',' regaddr
-// {
-// outcode(int($1), &$2, 0, &$4);
-// }
- MOVHBR R1, (R2)
- MOVHBR R1, (R2+R3) // MOVHBR R1, (R2)(R3*1)
-
-// LXOP regaddr
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
- DCBF (R1)
- DCBF (R1+R2) // DCBF (R1)(R2*1)
- DCBF (R1), $1
- DCBF (R1)(R2*1), $1
- DCBT (R1), $1
- DCBT (R1)(R2*1), $1
-
-// LDMX (RB)(RA*1),RT produces
-// ldmx RT,RA,RB
- LDMX (R2)(R1*1), R3
-
-// Population count, X-form
-// <MNEMONIC> RS,RA produces
-// <mnemonic> RA,RS
- POPCNTD R1,R2
- POPCNTW R1,R2
- POPCNTB R1,R2
-
-// Copysign
- FCPSGN F1,F2,F3
-
-// Random number generator, X-form
-// DARN L,RT produces
-// darn RT,L
- DARN $1, R1
-
-// Copy/Paste facility
-// <MNEMONIC> RB,RA produces
-// <mnemonic> RA,RB
- COPY R2,R1
- PASTECC R2,R1
-
-// Modulo signed/unsigned double/word X-form
-// <MNEMONIC> RA,RB,RT produces
-// <mnemonic> RT,RA,RB
- MODUD R3,R4,R5
- MODUW R3,R4,R5
- MODSD R3,R4,R5
- MODSW R3,R4,R5
-
-// VMX instructions
-
-// Described as:
-// <instruction type>, <instruction format>
-// <go asm operand order> produces
-// <Power ISA operand order>
-
-// Vector load, VX-form
-// <MNEMONIC> (RB)(RA*1),VRT produces
-// <mnemonic> VRT,RA,RB
- LVEBX (R1)(R2*1), V0
- LVEHX (R3)(R4*1), V1
- LVEWX (R5)(R6*1), V2
- LVX (R7)(R8*1), V3
- LVXL (R9)(R10*1), V4
- LVSL (R11)(R12*1), V5
- LVSR (R14)(R15*1), V6
-
-// Vector store, VX-form
-// <MNEMONIC> VRT,(RB)(RA*1) produces
-// <mnemonic> VRT,RA,RB
- STVEBX V31, (R1)(R2*1)
- STVEHX V30, (R2)(R3*1)
- STVEWX V29, (R4)(R5*1)
- STVX V28, (R6)(R7*1)
- STVXL V27, (R9)(R9*1)
-
-// Vector AND, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VAND V10, V9, V8
- VANDC V15, V14, V13
- VNAND V19, V18, V17
-
-// Vector OR, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VOR V26, V25, V24
- VORC V23, V22, V21
- VNOR V20, V19, V18
- VXOR V17, V16, V15
- VEQV V14, V13, V12
-
-// Vector ADD, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VADDUBM V3, V2, V1
- VADDUHM V3, V2, V1
- VADDUWM V3, V2, V1
- VADDUDM V3, V2, V1
- VADDUQM V3, V2, V1
- VADDCUQ V3, V2, V1
- VADDCUW V3, V2, V1
- VADDUBS V3, V2, V1
- VADDUHS V3, V2, V1
- VADDUWS V3, V2, V1
- VADDSBS V3, V2, V1
- VADDSHS V3, V2, V1
- VADDSWS V3, V2, V1
-
-// Vector ADD extended, VA-form
-// <MNEMONIC> VRA,VRB,VRC,VRT produces
-// <mnemonic> VRT,VRA,VRB,VRC
- VADDEUQM V4, V3, V2, V1
- VADDECUQ V4, V3, V2, V1
-
-// Vector multiply, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VMULESB V2, V3, V1
- VMULOSB V2, V3, V1
- VMULEUB V2, V3, V1
- VMULOUB V2, V3, V1
- VMULESH V2, V3, V1
- VMULOSH V2, V3, V1
- VMULEUH V2, V3, V1
- VMULOUH V2, V3, V1
- VMULESW V2, V3, V1
- VMULOSW V2, V3, V1
- VMULEUW V2, V3, V1
- VMULOUW V2, V3, V1
- VMULUWM V2, V3, V1
-
-// Vector polynomial multiply-sum, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VPMSUMB V2, V3, V1
- VPMSUMH V2, V3, V1
- VPMSUMW V2, V3, V1
- VPMSUMD V2, V3, V1
-
-// Vector multiply-sum, VA-form
-// <MNEMONIC> VRA, VRB, VRC, VRT produces
-// <mnemonic> VRT, VRA, VRB, VRC
- VMSUMUDM V4, V3, V2, V1
-
-// Vector SUB, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VSUBUBM V3, V2, V1
- VSUBUHM V3, V2, V1
- VSUBUWM V3, V2, V1
- VSUBUDM V3, V2, V1
- VSUBUQM V3, V2, V1
- VSUBCUQ V3, V2, V1
- VSUBCUW V3, V2, V1
- VSUBUBS V3, V2, V1
- VSUBUHS V3, V2, V1
- VSUBUWS V3, V2, V1
- VSUBSBS V3, V2, V1
- VSUBSHS V3, V2, V1
- VSUBSWS V3, V2, V1
-
-// Vector SUB extended, VA-form
-// <MNEMONIC> VRA,VRB,VRC,VRT produces
-// <mnemonic> VRT,VRA,VRB,VRC
- VSUBEUQM V4, V3, V2, V1
- VSUBECUQ V4, V3, V2, V1
-
-// Vector rotate, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VRLB V2, V1, V0
- VRLH V2, V1, V0
- VRLW V2, V1, V0
- VRLD V2, V1, V0
-
-// Vector shift, VX-form
-// <MNEMONIC> VRA,VRB,VRT
-// <mnemonic> VRT,VRA,VRB
- VSLB V2, V1, V0
- VSLH V2, V1, V0
- VSLW V2, V1, V0
- VSL V2, V1, V0
- VSLO V2, V1, V0
- VSRB V2, V1, V0
- VSRH V2, V1, V0
- VSRW V2, V1, V0
- VSR V2, V1, V0
- VSRO V2, V1, V0
- VSLD V2, V1, V0
- VSRD V2, V1, V0
- VSRAB V2, V1, V0
- VSRAH V2, V1, V0
- VSRAW V2, V1, V0
- VSRAD V2, V1, V0
-
-// Vector shift by octect immediate, VA-form with SHB 4-bit field
-// <MNEMONIC> SHB,VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB,SHB
- VSLDOI $4, V2, V1, V0
-
-// Vector merge odd and even word
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
-
- VMRGOW V4,V5,V6
- VMRGEW V4,V5,V6
-
-// Vector count, VX-form
-// <MNEMONIC> VRB,VRT produces
-// <mnemonic> VRT,VRB
- VCLZB V4, V5
- VCLZH V4, V5
- VCLZW V4, V5
- VCLZD V4, V5
- VPOPCNTB V4, V5
- VPOPCNTH V4, V5
- VPOPCNTW V4, V5
- VPOPCNTD V4, V5
-
-// Vector compare, VC-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
-// * Note: 'CC' suffix denotes Rc=1
-// i.e. vcmpequb. v3,v1,v2 equals VCMPEQUBCC V1,V2,V3
- VCMPEQUB V3, V2, V1
- VCMPEQUBCC V3, V2, V1
- VCMPEQUH V3, V2, V1
- VCMPEQUHCC V3, V2, V1
- VCMPEQUW V3, V2, V1
- VCMPEQUWCC V3, V2, V1
- VCMPEQUD V3, V2, V1
- VCMPEQUDCC V3, V2, V1
- VCMPGTUB V3, V2, V1
- VCMPGTUBCC V3, V2, V1
- VCMPGTUH V3, V2, V1
- VCMPGTUHCC V3, V2, V1
- VCMPGTUW V3, V2, V1
- VCMPGTUWCC V3, V2, V1
- VCMPGTUD V3, V2, V1
- VCMPGTUDCC V3, V2, V1
- VCMPGTSB V3, V2, V1
- VCMPGTSBCC V3, V2, V1
- VCMPGTSH V3, V2, V1
- VCMPGTSHCC V3, V2, V1
- VCMPGTSW V3, V2, V1
- VCMPGTSWCC V3, V2, V1
- VCMPGTSD V3, V2, V1
- VCMPGTSDCC V3, V2, V1
- VCMPNEZB V3, V2, V1
- VCMPNEZBCC V3, V2, V1
- VCMPNEB V3, V2, V1
- VCMPNEBCC V3, V2, V1
- VCMPNEH V3, V2, V1
- VCMPNEHCC V3, V2, V1
- VCMPNEW V3, V2, V1
- VCMPNEWCC V3, V2, V1
-
-// Vector permute, VA-form
-// <MNEMONIC> VRA,VRB,VRC,VRT produces
-// <mnemonic> VRT,VRA,VRB,VRC
- VPERM V3, V2, V1, V0
- VPERMXOR V3, V2, V1, V0
- VPERMR V3, V2, V1, V0
-
-// Vector bit permute, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VBPERMQ V3,V1,V2
- VBPERMD V3,V1,V2
-
-// Vector select, VA-form
-// <MNEMONIC> VRA,VRB,VRC,VRT produces
-// <mnemonic> VRT,VRA,VRB,VRC
- VSEL V3, V2, V1, V0
-
-// Vector splat, VX-form with 4-bit UIM field
-// <MNEMONIC> UIM,VRB,VRT produces
-// <mnemonic> VRT,VRB,UIM
- VSPLTB $15, V1, V0
- VSPLTH $7, V1, V0
- VSPLTW $3, V1, V0
-
-// Vector splat immediate signed, VX-form with 5-bit SIM field
-// <MNEMONIC> SIM,VRT produces
-// <mnemonic> VRT,SIM
- VSPLTISB $31, V4
- VSPLTISH $31, V4
- VSPLTISW $31, V4
-
-// Vector AES cipher, VX-form
-// <MNEMONIC> VRA,VRB,VRT produces
-// <mnemonic> VRT,VRA,VRB
- VCIPHER V3, V2, V1
- VCIPHERLAST V3, V2, V1
- VNCIPHER V3, V2, V1
- VNCIPHERLAST V3, V2, V1
-
-// Vector AES subbytes, VX-form
-// <MNEMONIC> VRA,VRT produces
-// <mnemonic> VRT,VRA
- VSBOX V2, V1
-
-// Vector SHA, VX-form with ST bit field and 4-bit SIX field
-// <MNEMONIC> SIX,VRA,ST,VRT produces
-// <mnemonic> VRT,VRA,ST,SIX
- VSHASIGMAW $15, V1, $1, V0
- VSHASIGMAD $15, V1, $1, V0
-
-// VSX instructions
-// Described as:
-// <instruction type>, <instruction format>
-// <go asm operand order> produces
-// <Power ISA operand order>
-
-// VSX load, XX1-form
-// <MNEMONIC> (RB)(RA*1),XT produces
-// <mnemonic> XT,RA,RB
- LXVD2X (R1)(R2*1), VS0
- LXVW4X (R1)(R2*1), VS0
- LXVH8X (R1)(R2*1), VS0
- LXVB16X (R1)(R2*1), VS0
- LXVDSX (R1)(R2*1), VS0
- LXSDX (R1)(R2*1), VS0
- LXSIWAX (R1)(R2*1), VS0
- LXSIWZX (R1)(R2*1), VS0
-
-// VSX load with length X-form (also left-justified)
- LXVL R3,R4, VS0
- LXVLL R3,R4, VS0
- LXVX R3,R4, VS0
-// VSX load, DQ-form
-// <MNEMONIC> DQ(RA), XS produces
-// <mnemonic> XS, DQ(RA)
- LXV 32752(R1), VS0
-
-// VSX store, XX1-form
-// <MNEMONIC> XS,(RB)(RA*1) produces
-// <mnemonic> XS,RA,RB
- STXVD2X VS63, (R1)(R2*1)
- STXVW4X VS63, (R1)(R2*1)
- STXVH8X VS63, (R1)(R2*1)
- STXVB16X VS63, (R1)(R2*1)
- STXSDX VS63, (R1)(R2*1)
- STXSIWX VS63, (R1)(R2*1)
-
-// VSX store, DQ-form
-// <MNEMONIC> DQ(RA), XS produces
-// <mnemonic> XS, DQ(RA)
- STXV VS63, -32752(R1)
-
-// VSX store with length, X-form (also left-justified)
- STXVL VS0, R3,R4
- STXVLL VS0, R3,R4
- STXVX VS0, R3,R4
-
-// VSX move from VSR, XX1-form
-// <MNEMONIC> XS,RA produces
-// <mnemonic> RA,XS
-// Extended mnemonics accept VMX and FP registers as sources
- MFVSRD VS0, R1
- MFVSRWZ VS33, R1
- MFVSRLD VS63, R1
- MFVRD V0, R1
- MFFPRD F0, R1
-
-// VSX move to VSR, XX1-form
-// <MNEMONIC> RA,XT produces
-// <mnemonic> XT,RA
-// Extended mnemonics accept VMX and FP registers as targets
- MTVSRD R1, VS0
- MTVSRWA R1, VS31
- MTVSRWZ R1, VS63
- MTVSRDD R1, R2, VS0
- MTVSRWS R1, VS32
- MTVRD R1, V13
- MTFPRD R1, F24
-
-// VSX AND, XX3-form
-// <MNEMONIC> XA,XB,XT produces
-// <mnemonic> XT,XA,XB
- XXLAND VS0,VS1,VS32
- XXLANDC VS0,VS1,VS32
- XXLEQV VS0,VS1,VS32
- XXLNAND VS0,VS1,VS32
-
-// VSX OR, XX3-form
-// <MNEMONIC> XA,XB,XT produces
-// <mnemonic> XT,XA,XB
- XXLORC VS0,VS1,VS32
- XXLNOR VS0,VS1,VS32
- XXLORQ VS0,VS1,VS32
- XXLXOR VS0,VS1,VS32
- XXLOR VS0,VS1,VS32
-
-// VSX select, XX4-form
-// <MNEMONIC> XA,XB,XC,XT produces
-// <mnemonic> XT,XA,XB,XC
- XXSEL VS0,VS1,VS3,VS32
-
-// VSX merge, XX3-form
-// <MNEMONIC> XA,XB,XT produces
-// <mnemonic> XT,XA,XB
- XXMRGHW VS0,VS1,VS32
- XXMRGLW VS0,VS1,VS32
-
-// VSX splat, XX2-form
-// <MNEMONIC> XB,UIM,XT produces
-// <mnemonic> XT,XB,UIM
- XXSPLTW VS0,$3,VS32
- XXSPLTIB $26,VS0
-
-// VSX permute, XX3-form
-// <MNEMONIC> XA,XB,XT produces
-// <mnemonic> XT,XA,XB
- XXPERM VS0,VS1,VS32
-
-// VSX permute, XX3-form
-// <MNEMONIC> XA,XB,DM,XT produces
-// <mnemonic> XT,XA,XB,DM
- XXPERMDI VS0,VS1,$3,VS32
-
-// VSX shift, XX3-form
-// <MNEMONIC> XA,XB,SHW,XT produces
-// <mnemonic> XT,XA,XB,SHW
- XXSLDWI VS0,VS1,$3,VS32
-
-// VSX byte-reverse XX2-form
-// <MNEMONIC> XB,XT produces
-// <mnemonic> XT,XB
- XXBRQ VS0,VS1
- XXBRD VS0,VS1
- XXBRW VS0,VS1
- XXBRH VS0,VS1
-
-// VSX scalar FP-FP conversion, XX2-form
-// <MNEMONIC> XB,XT produces
-// <mnemonic> XT,XB
- XSCVDPSP VS0,VS32
- XSCVSPDP VS0,VS32
- XSCVDPSPN VS0,VS32
- XSCVSPDPN VS0,VS32
-
-// VSX vector FP-FP conversion, XX2-form
-// <MNEMONIC> XB,XT produces
-// <mnemonic> XT,XB
- XVCVDPSP VS0,VS32
- XVCVSPDP VS0,VS32
-
-// VSX scalar FP-integer conversion, XX2-form
-// <MNEMONIC> XB,XT produces
-// <mnemonic> XT,XB
- XSCVDPSXDS VS0,VS32
- XSCVDPSXWS VS0,VS32
- XSCVDPUXDS VS0,VS32
- XSCVDPUXWS VS0,VS32
-
-// VSX scalar integer-FP conversion, XX2-form
-// <MNEMONIC> XB,XT produces
-// <mnemonic> XT,XB
- XSCVSXDDP VS0,VS32
- XSCVUXDDP VS0,VS32
- XSCVSXDSP VS0,VS32
- XSCVUXDSP VS0,VS32
-
-// VSX vector FP-integer conversion, XX2-form
-// <MNEMONIC> XB,XT produces
-// <mnemonic> XT,XB
- XVCVDPSXDS VS0,VS32
- XVCVDPSXWS VS0,VS32
- XVCVDPUXDS VS0,VS32
- XVCVDPUXWS VS0,VS32
- XVCVSPSXDS VS0,VS32
- XVCVSPSXWS VS0,VS32
- XVCVSPUXDS VS0,VS32
- XVCVSPUXWS VS0,VS32
-
-// VSX scalar integer-FP conversion, XX2-form
-// <MNEMONIC> XB,XT produces
-// <mnemonic> XT,XB
- XVCVSXDDP VS0,VS32
- XVCVSXWDP VS0,VS32
- XVCVUXDDP VS0,VS32
- XVCVUXWDP VS0,VS32
- XVCVSXDSP VS0,VS32
- XVCVSXWSP VS0,VS32
- XVCVUXDSP VS0,VS32
- XVCVUXWSP VS0,VS32
-
-// Multiply-Add High Doubleword
-// <MNEMONIC> RA,RB,RC,RT produces
-// <mnemonic> RT,RA,RB,RC
- MADDHD R1,R2,R3,R4
- MADDHDU R1,R2,R3,R4
-
-// Add Extended using alternate carry bit
-// ADDEX RA,RB,CY,RT produces
-// addex RT, RA, RB, CY
- ADDEX R1, R2, $0, R3
-
-// Immediate-shifted operations
-// ADDIS SI, RA, RT produces
-// addis RT, RA, SI
- ADDIS $8, R3, R4
- ADDIS $-1, R3, R4
-
-// ANDISCC UI, RS, RA produces
-// andis. RA, RS, UI
- ANDISCC $7, R4, R5
-
-// ORIS UI, RS, RA produces
-// oris RA, RS, UI
- ORIS $4, R2, R3
-
-// XORIS UI, RS, RA produces
-// xoris RA, RS, UI
- XORIS $1, R1, R2
-
-//
-// NOP
-//
-// LNOP comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &nullgen, 0, &nullgen);
-// }
NOP
-
-// LNOP rreg comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
NOP R2
+ NOP F2
+ NOP $4
+
+ CRAND CR1, CR2, CR3 // 4c620a02
+ CRANDN CR1, CR2, CR3 // 4c620902
+ CREQV CR1, CR2, CR3 // 4c620a42
+ CRNAND CR1, CR2, CR3 // 4c6209c2
+ CRNOR CR1, CR2, CR3 // 4c620842
+ CROR CR1, CR2, CR3 // 4c620b82
+ CRORN CR1, CR2, CR3 // 4c620b42
+ CRXOR CR1, CR2, CR3 // 4c620982
+
+ ISEL $1, R3, R4, R5 // 7ca3205e
+ ISEL $0, R3, R4, R5 // 7ca3201e
+ ISEL $2, R3, R4, R5 // 7ca3209e
+ ISEL $3, R3, R4, R5 // 7ca320de
+ ISEL $4, R3, R4, R5 // 7ca3211e
+ POPCNTB R3, R4 // 7c6400f4
+ POPCNTW R3, R4 // 7c6402f4
+ POPCNTD R3, R4 // 7c6403f4
+
+ PASTECC R3, R4 // 7c23270d
+ COPY R3, R4 // 7c23260c
+
+ // load-and-reserve
+ LBAR (R4)(R3*1),$1,R5 // 7ca32069
+ LBAR (R4),$0,R5 // 7ca02068
+ LBAR (R3),R5 // 7ca01868
+ LHAR (R4)(R3*1),$1,R5 // 7ca320e9
+ LHAR (R4),$0,R5 // 7ca020e8
+ LHAR (R3),R5 // 7ca018e8
+ LWAR (R4)(R3*1),$1,R5 // 7ca32029
+ LWAR (R4),$0,R5 // 7ca02028
+ LWAR (R3),R5 // 7ca01828
+ LDAR (R4)(R3*1),$1,R5 // 7ca320a9
+ LDAR (R4),$0,R5 // 7ca020a8
+ LDAR (R3),R5 // 7ca018a8
+
+ STBCCC R3, (R4)(R5) // 7c65256d
+ STWCCC R3, (R4)(R5) // 7c65212d
+ STDCCC R3, (R4)(R5) // 7c6521ad
+ STHCCC R3, (R4)(R5)
+ STSW R3, (R4)(R5)
+
+ SYNC // 7c0004ac
+ ISYNC // 4c00012c
+ LWSYNC // 7c2004ac
+
+ DARN $1, R5 // 7ca105e6
+
+ DCBF (R3)(R4) // 7c0418ac
+ DCBI (R3)(R4) // 7c041bac
+ DCBST (R3)(R4) // 7c04186c
+ DCBZ (R3)(R4) // 7c041fec
+ DCBT (R3)(R4) // 7c041a2c
+ ICBI (R3)(R4) // 7c041fac
+
+ // float constants
+ FMOVD $(0.0), F1 // f0210cd0
+ FMOVD $(-0.0), F1 // f0210cd0fc200850
+
+ FMOVD 8(R3), F1 // c8230008
+ FMOVD (R3)(R4), F1 // 7c241cae
+ FMOVDU 8(R3), F1 // cc230008
+ FMOVDU (R3)(R4), F1 // 7c241cee
+ FMOVS 4(R3), F1 // c0230004
+ FMOVS (R3)(R4), F1 // 7c241c2e
+ FMOVSU 4(R3), F1 // c4230004
+ FMOVSU (R3)(R4), F1 // 7c241c6e
+
+ FMOVD F1, 8(R3) // d8230008
+ FMOVD F1, (R3)(R4) // 7c241dae
+ FMOVDU F1, 8(R3) // dc230008
+ FMOVDU F1, (R3)(R4) // 7c241dee
+ FMOVS F1, 4(R3) // d0230004
+ FMOVS F1, (R3)(R4) // 7c241d2e
+ FMOVSU F1, 4(R3) // d4230004
+ FMOVSU F1, (R3)(R4) // 7c241d6e
+ FADD F1, F2 // fc42082a
+ FADD F1, F2, F3 // fc62082a
+ FADDCC F1, F2, F3 // fc62082b
+ FADDS F1, F2 // ec42082a
+ FADDS F1, F2, F3 // ec62082a
+ FADDSCC F1, F2, F3 // ec62082b
+ FSUB F1, F2 // fc420828
+ FSUB F1, F2, F3 // fc620828
+ FSUBCC F1, F2, F3 // fc620829
+ FSUBS F1, F2 // ec420828
+ FSUBS F1, F2, F3 // ec620828
+ FSUBCC F1, F2, F3 // fc620829
+ FMUL F1, F2 // fc420072
+ FMUL F1, F2, F3 // fc620072
+ FMULCC F1, F2, F3 // fc620073
+ FMULS F1, F2 // ec420072
+ FMULS F1, F2, F3 // ec620072
+ FMULSCC F1, F2, F3 // ec620073
+ FDIV F1, F2 // fc420824
+ FDIV F1, F2, F3 // fc620824
+ FDIVCC F1, F2, F3 // fc620825
+ FDIVS F1, F2 // ec420824
+ FDIVS F1, F2, F3 // ec620824
+ FDIVSCC F1, F2, F3 // ec620825
+ FMADD F1, F2, F3, F4 // fc8110fa
+ FMADDCC F1, F2, F3, F4 // fc8110fb
+ FMADDS F1, F2, F3, F4 // ec8110fa
+ FMADDSCC F1, F2, F3, F4 // ec8110fb
+ FMSUB F1, F2, F3, F4 // fc8110f8
+ FMSUBCC F1, F2, F3, F4 // fc8110f9
+ FMSUBS F1, F2, F3, F4 // ec8110f8
+ FMSUBSCC F1, F2, F3, F4 // ec8110f9
+ FNMADD F1, F2, F3, F4 // fc8110fe
+ FNMADDCC F1, F2, F3, F4 // fc8110ff
+ FNMADDS F1, F2, F3, F4 // ec8110fe
+ FNMADDSCC F1, F2, F3, F4 // ec8110ff
+ FNMSUB F1, F2, F3, F4 // fc8110fc
+ FNMSUBCC F1, F2, F3, F4 // fc8110fd
+ FNMSUBS F1, F2, F3, F4 // ec8110fc
+ FNMSUBSCC F1, F2, F3, F4 // ec8110fd
+ FSEL F1, F2, F3, F4 // fc8110ee
+ FSELCC F1, F2, F3, F4 // fc8110ef
+ FABS F1, F2 // fc400a10
+ FABSCC F1, F2 // fc400a11
+ FNEG F1, F2 // fc400850
+ FABSCC F1, F2 // fc400a11
+ FRSP F1, F2 // fc400818
+ FRSPCC F1, F2 // fc400819
+ FCTIW F1, F2 // fc40081c
+ FCTIWCC F1, F2 // fc40081d
+ FCTIWZ F1, F2 // fc40081e
+ FCTIWZCC F1, F2 // fc40081f
+ FCTID F1, F2 // fc400e5c
+ FCTIDCC F1, F2 // fc400e5d
+ FCTIDZ F1, F2 // fc400e5e
+ FCTIDZCC F1, F2 // fc400e5f
+ FCFID F1, F2 // fc400e9c
+ FCFIDCC F1, F2 // fc400e9d
+ FCFIDU F1, F2 // fc400f9c
+ FCFIDUCC F1, F2 // fc400f9d
+ FCFIDS F1, F2 // ec400e9c
+ FCFIDSCC F1, F2 // ec400e9d
+ FRES F1, F2 // ec400830
+ FRESCC F1, F2 // ec400831
+ FRIM F1, F2 // fc400bd0
+ FRIMCC F1, F2 // fc400bd1
+ FRIP F1, F2 // fc400b90
+ FRIPCC F1, F2 // fc400b91
+ FRIZ F1, F2 // fc400b50
+ FRIZCC F1, F2 // fc400b51
+ FRIN F1, F2 // fc400b10
+ FRINCC F1, F2 // fc400b11
+ FRSQRTE F1, F2 // fc400834
+ FRSQRTECC F1, F2 // fc400835
+ FSQRT F1, F2 // fc40082c
+ FSQRTCC F1, F2 // fc40082d
+ FSQRTS F1, F2 // ec40082c
+ FSQRTSCC F1, F2 // ec40082d
+ FCPSGN F1, F2 // fc420810
+ FCPSGNCC F1, F2 // fc420811
+ FCMPO F1, F2 // fc011040
+ FCMPU F1, F2 // fc011000
+ LVX (R3)(R4), V1 // 7c2418ce
+ LVXL (R3)(R4), V1 // 7c241ace
+ LVSL (R3)(R4), V1 // 7c24180c
+ LVSR (R3)(R4), V1 // 7c24184c
+ LVEBX (R3)(R4), V1 // 7c24180e
+ LVEHX (R3)(R4), V1 // 7c24184e
+ LVEWX (R3)(R4), V1 // 7c24188e
+ STVX V1, (R3)(R4) // 7c2419ce
+ STVXL V1, (R3)(R4) // 7c241bce
+ STVEBX V1, (R3)(R4) // 7c24190e
+ STVEHX V1, (R3)(R4) // 7c24194e
+ STVEWX V1, (R3)(R4) // 7c24198e
+
+ VAND V1, V2, V3 // 10611404
+ VANDC V1, V2, V3 // 10611444
+ VNAND V1, V2, V3 // 10611584
+ VOR V1, V2, V3 // 10611484
+ VORC V1, V2, V3 // 10611544
+ VXOR V1, V2, V3 // 106114c4
+ VNOR V1, V2, V3 // 10611504
+ VEQV V1, V2, V3 // 10611684
+ VADDUBM V1, V2, V3 // 10611000
+ VADDUHM V1, V2, V3 // 10611040
+ VADDUWM V1, V2, V3 // 10611080
+ VADDUDM V1, V2, V3 // 106110c0
+ VADDUQM V1, V2, V3 // 10611100
+ VADDCUQ V1, V2, V3 // 10611140
+ VADDCUW V1, V2, V3 // 10611180
+ VADDUBS V1, V2, V3 // 10611200
+ VADDUHS V1, V2, V3 // 10611240
+ VADDUWS V1, V2, V3 // 10611280
+ VSUBUBM V1, V2, V3 // 10611400
+ VSUBUHM V1, V2, V3 // 10611440
+ VSUBUWM V1, V2, V3 // 10611480
+ VSUBUDM V1, V2, V3 // 106114c0
+ VSUBUQM V1, V2, V3 // 10611500
+ VSUBCUQ V1, V2, V3 // 10611540
+ VSUBCUW V1, V2, V3 // 10611580
+ VSUBUBS V1, V2, V3 // 10611600
+ VSUBUHS V1, V2, V3 // 10611640
+ VSUBUWS V1, V2, V3 // 10611680
+ VSUBSBS V1, V2, V3 // 10611700
+ VSUBSHS V1, V2, V3 // 10611740
+ VSUBSWS V1, V2, V3 // 10611780
+ VSUBEUQM V1, V2, V3, V4 // 108110fe
+ VSUBECUQ V1, V2, V3, V4 // 108110ff
+ VMULESB V1, V2, V3 // 10611308
+ VMULOSB V1, V2, V3 // 10611108
+ VMULEUB V1, V2, V3 // 10611208
+ VMULOUB V1, V2, V3 // 10611008
+ VMULESH V1, V2, V3 // 10611348
+ VMULOSH V1, V2, V3 // 10611148
+ VMULEUH V1, V2, V3 // 10611248
+ VMULOUH V1, V2, V3 // 10611048
+ VMULESH V1, V2, V3 // 10611348
+ VMULOSW V1, V2, V3 // 10611188
+ VMULEUW V1, V2, V3 // 10611288
+ VMULOUW V1, V2, V3 // 10611088
+ VMULUWM V1, V2, V3 // 10611089
+ VPMSUMB V1, V2, V3 // 10611408
+ VPMSUMH V1, V2, V3 // 10611448
+ VPMSUMW V1, V2, V3 // 10611488
+ VPMSUMD V1, V2, V3 // 106114c8
+ VMSUMUDM V1, V2, V3, V4 // 108110e3
+ VRLB V1, V2, V3 // 10611004
+ VRLH V1, V2, V3 // 10611044
+ VRLW V1, V2, V3 // 10611084
+ VRLD V1, V2, V3 // 106110c4
+ VSLB V1, V2, V3 // 10611104
+ VSLH V1, V2, V3 // 10611144
+ VSLW V1, V2, V3 // 10611184
+ VSL V1, V2, V3 // 106111c4
+ VSLO V1, V2, V3 // 1061140c
+ VSRB V1, V2, V3 // 10611204
+ VSRH V1, V2, V3 // 10611244
+ VSRW V1, V2, V3 // 10611284
+ VSR V1, V2, V3 // 106112c4
+ VSRO V1, V2, V3 // 1061144c
+ VSLD V1, V2, V3 // 106115c4
+ VSRAB V1, V2, V3 // 10611304
+ VSRAH V1, V2, V3 // 10611344
+ VSRAW V1, V2, V3 // 10611384
+ VSRAD V1, V2, V3 // 106113c4
+ VSLDOI $3, V1, V2, V3 // 106110ec
+ VCLZB V1, V2 // 10400f02
+ VCLZH V1, V2 // 10400f42
+ VCLZW V1, V2 // 10400f82
+ VCLZD V1, V2 // 10400fc2
+ VPOPCNTB V1, V2 // 10400f03
+ VPOPCNTH V1, V2 // 10400f43
+ VPOPCNTW V1, V2 // 10400f83
+ VPOPCNTD V1, V2 // 10400fc3
+ VCMPEQUB V1, V2, V3 // 10611006
+ VCMPEQUBCC V1, V2, V3 // 10611406
+ VCMPEQUH V1, V2, V3 // 10611046
+ VCMPEQUHCC V1, V2, V3 // 10611446
+ VCMPEQUW V1, V2, V3 // 10611086
+ VCMPEQUWCC V1, V2, V3 // 10611486
+ VCMPEQUD V1, V2, V3 // 106110c7
+ VCMPEQUDCC V1, V2, V3 // 106114c7
+ VCMPGTUB V1, V2, V3 // 10611206
+ VCMPGTUBCC V1, V2, V3 // 10611606
+ VCMPGTUH V1, V2, V3 // 10611246
+ VCMPGTUHCC V1, V2, V3 // 10611646
+ VCMPGTUW V1, V2, V3 // 10611286
+ VCMPGTUWCC V1, V2, V3 // 10611686
+ VCMPGTUD V1, V2, V3 // 106112c7
+ VCMPGTUDCC V1, V2, V3 // 106116c7
+ VCMPGTSB V1, V2, V3 // 10611306
+ VCMPGTSBCC V1, V2, V3 // 10611706
+ VCMPGTSH V1, V2, V3 // 10611346
+ VCMPGTSHCC V1, V2, V3 // 10611746
+ VCMPGTSW V1, V2, V3 // 10611386
+ VCMPGTSWCC V1, V2, V3 // 10611786
+ VCMPGTSD V1, V2, V3 // 106113c7
+ VCMPGTSDCC V1, V2, V3 // 106117c7
+ VCMPNEZB V1, V2, V3 // 10611107
+ VCMPNEZBCC V1, V2, V3 // 10611507
+ VCMPNEB V1, V2, V3 // 10611007
+ VCMPNEBCC V1, V2, V3 // 10611407
+ VCMPNEH V1, V2, V3 // 10611047
+ VCMPNEHCC V1, V2, V3 // 10611447
+ VCMPNEW V1, V2, V3 // 10611087
+ VCMPNEWCC V1, V2, V3 // 10611487
+ VPERM V1, V2, V3, V4 // 108110eb
+ VPERMR V1, V2, V3, V4 // 108110fb
+ VPERMXOR V1, V2, V3, V4 // 108110ed
+ VBPERMQ V1, V2, V3 // 1061154c
+ VBPERMD V1, V2, V3 // 106115cc
+ VSEL V1, V2, V3, V4 // 108110ea
+ VSPLTB $1, V1, V2 // 10410a0c
+ VSPLTH $1, V1, V2 // 10410a4c
+ VSPLTW $1, V1, V2 // 10410a8c
+ VSPLTISB $1, V1 // 1021030c
+ VSPLTISW $1, V1 // 1021038c
+ VSPLTISH $1, V1 // 1021034c
+ VCIPHER V1, V2, V3 // 10611508
+ VCIPHERLAST V1, V2, V3 // 10611509
+ VNCIPHER V1, V2, V3 // 10611548
+ VNCIPHERLAST V1, V2, V3 // 10611549
+ VSBOX V1, V2 // 104105c8
+ VSHASIGMAW $1, V1, $15, V2 // 10418e82
+ VSHASIGMAD $2, V1, $15, V2 // 104196c2
+
+ LXVD2X (R3)(R4), VS1 // 7c241e98
+ LXVDSX (R3)(R4), VS1 // 7c241a98
+ LXVH8X (R3)(R4), VS1 // 7c241e58
+ LXVB16X (R3)(R4), VS1 // 7c241ed8
+ LXVW4X (R3)(R4), VS1 // 7c241e18
+ LXV 16(R3), VS1 // f4230011
+ LXVL R3, R4, VS1 // 7c23221a
+ LXVLL R3, R4, VS1 // 7c23225a
+ LXVX R3, R4, VS1 // 7c232218
+ LXSDX (R3)(R4), VS1 // 7c241c98
+ STXVD2X VS1, (R3)(R4) // 7c241f98
+ STXV VS1,16(R3) // f4230015
+ STXVL VS1, R3, R4 // 7c23231a
+ STXVLL VS1, R3, R4 // 7c23235a
+ STXVX VS1, R3, R4 // 7c232318
+ STXVB16X VS1, (R4)(R5) // 7c2527d8
+ STXVH8X VS1, (R4)(R5) // 7c252758
+
+ STXSDX VS1, (R3)(R4) // 7c241d98
+ LXSIWAX (R3)(R4), VS1 // 7c241898
+ STXSIWX VS1, (R3)(R4) // 7c241918
+ MFVSRD VS1, R3 // 7c230066
+ MTFPRD R3, F0 // 7c030166
+ MFVRD V0, R3 // 7c030067
+ MFVSRLD VS63,R4 // 7fe40267
+ MFVSRWZ VS33,R4 // 7c2400e7
+ MTVSRD R3, VS1 // 7c230166
+ MTVRD R3, V13 // 7da30167
+ MTVSRWA R4, VS31 // 7fe401a6
+ MTVSRWS R4, VS32 // 7c040327
+ MTVSRWZ R4, VS63 // 7fe401e7
+ XXBRD VS0, VS1 // f037076c
+ XXBRW VS1, VS2 // f04f0f6c
+ XXBRH VS2, VS3 // f067176c
+ XXLAND VS1, VS2, VS3 // f0611410
+ XXLANDC VS1, VS2, VS3 // f0611450
+ XXLEQV VS0, VS1, VS2 // f0400dd0
+ XXLNAND VS0, VS1, VS2 // f0400d90
+ XXLNOR VS0, VS1, VS32 // f0000d11
+ XXLOR VS1, VS2, VS3 // f0611490
+ XXLORC VS1, VS2, VS3 // f0611550
+ XXLORQ VS1, VS2, VS3 // f0611490
+ XXLXOR VS1, VS2, VS3 // f06114d0
+ XXSEL VS1, VS2, VS3, VS4 // f08110f0
+ XXMRGHW VS1, VS2, VS3 // f0611090
+ XXMRGLW VS1, VS2, VS3 // f0611190
+ XXSPLTW VS1, $1, VS2 // f0410a90
+ XXPERM VS1, VS2, VS3 // f06110d0
+ XXSLDWI VS1, VS2, $1, VS3 // f0611110
+ XSCVDPSP VS1, VS2 // f0400c24
+ XVCVDPSP VS1, VS2 // f0400e24
+ XSCVSXDDP VS1, VS2 // f0400de0
+ XVCVDPSXDS VS1, VS2 // f0400f60
+ XVCVSXDDP VS1, VS2 // f0400fe0
+ XSCVDPSPN VS1,VS32 // f0000c2d
+ XSCVDPSP VS1,VS32 // f0000c25
+ XSCVDPSXDS VS1,VS32 // f0000d61
+ XSCVDPSXWS VS1,VS32 // f0000961
+ XSCVDPUXDS VS1,VS32 // f0000d21
+ XSCVDPUXWS VS1,VS32 // f0000921
+ XSCVSPDPN VS1,VS32 // f0000d2d
+ XSCVSPDP VS1,VS32 // f0000d25
+ XSCVSXDDP VS1,VS32 // f0000de1
+ XSCVSXDSP VS1,VS32 // f0000ce1
+ XSCVUXDDP VS1,VS32 // f0000da1
+ XSCVUXDSP VS1,VS32 // f0000ca1
+ XVCVDPSP VS1,VS32 // f0000e25
+ XVCVDPSXDS VS1,VS32 // f0000f61
+ XVCVDPSXWS VS1,VS32 // f0000b61
+ XVCVDPUXDS VS1,VS32 // f0000f21
+ XVCVDPUXWS VS1,VS32 // f0000b21
+ XVCVSPDP VS1,VS32 // f0000f25
+ XVCVSPSXDS VS1,VS32 // f0000e61
+ XVCVSPSXWS VS1,VS32 // f0000a61
+ XVCVSPUXDS VS1,VS32 // f0000e21
+ XVCVSPUXWS VS1,VS32 // f0000a21
+ XVCVSXDDP VS1,VS32 // f0000fe1
+ XVCVSXDSP VS1,VS32 // f0000ee1
+ XVCVSXWDP VS1,VS32 // f0000be1
+ XVCVSXWSP VS1,VS32 // f0000ae1
+ XVCVUXDDP VS1,VS32 // f0000fa1
+ XVCVUXDSP VS1,VS32 // f0000ea1
+ XVCVUXWDP VS1,VS32 // f0000ba1
+ XVCVUXWSP VS1,VS32 // f0000aa1
+
+ MOVD R3, LR // 7c6803a6
+ MOVD R3, CTR // 7c6903a6
+ MOVD R3, XER // 7c6103a6
+ MOVD LR, R3 // 7c6802a6
+ MOVD CTR, R3 // 7c6902a6
+ MOVD XER, R3 // 7c6102a6
+ MOVFL CR3, CR1 // 4c8c0000
-// LNOP freg comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
- NOP F2
-
-// LNOP ',' rreg // asm doesn't support the leading comma.
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
- NOP R2
-
-// LNOP ',' freg // asm doesn't support the leading comma.
-// {
-// outcode(int($1), &nullgen, 0, &$3);
-// }
- NOP F2
-
-// LNOP imm // SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards.
-// {
-// outcode(int($1), &$2, 0, &nullgen);
-// }
- NOP $4
-
-// RET
-//
-// LRETRN comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &nullgen, 0, &nullgen);
-// }
- BEQ 2(PC)
RET
-
-// More BR/BL cases, and canonical names JMP, CALL.
-
- BEQ 2(PC)
- BR foo(SB) // JMP foo(SB)
- BL foo(SB) // CALL foo(SB)
- BEQ 2(PC)
- JMP foo(SB)
- CALL foo(SB)
- RET foo(SB)
-
-// load-and-reserve
-// L*AR (RB)(RA*1),EH,RT produces
-// l*arx RT,RA,RB,EH
-//
-// Extended forms also accepted. Assumes RA=0, EH=0:
-// L*AR (RB),RT
-// L*AR (RB),EH,RT
- LBAR (R4)(R3*1), $1, R5
- LBAR (R4), $0, R5
- LBAR (R3), R5
- LHAR (R4)(R3*1), $1, R5
- LHAR (R4), $0, R5
- LHAR (R3), R5
- LWAR (R4)(R3*1), $1, R5
- LWAR (R4), $0, R5
- LWAR (R3), R5
- LDAR (R4)(R3*1), $1, R5
- LDAR (R4), $0, R5
- LDAR (R3), R5
-
-// END
-//
-// LEND comma // asm doesn't support the trailing comma.
-// {
-// outcode(int($1), &nullgen, 0, &nullgen);
-// }
- END
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64enc.s b/src/cmd/asm/internal/asm/testdata/ppc64enc.s
deleted file mode 100644
index 88a7609ba8..0000000000
--- a/src/cmd/asm/internal/asm/testdata/ppc64enc.s
+++ /dev/null
@@ -1,638 +0,0 @@
-// Copyright 2018 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.
-
-// Initial set of opcode combinations based on
-// improvements to processing of constant
-// operands.
-
-// Full set will be added at a later date.
-
-#include "../../../../../runtime/textflag.h"
-
-TEXT asmtest(SB),DUPOK|NOSPLIT,$0
- // move constants
- MOVD $1, R3 // 38600001
- MOVD $-1, R4 // 3880ffff
- MOVD $65535, R5 // 6005ffff
- MOVD $65536, R6 // 64060001
- MOVD $-32767, R5 // 38a08001
- MOVD $-32768, R6 // 38c08000
- MOVD $1234567, R5 // 6405001260a5d687
- MOVW $1, R3 // 38600001
- MOVW $-1, R4 // 3880ffff
- MOVW $65535, R5 // 6005ffff
- MOVW $65536, R6 // 64060001
- MOVW $-32767, R5 // 38a08001
- MOVW $-32768, R6 // 38c08000
- MOVW $1234567, R5 // 6405001260a5d687
- MOVD 8(R3), R4 // e8830008
- MOVD (R3)(R4), R5 // 7ca4182a
- MOVW 4(R3), R4 // e8830006
- MOVW (R3)(R4), R5 // 7ca41aaa
- MOVWZ 4(R3), R4 // 80830004
- MOVWZ (R3)(R4), R5 // 7ca4182e
- MOVH 4(R3), R4 // a8830004
- MOVH (R3)(R4), R5 // 7ca41aae
- MOVHZ 2(R3), R4 // a0830002
- MOVHZ (R3)(R4), R5 // 7ca41a2e
- MOVB 1(R3), R4 // 888300017c840774
- MOVB (R3)(R4), R5 // 7ca418ae7ca50774
- MOVBZ 1(R3), R4 // 88830001
- MOVBZ (R3)(R4), R5 // 7ca418ae
- MOVDBR (R3)(R4), R5 // 7ca41c28
- MOVWBR (R3)(R4), R5 // 7ca41c2c
- MOVHBR (R3)(R4), R5 // 7ca41e2c
-
- MOVDU 8(R3), R4 // e8830009
- MOVDU (R3)(R4), R5 // 7ca4186a
- MOVWU (R3)(R4), R5 // 7ca41aea
- MOVWZU 4(R3), R4 // 84830004
- MOVWZU (R3)(R4), R5 // 7ca4186e
- MOVHU 2(R3), R4 // ac830002
- MOVHU (R3)(R4), R5 // 7ca41aee
- MOVHZU 2(R3), R4 // a4830002
- MOVHZU (R3)(R4), R5 // 7ca41a6e
- MOVBU 1(R3), R4 // 8c8300017c840774
- MOVBU (R3)(R4), R5 // 7ca418ee7ca50774
- MOVBZU 1(R3), R4 // 8c830001
- MOVBZU (R3)(R4), R5 // 7ca418ee
-
- MOVD R4, 8(R3) // f8830008
- MOVD R5, (R3)(R4) // 7ca4192a
- MOVW R4, 4(R3) // 90830004
- MOVW R5, (R3)(R4) // 7ca4192e
- MOVH R4, 2(R3) // b0830002
- MOVH R5, (R3)(R4) // 7ca41b2e
- MOVB R4, 1(R3) // 98830001
- MOVB R5, (R3)(R4) // 7ca419ae
- MOVDBR R5, (R3)(R4) // 7ca41d28
- MOVWBR R5, (R3)(R4) // 7ca41d2c
- MOVHBR R5, (R3)(R4) // 7ca41f2c
-
- MOVDU R4, 8(R3) // f8830009
- MOVDU R5, (R3)(R4) // 7ca4196a
- MOVWU R4, 4(R3) // 94830004
- MOVWU R5, (R3)(R4) // 7ca4196e
- MOVHU R4, 2(R3) // b4830002
- MOVHU R5, (R3)(R4) // 7ca41b6e
- MOVBU R4, 1(R3) // 9c830001
- MOVBU R5, (R3)(R4) // 7ca419ee
-
- ADD $1, R3 // 38630001
- ADD $1, R3, R4 // 38830001
- ADD $-1, R4 // 3884ffff
- ADD $-1, R4, R5 // 38a4ffff
- ADD $65535, R5 // 601fffff7cbf2a14
- ADD $65535, R5, R6 // 601fffff7cdf2a14
- ADD $65536, R6 // 3cc60001
- ADD $65536, R6, R7 // 3ce60001
- ADD $-32767, R5 // 38a58001
- ADD $-32767, R5, R4 // 38858001
- ADD $-32768, R6 // 38c68000
- ADD $-32768, R6, R5 // 38a68000
- ADD $1234567, R5 // 641f001263ffd6877cbf2a14
- ADD $1234567, R5, R6 // 641f001263ffd6877cdf2a14
- ADDIS $8, R3 // 3c630008
- ADDIS $1000, R3, R4 // 3c8303e8
-
- ANDCC $1, R3 // 70630001
- ANDCC $1, R3, R4 // 70640001
- ANDCC $-1, R4 // 3be0ffff7fe42039
- ANDCC $-1, R4, R5 // 3be0ffff7fe52039
- ANDCC $65535, R5 // 70a5ffff
- ANDCC $65535, R5, R6 // 70a6ffff
- ANDCC $65536, R6 // 74c60001
- ANDCC $65536, R6, R7 // 74c70001
- ANDCC $-32767, R5 // 3be080017fe52839
- ANDCC $-32767, R5, R4 // 3be080017fe42839
- ANDCC $-32768, R6 // 3be080007fe63039
- ANDCC $-32768, R5, R6 // 3be080007fe62839
- ANDCC $1234567, R5 // 641f001263ffd6877fe52839
- ANDCC $1234567, R5, R6 // 641f001263ffd6877fe62839
- ANDISCC $1, R3 // 74630001
- ANDISCC $1000, R3, R4 // 746403e8
-
- OR $1, R3 // 60630001
- OR $1, R3, R4 // 60640001
- OR $-1, R4 // 3be0ffff7fe42378
- OR $-1, R4, R5 // 3be0ffff7fe52378
- OR $65535, R5 // 60a5ffff
- OR $65535, R5, R6 // 60a6ffff
- OR $65536, R6 // 64c60001
- OR $65536, R6, R7 // 64c70001
- OR $-32767, R5 // 3be080017fe52b78
- OR $-32767, R5, R6 // 3be080017fe62b78
- OR $-32768, R6 // 3be080007fe63378
- OR $-32768, R6, R7 // 3be080007fe73378
- OR $1234567, R5 // 641f001263ffd6877fe52b78
- OR $1234567, R5, R3 // 641f001263ffd6877fe32b78
-
- XOR $1, R3 // 68630001
- XOR $1, R3, R4 // 68640001
- XOR $-1, R4 // 3be0ffff7fe42278
- XOR $-1, R4, R5 // 3be0ffff7fe52278
- XOR $65535, R5 // 68a5ffff
- XOR $65535, R5, R6 // 68a6ffff
- XOR $65536, R6 // 6cc60001
- XOR $65536, R6, R7 // 6cc70001
- XOR $-32767, R5 // 3be080017fe52a78
- XOR $-32767, R5, R6 // 3be080017fe62a78
- XOR $-32768, R6 // 3be080007fe63278
- XOR $-32768, R6, R7 // 3be080007fe73278
- XOR $1234567, R5 // 641f001263ffd6877fe52a78
- XOR $1234567, R5, R3 // 641f001263ffd6877fe32a78
-
- // TODO: the order of CR operands don't match
- CMP R3, R4 // 7c232000
- CMPU R3, R4 // 7c232040
- CMPW R3, R4 // 7c032000
- CMPWU R3, R4 // 7c032040
-
- // TODO: constants for ADDC?
- ADD R3, R4 // 7c841a14
- ADD R3, R4, R5 // 7ca41a14
- ADDC R3, R4 // 7c841814
- ADDC R3, R4, R5 // 7ca41814
- ADDE R3, R4 // 7c841914
- ADDECC R3, R4 // 7c841915
- ADDEV R3, R4 // 7c841d14
- ADDEVCC R3, R4 // 7c841d15
- ADDV R3, R4 // 7c841e14
- ADDVCC R3, R4 // 7c841e15
- ADDCCC R3, R4, R5 // 7ca41815
- ADDME R3, R4 // 7c8301d4
- ADDMECC R3, R4 // 7c8301d5
- ADDMEV R3, R4 // 7c8305d4
- ADDMEVCC R3, R4 // 7c8305d5
- ADDCV R3, R4 // 7c841c14
- ADDCVCC R3, R4 // 7c841c15
- ADDZE R3, R4 // 7c830194
- ADDZECC R3, R4 // 7c830195
- ADDZEV R3, R4 // 7c830594
- ADDZEVCC R3, R4 // 7c830595
- SUBME R3, R4 // 7c8301d0
- SUBMECC R3, R4 // 7c8301d1
- SUBMEV R3, R4 // 7c8305d0
- SUBZE R3, R4 // 7c830190
- SUBZECC R3, R4 // 7c830191
- SUBZEV R3, R4 // 7c830590
- SUBZEVCC R3, R4 // 7c830591
-
- AND R3, R4 // 7c841838
- AND R3, R4, R5 // 7c851838
- ANDN R3, R4, R5 // 7c851878
- ANDCC R3, R4, R5 // 7c851839
- OR R3, R4 // 7c841b78
- OR R3, R4, R5 // 7c851b78
- ORN R3, R4, R5 // 7c851b38
- ORCC R3, R4, R5 // 7c851b79
- XOR R3, R4 // 7c841a78
- XOR R3, R4, R5 // 7c851a78
- XORCC R3, R4, R5 // 7c851a79
- NAND R3, R4, R5 // 7c851bb8
- NANDCC R3, R4, R5 // 7c851bb9
- EQV R3, R4, R5 // 7c851a38
- EQVCC R3, R4, R5 // 7c851a39
- NOR R3, R4, R5 // 7c8518f8
- NORCC R3, R4, R5 // 7c8518f9
-
- SUB R3, R4 // 7c832050
- SUB R3, R4, R5 // 7ca32050
- SUBC R3, R4 // 7c832010
- SUBC R3, R4, R5 // 7ca32010
-
- MULLW R3, R4 // 7c8419d6
- MULLW R3, R4, R5 // 7ca419d6
- MULLWCC R3, R4, R5 // 7ca419d7
- MULHW R3, R4, R5 // 7ca41896
-
- MULHWU R3, R4, R5 // 7ca41816
- MULLD R3, R4 // 7c8419d2
- MULLD R4, R4, R5 // 7ca421d2
- MULLDCC R3, R4, R5 // 7ca419d3
- MULHD R3, R4, R5 // 7ca41892
- MULHDCC R3, R4, R5 // 7ca41893
-
- MULLWV R3, R4 // 7c841dd6
- MULLWV R3, R4, R5 // 7ca41dd6
- MULLWVCC R3, R4, R5 // 7ca41dd7
- MULHWUCC R3, R4, R5 // 7ca41817
- MULLDV R3, R4, R5 // 7ca41dd2
- MULLDVCC R3, R4, R5 // 7ca41dd3
-
- DIVD R3,R4 // 7c841bd2
- DIVD R3, R4, R5 // 7ca41bd2
- DIVDCC R3,R4, R5 // 7ca41bd3
- DIVDU R3, R4, R5 // 7ca41b92
- DIVDV R3, R4, R5 // 7ca41fd2
- DIVDUCC R3, R4, R5 // 7ca41b93
- DIVDVCC R3, R4, R5 // 7ca41fd3
- DIVDUV R3, R4, R5 // 7ca41f92
- DIVDUVCC R3, R4, R5 // 7ca41f93
- DIVDE R3, R4, R5 // 7ca41b52
- DIVDECC R3, R4, R5 // 7ca41b53
- DIVDEU R3, R4, R5 // 7ca41b12
- DIVDEUCC R3, R4, R5 // 7ca41b13
-
- REM R3, R4, R5 // 7fe41bd67fff19d67cbf2050
- REMU R3, R4, R5 // 7fe41b967fff19d67bff00287cbf2050
- REMD R3, R4, R5 // 7fe41bd27fff19d27cbf2050
- REMDU R3, R4, R5 // 7fe41b927fff19d27cbf2050
-
- MODUD R3, R4, R5 // 7ca41a12
- MODUW R3, R4, R5 // 7ca41a16
- MODSD R3, R4, R5 // 7ca41e12
- MODSW R3, R4, R5 // 7ca41e16
-
- SLW $8, R3, R4 // 5464402e
- SLW R3, R4, R5 // 7c851830
- SLWCC R3, R4 // 7c841831
- SLD $16, R3, R4 // 786483e4
- SLD R3, R4, R5 // 7c851836
- SLDCC R3, R4 // 7c841837
-
- SRW $8, R3, R4 // 5464c23e
- SRW R3, R4, R5 // 7c851c30
- SRWCC R3, R4 // 7c841c31
- SRAW $8, R3, R4 // 7c644670
- SRAW R3, R4, R5 // 7c851e30
- SRAWCC R3, R4 // 7c841e31
- SRD $16, R3, R4 // 78648402
- SRD R3, R4, R5 // 7c851c36
- SRDCC R3, R4 // 7c841c37
- SRAD $16, R3, R4 // 7c648674
- SRAD R3, R4, R5 // 7c851e34
- SRDCC R3, R4 // 7c841c37
- ROTLW $16, R3, R4 // 5464803e
- ROTLW R3, R4, R5 // 5c85183e
- EXTSWSLI $3, R4, R5 // 7c851ef4
- RLWMI $7, R3, $65535, R6 // 50663c3e
- RLWMICC $7, R3, $65535, R6 // 50663c3f
- RLWNM $3, R4, $7, R6 // 54861f7e
- RLWNMCC $3, R4, $7, R6 // 54861f7f
- RLDMI $0, R4, $7, R6 // 7886076c
- RLDMICC $0, R4, $7, R6 // 7886076d
- RLDIMI $0, R4, $7, R6 // 788601cc
- RLDIMICC $0, R4, $7, R6 // 788601cd
- RLDC $0, R4, $15, R6 // 78860728
- RLDCCC $0, R4, $15, R6 // 78860729
- RLDCL $0, R4, $7, R6 // 78860770
- RLDCLCC $0, R4, $15, R6 // 78860721
- RLDCR $0, R4, $-16, R6 // 788606f2
- RLDCRCC $0, R4, $-16, R6 // 788606f3
- RLDICL $0, R4, $15, R6 // 788603c0
- RLDICLCC $0, R4, $15, R6 // 788603c1
- RLDICR $0, R4, $15, R6 // 788603c4
- RLDICRCC $0, R4, $15, R6 // 788603c5
- RLDIC $0, R4, $15, R6 // 788603c8
- RLDICCC $0, R4, $15, R6 // 788603c9
- CLRLSLWI $16, R5, $8, R4 // 54a4861e
- CLRLSLDI $2, R4, $24, R3 // 78831588
-
- BEQ 0(PC) // 41820000
- BGE 0(PC) // 40800000
- BGT 4(PC) // 41810030
- BLE 0(PC) // 40810000
- BLT 0(PC) // 41800000
- BNE 0(PC) // 40820000
- JMP 8(PC) // 48000020
-
- CRAND CR1, CR2, CR3 // 4c620a02
- CRANDN CR1, CR2, CR3 // 4c620902
- CREQV CR1, CR2, CR3 // 4c620a42
- CRNAND CR1, CR2, CR3 // 4c6209c2
- CRNOR CR1, CR2, CR3 // 4c620842
- CROR CR1, CR2, CR3 // 4c620b82
- CRORN CR1, CR2, CR3 // 4c620b42
- CRXOR CR1, CR2, CR3 // 4c620982
-
- ISEL $1, R3, R4, R5 // 7ca3205e
- ISEL $0, R3, R4, R5 // 7ca3201e
- ISEL $2, R3, R4, R5 // 7ca3209e
- ISEL $3, R3, R4, R5 // 7ca320de
- ISEL $4, R3, R4, R5 // 7ca3211e
- POPCNTB R3, R4 // 7c6400f4
- POPCNTW R3, R4 // 7c6402f4
- POPCNTD R3, R4 // 7c6403f4
-
- PASTECC R3, R4 // 7c23270d
- COPY R3, R4 // 7c23260c
-
- // load-and-reserve
- LBAR (R4)(R3*1),$1,R5 // 7ca32069
- LBAR (R4),$0,R5 // 7ca02068
- LBAR (R3),R5 // 7ca01868
- LHAR (R4)(R3*1),$1,R5 // 7ca320e9
- LHAR (R4),$0,R5 // 7ca020e8
- LHAR (R3),R5 // 7ca018e8
- LWAR (R4)(R3*1),$1,R5 // 7ca32029
- LWAR (R4),$0,R5 // 7ca02028
- LWAR (R3),R5 // 7ca01828
- LDAR (R4)(R3*1),$1,R5 // 7ca320a9
- LDAR (R4),$0,R5 // 7ca020a8
- LDAR (R3),R5 // 7ca018a8
-
- STBCCC R3, (R4)(R5) // 7c65256d
- STWCCC R3, (R4)(R5) // 7c65212d
- STDCCC R3, (R4)(R5) // 7c6521ad
- STHCCC R3, (R4)(R5)
-
- SYNC // 7c0004ac
- ISYNC // 4c00012c
- LWSYNC // 7c2004ac
-
- DCBF (R3)(R4) // 7c0418ac
- DCBI (R3)(R4) // 7c041bac
- DCBST (R3)(R4) // 7c04186c
- DCBZ (R3)(R4) // 7c041fec
- DCBT (R3)(R4) // 7c041a2c
- ICBI (R3)(R4) // 7c041fac
-
- // float constants
- FMOVD $(0.0), F1 // f0210cd0
- FMOVD $(-0.0), F1 // f0210cd0fc200850
-
- FMOVD 8(R3), F1 // c8230008
- FMOVD (R3)(R4), F1 // 7c241cae
- FMOVDU 8(R3), F1 // cc230008
- FMOVDU (R3)(R4), F1 // 7c241cee
- FMOVS 4(R3), F1 // c0230004
- FMOVS (R3)(R4), F1 // 7c241c2e
- FMOVSU 4(R3), F1 // c4230004
- FMOVSU (R3)(R4), F1 // 7c241c6e
-
- FMOVD F1, 8(R3) // d8230008
- FMOVD F1, (R3)(R4) // 7c241dae
- FMOVDU F1, 8(R3) // dc230008
- FMOVDU F1, (R3)(R4) // 7c241dee
- FMOVS F1, 4(R3) // d0230004
- FMOVS F1, (R3)(R4) // 7c241d2e
- FMOVSU F1, 4(R3) // d4230004
- FMOVSU F1, (R3)(R4) // 7c241d6e
- FADD F1, F2 // fc42082a
- FADD F1, F2, F3 // fc62082a
- FADDCC F1, F2, F3 // fc62082b
- FADDS F1, F2 // ec42082a
- FADDS F1, F2, F3 // ec62082a
- FADDSCC F1, F2, F3 // ec62082b
- FSUB F1, F2 // fc420828
- FSUB F1, F2, F3 // fc620828
- FSUBCC F1, F2, F3 // fc620829
- FSUBS F1, F2 // ec420828
- FSUBS F1, F2, F3 // ec620828
- FSUBCC F1, F2, F3 // fc620829
- FMUL F1, F2 // fc420072
- FMUL F1, F2, F3 // fc620072
- FMULCC F1, F2, F3 // fc620073
- FMULS F1, F2 // ec420072
- FMULS F1, F2, F3 // ec620072
- FMULSCC F1, F2, F3 // ec620073
- FDIV F1, F2 // fc420824
- FDIV F1, F2, F3 // fc620824
- FDIVCC F1, F2, F3 // fc620825
- FDIVS F1, F2 // ec420824
- FDIVS F1, F2, F3 // ec620824
- FDIVSCC F1, F2, F3 // ec620825
- FMADD F1, F2, F3, F4 // fc8110fa
- FMADDCC F1, F2, F3, F4 // fc8110fb
- FMADDS F1, F2, F3, F4 // ec8110fa
- FMADDSCC F1, F2, F3, F4 // ec8110fb
- FMSUB F1, F2, F3, F4 // fc8110f8
- FMSUBCC F1, F2, F3, F4 // fc8110f9
- FMSUBS F1, F2, F3, F4 // ec8110f8
- FMSUBSCC F1, F2, F3, F4 // ec8110f9
- FNMADD F1, F2, F3, F4 // fc8110fe
- FNMADDCC F1, F2, F3, F4 // fc8110ff
- FNMADDS F1, F2, F3, F4 // ec8110fe
- FNMADDSCC F1, F2, F3, F4 // ec8110ff
- FNMSUB F1, F2, F3, F4 // fc8110fc
- FNMSUBCC F1, F2, F3, F4 // fc8110fd
- FNMSUBS F1, F2, F3, F4 // ec8110fc
- FNMSUBSCC F1, F2, F3, F4 // ec8110fd
- FSEL F1, F2, F3, F4 // fc8110ee
- FSELCC F1, F2, F3, F4 // fc8110ef
- FABS F1, F2 // fc400a10
- FABSCC F1, F2 // fc400a11
- FNEG F1, F2 // fc400850
- FABSCC F1, F2 // fc400a11
- FRSP F1, F2 // fc400818
- FRSPCC F1, F2 // fc400819
- FCTIW F1, F2 // fc40081c
- FCTIWCC F1, F2 // fc40081d
- FCTIWZ F1, F2 // fc40081e
- FCTIWZCC F1, F2 // fc40081f
- FCTID F1, F2 // fc400e5c
- FCTIDCC F1, F2 // fc400e5d
- FCTIDZ F1, F2 // fc400e5e
- FCTIDZCC F1, F2 // fc400e5f
- FCFID F1, F2 // fc400e9c
- FCFIDCC F1, F2 // fc400e9d
- FCFIDU F1, F2 // fc400f9c
- FCFIDUCC F1, F2 // fc400f9d
- FCFIDS F1, F2 // ec400e9c
- FCFIDSCC F1, F2 // ec400e9d
- FRES F1, F2 // ec400830
- FRESCC F1, F2 // ec400831
- FRIM F1, F2 // fc400bd0
- FRIMCC F1, F2 // fc400bd1
- FRIP F1, F2 // fc400b90
- FRIPCC F1, F2 // fc400b91
- FRIZ F1, F2 // fc400b50
- FRIZCC F1, F2 // fc400b51
- FRIN F1, F2 // fc400b10
- FRINCC F1, F2 // fc400b11
- FRSQRTE F1, F2 // fc400834
- FRSQRTECC F1, F2 // fc400835
- FSQRT F1, F2 // fc40082c
- FSQRTCC F1, F2 // fc40082d
- FSQRTS F1, F2 // ec40082c
- FSQRTSCC F1, F2 // ec40082d
- FCPSGN F1, F2 // fc420810
- FCPSGNCC F1, F2 // fc420811
- FCMPO F1, F2 // fc011040
- FCMPU F1, F2 // fc011000
- LVX (R3)(R4), V1 // 7c2418ce
- LVXL (R3)(R4), V1 // 7c241ace
- LVSL (R3)(R4), V1 // 7c24180c
- LVSR (R3)(R4), V1 // 7c24184c
- LVEBX (R3)(R4), V1 // 7c24180e
- LVEHX (R3)(R4), V1 // 7c24184e
- LVEWX (R3)(R4), V1 // 7c24188e
- STVX V1, (R3)(R4) // 7c2419ce
- STVXL V1, (R3)(R4) // 7c241bce
- STVEBX V1, (R3)(R4) // 7c24190e
- STVEHX V1, (R3)(R4) // 7c24194e
- STVEWX V1, (R3)(R4) // 7c24198e
-
- VAND V1, V2, V3 // 10611404
- VANDC V1, V2, V3 // 10611444
- VNAND V1, V2, V3 // 10611584
- VOR V1, V2, V3 // 10611484
- VORC V1, V2, V3 // 10611544
- VXOR V1, V2, V3 // 106114c4
- VNOR V1, V2, V3 // 10611504
- VEQV V1, V2, V3 // 10611684
- VADDUBM V1, V2, V3 // 10611000
- VADDUHM V1, V2, V3 // 10611040
- VADDUWM V1, V2, V3 // 10611080
- VADDUDM V1, V2, V3 // 106110c0
- VADDUQM V1, V2, V3 // 10611100
- VADDCUQ V1, V2, V3 // 10611140
- VADDCUW V1, V2, V3 // 10611180
- VADDUBS V1, V2, V3 // 10611200
- VADDUHS V1, V2, V3 // 10611240
- VADDUWS V1, V2, V3 // 10611280
- VSUBUBM V1, V2, V3 // 10611400
- VSUBUHM V1, V2, V3 // 10611440
- VSUBUWM V1, V2, V3 // 10611480
- VSUBUDM V1, V2, V3 // 106114c0
- VSUBUQM V1, V2, V3 // 10611500
- VSUBCUQ V1, V2, V3 // 10611540
- VSUBCUW V1, V2, V3 // 10611580
- VSUBUBS V1, V2, V3 // 10611600
- VSUBUHS V1, V2, V3 // 10611640
- VSUBUWS V1, V2, V3 // 10611680
- VSUBSBS V1, V2, V3 // 10611700
- VSUBSHS V1, V2, V3 // 10611740
- VSUBSWS V1, V2, V3 // 10611780
- VSUBEUQM V1, V2, V3, V4 // 108110fe
- VSUBECUQ V1, V2, V3, V4 // 108110ff
- VMULESB V1, V2, V3 // 10611308
- VMULOSB V1, V2, V3 // 10611108
- VMULEUB V1, V2, V3 // 10611208
- VMULOUB V1, V2, V3 // 10611008
- VMULESH V1, V2, V3 // 10611348
- VMULOSH V1, V2, V3 // 10611148
- VMULEUH V1, V2, V3 // 10611248
- VMULOUH V1, V2, V3 // 10611048
- VMULESH V1, V2, V3 // 10611348
- VMULOSW V1, V2, V3 // 10611188
- VMULEUW V1, V2, V3 // 10611288
- VMULOUW V1, V2, V3 // 10611088
- VMULUWM V1, V2, V3 // 10611089
- VPMSUMB V1, V2, V3 // 10611408
- VPMSUMH V1, V2, V3 // 10611448
- VPMSUMW V1, V2, V3 // 10611488
- VPMSUMD V1, V2, V3 // 106114c8
- VMSUMUDM V1, V2, V3, V4 // 108110e3
- VRLB V1, V2, V3 // 10611004
- VRLH V1, V2, V3 // 10611044
- VRLW V1, V2, V3 // 10611084
- VRLD V1, V2, V3 // 106110c4
- VSLB V1, V2, V3 // 10611104
- VSLH V1, V2, V3 // 10611144
- VSLW V1, V2, V3 // 10611184
- VSL V1, V2, V3 // 106111c4
- VSLO V1, V2, V3 // 1061140c
- VSRB V1, V2, V3 // 10611204
- VSRH V1, V2, V3 // 10611244
- VSRW V1, V2, V3 // 10611284
- VSR V1, V2, V3 // 106112c4
- VSRO V1, V2, V3 // 1061144c
- VSLD V1, V2, V3 // 106115c4
- VSRAB V1, V2, V3 // 10611304
- VSRAH V1, V2, V3 // 10611344
- VSRAW V1, V2, V3 // 10611384
- VSRAD V1, V2, V3 // 106113c4
- VSLDOI $3, V1, V2, V3 // 106110ec
- VCLZB V1, V2 // 10400f02
- VCLZH V1, V2 // 10400f42
- VCLZW V1, V2 // 10400f82
- VCLZD V1, V2 // 10400fc2
- VPOPCNTB V1, V2 // 10400f03
- VPOPCNTH V1, V2 // 10400f43
- VPOPCNTW V1, V2 // 10400f83
- VPOPCNTD V1, V2 // 10400fc3
- VCMPEQUB V1, V2, V3 // 10611006
- VCMPEQUBCC V1, V2, V3 // 10611406
- VCMPEQUH V1, V2, V3 // 10611046
- VCMPEQUHCC V1, V2, V3 // 10611446
- VCMPEQUW V1, V2, V3 // 10611086
- VCMPEQUWCC V1, V2, V3 // 10611486
- VCMPEQUD V1, V2, V3 // 106110c7
- VCMPEQUDCC V1, V2, V3 // 106114c7
- VCMPGTUB V1, V2, V3 // 10611206
- VCMPGTUBCC V1, V2, V3 // 10611606
- VCMPGTUH V1, V2, V3 // 10611246
- VCMPGTUHCC V1, V2, V3 // 10611646
- VCMPGTUW V1, V2, V3 // 10611286
- VCMPGTUWCC V1, V2, V3 // 10611686
- VCMPGTUD V1, V2, V3 // 106112c7
- VCMPGTUDCC V1, V2, V3 // 106116c7
- VCMPGTSB V1, V2, V3 // 10611306
- VCMPGTSBCC V1, V2, V3 // 10611706
- VCMPGTSH V1, V2, V3 // 10611346
- VCMPGTSHCC V1, V2, V3 // 10611746
- VCMPGTSW V1, V2, V3 // 10611386
- VCMPGTSWCC V1, V2, V3 // 10611786
- VCMPGTSD V1, V2, V3 // 106113c7
- VCMPGTSDCC V1, V2, V3 // 106117c7
- VCMPNEZB V1, V2, V3 // 10611107
- VCMPNEZBCC V1, V2, V3 // 10611507
- VCMPNEB V1, V2, V3 // 10611007
- VCMPNEBCC V1, V2, V3 // 10611407
- VCMPNEH V1, V2, V3 // 10611047
- VCMPNEHCC V1, V2, V3 // 10611447
- VCMPNEW V1, V2, V3 // 10611087
- VCMPNEWCC V1, V2, V3 // 10611487
- VPERM V1, V2, V3, V4 // 108110eb
- VPERMR V1, V2, V3, V4 // 108110fb
- VPERMXOR V1, V2, V3, V4 // 108110ed
- VBPERMQ V1, V2, V3 // 1061154c
- VBPERMD V1, V2, V3 // 106115cc
- VSEL V1, V2, V3, V4 // 108110ea
- VSPLTB $1, V1, V2 // 10410a0c
- VSPLTH $1, V1, V2 // 10410a4c
- VSPLTW $1, V1, V2 // 10410a8c
- VSPLTISB $1, V1 // 1021030c
- VSPLTISW $1, V1 // 1021038c
- VSPLTISH $1, V1 // 1021034c
- VCIPHER V1, V2, V3 // 10611508
- VCIPHERLAST V1, V2, V3 // 10611509
- VNCIPHER V1, V2, V3 // 10611548
- VNCIPHERLAST V1, V2, V3 // 10611549
- VSBOX V1, V2 // 104105c8
- VSHASIGMAW $1, V1, $15, V2 // 10418e82
- VSHASIGMAD $2, V1, $15, V2 // 104196c2
-
- LXVD2X (R3)(R4), VS1 // 7c241e98
- LXV 16(R3), VS1 // f4230011
- LXVL R3, R4, VS1 // 7c23221a
- LXVLL R3, R4, VS1 // 7c23225a
- LXVX R3, R4, VS1 // 7c232218
- LXSDX (R3)(R4), VS1 // 7c241c98
- STXVD2X VS1, (R3)(R4) // 7c241f98
- STXV VS1,16(R3) // f4230015
- STXVL VS1, R3, R4 // 7c23231a
- STXVLL VS1, R3, R4 // 7c23235a
- STXVX VS1, R3, R4 // 7c232318
- STXSDX VS1, (R3)(R4) // 7c241d98
- LXSIWAX (R3)(R4), VS1 // 7c241898
- STXSIWX VS1, (R3)(R4) // 7c241918
- MFVSRD VS1, R3 // 7c230066
- MTVSRD R3, VS1 // 7c230166
- XXLAND VS1, VS2, VS3 // f0611410
- XXLOR VS1, VS2, VS3 // f0611490
- XXLORC VS1, VS2, VS3 // f0611550
- XXLXOR VS1, VS2, VS3 // f06114d0
- XXSEL VS1, VS2, VS3, VS4 // f08110f0
- XXMRGHW VS1, VS2, VS3 // f0611090
- XXSPLTW VS1, $1, VS2 // f0410a90
- XXPERM VS1, VS2, VS3 // f06110d0
- XXSLDWI VS1, VS2, $1, VS3 // f0611110
- XSCVDPSP VS1, VS2 // f0400c24
- XVCVDPSP VS1, VS2 // f0400e24
- XSCVSXDDP VS1, VS2 // f0400de0
- XVCVDPSXDS VS1, VS2 // f0400f60
- XVCVSXDDP VS1, VS2 // f0400fe0
-
- MOVD R3, LR // 7c6803a6
- MOVD R3, CTR // 7c6903a6
- MOVD R3, XER // 7c6103a6
- MOVD LR, R3 // 7c6802a6
- MOVD CTR, R3 // 7c6902a6
- MOVD XER, R3 // 7c6102a6
- MOVFL CR3, CR1 // 4c8c0000
-
- RET
diff --git a/src/cmd/asm/internal/asm/testdata/riscvenc.s b/src/cmd/asm/internal/asm/testdata/riscvenc.s
index 8d301f2dd5..e30a576473 100644
--- a/src/cmd/asm/internal/asm/testdata/riscvenc.s
+++ b/src/cmd/asm/internal/asm/testdata/riscvenc.s
@@ -297,6 +297,13 @@ start:
MOVW X5, (X6) // 23205300
MOVW X5, 4(X6) // 23225300
+ MOVB X5, X6 // 1393820313538343
+ MOVH X5, X6 // 1393020313530343
+ MOVW X5, X6 // 1b830200
+ MOVBU X5, X6 // 13f3f20f
+ MOVHU X5, X6 // 1393020313530303
+ MOVWU X5, X6 // 1393020213530302
+
MOVF 4(X5), F0 // 07a04200
MOVF F0, 4(X5) // 27a20200
MOVF F0, F1 // d3000020
@@ -318,7 +325,7 @@ start:
// These jumps can get printed as jumps to 2 because they go to the
// second instruction in the function (the first instruction is an
// invisible stack pointer adjustment).
- JMP start // JMP 2 // 6ff01fc5
+ JMP start // JMP 2 // 6ff09fc2
JMP (X5) // 67800200
JMP 4(X5) // 67804200
@@ -331,16 +338,16 @@ start:
JMP asmtest(SB) // 970f0000
// Branch pseudo-instructions
- BEQZ X5, start // BEQZ X5, 2 // e38a02c2
- BGEZ X5, start // BGEZ X5, 2 // e3d802c2
- BGT X5, X6, start // BGT X5, X6, 2 // e3c662c2
- BGTU X5, X6, start // BGTU X5, X6, 2 // e3e462c2
- BGTZ X5, start // BGTZ X5, 2 // e34250c2
- BLE X5, X6, start // BLE X5, X6, 2 // e3d062c2
- BLEU X5, X6, start // BLEU X5, X6, 2 // e3fe62c0
- BLEZ X5, start // BLEZ X5, 2 // e35c50c0
- BLTZ X5, start // BLTZ X5, 2 // e3ca02c0
- BNEZ X5, start // BNEZ X5, 2 // e39802c0
+ BEQZ X5, start // BEQZ X5, 2 // e38602c0
+ BGEZ X5, start // BGEZ X5, 2 // e3d402c0
+ BGT X5, X6, start // BGT X5, X6, 2 // e3c262c0
+ BGTU X5, X6, start // BGTU X5, X6, 2 // e3e062c0
+ BGTZ X5, start // BGTZ X5, 2 // e34e50be
+ BLE X5, X6, start // BLE X5, X6, 2 // e3dc62be
+ BLEU X5, X6, start // BLEU X5, X6, 2 // e3fa62be
+ BLEZ X5, start // BLEZ X5, 2 // e35850be
+ BLTZ X5, start // BLTZ X5, 2 // e3c602be
+ BNEZ X5, start // BNEZ X5, 2 // e39402be
// Set pseudo-instructions
SEQZ X15, X15 // 93b71700
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index 64024cc97d..426e0156aa 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -15,15 +15,16 @@ import (
)
var (
- Debug = flag.Bool("debug", false, "dump instructions as they are parsed")
- OutputFile = flag.String("o", "", "output file; default foo.o for /a/b/c/foo.s as first argument")
- TrimPath = flag.String("trimpath", "", "remove prefix from recorded source file paths")
- Shared = flag.Bool("shared", false, "generate code that can be linked into a shared library")
- Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
- AllErrors = flag.Bool("e", false, "no limit on number of errors reported")
- SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
- Importpath = flag.String("p", "", "set expected package import to path")
- Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
+ Debug = flag.Bool("debug", false, "dump instructions as they are parsed")
+ OutputFile = flag.String("o", "", "output file; default foo.o for /a/b/c/foo.s as first argument")
+ TrimPath = flag.String("trimpath", "", "remove prefix from recorded source file paths")
+ Shared = flag.Bool("shared", false, "generate code that can be linked into a shared library")
+ Dynlink = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
+ AllErrors = flag.Bool("e", false, "no limit on number of errors reported")
+ SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
+ Importpath = flag.String("p", "", "set expected package import to path")
+ Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
+ CompilingRuntime = flag.Bool("compiling-runtime", false, "source to be compiled is part of the Go runtime")
)
var (
diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go
index a43953b515..da4ebe6d6e 100644
--- a/src/cmd/asm/internal/lex/input.go
+++ b/src/cmd/asm/internal/lex/input.go
@@ -109,6 +109,9 @@ func (in *Input) Next() ScanToken {
in.Error("'#' must be first item on line")
}
in.beginningOfLine = in.hash()
+ in.text = "#"
+ return '#'
+
case scanner.Ident:
// Is it a macro name?
name := in.Stack.Text()
diff --git a/src/cmd/asm/internal/lex/lex.go b/src/cmd/asm/internal/lex/lex.go
index f1f7da7911..7cd41a55a9 100644
--- a/src/cmd/asm/internal/lex/lex.go
+++ b/src/cmd/asm/internal/lex/lex.go
@@ -22,11 +22,13 @@ type ScanToken rune
const (
// Asm defines some two-character lexemes. We make up
// a rune/ScanToken value for them - ugly but simple.
- LSH ScanToken = -1000 - iota // << Left shift.
- RSH // >> Logical right shift.
- ARR // -> Used on ARM for shift type 3, arithmetic right shift.
- ROT // @> Used on ARM for shift type 4, rotate right.
- macroName // name of macro that should not be expanded
+ LSH ScanToken = -1000 - iota // << Left shift.
+ RSH // >> Logical right shift.
+ ARR // -> Used on ARM for shift type 3, arithmetic right shift.
+ ROT // @> Used on ARM for shift type 4, rotate right.
+ Include // included file started here
+ BuildComment // //go:build or +build comment
+ macroName // name of macro that should not be expanded
)
// IsRegisterShift reports whether the token is one of the ARM register shift operators.
diff --git a/src/cmd/asm/internal/lex/lex_test.go b/src/cmd/asm/internal/lex/lex_test.go
index f606ffe07b..51679d2fbc 100644
--- a/src/cmd/asm/internal/lex/lex_test.go
+++ b/src/cmd/asm/internal/lex/lex_test.go
@@ -281,6 +281,9 @@ func drain(input *Input) string {
if tok == scanner.EOF {
return buf.String()
}
+ if tok == '#' {
+ continue
+ }
if buf.Len() > 0 {
buf.WriteByte('.')
}
diff --git a/src/cmd/asm/internal/lex/tokenizer.go b/src/cmd/asm/internal/lex/tokenizer.go
index aef9ea8636..861a2d421d 100644
--- a/src/cmd/asm/internal/lex/tokenizer.go
+++ b/src/cmd/asm/internal/lex/tokenizer.go
@@ -107,10 +107,13 @@ func (t *Tokenizer) Next() ScanToken {
if t.tok != scanner.Comment {
break
}
- length := strings.Count(s.TokenText(), "\n")
- t.line += length
- // TODO: If we ever have //go: comments in assembly, will need to keep them here.
- // For now, just discard all comments.
+ text := s.TokenText()
+ t.line += strings.Count(text, "\n")
+ // TODO: Use constraint.IsGoBuild once it exists.
+ if strings.HasPrefix(text, "//go:build") {
+ t.tok = BuildComment
+ break
+ }
}
switch t.tok {
case '\n':
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index fd079a2ccd..149925d23f 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -74,7 +74,8 @@ func main() {
var failedFile string
for _, f := range flag.Args() {
lexer := lex.NewLexer(f)
- parser := asm.NewParser(ctxt, architecture, lexer)
+ parser := asm.NewParser(ctxt, architecture, lexer,
+ *flags.CompilingRuntime)
ctxt.DiagFunc = func(format string, args ...interface{}) {
diag = true
log.Printf(format, args...)
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index b3f371b08c..e782c866ac 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -721,7 +721,7 @@ linkage to the desired libraries. The main function is provided by
_cgo_main.c:
int main() { return 0; }
- void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { }
+ void crosscall2(void(*fn)(void*), void *a, int c, uintptr_t ctxt) { }
uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
void _cgo_release_context(uintptr_t ctxt) { }
char* _cgo_topofstack(void) { return (char*)0; }
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index ef3ed968e4..7d02ac3c54 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -170,35 +170,51 @@ func usage() {
var ptrSizeMap = map[string]int64{
"386": 4,
+ "alpha": 8,
"amd64": 8,
"arm": 4,
"arm64": 8,
+ "m68k": 4,
"mips": 4,
"mipsle": 4,
"mips64": 8,
"mips64le": 8,
+ "nios2": 4,
+ "ppc": 4,
"ppc64": 8,
"ppc64le": 8,
+ "riscv": 4,
"riscv64": 8,
"s390": 4,
"s390x": 8,
+ "sh": 4,
+ "shbe": 4,
+ "sparc": 4,
"sparc64": 8,
}
var intSizeMap = map[string]int64{
"386": 4,
+ "alpha": 8,
"amd64": 8,
"arm": 4,
"arm64": 8,
+ "m68k": 4,
"mips": 4,
"mipsle": 4,
"mips64": 8,
"mips64le": 8,
+ "nios2": 4,
+ "ppc": 4,
"ppc64": 8,
"ppc64le": 8,
+ "riscv": 4,
"riscv64": 8,
"s390": 4,
"s390x": 8,
+ "sh": 4,
+ "shbe": 4,
+ "sparc": 4,
"sparc64": 8,
}
@@ -224,8 +240,7 @@ var exportHeader = flag.String("exportheader", "", "where to write export header
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
-var gccgoMangleCheckDone bool
-var gccgoNewmanglingInEffect bool
+var gccgoMangler func(string) string
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
var goarch, goos string
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 03b8333b10..eef54f2d0f 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -6,6 +6,7 @@ package main
import (
"bytes"
+ "cmd/internal/pkgpath"
"debug/elf"
"debug/macho"
"debug/pe"
@@ -15,7 +16,6 @@ import (
"go/token"
"internal/xcoff"
"io"
- "io/ioutil"
"os"
"os/exec"
"path/filepath"
@@ -59,14 +59,14 @@ func (p *Package) writeDefs() {
// Write C main file for using gcc to resolve imports.
fmt.Fprintf(fm, "int main() { return 0; }\n")
if *importRuntimeCgo {
- fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n")
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
} else {
// If we're not importing runtime/cgo, we *are* runtime/cgo,
// which provides these functions. We just need a prototype.
- fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n")
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt);\n")
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
}
@@ -852,7 +852,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
- fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
+ fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, __SIZE_TYPE__);\n")
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
@@ -862,59 +862,48 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
for _, exp := range p.ExpFunc {
fn := exp.Func
- // Construct a gcc struct matching the gc argument and
- // result frame. The gcc struct will be compiled with
- // __attribute__((packed)) so all padding must be accounted
- // for explicitly.
+ // Construct a struct that will be used to communicate
+ // arguments from C to Go. The C and Go definitions
+ // just have to agree. The gcc struct will be compiled
+ // with __attribute__((packed)) so all padding must be
+ // accounted for explicitly.
ctype := "struct {\n"
+ gotype := new(bytes.Buffer)
+ fmt.Fprintf(gotype, "struct {\n")
off := int64(0)
npad := 0
- if fn.Recv != nil {
- t := p.cgoType(fn.Recv.List[0].Type)
- ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
+ argField := func(typ ast.Expr, namePat string, args ...interface{}) {
+ name := fmt.Sprintf(namePat, args...)
+ t := p.cgoType(typ)
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ off += pad
+ npad++
+ }
+ ctype += fmt.Sprintf("\t\t%s %s;\n", t.C, name)
+ fmt.Fprintf(gotype, "\t\t%s ", name)
+ noSourceConf.Fprint(gotype, fset, typ)
+ fmt.Fprintf(gotype, "\n")
off += t.Size
}
+ if fn.Recv != nil {
+ argField(fn.Recv.List[0].Type, "recv")
+ }
fntype := fn.Type
forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) {
- t := p.cgoType(atype)
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
- off += t.Size
+ argField(atype, "p%d", i)
})
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
forFieldList(fntype.Results,
func(i int, aname string, atype ast.Expr) {
- t := p.cgoType(atype)
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
- off += t.Size
+ argField(atype, "r%d", i)
})
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
if ctype == "struct {\n" {
ctype += "\t\tchar unused;\n" // avoid empty struct
}
ctype += "\t}"
+ fmt.Fprintf(gotype, "\t}")
// Get the return type of the wrapper function
// compiled by gcc.
@@ -939,7 +928,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
// Build the wrapper function compiled by gcc.
- s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
+ gccExport := ""
+ if goos == "windows" {
+ gccExport = "__declspec(dllexport)"
+ }
+ s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName)
if fn.Recv != nil {
s += p.cgoType(fn.Recv.List[0].Type).C.String()
s += " recv"
@@ -961,12 +954,15 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
fmt.Fprintf(fgcch, "extern %s;\n", s)
- fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
+ fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
- fmt.Fprintf(fgcc, "\t%s %v _cgo_a;\n", ctype, p.packedAttribute())
+ // The results part of the argument structure must be
+ // initialized to 0 so the write barriers generated by
+ // the assignments to these fields in Go are safe.
+ fmt.Fprintf(fgcc, "\t%s %v _cgo_a = {0};\n", ctype, p.packedAttribute())
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
}
@@ -995,82 +991,28 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "}\n")
// Build the wrapper function compiled by cmd/compile.
- goname := "_cgoexpwrap" + cPrefix + "_"
- if fn.Recv != nil {
- goname += fn.Recv.List[0].Names[0].Name + "_"
- }
- goname += exp.Func.Name.Name
+ // This unpacks the argument struct above and calls the Go function.
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
- fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
- fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
- fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix, exp.ExpName)
- fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
- // The indirect here is converting from a Go function pointer to a C function pointer.
- fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n")
- fmt.Fprintf(fgo2, "}\n")
+ fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
- // This code uses printer.Fprint, not conf.Fprint,
- // because we don't want //line comments in the middle
- // of the function types.
- fmt.Fprintf(fgo2, "\n")
- fmt.Fprintf(fgo2, "func %s(", goname)
- comma := false
- if fn.Recv != nil {
- fmt.Fprintf(fgo2, "recv ")
- printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
- comma = true
- }
- forFieldList(fntype.Params,
- func(i int, aname string, atype ast.Expr) {
- if comma {
- fmt.Fprintf(fgo2, ", ")
- }
- fmt.Fprintf(fgo2, "p%d ", i)
- printer.Fprint(fgo2, fset, atype)
- comma = true
- })
- fmt.Fprintf(fgo2, ")")
if gccResult != "void" {
- fmt.Fprint(fgo2, " (")
+ // Write results back to frame.
+ fmt.Fprintf(fgo2, "\t")
forFieldList(fntype.Results,
func(i int, aname string, atype ast.Expr) {
if i > 0 {
- fmt.Fprint(fgo2, ", ")
+ fmt.Fprintf(fgo2, ", ")
}
- fmt.Fprintf(fgo2, "r%d ", i)
- printer.Fprint(fgo2, fset, atype)
+ fmt.Fprintf(fgo2, "a.r%d", i)
})
- fmt.Fprint(fgo2, ")")
- }
- fmt.Fprint(fgo2, " {\n")
- if gccResult == "void" {
- fmt.Fprint(fgo2, "\t")
- } else {
- // Verify that any results don't contain any
- // Go pointers.
- addedDefer := false
- forFieldList(fntype.Results,
- func(i int, aname string, atype ast.Expr) {
- if !p.hasPointer(nil, atype, false) {
- return
- }
- if !addedDefer {
- fmt.Fprint(fgo2, "\tdefer func() {\n")
- addedDefer = true
- }
- fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
- })
- if addedDefer {
- fmt.Fprint(fgo2, "\t}()\n")
- }
- fmt.Fprint(fgo2, "\treturn ")
+ fmt.Fprintf(fgo2, " = ")
}
if fn.Recv != nil {
- fmt.Fprintf(fgo2, "recv.")
+ fmt.Fprintf(fgo2, "a.recv.")
}
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
forFieldList(fntype.Params,
@@ -1078,9 +1020,20 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
- fmt.Fprintf(fgo2, "p%d", i)
+ fmt.Fprintf(fgo2, "a.p%d", i)
})
fmt.Fprint(fgo2, ")\n")
+ if gccResult != "void" {
+ // Verify that any results don't contain any
+ // Go pointers.
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
+ if !p.hasPointer(nil, atype, false) {
+ return
+ }
+ fmt.Fprintf(fgo2, "\t_cgoCheckResult(a.r%d)\n", i)
+ })
+ }
fmt.Fprint(fgo2, "}\n")
}
@@ -1282,112 +1235,24 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
}
-// gccgoUsesNewMangling reports whether gccgo uses the new collision-free
-// packagepath mangling scheme (see determineGccgoManglingScheme for more
-// info).
-func gccgoUsesNewMangling() bool {
- if !gccgoMangleCheckDone {
- gccgoNewmanglingInEffect = determineGccgoManglingScheme()
- gccgoMangleCheckDone = true
- }
- return gccgoNewmanglingInEffect
-}
-
-const mangleCheckCode = `
-package läufer
-func Run(x int) int {
- return 1
-}
-`
-
-// determineGccgoManglingScheme performs a runtime test to see which
-// flavor of packagepath mangling gccgo is using. Older versions of
-// gccgo use a simple mangling scheme where there can be collisions
-// between packages whose paths are different but mangle to the same
-// string. More recent versions of gccgo use a new mangler that avoids
-// these collisions. Return value is whether gccgo uses the new mangling.
-func determineGccgoManglingScheme() bool {
-
- // Emit a small Go file for gccgo to compile.
- filepat := "*_gccgo_manglecheck.go"
- var f *os.File
- var err error
- if f, err = ioutil.TempFile(*objDir, filepat); err != nil {
- fatalf("%v", err)
- }
- gofilename := f.Name()
- defer os.Remove(gofilename)
-
- if err = ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0666); err != nil {
- fatalf("%v", err)
- }
-
- // Compile with gccgo, capturing generated assembly.
- gccgocmd := os.Getenv("GCCGO")
- if gccgocmd == "" {
- gpath, gerr := exec.LookPath("gccgo")
- if gerr != nil {
- fatalf("unable to locate gccgo: %v", gerr)
- }
- gccgocmd = gpath
- }
- cmd := exec.Command(gccgocmd, "-S", "-o", "-", gofilename)
- buf, cerr := cmd.CombinedOutput()
- if cerr != nil {
- fatalf("%s", cerr)
- }
-
- // New mangling: expect go.l..u00e4ufer.Run
- // Old mangling: expect go.l__ufer.Run
- return regexp.MustCompile(`go\.l\.\.u00e4ufer\.Run`).Match(buf)
-}
-
-// gccgoPkgpathToSymbolNew converts a package path to a gccgo-style
-// package symbol.
-func gccgoPkgpathToSymbolNew(ppath string) string {
- bsl := []byte{}
- changed := false
- for _, c := range []byte(ppath) {
- switch {
- case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z',
- '0' <= c && c <= '9', c == '_':
- bsl = append(bsl, c)
- case c == '.':
- bsl = append(bsl, ".x2e"...)
- default:
- changed = true
- encbytes := []byte(fmt.Sprintf("..z%02x", c))
- bsl = append(bsl, encbytes...)
- }
- }
- if !changed {
- return ppath
- }
- return string(bsl)
-}
-
-// gccgoPkgpathToSymbolOld converts a package path to a gccgo-style
-// package symbol using the older mangling scheme.
-func gccgoPkgpathToSymbolOld(ppath string) string {
- clean := func(r rune) rune {
- switch {
- case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
- '0' <= r && r <= '9':
- return r
- }
- return '_'
- }
- return strings.Map(clean, ppath)
-}
-
// gccgoPkgpathToSymbol converts a package path to a mangled packagepath
// symbol.
func gccgoPkgpathToSymbol(ppath string) string {
- if gccgoUsesNewMangling() {
- return gccgoPkgpathToSymbolNew(ppath)
- } else {
- return gccgoPkgpathToSymbolOld(ppath)
+ if gccgoMangler == nil {
+ var err error
+ cmd := os.Getenv("GCCGO")
+ if cmd == "" {
+ cmd, err = exec.LookPath("gccgo")
+ if err != nil {
+ fatalf("unable to locate gccgo: %v", err)
+ }
+ }
+ gccgoMangler, err = pkgpath.ToSymbolFunc(cmd, *objDir)
+ if err != nil {
+ fatalf("%v", err)
+ }
}
+ return gccgoMangler(ppath)
}
// Return the package prefix when using gccgo.
@@ -1666,9 +1531,6 @@ const goProlog = `
//go:linkname _cgo_runtime_cgocall runtime.cgocall
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
-//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
-func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
-
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
func _cgoCheckPointer(interface{}, interface{})
diff --git a/src/cmd/compile/fmtmap_test.go b/src/cmd/compile/fmtmap_test.go
index 179c60187f..f8c33ec1f9 100644
--- a/src/cmd/compile/fmtmap_test.go
+++ b/src/cmd/compile/fmtmap_test.go
@@ -136,6 +136,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/types.EType %s": "",
"cmd/compile/internal/types.EType %v": "",
"cmd/internal/obj.ABI %v": "",
+ "cmd/internal/src.XPos %v": "",
"error %v": "",
"float64 %.2f": "",
"float64 %.3f": "",
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index 4ac877986c..f30a47b903 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -1210,7 +1210,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p = s.Prog(x86.ASETEQ)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg0()
- case ssa.OpAMD64ANDBlock, ssa.OpAMD64ORBlock:
+ case ssa.OpAMD64ANDBlock, ssa.OpAMD64ANDLlock, ssa.OpAMD64ORBlock, ssa.OpAMD64ORLlock:
s.Prog(x86.ALOCK)
p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go
index 1d6ea6b9d8..5c695ef84c 100644
--- a/src/cmd/compile/internal/arm64/ssa.go
+++ b/src/cmd/compile/internal/arm64/ssa.go
@@ -688,15 +688,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p5.To.Reg = out
gc.Patch(p2, p5)
case ssa.OpARM64LoweredAtomicAnd8,
- ssa.OpARM64LoweredAtomicOr8:
- // LDAXRB (Rarg0), Rout
+ ssa.OpARM64LoweredAtomicAnd32,
+ ssa.OpARM64LoweredAtomicOr8,
+ ssa.OpARM64LoweredAtomicOr32:
+ // LDAXRB/LDAXRW (Rarg0), Rout
// AND/OR Rarg1, Rout
- // STLXRB Rout, (Rarg0), Rtmp
+ // STLXRB/STLXRB Rout, (Rarg0), Rtmp
// CBNZ Rtmp, -3(PC)
+ ld := arm64.ALDAXRB
+ st := arm64.ASTLXRB
+ if v.Op == ssa.OpARM64LoweredAtomicAnd32 || v.Op == ssa.OpARM64LoweredAtomicOr32 {
+ ld = arm64.ALDAXRW
+ st = arm64.ASTLXRW
+ }
r0 := v.Args[0].Reg()
r1 := v.Args[1].Reg()
out := v.Reg0()
- p := s.Prog(arm64.ALDAXRB)
+ p := s.Prog(ld)
p.From.Type = obj.TYPE_MEM
p.From.Reg = r0
p.To.Type = obj.TYPE_REG
@@ -706,7 +714,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p1.From.Reg = r1
p1.To.Type = obj.TYPE_REG
p1.To.Reg = out
- p2 := s.Prog(arm64.ASTLXRB)
+ p2 := s.Prog(st)
p2.From.Type = obj.TYPE_REG
p2.From.Reg = out
p2.To.Type = obj.TYPE_MEM
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index 6302b88f59..2f7fa27bb9 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -282,7 +282,7 @@ func genhash(t *types.Type) *obj.LSym {
}
sym := typesymprefix(".hash", t)
- if Debug['r'] != 0 {
+ if Debug.r != 0 {
fmt.Printf("genhash %v %v %v\n", closure, sym, t)
}
@@ -374,7 +374,7 @@ func genhash(t *types.Type) *obj.LSym {
r.List.Append(nh)
fn.Nbody.Append(r)
- if Debug['r'] != 0 {
+ if Debug.r != 0 {
dumplist("genhash body", fn.Nbody)
}
@@ -509,7 +509,7 @@ func geneq(t *types.Type) *obj.LSym {
return closure
}
sym := typesymprefix(".eq", t)
- if Debug['r'] != 0 {
+ if Debug.r != 0 {
fmt.Printf("geneq %v\n", t)
}
@@ -529,6 +529,10 @@ func geneq(t *types.Type) *obj.LSym {
fn := dclfunc(sym, tfn)
np := asNode(tfn.Type.Params().Field(0).Nname)
nq := asNode(tfn.Type.Params().Field(1).Nname)
+ nr := asNode(tfn.Type.Results().Field(0).Nname)
+
+ // Label to jump to if an equality test fails.
+ neq := autolabel(".neq")
// We reach here only for types that have equality but
// cannot be handled by the standard algorithms,
@@ -555,13 +559,13 @@ func geneq(t *types.Type) *obj.LSym {
// for i := 0; i < nelem; i++ {
// if eq(p[i], q[i]) {
// } else {
- // return
+ // goto neq
// }
// }
//
// TODO(josharian): consider doing some loop unrolling
// for larger nelem as well, processing a few elements at a time in a loop.
- checkAll := func(unroll int64, eq func(pi, qi *Node) *Node) {
+ checkAll := func(unroll int64, last bool, eq func(pi, qi *Node) *Node) {
// checkIdx generates a node to check for equality at index i.
checkIdx := func(i *Node) *Node {
// pi := p[i]
@@ -576,37 +580,38 @@ func geneq(t *types.Type) *obj.LSym {
}
if nelem <= unroll {
+ if last {
+ // Do last comparison in a different manner.
+ nelem--
+ }
// Generate a series of checks.
- var cond *Node
for i := int64(0); i < nelem; i++ {
- c := nodintconst(i)
- check := checkIdx(c)
- if cond == nil {
- cond = check
- continue
- }
- cond = nod(OANDAND, cond, check)
+ // if check {} else { goto neq }
+ nif := nod(OIF, checkIdx(nodintconst(i)), nil)
+ nif.Rlist.Append(nodSym(OGOTO, nil, neq))
+ fn.Nbody.Append(nif)
+ }
+ if last {
+ fn.Nbody.Append(nod(OAS, nr, checkIdx(nodintconst(nelem))))
+ }
+ } else {
+ // Generate a for loop.
+ // for i := 0; i < nelem; i++
+ i := temp(types.Types[TINT])
+ init := nod(OAS, i, nodintconst(0))
+ cond := nod(OLT, i, nodintconst(nelem))
+ post := nod(OAS, i, nod(OADD, i, nodintconst(1)))
+ loop := nod(OFOR, cond, post)
+ loop.Ninit.Append(init)
+ // if eq(pi, qi) {} else { goto neq }
+ nif := nod(OIF, checkIdx(i), nil)
+ nif.Rlist.Append(nodSym(OGOTO, nil, neq))
+ loop.Nbody.Append(nif)
+ fn.Nbody.Append(loop)
+ if last {
+ fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
}
- nif := nod(OIF, cond, nil)
- nif.Rlist.Append(nod(ORETURN, nil, nil))
- fn.Nbody.Append(nif)
- return
}
-
- // Generate a for loop.
- // for i := 0; i < nelem; i++
- i := temp(types.Types[TINT])
- init := nod(OAS, i, nodintconst(0))
- cond := nod(OLT, i, nodintconst(nelem))
- post := nod(OAS, i, nod(OADD, i, nodintconst(1)))
- loop := nod(OFOR, cond, post)
- loop.Ninit.Append(init)
- // if eq(pi, qi) {} else { return }
- check := checkIdx(i)
- nif := nod(OIF, check, nil)
- nif.Rlist.Append(nod(ORETURN, nil, nil))
- loop.Nbody.Append(nif)
- fn.Nbody.Append(loop)
}
switch t.Elem().Etype {
@@ -614,32 +619,28 @@ func geneq(t *types.Type) *obj.LSym {
// Do two loops. First, check that all the lengths match (cheap).
// Second, check that all the contents match (expensive).
// TODO: when the array size is small, unroll the length match checks.
- checkAll(3, func(pi, qi *Node) *Node {
+ checkAll(3, false, func(pi, qi *Node) *Node {
// Compare lengths.
eqlen, _ := eqstring(pi, qi)
return eqlen
})
- checkAll(1, func(pi, qi *Node) *Node {
+ checkAll(1, true, func(pi, qi *Node) *Node {
// Compare contents.
_, eqmem := eqstring(pi, qi)
return eqmem
})
case TFLOAT32, TFLOAT64:
- checkAll(2, func(pi, qi *Node) *Node {
+ checkAll(2, true, func(pi, qi *Node) *Node {
// p[i] == q[i]
return nod(OEQ, pi, qi)
})
// TODO: pick apart structs, do them piecemeal too
default:
- checkAll(1, func(pi, qi *Node) *Node {
+ checkAll(1, true, func(pi, qi *Node) *Node {
// p[i] == q[i]
return nod(OEQ, pi, qi)
})
}
- // return true
- ret := nod(ORETURN, nil, nil)
- ret.List.Append(nodbool(true))
- fn.Nbody.Append(ret)
case TSTRUCT:
// Build a list of conditions to satisfy.
@@ -717,22 +718,42 @@ func geneq(t *types.Type) *obj.LSym {
flatConds = append(flatConds, c...)
}
- var cond *Node
if len(flatConds) == 0 {
- cond = nodbool(true)
+ fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
} else {
- cond = flatConds[0]
- for _, c := range flatConds[1:] {
- cond = nod(OANDAND, cond, c)
+ for _, c := range flatConds[:len(flatConds)-1] {
+ // if cond {} else { goto neq }
+ n := nod(OIF, c, nil)
+ n.Rlist.Append(nodSym(OGOTO, nil, neq))
+ fn.Nbody.Append(n)
}
+ fn.Nbody.Append(nod(OAS, nr, flatConds[len(flatConds)-1]))
}
+ }
- ret := nod(ORETURN, nil, nil)
- ret.List.Append(cond)
- fn.Nbody.Append(ret)
+ // ret:
+ // return
+ ret := autolabel(".ret")
+ fn.Nbody.Append(nodSym(OLABEL, nil, ret))
+ fn.Nbody.Append(nod(ORETURN, nil, nil))
+
+ // neq:
+ // r = false
+ // return (or goto ret)
+ fn.Nbody.Append(nodSym(OLABEL, nil, neq))
+ fn.Nbody.Append(nod(OAS, nr, nodbool(false)))
+ if EqCanPanic(t) || hasCall(fn) {
+ // Epilogue is large, so share it with the equal case.
+ fn.Nbody.Append(nodSym(OGOTO, nil, ret))
+ } else {
+ // Epilogue is small, so don't bother sharing.
+ fn.Nbody.Append(nod(ORETURN, nil, nil))
}
+ // TODO(khr): the epilogue size detection condition above isn't perfect.
+ // We should really do a generic CL that shares epilogues across
+ // the board. See #24936.
- if Debug['r'] != 0 {
+ if Debug.r != 0 {
dumplist("geneq body", fn.Nbody)
}
@@ -762,6 +783,39 @@ func geneq(t *types.Type) *obj.LSym {
return closure
}
+func hasCall(n *Node) bool {
+ if n.Op == OCALL || n.Op == OCALLFUNC {
+ return true
+ }
+ if n.Left != nil && hasCall(n.Left) {
+ return true
+ }
+ if n.Right != nil && hasCall(n.Right) {
+ return true
+ }
+ for _, x := range n.Ninit.Slice() {
+ if hasCall(x) {
+ return true
+ }
+ }
+ for _, x := range n.Nbody.Slice() {
+ if hasCall(x) {
+ return true
+ }
+ }
+ for _, x := range n.List.Slice() {
+ if hasCall(x) {
+ return true
+ }
+ }
+ for _, x := range n.Rlist.Slice() {
+ if hasCall(x) {
+ return true
+ }
+ }
+ return false
+}
+
// eqfield returns the node
// p.field == q.field
func eqfield(p *Node, q *Node, field *types.Sym) *Node {
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index 5af403afa3..a3a0c8fce8 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -86,7 +86,7 @@ func expandiface(t *types.Type) {
sort.Sort(methcmp(methods))
if int64(len(methods)) >= thearch.MAXWIDTH/int64(Widthptr) {
- yyerror("interface too large")
+ yyerrorl(typePos(t), "interface too large")
}
for i, m := range methods {
m.Offset = int64(i) * int64(Widthptr)
@@ -150,7 +150,7 @@ func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 {
maxwidth = 1<<31 - 1
}
if o >= maxwidth {
- yyerror("type %L too large", errtype)
+ yyerrorl(typePos(errtype), "type %L too large", errtype)
o = 8 // small but nonzero
}
}
@@ -199,7 +199,7 @@ func findTypeLoop(t *types.Type, path *[]*types.Type) bool {
}
*path = append(*path, t)
- if findTypeLoop(asNode(t.Nod).Name.Param.Ntype.Type, path) {
+ if p := asNode(t.Nod).Name.Param; p != nil && findTypeLoop(p.Ntype.Type, path) {
return true
}
*path = (*path)[:len(*path)-1]
@@ -381,7 +381,7 @@ func dowidth(t *types.Type) {
t1 := t.ChanArgs()
dowidth(t1) // just in case
if t1.Elem().Width >= 1<<16 {
- yyerror("channel element type too large (>64kB)")
+ yyerrorl(typePos(t1), "channel element type too large (>64kB)")
}
w = 1 // anything will do
@@ -414,7 +414,7 @@ func dowidth(t *types.Type) {
if t.Elem().Width != 0 {
cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
if uint64(t.NumElem()) > cap {
- yyerror("type %L larger than address space", t)
+ yyerrorl(typePos(t), "type %L larger than address space", t)
}
}
w = t.NumElem() * t.Elem().Width
@@ -456,7 +456,7 @@ func dowidth(t *types.Type) {
}
if Widthptr == 4 && w != int64(int32(w)) {
- yyerror("type %v too large", t)
+ yyerrorl(typePos(t), "type %v too large", t)
}
t.Width = w
diff --git a/src/cmd/compile/internal/gc/bench_test.go b/src/cmd/compile/internal/gc/bench_test.go
index a2887f2f7b..8c4288128f 100644
--- a/src/cmd/compile/internal/gc/bench_test.go
+++ b/src/cmd/compile/internal/gc/bench_test.go
@@ -7,6 +7,7 @@ package gc
import "testing"
var globl int64
+var globl32 int32
func BenchmarkLoadAdd(b *testing.B) {
x := make([]int64, 1024)
@@ -42,6 +43,17 @@ func BenchmarkModify(b *testing.B) {
}
}
+func BenchmarkMullImm(b *testing.B) {
+ x := make([]int32, 1024)
+ for i := 0; i < b.N; i++ {
+ var s int32
+ for i := range x {
+ s += x[i] * 100
+ }
+ globl32 = s
+ }
+}
+
func BenchmarkConstModify(b *testing.B) {
a := make([]int64, 1024)
for i := 0; i < b.N; i++ {
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index 5ced66c0da..10f21f86df 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -81,11 +81,6 @@ func (p *exporter) markType(t *types.Type) {
}
}
-// deltaNewFile is a magic line delta offset indicating a new file.
-// We use -64 because it is rare; see issue 20080 and CL 41619.
-// -64 is the smallest int that fits in a single byte as a varint.
-const deltaNewFile = -64
-
// ----------------------------------------------------------------------------
// Export format
@@ -126,30 +121,6 @@ const (
aliasTag
)
-// untype returns the "pseudo" untyped type for a Ctype (import/export use only).
-// (we can't use a pre-initialized array because we must be sure all types are
-// set up)
-func untype(ctype Ctype) *types.Type {
- switch ctype {
- case CTINT:
- return types.Idealint
- case CTRUNE:
- return types.Idealrune
- case CTFLT:
- return types.Idealfloat
- case CTCPLX:
- return types.Idealcomplex
- case CTSTR:
- return types.Idealstring
- case CTBOOL:
- return types.Idealbool
- case CTNIL:
- return types.Types[TNIL]
- }
- Fatalf("exporter: unknown Ctype")
- return nil
-}
-
var predecl []*types.Type // initialized lazily
func predeclared() []*types.Type {
@@ -184,13 +155,13 @@ func predeclared() []*types.Type {
types.Errortype,
// untyped types
- untype(CTBOOL),
- untype(CTINT),
- untype(CTRUNE),
- untype(CTFLT),
- untype(CTCPLX),
- untype(CTSTR),
- untype(CTNIL),
+ types.UntypedBool,
+ types.UntypedInt,
+ types.UntypedRune,
+ types.UntypedFloat,
+ types.UntypedComplex,
+ types.UntypedString,
+ types.Types[TNIL],
// package unsafe
types.Types[TUNSAFEPTR],
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index da7b107bfe..fd95b657b2 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -44,6 +44,7 @@ var runtimeDecls = [...]struct {
{"printcomplex", funcTag, 27},
{"printstring", funcTag, 29},
{"printpointer", funcTag, 30},
+ {"printuintptr", funcTag, 31},
{"printiface", funcTag, 30},
{"printeface", funcTag, 30},
{"printslice", funcTag, 30},
@@ -51,134 +52,134 @@ var runtimeDecls = [...]struct {
{"printsp", funcTag, 9},
{"printlock", funcTag, 9},
{"printunlock", funcTag, 9},
- {"concatstring2", funcTag, 33},
- {"concatstring3", funcTag, 34},
- {"concatstring4", funcTag, 35},
- {"concatstring5", funcTag, 36},
- {"concatstrings", funcTag, 38},
- {"cmpstring", funcTag, 39},
- {"intstring", funcTag, 42},
- {"slicebytetostring", funcTag, 43},
- {"slicebytetostringtmp", funcTag, 44},
- {"slicerunetostring", funcTag, 47},
- {"stringtoslicebyte", funcTag, 49},
- {"stringtoslicerune", funcTag, 52},
- {"slicecopy", funcTag, 53},
- {"decoderune", funcTag, 54},
- {"countrunes", funcTag, 55},
- {"convI2I", funcTag, 56},
- {"convT16", funcTag, 57},
- {"convT32", funcTag, 57},
- {"convT64", funcTag, 57},
- {"convTstring", funcTag, 57},
- {"convTslice", funcTag, 57},
- {"convT2E", funcTag, 58},
- {"convT2Enoptr", funcTag, 58},
- {"convT2I", funcTag, 58},
- {"convT2Inoptr", funcTag, 58},
- {"assertE2I", funcTag, 56},
- {"assertE2I2", funcTag, 59},
- {"assertI2I", funcTag, 56},
- {"assertI2I2", funcTag, 59},
- {"panicdottypeE", funcTag, 60},
- {"panicdottypeI", funcTag, 60},
- {"panicnildottype", funcTag, 61},
- {"ifaceeq", funcTag, 63},
- {"efaceeq", funcTag, 63},
- {"fastrand", funcTag, 65},
- {"makemap64", funcTag, 67},
- {"makemap", funcTag, 68},
- {"makemap_small", funcTag, 69},
- {"mapaccess1", funcTag, 70},
- {"mapaccess1_fast32", funcTag, 71},
- {"mapaccess1_fast64", funcTag, 71},
- {"mapaccess1_faststr", funcTag, 71},
- {"mapaccess1_fat", funcTag, 72},
- {"mapaccess2", funcTag, 73},
- {"mapaccess2_fast32", funcTag, 74},
- {"mapaccess2_fast64", funcTag, 74},
- {"mapaccess2_faststr", funcTag, 74},
- {"mapaccess2_fat", funcTag, 75},
- {"mapassign", funcTag, 70},
- {"mapassign_fast32", funcTag, 71},
- {"mapassign_fast32ptr", funcTag, 71},
- {"mapassign_fast64", funcTag, 71},
- {"mapassign_fast64ptr", funcTag, 71},
- {"mapassign_faststr", funcTag, 71},
- {"mapiterinit", funcTag, 76},
- {"mapdelete", funcTag, 76},
- {"mapdelete_fast32", funcTag, 77},
- {"mapdelete_fast64", funcTag, 77},
- {"mapdelete_faststr", funcTag, 77},
- {"mapiternext", funcTag, 78},
- {"mapclear", funcTag, 79},
- {"makechan64", funcTag, 81},
- {"makechan", funcTag, 82},
- {"chanrecv1", funcTag, 84},
- {"chanrecv2", funcTag, 85},
- {"chansend1", funcTag, 87},
+ {"concatstring2", funcTag, 34},
+ {"concatstring3", funcTag, 35},
+ {"concatstring4", funcTag, 36},
+ {"concatstring5", funcTag, 37},
+ {"concatstrings", funcTag, 39},
+ {"cmpstring", funcTag, 40},
+ {"intstring", funcTag, 43},
+ {"slicebytetostring", funcTag, 44},
+ {"slicebytetostringtmp", funcTag, 45},
+ {"slicerunetostring", funcTag, 48},
+ {"stringtoslicebyte", funcTag, 50},
+ {"stringtoslicerune", funcTag, 53},
+ {"slicecopy", funcTag, 54},
+ {"decoderune", funcTag, 55},
+ {"countrunes", funcTag, 56},
+ {"convI2I", funcTag, 57},
+ {"convT16", funcTag, 58},
+ {"convT32", funcTag, 58},
+ {"convT64", funcTag, 58},
+ {"convTstring", funcTag, 58},
+ {"convTslice", funcTag, 58},
+ {"convT2E", funcTag, 59},
+ {"convT2Enoptr", funcTag, 59},
+ {"convT2I", funcTag, 59},
+ {"convT2Inoptr", funcTag, 59},
+ {"assertE2I", funcTag, 57},
+ {"assertE2I2", funcTag, 60},
+ {"assertI2I", funcTag, 57},
+ {"assertI2I2", funcTag, 60},
+ {"panicdottypeE", funcTag, 61},
+ {"panicdottypeI", funcTag, 61},
+ {"panicnildottype", funcTag, 62},
+ {"ifaceeq", funcTag, 64},
+ {"efaceeq", funcTag, 64},
+ {"fastrand", funcTag, 66},
+ {"makemap64", funcTag, 68},
+ {"makemap", funcTag, 69},
+ {"makemap_small", funcTag, 70},
+ {"mapaccess1", funcTag, 71},
+ {"mapaccess1_fast32", funcTag, 72},
+ {"mapaccess1_fast64", funcTag, 72},
+ {"mapaccess1_faststr", funcTag, 72},
+ {"mapaccess1_fat", funcTag, 73},
+ {"mapaccess2", funcTag, 74},
+ {"mapaccess2_fast32", funcTag, 75},
+ {"mapaccess2_fast64", funcTag, 75},
+ {"mapaccess2_faststr", funcTag, 75},
+ {"mapaccess2_fat", funcTag, 76},
+ {"mapassign", funcTag, 71},
+ {"mapassign_fast32", funcTag, 72},
+ {"mapassign_fast32ptr", funcTag, 72},
+ {"mapassign_fast64", funcTag, 72},
+ {"mapassign_fast64ptr", funcTag, 72},
+ {"mapassign_faststr", funcTag, 72},
+ {"mapiterinit", funcTag, 77},
+ {"mapdelete", funcTag, 77},
+ {"mapdelete_fast32", funcTag, 78},
+ {"mapdelete_fast64", funcTag, 78},
+ {"mapdelete_faststr", funcTag, 78},
+ {"mapiternext", funcTag, 79},
+ {"mapclear", funcTag, 80},
+ {"makechan64", funcTag, 82},
+ {"makechan", funcTag, 83},
+ {"chanrecv1", funcTag, 85},
+ {"chanrecv2", funcTag, 86},
+ {"chansend1", funcTag, 88},
{"closechan", funcTag, 30},
- {"writeBarrier", varTag, 89},
- {"typedmemmove", funcTag, 90},
- {"typedmemclr", funcTag, 91},
- {"typedslicecopy", funcTag, 92},
- {"selectnbsend", funcTag, 93},
- {"selectnbrecv", funcTag, 94},
- {"selectnbrecv2", funcTag, 96},
- {"selectsetpc", funcTag, 97},
- {"selectgo", funcTag, 98},
+ {"writeBarrier", varTag, 90},
+ {"typedmemmove", funcTag, 91},
+ {"typedmemclr", funcTag, 92},
+ {"typedslicecopy", funcTag, 93},
+ {"selectnbsend", funcTag, 94},
+ {"selectnbrecv", funcTag, 95},
+ {"selectnbrecv2", funcTag, 97},
+ {"selectsetpc", funcTag, 98},
+ {"selectgo", funcTag, 99},
{"block", funcTag, 9},
- {"makeslice", funcTag, 99},
- {"makeslice64", funcTag, 100},
- {"makeslicecopy", funcTag, 101},
- {"growslice", funcTag, 103},
- {"memmove", funcTag, 104},
- {"memclrNoHeapPointers", funcTag, 105},
- {"memclrHasPointers", funcTag, 105},
- {"memequal", funcTag, 106},
- {"memequal0", funcTag, 107},
- {"memequal8", funcTag, 107},
- {"memequal16", funcTag, 107},
- {"memequal32", funcTag, 107},
- {"memequal64", funcTag, 107},
- {"memequal128", funcTag, 107},
- {"f32equal", funcTag, 108},
- {"f64equal", funcTag, 108},
- {"c64equal", funcTag, 108},
- {"c128equal", funcTag, 108},
- {"strequal", funcTag, 108},
- {"interequal", funcTag, 108},
- {"nilinterequal", funcTag, 108},
- {"memhash", funcTag, 109},
- {"memhash0", funcTag, 110},
- {"memhash8", funcTag, 110},
- {"memhash16", funcTag, 110},
- {"memhash32", funcTag, 110},
- {"memhash64", funcTag, 110},
- {"memhash128", funcTag, 110},
- {"f32hash", funcTag, 110},
- {"f64hash", funcTag, 110},
- {"c64hash", funcTag, 110},
- {"c128hash", funcTag, 110},
- {"strhash", funcTag, 110},
- {"interhash", funcTag, 110},
- {"nilinterhash", funcTag, 110},
- {"int64div", funcTag, 111},
- {"uint64div", funcTag, 112},
- {"int64mod", funcTag, 111},
- {"uint64mod", funcTag, 112},
- {"float64toint64", funcTag, 113},
- {"float64touint64", funcTag, 114},
- {"float64touint32", funcTag, 115},
- {"int64tofloat64", funcTag, 116},
- {"uint64tofloat64", funcTag, 117},
- {"uint32tofloat64", funcTag, 118},
- {"complex128div", funcTag, 119},
- {"racefuncenter", funcTag, 120},
+ {"makeslice", funcTag, 100},
+ {"makeslice64", funcTag, 101},
+ {"makeslicecopy", funcTag, 102},
+ {"growslice", funcTag, 104},
+ {"memmove", funcTag, 105},
+ {"memclrNoHeapPointers", funcTag, 106},
+ {"memclrHasPointers", funcTag, 106},
+ {"memequal", funcTag, 107},
+ {"memequal0", funcTag, 108},
+ {"memequal8", funcTag, 108},
+ {"memequal16", funcTag, 108},
+ {"memequal32", funcTag, 108},
+ {"memequal64", funcTag, 108},
+ {"memequal128", funcTag, 108},
+ {"f32equal", funcTag, 109},
+ {"f64equal", funcTag, 109},
+ {"c64equal", funcTag, 109},
+ {"c128equal", funcTag, 109},
+ {"strequal", funcTag, 109},
+ {"interequal", funcTag, 109},
+ {"nilinterequal", funcTag, 109},
+ {"memhash", funcTag, 110},
+ {"memhash0", funcTag, 111},
+ {"memhash8", funcTag, 111},
+ {"memhash16", funcTag, 111},
+ {"memhash32", funcTag, 111},
+ {"memhash64", funcTag, 111},
+ {"memhash128", funcTag, 111},
+ {"f32hash", funcTag, 111},
+ {"f64hash", funcTag, 111},
+ {"c64hash", funcTag, 111},
+ {"c128hash", funcTag, 111},
+ {"strhash", funcTag, 111},
+ {"interhash", funcTag, 111},
+ {"nilinterhash", funcTag, 111},
+ {"int64div", funcTag, 112},
+ {"uint64div", funcTag, 113},
+ {"int64mod", funcTag, 112},
+ {"uint64mod", funcTag, 113},
+ {"float64toint64", funcTag, 114},
+ {"float64touint64", funcTag, 115},
+ {"float64touint32", funcTag, 116},
+ {"int64tofloat64", funcTag, 117},
+ {"uint64tofloat64", funcTag, 118},
+ {"uint32tofloat64", funcTag, 119},
+ {"complex128div", funcTag, 120},
+ {"racefuncenter", funcTag, 31},
{"racefuncenterfp", funcTag, 9},
{"racefuncexit", funcTag, 9},
- {"raceread", funcTag, 120},
- {"racewrite", funcTag, 120},
+ {"raceread", funcTag, 31},
+ {"racewrite", funcTag, 31},
{"racereadrange", funcTag, 121},
{"racewriterange", funcTag, 121},
{"msanread", funcTag, 121},
@@ -233,96 +234,96 @@ func runtimeTypes() []*types.Type {
typs[28] = types.Types[TSTRING]
typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
- typs[31] = types.NewArray(typs[0], 32)
- typs[32] = types.NewPtr(typs[31])
- typs[33] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
- typs[34] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
- typs[35] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
- typs[36] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
- typs[37] = types.NewSlice(typs[28])
- typs[38] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[37])}, []*Node{anonfield(typs[28])})
- typs[39] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
- typs[40] = types.NewArray(typs[0], 4)
- typs[41] = types.NewPtr(typs[40])
- typs[42] = functype(nil, []*Node{anonfield(typs[41]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
- typs[43] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
- typs[44] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
- typs[45] = types.Runetype
- typs[46] = types.NewSlice(typs[45])
- typs[47] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[46])}, []*Node{anonfield(typs[28])})
- typs[48] = types.NewSlice(typs[0])
- typs[49] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28])}, []*Node{anonfield(typs[48])})
- typs[50] = types.NewArray(typs[45], 32)
- typs[51] = types.NewPtr(typs[50])
- typs[52] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[28])}, []*Node{anonfield(typs[46])})
- typs[53] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
- typs[54] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[45]), anonfield(typs[15])})
- typs[55] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
- typs[56] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
- typs[57] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
- typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
- typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
- typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
- typs[61] = functype(nil, []*Node{anonfield(typs[1])}, nil)
- typs[62] = types.NewPtr(typs[5])
- typs[63] = functype(nil, []*Node{anonfield(typs[62]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
- typs[64] = types.Types[TUINT32]
- typs[65] = functype(nil, nil, []*Node{anonfield(typs[64])})
- typs[66] = types.NewMap(typs[2], typs[2])
- typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
- typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
- typs[69] = functype(nil, nil, []*Node{anonfield(typs[66])})
- typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
- typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
- typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
- typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
- typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
- typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
- typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, nil)
- typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, nil)
- typs[78] = functype(nil, []*Node{anonfield(typs[3])}, nil)
- typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66])}, nil)
- typs[80] = types.NewChan(typs[2], types.Cboth)
- typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[80])})
- typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[80])})
- typs[83] = types.NewChan(typs[2], types.Crecv)
- typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
- typs[85] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
- typs[86] = types.NewChan(typs[2], types.Csend)
- typs[87] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, nil)
- typs[88] = types.NewArray(typs[0], 3)
- typs[89] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[88]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
- typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
- typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
- typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
- typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
- typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[6])})
- typs[95] = types.NewPtr(typs[6])
- typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[95]), anonfield(typs[83])}, []*Node{anonfield(typs[6])})
- typs[97] = functype(nil, []*Node{anonfield(typs[62])}, nil)
- typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
- typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
- typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
- typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
- typs[102] = types.NewSlice(typs[2])
- typs[103] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[102]), anonfield(typs[15])}, []*Node{anonfield(typs[102])})
- typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
- typs[105] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
- typs[106] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
- typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
- typs[108] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
- typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
- typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
- typs[111] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
- typs[112] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
- typs[113] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
- typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
- typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[64])})
- typs[116] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
- typs[117] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
- typs[118] = functype(nil, []*Node{anonfield(typs[64])}, []*Node{anonfield(typs[20])})
- typs[119] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
- typs[120] = functype(nil, []*Node{anonfield(typs[5])}, nil)
+ typs[31] = functype(nil, []*Node{anonfield(typs[5])}, nil)
+ typs[32] = types.NewArray(typs[0], 32)
+ typs[33] = types.NewPtr(typs[32])
+ typs[34] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[35] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[36] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[37] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[38] = types.NewSlice(typs[28])
+ typs[39] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[38])}, []*Node{anonfield(typs[28])})
+ typs[40] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
+ typs[41] = types.NewArray(typs[0], 4)
+ typs[42] = types.NewPtr(typs[41])
+ typs[43] = functype(nil, []*Node{anonfield(typs[42]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
+ typs[44] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
+ typs[45] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
+ typs[46] = types.Runetype
+ typs[47] = types.NewSlice(typs[46])
+ typs[48] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[47])}, []*Node{anonfield(typs[28])})
+ typs[49] = types.NewSlice(typs[0])
+ typs[50] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28])}, []*Node{anonfield(typs[49])})
+ typs[51] = types.NewArray(typs[46], 32)
+ typs[52] = types.NewPtr(typs[51])
+ typs[53] = functype(nil, []*Node{anonfield(typs[52]), anonfield(typs[28])}, []*Node{anonfield(typs[47])})
+ typs[54] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
+ typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[46]), anonfield(typs[15])})
+ typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
+ typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
+ typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
+ typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
+ typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
+ typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
+ typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
+ typs[63] = types.NewPtr(typs[5])
+ typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
+ typs[65] = types.Types[TUINT32]
+ typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
+ typs[67] = types.NewMap(typs[2], typs[2])
+ typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
+ typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
+ typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
+ typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
+ typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
+ typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
+ typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
+ typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
+ typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
+ typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
+ typs[81] = types.NewChan(typs[2], types.Cboth)
+ typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
+ typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
+ typs[84] = types.NewChan(typs[2], types.Crecv)
+ typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
+ typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[87] = types.NewChan(typs[2], types.Csend)
+ typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
+ typs[89] = types.NewArray(typs[0], 3)
+ typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
+ typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
+ typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
+ typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
+ typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
+ typs[96] = types.NewPtr(typs[6])
+ typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
+ typs[98] = functype(nil, []*Node{anonfield(typs[63])}, nil)
+ typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
+ typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
+ typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
+ typs[102] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
+ typs[103] = types.NewSlice(typs[2])
+ typs[104] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[103]), anonfield(typs[15])}, []*Node{anonfield(typs[103])})
+ typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
+ typs[106] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
+ typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
+ typs[108] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
+ typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
+ typs[111] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
+ typs[112] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
+ typs[113] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
+ typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
+ typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
+ typs[116] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
+ typs[117] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
+ typs[118] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
+ typs[119] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
+ typs[120] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
typs[123] = types.NewSlice(typs[7])
@@ -331,7 +332,7 @@ func runtimeTypes() []*types.Type {
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
typs[127] = types.Types[TUINT16]
typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
- typs[129] = functype(nil, []*Node{anonfield(typs[64]), anonfield(typs[64])}, nil)
+ typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
return typs[:]
}
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index 02d6c7b7f5..aac2de38c6 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -54,6 +54,7 @@ func printuint(uint64)
func printcomplex(complex128)
func printstring(string)
func printpointer(any)
+func printuintptr(uintptr)
func printiface(any)
func printeface(any)
func printslice(any)
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 250be38e5b..902d2e34a3 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -198,7 +198,7 @@ func capturevars(xfunc *Node) {
outer = nod(OADDR, outer, nil)
}
- if Debug['m'] > 1 {
+ if Debug.m > 1 {
var name *types.Sym
if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
name = v.Name.Curfn.Func.Nname.Sym
@@ -434,6 +434,8 @@ func typecheckpartialcall(fn *Node, sym *types.Sym) {
fn.Type = xfunc.Type
}
+// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
+// for partial calls.
func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
rcvrtype := fn.Left.Type
sym := methodSymSuffix(rcvrtype, meth, "-fm")
@@ -500,6 +502,10 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
funcbody()
xfunc = typecheck(xfunc, ctxStmt)
+ // Need to typecheck the body of the just-generated wrapper.
+ // typecheckslice() requires that Curfn is set when processing an ORETURN.
+ Curfn = xfunc
+ typecheckslice(xfunc.Nbody.Slice(), ctxStmt)
sym.Def = asTypesNode(xfunc)
xtop = append(xtop, xfunc)
Curfn = savecurfn
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index c0ed8192d9..b92c8d66b5 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -114,16 +114,16 @@ func (v Val) Interface() interface{} {
type NilVal struct{}
-// Int64 returns n as an int64.
+// Int64Val returns n as an int64.
// n must be an integer or rune constant.
-func (n *Node) Int64() int64 {
+func (n *Node) Int64Val() int64 {
if !Isconst(n, CTINT) {
- Fatalf("Int64(%v)", n)
+ Fatalf("Int64Val(%v)", n)
}
return n.Val().U.(*Mpint).Int64()
}
-// CanInt64 reports whether it is safe to call Int64() on n.
+// CanInt64 reports whether it is safe to call Int64Val() on n.
func (n *Node) CanInt64() bool {
if !Isconst(n, CTINT) {
return false
@@ -131,18 +131,27 @@ func (n *Node) CanInt64() bool {
// if the value inside n cannot be represented as an int64, the
// return value of Int64 is undefined
- return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0
+ return n.Val().U.(*Mpint).CmpInt64(n.Int64Val()) == 0
}
-// Bool returns n as a bool.
+// BoolVal returns n as a bool.
// n must be a boolean constant.
-func (n *Node) Bool() bool {
+func (n *Node) BoolVal() bool {
if !Isconst(n, CTBOOL) {
- Fatalf("Bool(%v)", n)
+ Fatalf("BoolVal(%v)", n)
}
return n.Val().U.(bool)
}
+// StringVal returns the value of a literal string Node as a string.
+// n must be a string constant.
+func (n *Node) StringVal() string {
+ if !Isconst(n, CTSTR) {
+ Fatalf("StringVal(%v)", n)
+ }
+ return n.Val().U.(string)
+}
+
// truncate float literal fv to 32-bit or 64-bit precision
// according to type; return truncated value.
func truncfltlit(oldv *Mpflt, t *types.Type) *Mpflt {
@@ -612,7 +621,7 @@ func evconst(n *Node) {
var strs []string
i2 := i1
for i2 < len(s) && Isconst(s[i2], CTSTR) {
- strs = append(strs, strlit(s[i2]))
+ strs = append(strs, s[i2].StringVal())
i2++
}
@@ -635,7 +644,7 @@ func evconst(n *Node) {
switch nl.Type.Etype {
case TSTRING:
if Isconst(nl, CTSTR) {
- setintconst(n, int64(len(strlit(nl))))
+ setintconst(n, int64(len(nl.StringVal())))
}
case TARRAY:
if !hascallchan(nl) {
@@ -1019,17 +1028,17 @@ func nodlit(v Val) *Node {
func idealType(ct Ctype) *types.Type {
switch ct {
case CTSTR:
- return types.Idealstring
+ return types.UntypedString
case CTBOOL:
- return types.Idealbool
+ return types.UntypedBool
case CTINT:
- return types.Idealint
+ return types.UntypedInt
case CTRUNE:
- return types.Idealrune
+ return types.UntypedRune
case CTFLT:
- return types.Idealfloat
+ return types.UntypedFloat
case CTCPLX:
- return types.Idealcomplex
+ return types.UntypedComplex
case CTNIL:
return types.Types[TNIL]
}
@@ -1080,17 +1089,17 @@ func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
func ctype(t *types.Type) Ctype {
switch t {
- case types.Idealbool:
+ case types.UntypedBool:
return CTBOOL
- case types.Idealstring:
+ case types.UntypedString:
return CTSTR
- case types.Idealint:
+ case types.UntypedInt:
return CTINT
- case types.Idealrune:
+ case types.UntypedRune:
return CTRUNE
- case types.Idealfloat:
+ case types.UntypedFloat:
return CTFLT
- case types.Idealcomplex:
+ case types.UntypedComplex:
return CTCPLX
}
Fatalf("bad type %v", t)
@@ -1111,17 +1120,17 @@ func defaultType(t *types.Type) *types.Type {
}
switch t {
- case types.Idealbool:
+ case types.UntypedBool:
return types.Types[TBOOL]
- case types.Idealstring:
+ case types.UntypedString:
return types.Types[TSTRING]
- case types.Idealint:
+ case types.UntypedInt:
return types.Types[TINT]
- case types.Idealrune:
+ case types.UntypedRune:
return types.Runetype
- case types.Idealfloat:
+ case types.UntypedFloat:
return types.Types[TFLOAT64]
- case types.Idealcomplex:
+ case types.UntypedComplex:
return types.Types[TCOMPLEX128]
}
@@ -1129,12 +1138,6 @@ func defaultType(t *types.Type) *types.Type {
return nil
}
-// strlit returns the value of a literal string Node as a string.
-func strlit(n *Node) string {
- return n.Val().U.(string)
-}
-
-// TODO(gri) smallintconst is only used in one place - can we used indexconst?
func smallintconst(n *Node) bool {
if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
switch simtype[n.Type.Etype] {
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index a362d1a643..b8ca0d2e03 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -283,7 +283,7 @@ func oldname(s *types.Sym) *Node {
c.Name.Defn = n
// Link into list of active closure variables.
- // Popped from list in func closurebody.
+ // Popped from list in func funcLit.
c.Name.Param.Outer = n.Name.Param.Innermost
n.Name.Param.Innermost = c
diff --git a/src/cmd/compile/internal/gc/dwinl.go b/src/cmd/compile/internal/gc/dwinl.go
index 27e2cbcd98..5120fa1166 100644
--- a/src/cmd/compile/internal/gc/dwinl.go
+++ b/src/cmd/compile/internal/gc/dwinl.go
@@ -34,7 +34,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
// Walk progs to build up the InlCalls data structure
var prevpos src.XPos
- for p := fnsym.Func.Text; p != nil; p = p.Link {
+ for p := fnsym.Func().Text; p != nil; p = p.Link {
if p.Pos == prevpos {
continue
}
@@ -150,7 +150,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
start := int64(-1)
curii := -1
var prevp *obj.Prog
- for p := fnsym.Func.Text; p != nil; prevp, p = p, p.Link {
+ for p := fnsym.Func().Text; p != nil; prevp, p = p, p.Link {
if prevp != nil && p.Pos == prevp.Pos {
continue
}
diff --git a/src/cmd/compile/internal/gc/embed.go b/src/cmd/compile/internal/gc/embed.go
new file mode 100644
index 0000000000..103949c1f9
--- /dev/null
+++ b/src/cmd/compile/internal/gc/embed.go
@@ -0,0 +1,273 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/syntax"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "encoding/json"
+ "io/ioutil"
+ "log"
+ "path"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+var embedlist []*Node
+
+var embedCfg struct {
+ Patterns map[string][]string
+ Files map[string]string
+}
+
+func readEmbedCfg(file string) {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ log.Fatalf("-embedcfg: %v", err)
+ }
+ if err := json.Unmarshal(data, &embedCfg); err != nil {
+ log.Fatalf("%s: %v", file, err)
+ }
+ if embedCfg.Patterns == nil {
+ log.Fatalf("%s: invalid embedcfg: missing Patterns", file)
+ }
+ if embedCfg.Files == nil {
+ log.Fatalf("%s: invalid embedcfg: missing Files", file)
+ }
+}
+
+const (
+ embedUnknown = iota
+ embedBytes
+ embedString
+ embedFiles
+)
+
+var numLocalEmbed int
+
+func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []PragmaEmbed) (newExprs []*Node) {
+ haveEmbed := false
+ for _, decl := range p.file.DeclList {
+ imp, ok := decl.(*syntax.ImportDecl)
+ if !ok {
+ // imports always come first
+ break
+ }
+ path, _ := strconv.Unquote(imp.Path.Value)
+ if path == "embed" {
+ haveEmbed = true
+ break
+ }
+ }
+
+ pos := embeds[0].Pos
+ if !haveEmbed {
+ p.yyerrorpos(pos, "invalid go:embed: missing import \"embed\"")
+ return exprs
+ }
+ if embedCfg.Patterns == nil {
+ p.yyerrorpos(pos, "invalid go:embed: build system did not supply embed configuration")
+ return exprs
+ }
+ if len(names) > 1 {
+ p.yyerrorpos(pos, "go:embed cannot apply to multiple vars")
+ return exprs
+ }
+ if len(exprs) > 0 {
+ p.yyerrorpos(pos, "go:embed cannot apply to var with initializer")
+ return exprs
+ }
+ if typ == nil {
+ // Should not happen, since len(exprs) == 0 now.
+ p.yyerrorpos(pos, "go:embed cannot apply to var without type")
+ return exprs
+ }
+
+ kind := embedKindApprox(typ)
+ if kind == embedUnknown {
+ p.yyerrorpos(pos, "go:embed cannot apply to var of type %v", typ)
+ return exprs
+ }
+
+ // Build list of files to store.
+ have := make(map[string]bool)
+ var list []string
+ for _, e := range embeds {
+ for _, pattern := range e.Patterns {
+ files, ok := embedCfg.Patterns[pattern]
+ if !ok {
+ p.yyerrorpos(e.Pos, "invalid go:embed: build system did not map pattern: %s", pattern)
+ }
+ for _, file := range files {
+ if embedCfg.Files[file] == "" {
+ p.yyerrorpos(e.Pos, "invalid go:embed: build system did not map file: %s", file)
+ continue
+ }
+ if !have[file] {
+ have[file] = true
+ list = append(list, file)
+ }
+ if kind == embedFiles {
+ for dir := path.Dir(file); dir != "." && !have[dir]; dir = path.Dir(dir) {
+ have[dir] = true
+ list = append(list, dir+"/")
+ }
+ }
+ }
+ }
+ }
+ sort.Slice(list, func(i, j int) bool {
+ return embedFileLess(list[i], list[j])
+ })
+
+ if kind == embedString || kind == embedBytes {
+ if len(list) > 1 {
+ p.yyerrorpos(pos, "invalid go:embed: multiple files for type %v", typ)
+ return exprs
+ }
+ }
+
+ v := names[0]
+ if dclcontext != PEXTERN {
+ numLocalEmbed++
+ v = newnamel(v.Pos, lookupN("embed.", numLocalEmbed))
+ v.Sym.Def = asTypesNode(v)
+ v.Name.Param.Ntype = typ
+ v.SetClass(PEXTERN)
+ externdcl = append(externdcl, v)
+ exprs = []*Node{v}
+ }
+
+ v.Name.Param.SetEmbedFiles(list)
+ embedlist = append(embedlist, v)
+ return exprs
+}
+
+// embedKindApprox determines the kind of embedding variable, approximately.
+// The match is approximate because we haven't done scope resolution yet and
+// can't tell whether "string" and "byte" really mean "string" and "byte".
+// The result must be confirmed later, after type checking, using embedKind.
+func embedKindApprox(typ *Node) int {
+ if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && myimportpath == "embed")) {
+ return embedFiles
+ }
+ // These are not guaranteed to match only string and []byte -
+ // maybe the local package has redefined one of those words.
+ // But it's the best we can do now during the noder.
+ // The stricter check happens later, in initEmbed calling embedKind.
+ if typ.Sym != nil && typ.Sym.Name == "string" && typ.Sym.Pkg == localpkg {
+ return embedString
+ }
+ if typ.Op == OTARRAY && typ.Left == nil && typ.Right.Sym != nil && typ.Right.Sym.Name == "byte" && typ.Right.Sym.Pkg == localpkg {
+ return embedBytes
+ }
+ return embedUnknown
+}
+
+// embedKind determines the kind of embedding variable.
+func embedKind(typ *types.Type) int {
+ if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && myimportpath == "embed")) {
+ return embedFiles
+ }
+ if typ == types.Types[TSTRING] {
+ return embedString
+ }
+ if typ.Sym == nil && typ.IsSlice() && typ.Elem() == types.Bytetype {
+ return embedBytes
+ }
+ return embedUnknown
+}
+
+func embedFileNameSplit(name string) (dir, elem string, isDir bool) {
+ if name[len(name)-1] == '/' {
+ isDir = true
+ name = name[:len(name)-1]
+ }
+ i := len(name) - 1
+ for i >= 0 && name[i] != '/' {
+ i--
+ }
+ if i < 0 {
+ return ".", name, isDir
+ }
+ return name[:i], name[i+1:], isDir
+}
+
+// embedFileLess implements the sort order for a list of embedded files.
+// See the comment inside ../../../../embed/embed.go's Files struct for rationale.
+func embedFileLess(x, y string) bool {
+ xdir, xelem, _ := embedFileNameSplit(x)
+ ydir, yelem, _ := embedFileNameSplit(y)
+ return xdir < ydir || xdir == ydir && xelem < yelem
+}
+
+func dumpembeds() {
+ for _, v := range embedlist {
+ initEmbed(v)
+ }
+}
+
+// initEmbed emits the init data for a //go:embed variable,
+// which is either a string, a []byte, or an embed.FS.
+func initEmbed(v *Node) {
+ files := v.Name.Param.EmbedFiles()
+ switch kind := embedKind(v.Type); kind {
+ case embedUnknown:
+ yyerrorl(v.Pos, "go:embed cannot apply to var of type %v", v.Type)
+
+ case embedString, embedBytes:
+ file := files[0]
+ fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], kind == embedString, nil)
+ if err != nil {
+ yyerrorl(v.Pos, "embed %s: %v", file, err)
+ }
+ sym := v.Sym.Linksym()
+ off := 0
+ off = dsymptr(sym, off, fsym, 0) // data string
+ off = duintptr(sym, off, uint64(size)) // len
+ if kind == embedBytes {
+ duintptr(sym, off, uint64(size)) // cap for slice
+ }
+
+ case embedFiles:
+ slicedata := Ctxt.Lookup(`"".` + v.Sym.Name + `.files`)
+ off := 0
+ // []files pointed at by Files
+ off = dsymptr(slicedata, off, slicedata, 3*Widthptr) // []file, pointing just past slice
+ off = duintptr(slicedata, off, uint64(len(files)))
+ off = duintptr(slicedata, off, uint64(len(files)))
+
+ // embed/embed.go type file is:
+ // name string
+ // data string
+ // hash [16]byte
+ // Emit one of these per file in the set.
+ const hashSize = 16
+ hash := make([]byte, hashSize)
+ for _, file := range files {
+ off = dsymptr(slicedata, off, stringsym(v.Pos, file), 0) // file string
+ off = duintptr(slicedata, off, uint64(len(file)))
+ if strings.HasSuffix(file, "/") {
+ // entry for directory - no data
+ off = duintptr(slicedata, off, 0)
+ off = duintptr(slicedata, off, 0)
+ off += hashSize
+ } else {
+ fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], true, hash)
+ if err != nil {
+ yyerrorl(v.Pos, "embed %s: %v", file, err)
+ }
+ off = dsymptr(slicedata, off, fsym, 0) // data string
+ off = duintptr(slicedata, off, uint64(size))
+ off = int(slicedata.WriteBytes(Ctxt, int64(off), hash))
+ }
+ }
+ ggloblsym(slicedata, int32(off), obj.RODATA|obj.LOCAL)
+ sym := v.Sym.Linksym()
+ dsymptr(sym, 0, slicedata, 0)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 375331d1f5..6f328ab5ea 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -169,36 +169,47 @@ func mayAffectMemory(n *Node) bool {
}
}
-func mustHeapAlloc(n *Node) bool {
+// heapAllocReason returns the reason the given Node must be heap
+// allocated, or the empty string if it doesn't.
+func heapAllocReason(n *Node) string {
if n.Type == nil {
- return false
+ return ""
}
// Parameters are always passed via the stack.
if n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) {
- return false
+ return ""
}
if n.Type.Width > maxStackVarSize {
- return true
+ return "too large for stack"
}
if (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize {
- return true
+ return "too large for stack"
}
if n.Op == OCLOSURE && closureType(n).Size() >= maxImplicitStackVarSize {
- return true
+ return "too large for stack"
}
if n.Op == OCALLPART && partialCallType(n).Size() >= maxImplicitStackVarSize {
- return true
+ return "too large for stack"
}
- if n.Op == OMAKESLICE && !isSmallMakeSlice(n) {
- return true
+ if n.Op == OMAKESLICE {
+ r := n.Right
+ if r == nil {
+ r = n.Left
+ }
+ if !smallintconst(r) {
+ return "non-constant size"
+ }
+ if t := n.Type; t.Elem().Width != 0 && r.Int64Val() >= maxImplicitStackVarSize/t.Elem().Width {
+ return "too large for stack"
+ }
}
- return false
+ return ""
}
// addrescapes tags node n as having had its address taken
@@ -271,7 +282,7 @@ func addrescapes(n *Node) {
// moveToHeap records the parameter or local variable n as moved to the heap.
func moveToHeap(n *Node) {
- if Debug['r'] != 0 {
+ if Debug.r != 0 {
Dump("MOVE", n)
}
if compiling_runtime {
@@ -348,7 +359,7 @@ func moveToHeap(n *Node) {
n.Xoffset = 0
n.Name.Param.Heapaddr = heapaddr
n.Esc = EscHeap
- if Debug['m'] != 0 {
+ if Debug.m != 0 {
Warnl(n.Pos, "moved to heap: %v", n)
}
}
@@ -378,7 +389,7 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
// but we are reusing the ability to annotate an individual function
// argument and pass those annotations along to importing code.
if f.Type.IsUintptr() {
- if Debug['m'] != 0 {
+ if Debug.m != 0 {
Warnl(f.Pos, "assuming %v is unsafe uintptr", name())
}
return unsafeUintptrTag
@@ -393,11 +404,11 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
// External functions are assumed unsafe, unless
// //go:noescape is given before the declaration.
if fn.Func.Pragma&Noescape != 0 {
- if Debug['m'] != 0 && f.Sym != nil {
+ if Debug.m != 0 && f.Sym != nil {
Warnl(f.Pos, "%v does not escape", name())
}
} else {
- if Debug['m'] != 0 && f.Sym != nil {
+ if Debug.m != 0 && f.Sym != nil {
Warnl(f.Pos, "leaking param: %v", name())
}
esc.AddHeap(0)
@@ -408,14 +419,14 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
if fn.Func.Pragma&UintptrEscapes != 0 {
if f.Type.IsUintptr() {
- if Debug['m'] != 0 {
+ if Debug.m != 0 {
Warnl(f.Pos, "marking %v as escaping uintptr", name())
}
return uintptrEscapesTag
}
if f.IsDDD() && f.Type.Elem().IsUintptr() {
// final argument is ...uintptr.
- if Debug['m'] != 0 {
+ if Debug.m != 0 {
Warnl(f.Pos, "marking %v as escaping ...uintptr", name())
}
return uintptrEscapesTag
@@ -437,7 +448,7 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
esc := loc.paramEsc
esc.Optimize()
- if Debug['m'] != 0 && !loc.escapes {
+ if Debug.m != 0 && !loc.escapes {
if esc.Empty() {
Warnl(f.Pos, "%v does not escape", name())
}
diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go
index d79d32ec48..618bdf78e2 100644
--- a/src/cmd/compile/internal/gc/escape.go
+++ b/src/cmd/compile/internal/gc/escape.go
@@ -170,7 +170,7 @@ func (e *Escape) initFunc(fn *Node) {
Fatalf("unexpected node: %v", fn)
}
fn.Esc = EscFuncPlanned
- if Debug['m'] > 3 {
+ if Debug.m > 3 {
Dump("escAnalyze", fn)
}
@@ -247,7 +247,7 @@ func (e *Escape) stmt(n *Node) {
lineno = lno
}()
- if Debug['m'] > 2 {
+ if Debug.m > 2 {
fmt.Printf("%v:[%d] %v stmt: %v\n", linestr(lineno), e.loopDepth, funcSym(e.curfn), n)
}
@@ -275,11 +275,11 @@ func (e *Escape) stmt(n *Node) {
case OLABEL:
switch asNode(n.Sym.Label) {
case &nonlooping:
- if Debug['m'] > 2 {
+ if Debug.m > 2 {
fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n)
}
case &looping:
- if Debug['m'] > 2 {
+ if Debug.m > 2 {
fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
}
e.loopDepth++
@@ -717,7 +717,7 @@ func (e *Escape) addrs(l Nodes) []EscHole {
func (e *Escape) assign(dst, src *Node, why string, where *Node) {
// Filter out some no-op assignments for escape analysis.
ignore := dst != nil && src != nil && isSelfAssign(dst, src)
- if ignore && Debug['m'] != 0 {
+ if ignore && Debug.m != 0 {
Warnl(where.Pos, "%v ignoring self-assignment in %S", funcSym(e.curfn), where)
}
@@ -771,10 +771,11 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
var fn *Node
switch call.Op {
case OCALLFUNC:
- if call.Left.Op == ONAME && call.Left.Class() == PFUNC {
- fn = call.Left
- } else if call.Left.Op == OCLOSURE {
- fn = call.Left.Func.Closure.Func.Nname
+ switch v := staticValue(call.Left); {
+ case v.Op == ONAME && v.Class() == PFUNC:
+ fn = v
+ case v.Op == OCLOSURE:
+ fn = v.Func.Closure.Func.Nname
}
case OCALLMETH:
fn = asNode(call.Left.Type.FuncType().Nname)
@@ -930,7 +931,7 @@ func (k EscHole) note(where *Node, why string) EscHole {
if where == nil || why == "" {
Fatalf("note: missing where/why")
}
- if Debug['m'] >= 2 || logopt.Enabled() {
+ if Debug.m >= 2 || logopt.Enabled() {
k.notes = &EscNote{
next: k.notes,
where: where,
@@ -1051,11 +1052,7 @@ func (e *Escape) newLoc(n *Node, transient bool) *EscLocation {
}
n.SetOpt(loc)
- if mustHeapAlloc(n) {
- why := "too large for stack"
- if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || (n.Right != nil && !Isconst(n.Right, CTINT))) {
- why = "non-constant size"
- }
+ if why := heapAllocReason(n); why != "" {
e.flow(e.heapHole().addr(n, why), loc)
}
}
@@ -1080,9 +1077,9 @@ func (e *Escape) flow(k EscHole, src *EscLocation) {
return
}
if dst.escapes && k.derefs < 0 { // dst = &src
- if Debug['m'] >= 2 || logopt.Enabled() {
+ if Debug.m >= 2 || logopt.Enabled() {
pos := linestr(src.n.Pos)
- if Debug['m'] >= 2 {
+ if Debug.m >= 2 {
fmt.Printf("%s: %v escapes to heap:\n", pos, src.n)
}
explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{})
@@ -1182,8 +1179,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
// that value flow for tagging the function
// later.
if l.isName(PPARAM) {
- if (logopt.Enabled() || Debug['m'] >= 2) && !l.escapes {
- if Debug['m'] >= 2 {
+ if (logopt.Enabled() || Debug.m >= 2) && !l.escapes {
+ if Debug.m >= 2 {
fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", linestr(l.n.Pos), l.n, e.explainLoc(root), base)
}
explanation := e.explainPath(root, l)
@@ -1199,8 +1196,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
// outlives it, then l needs to be heap
// allocated.
if addressOf && !l.escapes {
- if logopt.Enabled() || Debug['m'] >= 2 {
- if Debug['m'] >= 2 {
+ if logopt.Enabled() || Debug.m >= 2 {
+ if Debug.m >= 2 {
fmt.Printf("%s: %v escapes to heap:\n", linestr(l.n.Pos), l.n)
}
explanation := e.explainPath(root, l)
@@ -1238,7 +1235,7 @@ func (e *Escape) explainPath(root, src *EscLocation) []*logopt.LoggedOpt {
for {
// Prevent infinite loop.
if visited[src] {
- if Debug['m'] >= 2 {
+ if Debug.m >= 2 {
fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos)
}
break
@@ -1266,7 +1263,7 @@ func (e *Escape) explainFlow(pos string, dst, srcloc *EscLocation, derefs int, n
if derefs >= 0 {
ops = strings.Repeat("*", derefs)
}
- print := Debug['m'] >= 2
+ print := Debug.m >= 2
flow := fmt.Sprintf(" flow: %s = %s%v:", e.explainLoc(dst), ops, e.explainLoc(srcloc))
if print {
@@ -1420,7 +1417,7 @@ func (e *Escape) finish(fns []*Node) {
if loc.escapes {
if n.Op != ONAME {
- if Debug['m'] != 0 {
+ if Debug.m != 0 {
Warnl(n.Pos, "%S escapes to heap", n)
}
if logopt.Enabled() {
@@ -1430,7 +1427,7 @@ func (e *Escape) finish(fns []*Node) {
n.Esc = EscHeap
addrescapes(n)
} else {
- if Debug['m'] != 0 && n.Op != ONAME {
+ if Debug.m != 0 && n.Op != ONAME {
Warnl(n.Pos, "%S does not escape", n)
}
n.Esc = EscNone
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index 44bea2b1fd..c6917e0f81 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -31,7 +31,7 @@ func exportsym(n *Node) {
}
n.Sym.SetOnExportList(true)
- if Debug['E'] != 0 {
+ if Debug.E != 0 {
fmt.Printf("export symbol %v\n", n.Sym)
}
@@ -96,7 +96,7 @@ func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node {
return n
}
-// pkgtype returns the named type declared by symbol s.
+// importtype returns the named type declared by symbol s.
// If no such type has been declared yet, a forward declaration is returned.
// ipkg is the package being imported
func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type {
@@ -150,7 +150,7 @@ func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val
n.SetVal(val)
- if Debug['E'] != 0 {
+ if Debug.E != 0 {
fmt.Printf("import const %v %L = %v\n", s, t, val)
}
}
@@ -166,7 +166,7 @@ func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
n.Func = new(Func)
t.SetNname(asTypesNode(n))
- if Debug['E'] != 0 {
+ if Debug.E != 0 {
fmt.Printf("import func %v%S\n", s, t)
}
}
@@ -179,7 +179,7 @@ func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
return
}
- if Debug['E'] != 0 {
+ if Debug.E != 0 {
fmt.Printf("import var %v %L\n", s, t)
}
}
@@ -192,7 +192,7 @@ func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
return
}
- if Debug['E'] != 0 {
+ if Debug.E != 0 {
fmt.Printf("import type %v = %L\n", s, t)
}
}
diff --git a/src/cmd/compile/internal/gc/float_test.go b/src/cmd/compile/internal/gc/float_test.go
index 6ae363be22..c619d25705 100644
--- a/src/cmd/compile/internal/gc/float_test.go
+++ b/src/cmd/compile/internal/gc/float_test.go
@@ -6,17 +6,9 @@ package gc
import (
"math"
- "os"
- "runtime"
"testing"
)
-// For GO386=387, make sure fucomi* opcodes are not used
-// for comparison operations.
-// Note that this test will fail only on a Pentium MMX
-// processor (with GOARCH=386 GO386=387), as it just runs
-// some code and looks for an unimplemented instruction fault.
-
//go:noinline
func compare1(a, b float64) bool {
return a < b
@@ -137,9 +129,6 @@ func TestFloatCompareFolded(t *testing.T) {
}
}
-// For GO386=387, make sure fucomi* opcodes are not used
-// for float->int conversions.
-
//go:noinline
func cvt1(a float64) uint64 {
return uint64(a)
@@ -370,14 +359,6 @@ func TestFloat32StoreToLoadConstantFold(t *testing.T) {
// are not converted to quiet NaN (qNaN) values during compilation.
// See issue #27193 for more information.
- // TODO: this method for detecting 387 won't work if the compiler has been
- // built using GOARCH=386 GO386=387 and either the target is a different
- // architecture or the GO386=387 environment variable is not set when the
- // test is run.
- if runtime.GOARCH == "386" && os.Getenv("GO386") == "387" {
- t.Skip("signaling NaNs are not propagated on 387 (issue #27516)")
- }
-
// signaling NaNs
{
const nan = uint32(0x7f800001) // sNaN
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index d4af451506..d7ed1d2ff0 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -773,17 +773,17 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
var name string
switch t {
- case types.Idealbool:
+ case types.UntypedBool:
name = "untyped bool"
- case types.Idealstring:
+ case types.UntypedString:
name = "untyped string"
- case types.Idealint:
+ case types.UntypedInt:
name = "untyped int"
- case types.Idealrune:
+ case types.UntypedRune:
name = "untyped rune"
- case types.Idealfloat:
+ case types.UntypedFloat:
name = "untyped float"
- case types.Idealcomplex:
+ case types.UntypedComplex:
name = "untyped complex"
default:
name = basicnames[t.Etype]
@@ -792,6 +792,13 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
return
}
+ if mode == FDbg {
+ b.WriteString(t.Etype.String())
+ b.WriteByte('-')
+ tconv2(b, t, flag, FErr, visited)
+ return
+ }
+
// At this point, we might call tconv2 recursively. Add the current type to the visited list so we don't
// try to print it recursively.
// We record the offset in the result buffer where the type's text starts. This offset serves as a reference
@@ -805,12 +812,6 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
visited[t] = b.Len()
defer delete(visited, t)
- if mode == FDbg {
- b.WriteString(t.Etype.String())
- b.WriteByte('-')
- tconv2(b, t, flag, FErr, visited)
- return
- }
switch t.Etype {
case TPTR:
b.WriteByte('*')
@@ -1333,7 +1334,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
n.Orig.exprfmt(s, prec, mode)
return
}
- if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != types.Idealbool && n.Type != types.Idealstring {
+ if n.Type != nil && !n.Type.IsUntyped() {
// Need parens when type begins with what might
// be misinterpreted as a unary operator: * or <-.
if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == types.Crecv) {
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index 9079ce2afc..da6b6d6e72 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -61,12 +61,12 @@ type Class uint8
//go:generate stringer -type=Class
const (
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
- PEXTERN // global variable
+ PEXTERN // global variables
PAUTO // local variables
- PAUTOHEAP // local variable or parameter moved to heap
+ PAUTOHEAP // local variables or parameters moved to heap
PPARAM // input arguments
PPARAMOUT // output results
- PFUNC // global function
+ PFUNC // global functions
// Careful: Class is stored in three bits in Node.flags.
_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
@@ -116,7 +116,15 @@ var decldepth int32
var nolocalimports bool
-var Debug [256]int
+// gc debug flags
+type DebugFlags struct {
+ P, B, C, E,
+ K, L, N, S,
+ W, e, h, j,
+ l, m, r, w int
+}
+
+var Debug DebugFlags
var debugstr string
@@ -259,7 +267,6 @@ type Arch struct {
REGSP int
MAXWIDTH int64
- Use387 bool // should 386 backend use 387 FP instructions instead of sse2.
SoftFloat bool
PadFrame func(int64) int64
@@ -328,10 +335,6 @@ var (
BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym
- // GO386=387
- ControlWord64trunc,
- ControlWord32 *obj.LSym
-
// Wasm
WasmMove,
WasmZero,
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index 480d411f49..ce5182f203 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -153,7 +153,7 @@ func (pp *Progs) Prog(as obj.As) *obj.Prog {
pp.clearp(pp.next)
p.Link = pp.next
- if !pp.pos.IsKnown() && Debug['K'] != 0 {
+ if !pp.pos.IsKnown() && Debug.K != 0 {
Warn("prog: unknown position (line 0)")
}
@@ -199,7 +199,7 @@ func (pp *Progs) settext(fn *Node) {
ptxt := pp.Prog(obj.ATEXT)
pp.Text = ptxt
- fn.Func.lsym.Func.Text = ptxt
+ fn.Func.lsym.Func().Text = ptxt
ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN
ptxt.From.Sym = fn.Func.lsym
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index b3f50b63af..9bc1f64600 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -751,11 +751,11 @@ func (w *exportWriter) param(f *types.Field) {
func constTypeOf(typ *types.Type) Ctype {
switch typ {
- case types.Idealint, types.Idealrune:
+ case types.UntypedInt, types.UntypedRune:
return CTINT
- case types.Idealfloat:
+ case types.UntypedFloat:
return CTFLT
- case types.Idealcomplex:
+ case types.UntypedComplex:
return CTCPLX
}
@@ -780,8 +780,8 @@ func constTypeOf(typ *types.Type) Ctype {
}
func (w *exportWriter) value(typ *types.Type, v Val) {
- if typ.IsUntyped() {
- typ = untype(v.Ctype())
+ if vt := idealType(v.Ctype()); typ.IsUntyped() && typ != vt {
+ Fatalf("exporter: untyped type mismatch, have: %v, want: %v", typ, vt)
}
w.typ(typ)
@@ -1017,6 +1017,8 @@ func (w *exportWriter) symIdx(s *types.Sym) {
}
func (w *exportWriter) typeExt(t *types.Type) {
+ // Export whether this type is marked notinheap.
+ w.bool(t.NotInHeap())
// For type T, export the index of type descriptor symbols of T and *T.
if i, ok := typeSymIdx[t]; ok {
w.int64(i[0])
@@ -1264,8 +1266,13 @@ func (w *exportWriter) expr(n *Node) {
// case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList
- // case OCALLPART:
- // unimplemented - handled by default case
+ case OCALLPART:
+ // An OCALLPART is an OXDOT before type checking.
+ w.op(OXDOT)
+ w.pos(n.Pos)
+ w.expr(n.Left)
+ // Right node should be ONAME
+ w.selector(n.Right.Sym)
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
w.op(OXDOT)
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go
index 4169222c14..7f2b05f288 100644
--- a/src/cmd/compile/internal/gc/iimport.go
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -375,7 +375,7 @@ func (p *importReader) value() (typ *types.Type, v Val) {
v.U = p.string()
case CTINT:
x := new(Mpint)
- x.Rune = typ == types.Idealrune
+ x.Rune = typ == types.UntypedRune
p.mpint(&x.Val, typ)
v.U = x
case CTFLT:
@@ -596,7 +596,6 @@ func (r *importReader) typ1() *types.Type {
// Ensure we expand the interface in the frontend (#25055).
checkwidth(t)
-
return t
}
}
@@ -711,6 +710,7 @@ func (r *importReader) symIdx(s *types.Sym) {
}
func (r *importReader) typeExt(t *types.Type) {
+ t.SetNotInHeap(r.bool())
i, pi := r.int64(), r.int64()
if i != -1 && pi != -1 {
typeSymIdx[t] = [2]int64{i, pi}
@@ -742,8 +742,8 @@ func (r *importReader) doInline(n *Node) {
importlist = append(importlist, n)
- if Debug['E'] > 0 && Debug['m'] > 2 {
- if Debug['m'] > 3 {
+ if Debug.E > 0 && Debug.m > 2 {
+ if Debug.m > 3 {
fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body))
} else {
fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body))
@@ -866,7 +866,7 @@ func (r *importReader) node() *Node {
// unreachable - handled in case OSTRUCTLIT by elemList
// case OCALLPART:
- // unimplemented
+ // unreachable - mapped to case OXDOT below by exporter
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
// unreachable - mapped to case OXDOT below by exporter
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index fa5b3ec698..a2fb00e132 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -7,7 +7,7 @@
// saves a copy of the body. Then inlcalls walks each function body to
// expand calls to inlinable functions.
//
-// The debug['l'] flag controls the aggressiveness. Note that main() swaps level 0 and 1,
+// The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
// making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
// are not supported.
// 0: disabled
@@ -21,7 +21,7 @@
// The -d typcheckinl flag enables early typechecking of all imported bodies,
// which is useful to flush out bugs.
//
-// The debug['m'] flag enables diagnostic output. a single -m is useful for verifying
+// The Debug.m flag enables diagnostic output. a single -m is useful for verifying
// which calls get inlined or not, more is for debugging, and may go away at any point.
package gc
@@ -85,7 +85,7 @@ func typecheckinl(fn *Node) {
return // typecheckinl on local function
}
- if Debug['m'] > 2 || Debug_export != 0 {
+ if Debug.m > 2 || Debug_export != 0 {
fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
}
@@ -116,10 +116,10 @@ func caninl(fn *Node) {
}
var reason string // reason, if any, that the function was not inlined
- if Debug['m'] > 1 || logopt.Enabled() {
+ if Debug.m > 1 || logopt.Enabled() {
defer func() {
if reason != "" {
- if Debug['m'] > 1 {
+ if Debug.m > 1 {
fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
}
if logopt.Enabled() {
@@ -187,7 +187,7 @@ func caninl(fn *Node) {
defer n.Func.SetInlinabilityChecked(true)
cc := int32(inlineExtraCallCost)
- if Debug['l'] == 4 {
+ if Debug.l == 4 {
cc = 1 // this appears to yield better performance than 0.
}
@@ -224,9 +224,9 @@ func caninl(fn *Node) {
// this is so export can find the body of a method
fn.Type.FuncType().Nname = asTypesNode(n)
- if Debug['m'] > 1 {
+ if Debug.m > 1 {
fmt.Printf("%v: can inline %#v with cost %d as: %#v { %#v }\n", fn.Line(), n, inlineMaxBudget-visitor.budget, fn.Type, asNodes(n.Func.Inl.Body))
- } else if Debug['m'] != 0 {
+ } else if Debug.m != 0 {
fmt.Printf("%v: can inline %v\n", fn.Line(), n)
}
if logopt.Enabled() {
@@ -325,18 +325,10 @@ func (v *hairyVisitor) visit(n *Node) bool {
break
}
- if fn := n.Left.Func; fn != nil && fn.Inl != nil {
- v.budget -= fn.Inl.Cost
+ if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
+ v.budget -= fn.Func.Inl.Cost
break
}
- if n.Left.isMethodExpression() {
- if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl != nil {
- v.budget -= d.Func.Inl.Cost
- break
- }
- }
- // TODO(mdempsky): Budget for OCLOSURE calls if we
- // ever allow that. See #15561 and #23093.
// Call cost for non-leaf inlining.
v.budget -= v.extraCallCost
@@ -382,17 +374,16 @@ func (v *hairyVisitor) visit(n *Node) bool {
v.reason = "call to recover"
return true
+ case OCALLPART:
+ // OCALLPART is inlineable, but no extra cost to the budget
+
case OCLOSURE,
- OCALLPART,
ORANGE,
- OFOR,
- OFORUNTIL,
OSELECT,
OTYPESW,
OGO,
ODEFER,
ODCLTYPE, // can't print yet
- OBREAK,
ORETJMP:
v.reason = "unhandled op " + n.Op.String()
return true
@@ -400,10 +391,23 @@ func (v *hairyVisitor) visit(n *Node) bool {
case OAPPEND:
v.budget -= inlineExtraAppendCost
- case ODCLCONST, OEMPTY, OFALL, OLABEL:
+ case ODCLCONST, OEMPTY, OFALL:
// These nodes don't produce code; omit from inlining budget.
return false
+ case OLABEL:
+ // TODO(mdempsky): Add support for inlining labeled control statements.
+ if n.labeledControl() != nil {
+ v.reason = "labeled control"
+ return true
+ }
+
+ case OBREAK, OCONTINUE:
+ if n.Sym != nil {
+ // Should have short-circuited due to labeledControl above.
+ Fatalf("unexpected labeled break/continue: %v", n)
+ }
+
case OIF:
if Isconst(n.Left, CTBOOL) {
// This if and the condition cost nothing.
@@ -421,7 +425,7 @@ func (v *hairyVisitor) visit(n *Node) bool {
v.budget--
// When debugging, don't stop early, to get full cost of inlining this function
- if v.budget < 0 && Debug['m'] < 2 && !logopt.Enabled() {
+ if v.budget < 0 && Debug.m < 2 && !logopt.Enabled() {
return true
}
@@ -452,7 +456,7 @@ func inlcopy(n *Node) *Node {
}
m := n.copy()
- if m.Func != nil {
+ if n.Op != OCALLPART && m.Func != nil {
Fatalf("unexpected Func: %v", m)
}
m.Left = inlcopy(n.Left)
@@ -666,60 +670,18 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
switch n.Op {
case OCALLFUNC:
- if Debug['m'] > 3 {
+ if Debug.m > 3 {
fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
}
- if n.Left.Func != nil && n.Left.Func.Inl != nil && !isIntrinsicCall(n) { // normal case
- n = mkinlcall(n, n.Left, maxCost, inlMap)
- } else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil {
- n = mkinlcall(n, asNode(n.Left.Sym.Def), maxCost, inlMap)
- } else if n.Left.Op == OCLOSURE {
- if f := inlinableClosure(n.Left); f != nil {
- n = mkinlcall(n, f, maxCost, inlMap)
- }
- } else if n.Left.Op == ONAME && n.Left.Name != nil && n.Left.Name.Defn != nil {
- if d := n.Left.Name.Defn; d.Op == OAS && d.Right.Op == OCLOSURE {
- if f := inlinableClosure(d.Right); f != nil {
- // NB: this check is necessary to prevent indirect re-assignment of the variable
- // having the address taken after the invocation or only used for reads is actually fine
- // but we have no easy way to distinguish the safe cases
- if d.Left.Name.Addrtaken() {
- if Debug['m'] > 1 {
- fmt.Printf("%v: cannot inline escaping closure variable %v\n", n.Line(), n.Left)
- }
- if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
- fmt.Sprintf("%v cannot be inlined (escaping closure variable)", n.Left))
- }
- break
- }
-
- // ensure the variable is never re-assigned
- if unsafe, a := reassigned(n.Left); unsafe {
- if Debug['m'] > 1 {
- if a != nil {
- fmt.Printf("%v: cannot inline re-assigned closure variable at %v: %v\n", n.Line(), a.Line(), a)
- if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
- fmt.Sprintf("%v cannot be inlined (re-assigned closure variable)", a))
- }
- } else {
- fmt.Printf("%v: cannot inline global closure variable %v\n", n.Line(), n.Left)
- if logopt.Enabled() {
- logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
- fmt.Sprintf("%v cannot be inlined (global closure variable)", n.Left))
- }
- }
- }
- break
- }
- n = mkinlcall(n, f, maxCost, inlMap)
- }
- }
+ if isIntrinsicCall(n) {
+ break
+ }
+ if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
+ n = mkinlcall(n, fn, maxCost, inlMap)
}
case OCALLMETH:
- if Debug['m'] > 3 {
+ if Debug.m > 3 {
fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
}
@@ -739,16 +701,73 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
return n
}
-// inlinableClosure takes an OCLOSURE node and follows linkage to the matching ONAME with
-// the inlinable body. Returns nil if the function is not inlinable.
-func inlinableClosure(n *Node) *Node {
- c := n.Func.Closure
- caninl(c)
- f := c.Func.Nname
- if f == nil || f.Func.Inl == nil {
+// inlCallee takes a function-typed expression and returns the underlying function ONAME
+// that it refers to if statically known. Otherwise, it returns nil.
+func inlCallee(fn *Node) *Node {
+ fn = staticValue(fn)
+ switch {
+ case fn.Op == ONAME && fn.Class() == PFUNC:
+ if fn.isMethodExpression() {
+ return asNode(fn.Sym.Def)
+ }
+ return fn
+ case fn.Op == OCLOSURE:
+ c := fn.Func.Closure
+ caninl(c)
+ return c.Func.Nname
+ }
+ return nil
+}
+
+func staticValue(n *Node) *Node {
+ for {
+ n1 := staticValue1(n)
+ if n1 == nil {
+ return n
+ }
+ n = n1
+ }
+}
+
+// staticValue1 implements a simple SSA-like optimization. If n is a local variable
+// that is initialized and never reassigned, staticValue1 returns the initializer
+// expression. Otherwise, it returns nil.
+func staticValue1(n *Node) *Node {
+ if n.Op != ONAME || n.Class() != PAUTO || n.Name.Addrtaken() {
+ return nil
+ }
+
+ defn := n.Name.Defn
+ if defn == nil {
+ return nil
+ }
+
+ var rhs *Node
+FindRHS:
+ switch defn.Op {
+ case OAS:
+ rhs = defn.Right
+ case OAS2:
+ for i, lhs := range defn.List.Slice() {
+ if lhs == n {
+ rhs = defn.Rlist.Index(i)
+ break FindRHS
+ }
+ }
+ Fatalf("%v missing from LHS of %v", n, defn)
+ default:
+ return nil
+ }
+ if rhs == nil {
+ Fatalf("RHS is nil: %v", defn)
+ }
+
+ unsafe, _ := reassigned(n)
+ if unsafe {
return nil
}
- return f
+
+ return rhs
}
// reassigned takes an ONAME node, walks the function in which it is defined, and returns a boolean
@@ -831,16 +850,19 @@ func (v *reassignVisitor) visitList(l Nodes) *Node {
return nil
}
-func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
- if n := asNode(t.Nname); n != nil && !n.isBlank() {
- inlvar := inlvars[n]
- if inlvar == nil {
- Fatalf("missing inlvar for %v\n", n)
- }
- return inlvar
+func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
+ n := asNode(t.Nname)
+ if n == nil || n.isBlank() {
+ return nblank
}
- return typecheck(nblank, ctxExpr|ctxAssign)
+ inlvar := inlvars[n]
+ if inlvar == nil {
+ Fatalf("missing inlvar for %v", n)
+ }
+ as.Ninit.Append(nod(ODCL, inlvar, nil))
+ inlvar.Name.Defn = as
+ return inlvar
}
var inlgen int
@@ -889,7 +911,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
}
if inlMap[fn] {
- if Debug['m'] > 1 {
+ if Debug.m > 1 {
fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", n.Line(), fn, Curfn.funcname())
}
return n
@@ -903,12 +925,12 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
}
// We have a function node, and it has an inlineable body.
- if Debug['m'] > 1 {
+ if Debug.m > 1 {
fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
- } else if Debug['m'] != 0 {
+ } else if Debug.m != 0 {
fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
}
- if Debug['m'] > 2 {
+ if Debug.m > 2 {
fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
}
@@ -970,14 +992,15 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
continue
}
if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
- continue
- }
- inlvars[ln] = typecheck(inlvar(ln), ctxExpr)
- if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
- ninit.Append(nod(ODCL, inlvars[ln], nil))
+ // TODO(mdempsky): Remove once I'm confident
+ // this never actually happens. We currently
+ // perform inlining before escape analysis, so
+ // nothing should have moved to the heap yet.
+ Fatalf("impossible: %v", ln)
}
+ inlf := typecheck(inlvar(ln), ctxExpr)
+ inlvars[ln] = inlf
if genDwarfInline > 0 {
- inlf := inlvars[ln]
if ln.Class() == PPARAM {
inlf.Name.SetInlFormal(true)
} else {
@@ -1019,56 +1042,42 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
// Assign arguments to the parameters' temp names.
as := nod(OAS2, nil, nil)
- as.Rlist.Set(n.List.Slice())
+ as.SetColas(true)
+ if n.Op == OCALLMETH {
+ if n.Left.Left == nil {
+ Fatalf("method call without receiver: %+v", n)
+ }
+ as.Rlist.Append(n.Left.Left)
+ }
+ as.Rlist.Append(n.List.Slice()...)
// For non-dotted calls to variadic functions, we assign the
// variadic parameter's temp name separately.
var vas *Node
- if fn.IsMethod() {
- rcv := fn.Type.Recv()
-
- if n.Left.Op == ODOTMETH {
- // For x.M(...), assign x directly to the
- // receiver parameter.
- if n.Left.Left == nil {
- Fatalf("method call without receiver: %+v", n)
- }
- ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
- ras = typecheck(ras, ctxStmt)
- ninit.Append(ras)
- } else {
- // For T.M(...), add the receiver parameter to
- // as.List, so it's assigned by the normal
- // arguments.
- if as.Rlist.Len() == 0 {
- Fatalf("non-method call to method without first arg: %+v", n)
- }
- as.List.Append(tinlvar(rcv, inlvars))
- }
+ if recv := fn.Type.Recv(); recv != nil {
+ as.List.Append(inlParam(recv, as, inlvars))
}
-
for _, param := range fn.Type.Params().Fields().Slice() {
// For ordinary parameters or variadic parameters in
// dotted calls, just add the variable to the
// assignment list, and we're done.
if !param.IsDDD() || n.IsDDD() {
- as.List.Append(tinlvar(param, inlvars))
+ as.List.Append(inlParam(param, as, inlvars))
continue
}
// Otherwise, we need to collect the remaining values
// to pass as a slice.
- numvals := n.List.Len()
-
x := as.List.Len()
- for as.List.Len() < numvals {
+ for as.List.Len() < as.Rlist.Len() {
as.List.Append(argvar(param.Type, as.List.Len()))
}
varargs := as.List.Slice()[x:]
- vas = nod(OAS, tinlvar(param, inlvars), nil)
+ vas = nod(OAS, nil, nil)
+ vas.Left = inlParam(param, vas, inlvars)
if len(varargs) == 0 {
vas.Right = nodnil()
vas.Right.Type = param.Type
@@ -1165,7 +1174,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
}
}
- if Debug['m'] > 2 {
+ if Debug.m > 2 {
fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
}
@@ -1176,7 +1185,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
// PAUTO's in the calling functions, and link them off of the
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
func inlvar(var_ *Node) *Node {
- if Debug['m'] > 3 {
+ if Debug.m > 3 {
fmt.Printf("inlvar %+v\n", var_)
}
@@ -1255,13 +1264,13 @@ func (subst *inlsubst) node(n *Node) *Node {
switch n.Op {
case ONAME:
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
- if Debug['m'] > 2 {
+ if Debug.m > 2 {
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
}
return inlvar
}
- if Debug['m'] > 2 {
+ if Debug.m > 2 {
fmt.Printf("not substituting name %+v\n", n)
}
return n
diff --git a/src/cmd/compile/internal/gc/inl_test.go b/src/cmd/compile/internal/gc/inl_test.go
index 9d3b8c59fd..afa6b98315 100644
--- a/src/cmd/compile/internal/gc/inl_test.go
+++ b/src/cmd/compile/internal/gc/inl_test.go
@@ -83,7 +83,7 @@ func TestIntendedInlining(t *testing.T) {
"puintptr.ptr",
"spanOf",
"spanOfUnchecked",
- //"(*gcWork).putFast", // TODO(austin): For debugging #27993
+ "(*gcWork).putFast",
"(*gcWork).tryGetFast",
"(*guintptr).set",
"(*markBits).advance",
@@ -115,6 +115,7 @@ func TestIntendedInlining(t *testing.T) {
"byLiteral.Len",
"byLiteral.Less",
"byLiteral.Swap",
+ "(*dictDecoder).tryWriteCopy",
},
"encoding/base64": {
"assemble32",
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index 1a344c6566..7cce371408 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -48,8 +48,11 @@ const (
Nowritebarrierrec // error on write barrier in this or recursive callees
Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
- // Runtime-only type pragmas
+ // Runtime and cgo type pragmas
NotInHeap // values of this type must not be heap allocated
+
+ // Go command pragmas
+ GoBuildPragma
)
const (
@@ -71,6 +74,8 @@ const (
func pragmaFlag(verb string) PragmaFlag {
switch verb {
+ case "go:build":
+ return GoBuildPragma
case "go:nointerface":
if objabi.Fieldtrack_enabled != 0 {
return Nointerface
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 7ad3bfe0c8..0b65e8a0b4 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -34,8 +34,6 @@ import (
"strings"
)
-var imported_unsafe bool
-
var (
buildid string
spectre string
@@ -132,7 +130,7 @@ func hidePanic() {
// supportsDynlink reports whether or not the code generator for the given
// architecture supports the -shared and -dynlink flags.
func supportsDynlink(arch *sys.Arch) bool {
- return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
+ return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X)
}
// timing data for compiler phases
@@ -211,18 +209,27 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
- objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
- objabi.Flagcount("B", "disable bounds checking", &Debug['B'])
- objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C']) // TODO(gri) remove eventually
flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
- objabi.Flagcount("E", "debug symbol export", &Debug['E'])
+
+ objabi.Flagcount("%", "debug non-static initializers", &Debug.P)
+ objabi.Flagcount("B", "disable bounds checking", &Debug.B)
+ objabi.Flagcount("C", "disable printing of columns in error messages", &Debug.C)
+ objabi.Flagcount("E", "debug symbol export", &Debug.E)
+ objabi.Flagcount("K", "debug missing line numbers", &Debug.K)
+ objabi.Flagcount("L", "show full file names in error messages", &Debug.L)
+ objabi.Flagcount("N", "disable optimizations", &Debug.N)
+ objabi.Flagcount("S", "print assembly listing", &Debug.S)
+ objabi.Flagcount("W", "debug parse tree after type checking", &Debug.W)
+ objabi.Flagcount("e", "no limit on number of errors reported", &Debug.e)
+ objabi.Flagcount("h", "halt on error", &Debug.h)
+ objabi.Flagcount("j", "debug runtime-initialized variables", &Debug.j)
+ objabi.Flagcount("l", "disable inlining", &Debug.l)
+ objabi.Flagcount("m", "print optimization decisions", &Debug.m)
+ objabi.Flagcount("r", "debug generated wrappers", &Debug.r)
+ objabi.Flagcount("w", "debug type checking", &Debug.w)
+
objabi.Flagfn1("I", "add `directory` to import search path", addidir)
- objabi.Flagcount("K", "debug missing line numbers", &Debug['K'])
- objabi.Flagcount("L", "show full file names in error messages", &Debug['L'])
- objabi.Flagcount("N", "disable optimizations", &Debug['N'])
- objabi.Flagcount("S", "print assembly listing", &Debug['S'])
objabi.AddVersionFlag() // -V
- objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
@@ -231,17 +238,13 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
- objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
- objabi.Flagcount("h", "halt on error", &Debug['h'])
+ objabi.Flagfn1("embedcfg", "read go:embed configuration from `file`", readEmbedCfg)
objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
- objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
- objabi.Flagcount("l", "disable inlining", &Debug['l'])
flag.StringVar(&flag_lang, "lang", "", "release to compile for")
flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
objabi.Flagcount("live", "debug liveness analysis", &debuglive)
- objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
}
@@ -249,7 +252,6 @@ func Main(archInit func(*Arch)) {
flag.StringVar(&outfile, "o", "", "write output to `file`")
flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o")
- objabi.Flagcount("r", "debug generated wrappers", &Debug['r'])
if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
flag.BoolVar(&flag_race, "race", false, "enable race detector")
}
@@ -259,7 +261,6 @@ func Main(archInit func(*Arch)) {
}
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
- objabi.Flagcount("w", "debug type checking", &Debug['w'])
flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
var flag_shared bool
var flag_dynlink bool
@@ -325,9 +326,9 @@ func Main(archInit func(*Arch)) {
Ctxt.Flag_shared = flag_dynlink || flag_shared
Ctxt.Flag_dynlink = flag_dynlink
- Ctxt.Flag_optimize = Debug['N'] == 0
+ Ctxt.Flag_optimize = Debug.N == 0
- Ctxt.Debugasm = Debug['S']
+ Ctxt.Debugasm = Debug.S
Ctxt.Debugvlog = Debug_vlog
if flagDWARF {
Ctxt.DebugInfo = debuginfo
@@ -399,7 +400,7 @@ func Main(archInit func(*Arch)) {
instrumenting = true
}
- if compiling_runtime && Debug['N'] != 0 {
+ if compiling_runtime && Debug.N != 0 {
log.Fatal("cannot disable optimizations while compiling runtime")
}
if nBackendWorkers < 1 {
@@ -504,11 +505,11 @@ func Main(archInit func(*Arch)) {
}
// enable inlining. for now:
- // default: inlining on. (debug['l'] == 1)
- // -l: inlining off (debug['l'] == 0)
- // -l=2, -l=3: inlining on again, with extra debugging (debug['l'] > 1)
- if Debug['l'] <= 1 {
- Debug['l'] = 1 - Debug['l']
+ // default: inlining on. (Debug.l == 1)
+ // -l: inlining off (Debug.l == 0)
+ // -l=2, -l=3: inlining on again, with extra debugging (Debug.l > 1)
+ if Debug.l <= 1 {
+ Debug.l = 1 - Debug.l
}
if jsonLogOpt != "" { // parse version,destination from json logging optimization.
@@ -516,6 +517,7 @@ func Main(archInit func(*Arch)) {
}
ssaDump = os.Getenv("GOSSAFUNC")
+ ssaDir = os.Getenv("GOSSADIR")
if ssaDump != "" {
if strings.HasSuffix(ssaDump, "+") {
ssaDump = ssaDump[:len(ssaDump)-1]
@@ -594,7 +596,7 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "typecheck", "top1")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
+ if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias()) {
xtop[i] = typecheck(n, ctxStmt)
}
}
@@ -606,7 +608,7 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "typecheck", "top2")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
+ if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias() {
xtop[i] = typecheck(n, ctxStmt)
}
}
@@ -665,7 +667,7 @@ func Main(archInit func(*Arch)) {
// Phase 5: Inlining
timings.Start("fe", "inlining")
if Debug_typecheckinl != 0 {
- // Typecheck imported function bodies if debug['l'] > 1,
+ // Typecheck imported function bodies if Debug.l > 1,
// otherwise lazily when used or re-exported.
for _, n := range importlist {
if n.Func.Inl != nil {
@@ -679,7 +681,7 @@ func Main(archInit func(*Arch)) {
}
}
- if Debug['l'] != 0 {
+ if Debug.l != 0 {
// Find functions that can be inlined and clone them before walk expands them.
visitBottomUp(xtop, func(list []*Node, recursive bool) {
numfns := numNonClosures(list)
@@ -690,7 +692,7 @@ func Main(archInit func(*Arch)) {
// across more than one function.
caninl(n)
} else {
- if Debug['m'] > 1 {
+ if Debug.m > 1 {
fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
}
}
@@ -967,9 +969,10 @@ func readSymABIs(file, myimportpath string) {
if len(parts) != 3 {
log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
}
- sym, abi := parts[1], parts[2]
- if abi != "ABI0" { // Only supported external ABI right now
- log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi)
+ sym, abistr := parts[1], parts[2]
+ abi, valid := obj.ParseABI(abistr)
+ if !valid {
+ log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
}
// If the symbol is already prefixed with
@@ -982,9 +985,9 @@ func readSymABIs(file, myimportpath string) {
// Record for later.
if parts[0] == "def" {
- symabiDefs[sym] = obj.ABI0
+ symabiDefs[sym] = abi
} else {
- symabiRefs[sym] = obj.ABI0
+ symabiRefs[sym] = abi
}
default:
log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
@@ -1173,7 +1176,6 @@ func importfile(f *Val) *types.Pkg {
}
if path_ == "unsafe" {
- imported_unsafe = true
return unsafepkg
}
@@ -1406,29 +1408,34 @@ func IsAlias(sym *types.Sym) bool {
return sym.Def != nil && asNode(sym.Def).Sym != sym
}
-// By default, assume any debug flags are incompatible with concurrent compilation.
-// A few are safe and potentially in common use for normal compiles, though; mark them as such here.
-var concurrentFlagOK = [256]bool{
- 'B': true, // disabled bounds checking
- 'C': true, // disable printing of columns in error messages
- 'e': true, // no limit on errors; errors all come from non-concurrent code
- 'I': true, // add `directory` to import search path
- 'N': true, // disable optimizations
- 'l': true, // disable inlining
- 'w': true, // all printing happens before compilation
- 'W': true, // all printing happens before compilation
- 'S': true, // printing disassembly happens at the end (but see concurrentBackendAllowed below)
+// By default, assume any debug flags are incompatible with concurrent
+// compilation. A few are safe and potentially in common use for
+// normal compiles, though; return true for those.
+func concurrentFlagOk() bool {
+ // Report whether any debug flag that would prevent concurrent
+ // compilation is set, by zeroing out the allowed ones and then
+ // checking if the resulting struct is zero.
+ d := Debug
+ d.B = 0 // disable bounds checking
+ d.C = 0 // disable printing of columns in error messages
+ d.e = 0 // no limit on errors; errors all come from non-concurrent code
+ d.N = 0 // disable optimizations
+ d.l = 0 // disable inlining
+ d.w = 0 // all printing happens before compilation
+ d.W = 0 // all printing happens before compilation
+ d.S = 0 // printing disassembly happens at the end (but see concurrentBackendAllowed below)
+
+ return d == DebugFlags{}
}
func concurrentBackendAllowed() bool {
- for i, x := range &Debug {
- if x != 0 && !concurrentFlagOK[i] {
- return false
- }
+ if !concurrentFlagOk() {
+ return false
}
- // Debug['S'] by itself is ok, because all printing occurs
+
+ // Debug.S by itself is ok, because all printing occurs
// while writing the object file, and that is non-concurrent.
- // Adding Debug_vlog, however, causes Debug['S'] to also print
+ // Adding Debug_vlog, however, causes Debug.S to also print
// while flushing the plist, which happens concurrently.
if Debug_vlog || debugstr != "" || debuglive > 0 {
return false
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index 5dce533e4b..67d24ef0bc 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -11,6 +11,7 @@ import (
"runtime"
"strconv"
"strings"
+ "unicode"
"unicode/utf8"
"cmd/compile/internal/syntax"
@@ -90,7 +91,11 @@ func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
} else {
// line directive base
p0 := b0.Pos()
- p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line(), p0.Col())
+ p0b := p0.Base()
+ if p0b == b0 {
+ panic("infinite recursion in makeSrcPosBase")
+ }
+ p1 := src.MakePos(p.makeSrcPosBase(p0b), p0.Line(), p0.Col())
b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
}
p.basemap[b0] = b1
@@ -130,11 +135,13 @@ type noder struct {
base *src.PosBase
}
- file *syntax.File
- linknames []linkname
- pragcgobuf [][]string
- err chan syntax.Error
- scope ScopeID
+ file *syntax.File
+ linknames []linkname
+ pragcgobuf [][]string
+ err chan syntax.Error
+ scope ScopeID
+ importedUnsafe bool
+ importedEmbed bool
// scopeVars is a stack tracking the number of variables declared in the
// current function at the moment each open scope was opened.
@@ -236,19 +243,21 @@ type linkname struct {
func (p *noder) node() {
types.Block = 1
- imported_unsafe = false
+ p.importedUnsafe = false
+ p.importedEmbed = false
p.setlineno(p.file.PkgName)
mkpackage(p.file.PkgName.Value)
if pragma, ok := p.file.Pragma.(*Pragma); ok {
+ pragma.Flag &^= GoBuildPragma
p.checkUnused(pragma)
}
xtop = append(xtop, p.decls(p.file.DeclList)...)
for _, n := range p.linknames {
- if !imported_unsafe {
+ if !p.importedUnsafe {
p.yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
continue
}
@@ -323,7 +332,6 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
val := p.basicLit(imp.Path)
ipkg := importfile(&val)
-
if ipkg == nil {
if nerrors == 0 {
Fatalf("phase error in import")
@@ -331,6 +339,13 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
return
}
+ if ipkg == unsafepkg {
+ p.importedUnsafe = true
+ }
+ if ipkg.Path == "embed" {
+ p.importedEmbed = true
+ }
+
ipkg.Direct = true
var my *types.Sym
@@ -372,6 +387,20 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
}
if pragma, ok := decl.Pragma.(*Pragma); ok {
+ if len(pragma.Embeds) > 0 {
+ if !p.importedEmbed {
+ // This check can't be done when building the list pragma.Embeds
+ // because that list is created before the noder starts walking over the file,
+ // so at that point it hasn't seen the imports.
+ // We're left to check now, just before applying the //go:embed lines.
+ for _, e := range pragma.Embeds {
+ p.yyerrorpos(e.Pos, "//go:embed only allowed in Go files that import \"embed\"")
+ }
+ } else {
+ exprs = varEmbed(p, names, typ, exprs, pragma.Embeds)
+ }
+ pragma.Embeds = nil
+ }
p.checkUnused(pragma)
}
@@ -454,17 +483,17 @@ func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
param := n.Name.Param
param.Ntype = typ
- param.Alias = decl.Alias
+ param.SetAlias(decl.Alias)
if pragma, ok := decl.Pragma.(*Pragma); ok {
if !decl.Alias {
- param.Pragma = pragma.Flag & TypePragmas
+ param.SetPragma(pragma.Flag & TypePragmas)
pragma.Flag &^= TypePragmas
}
p.checkUnused(pragma)
}
nod := p.nod(decl, ODCLTYPE, n, nil)
- if param.Alias && !langSupported(1, 9, localpkg) {
+ if param.Alias() && !langSupported(1, 9, localpkg) {
yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9")
}
return nod
@@ -773,7 +802,7 @@ func (p *noder) sum(x syntax.Expr) *Node {
n := p.expr(x)
if Isconst(n, CTSTR) && n.Sym == nil {
nstr = n
- chunks = append(chunks, strlit(nstr))
+ chunks = append(chunks, nstr.StringVal())
}
for i := len(adds) - 1; i >= 0; i-- {
@@ -783,12 +812,12 @@ func (p *noder) sum(x syntax.Expr) *Node {
if Isconst(r, CTSTR) && r.Sym == nil {
if nstr != nil {
// Collapse r into nstr instead of adding to n.
- chunks = append(chunks, strlit(r))
+ chunks = append(chunks, r.StringVal())
continue
}
nstr = r
- chunks = append(chunks, strlit(nstr))
+ chunks = append(chunks, nstr.StringVal())
} else {
if len(chunks) > 1 {
nstr.SetVal(Val{U: strings.Join(chunks, "")})
@@ -1437,11 +1466,6 @@ func (p *noder) mkname(name *syntax.Name) *Node {
return mkname(p.name(name))
}
-func (p *noder) newname(name *syntax.Name) *Node {
- // TODO(mdempsky): Set line number?
- return newname(p.name(name))
-}
-
func (p *noder) wrapname(n syntax.Node, x *Node) *Node {
// These nodes do not carry line numbers.
// Introduce a wrapper node to give them the correct line.
@@ -1497,13 +1521,15 @@ var allowedStdPragmas = map[string]bool{
"go:cgo_import_dynamic": true,
"go:cgo_ldflag": true,
"go:cgo_dynamic_linker": true,
+ "go:embed": true,
"go:generate": true,
}
// *Pragma is the value stored in a syntax.Pragma during parsing.
type Pragma struct {
- Flag PragmaFlag // collected bits
- Pos []PragmaPos // position of each individual flag
+ Flag PragmaFlag // collected bits
+ Pos []PragmaPos // position of each individual flag
+ Embeds []PragmaEmbed
}
type PragmaPos struct {
@@ -1511,12 +1537,22 @@ type PragmaPos struct {
Pos syntax.Pos
}
+type PragmaEmbed struct {
+ Pos syntax.Pos
+ Patterns []string
+}
+
func (p *noder) checkUnused(pragma *Pragma) {
for _, pos := range pragma.Pos {
if pos.Flag&pragma.Flag != 0 {
p.yyerrorpos(pos.Pos, "misplaced compiler directive")
}
}
+ if len(pragma.Embeds) > 0 {
+ for _, e := range pragma.Embeds {
+ p.yyerrorpos(e.Pos, "misplaced go:embed directive")
+ }
+ }
}
func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
@@ -1525,6 +1561,11 @@ func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
p.error(syntax.Error{Pos: pos.Pos, Msg: "misplaced compiler directive"})
}
}
+ if len(pragma.Embeds) > 0 {
+ for _, e := range pragma.Embeds {
+ p.error(syntax.Error{Pos: e.Pos, Msg: "misplaced go:embed directive"})
+ }
+ }
}
// pragma is called concurrently if files are parsed concurrently.
@@ -1569,6 +1610,17 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P
}
p.linknames = append(p.linknames, linkname{pos, f[1], target})
+ case text == "go:embed", strings.HasPrefix(text, "go:embed "):
+ args, err := parseGoEmbed(text[len("go:embed"):])
+ if err != nil {
+ p.error(syntax.Error{Pos: pos, Msg: err.Error()})
+ }
+ if len(args) == 0 {
+ p.error(syntax.Error{Pos: pos, Msg: "usage: //go:embed pattern..."})
+ break
+ }
+ pragma.Embeds = append(pragma.Embeds, PragmaEmbed{pos, args})
+
case strings.HasPrefix(text, "go:cgo_import_dynamic "):
// This is permitted for general use because Solaris
// code relies on it in golang.org/x/sys/unix and others.
@@ -1641,3 +1693,64 @@ func mkname(sym *types.Sym) *Node {
}
return n
}
+
+// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
+// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
+// go/build/read.go also processes these strings and contains similar logic.
+func parseGoEmbed(args string) ([]string, error) {
+ var list []string
+ for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) {
+ var path string
+ Switch:
+ switch args[0] {
+ default:
+ i := len(args)
+ for j, c := range args {
+ if unicode.IsSpace(c) {
+ i = j
+ break
+ }
+ }
+ path = args[:i]
+ args = args[i:]
+
+ case '`':
+ i := strings.Index(args[1:], "`")
+ if i < 0 {
+ return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+ }
+ path = args[1 : 1+i]
+ args = args[1+i+1:]
+
+ case '"':
+ i := 1
+ for ; i < len(args); i++ {
+ if args[i] == '\\' {
+ i++
+ continue
+ }
+ if args[i] == '"' {
+ q, err := strconv.Unquote(args[:i+1])
+ if err != nil {
+ return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
+ }
+ path = q
+ args = args[i+1:]
+ break Switch
+ }
+ }
+ if i >= len(args) {
+ return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+ }
+ }
+
+ if args != "" {
+ r, _ := utf8.DecodeRuneInString(args)
+ if !unicode.IsSpace(r) {
+ return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
+ }
+ }
+ list = append(list, path)
+ }
+ return list, nil
+}
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index b55331a948..226eb45252 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -14,6 +14,8 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
+ "os"
"sort"
"strconv"
)
@@ -125,6 +127,7 @@ func dumpdata() {
itabsLen := len(itabs)
dumpimportstrings()
dumpbasictypes()
+ dumpembeds()
// Calls to dumpsignats can generate functions,
// like method wrappers and hash and equality routines.
@@ -272,7 +275,7 @@ func dumpGlobalConst(n *Node) {
default:
return
}
- Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64())
+ Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64Val())
}
func dumpglobls() {
@@ -305,20 +308,21 @@ func dumpglobls() {
// global symbols can't be declared during parallel compilation.
func addGCLocals() {
for _, s := range Ctxt.Text {
- if s.Func == nil {
+ fn := s.Func()
+ if fn == nil {
continue
}
- for _, gcsym := range []*obj.LSym{s.Func.GCArgs, s.Func.GCLocals, s.Func.GCRegs} {
+ for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals, fn.GCRegs} {
if gcsym != nil && !gcsym.OnList() {
ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
}
}
- if x := s.Func.StackObjects; x != nil {
+ if x := fn.StackObjects; x != nil {
attr := int16(obj.RODATA)
ggloblsym(x, int32(len(x.P)), attr)
x.Set(obj.AttrStatic, true)
}
- if x := s.Func.OpenCodedDeferInfo; x != nil {
+ if x := fn.OpenCodedDeferInfo; x != nil {
ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
}
}
@@ -357,28 +361,31 @@ func dbvec(s *obj.LSym, off int, bv bvec) int {
return off
}
+const (
+ stringSymPrefix = "go.string."
+ stringSymPattern = ".gostring.%d.%x"
+)
+
+// stringsym returns a symbol containing the string s.
+// The symbol contains the string data, not a string header.
func stringsym(pos src.XPos, s string) (data *obj.LSym) {
var symname string
if len(s) > 100 {
// Huge strings are hashed to avoid long names in object files.
// Indulge in some paranoia by writing the length of s, too,
// as protection against length extension attacks.
+ // Same pattern is known to fileStringSym below.
h := sha256.New()
io.WriteString(h, s)
- symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil))
+ symname = fmt.Sprintf(stringSymPattern, len(s), h.Sum(nil))
} else {
// Small strings get named directly by their contents.
symname = strconv.Quote(s)
}
- const prefix = "go.string."
- symdataname := prefix + symname
-
- symdata := Ctxt.Lookup(symdataname)
-
+ symdata := Ctxt.Lookup(stringSymPrefix + symname)
if !symdata.OnList() {
- // string data
- off := dsname(symdata, 0, s, pos, "string")
+ off := dstringdata(symdata, 0, s, pos, "string")
ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
symdata.Set(obj.AttrContentAddressable, true)
}
@@ -386,26 +393,122 @@ func stringsym(pos src.XPos, s string) (data *obj.LSym) {
return symdata
}
-var slicebytes_gen int
+// fileStringSym returns a symbol for the contents and the size of file.
+// If readonly is true, the symbol shares storage with any literal string
+// or other file with the same content and is placed in a read-only section.
+// If readonly is false, the symbol is a read-write copy separate from any other,
+// for use as the backing store of a []byte.
+// The content hash of file is copied into hash. (If hash is nil, nothing is copied.)
+// The returned symbol contains the data itself, not a string header.
+func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.LSym, int64, error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return nil, 0, err
+ }
+ defer f.Close()
+ info, err := f.Stat()
+ if err != nil {
+ return nil, 0, err
+ }
+ if !info.Mode().IsRegular() {
+ return nil, 0, fmt.Errorf("not a regular file")
+ }
+ size := info.Size()
+ if size <= 1*1024 {
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return nil, 0, err
+ }
+ if int64(len(data)) != size {
+ return nil, 0, fmt.Errorf("file changed between reads")
+ }
+ var sym *obj.LSym
+ if readonly {
+ sym = stringsym(pos, string(data))
+ } else {
+ sym = slicedata(pos, string(data)).Sym.Linksym()
+ }
+ if len(hash) > 0 {
+ sum := sha256.Sum256(data)
+ copy(hash, sum[:])
+ }
+ return sym, size, nil
+ }
+ if size > 2e9 {
+ // ggloblsym takes an int32,
+ // and probably the rest of the toolchain
+ // can't handle such big symbols either.
+ // See golang.org/issue/9862.
+ return nil, 0, fmt.Errorf("file too large")
+ }
-func slicebytes(nam *Node, s string) {
- slicebytes_gen++
- symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
+ // File is too big to read and keep in memory.
+ // Compute hash if needed for read-only content hashing or if the caller wants it.
+ var sum []byte
+ if readonly || len(hash) > 0 {
+ h := sha256.New()
+ n, err := io.Copy(h, f)
+ if err != nil {
+ return nil, 0, err
+ }
+ if n != size {
+ return nil, 0, fmt.Errorf("file changed between reads")
+ }
+ sum = h.Sum(nil)
+ copy(hash, sum)
+ }
+
+ var symdata *obj.LSym
+ if readonly {
+ symname := fmt.Sprintf(stringSymPattern, size, sum)
+ symdata = Ctxt.Lookup(stringSymPrefix + symname)
+ if !symdata.OnList() {
+ info := symdata.NewFileInfo()
+ info.Name = file
+ info.Size = size
+ ggloblsym(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ // Note: AttrContentAddressable cannot be set here,
+ // because the content-addressable-handling code
+ // does not know about file symbols.
+ }
+ } else {
+ // Emit a zero-length data symbol
+ // and then fix up length and content to use file.
+ symdata = slicedata(pos, "").Sym.Linksym()
+ symdata.Size = size
+ symdata.Type = objabi.SNOPTRDATA
+ info := symdata.NewFileInfo()
+ info.Name = file
+ info.Size = size
+ }
+
+ return symdata, size, nil
+}
+
+var slicedataGen int
+
+func slicedata(pos src.XPos, s string) *Node {
+ slicedataGen++
+ symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
sym := localpkg.Lookup(symname)
symnode := newname(sym)
sym.Def = asTypesNode(symnode)
lsym := sym.Linksym()
- off := dsname(lsym, 0, s, nam.Pos, "slice")
+ off := dstringdata(lsym, 0, s, pos, "slice")
ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL)
+ return symnode
+}
+
+func slicebytes(nam *Node, s string) {
if nam.Op != ONAME {
Fatalf("slicebytes %v", nam)
}
- slicesym(nam, symnode, int64(len(s)))
+ slicesym(nam, slicedata(nam.Pos, s), int64(len(s)))
}
-func dsname(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
+func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
// Objects that are too large will cause the data section to overflow right away,
// causing a cryptic error message by the linker. Check for oversize objects here
// and provide a useful error message instead.
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 75da154fe2..863de5b6c7 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -50,7 +50,7 @@ type Order struct {
// Order rewrites fn.Nbody to apply the ordering constraints
// described in the comment at the top of the file.
func order(fn *Node) {
- if Debug['W'] > 1 {
+ if Debug.W > 1 {
s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
dumplist(s, fn.Nbody)
}
@@ -323,12 +323,7 @@ func (o *Order) stmtList(l Nodes) {
// and rewrites it to:
// m = OMAKESLICECOPY([]T, x, s); nil
func orderMakeSliceCopy(s []*Node) {
- const go115makeslicecopy = true
- if !go115makeslicecopy {
- return
- }
-
- if Debug['N'] != 0 || instrumenting {
+ if Debug.N != 0 || instrumenting {
return
}
@@ -1102,7 +1097,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
haslit := false
for _, n1 := range n.List.Slice() {
hasbyte = hasbyte || n1.Op == OBYTES2STR
- haslit = haslit || n1.Op == OLITERAL && len(strlit(n1)) != 0
+ haslit = haslit || n1.Op == OLITERAL && len(n1.StringVal()) != 0
}
if haslit && hasbyte {
@@ -1274,7 +1269,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
var t *types.Type
switch n.Op {
case OSLICELIT:
- t = types.NewArray(n.Type.Elem(), n.Right.Int64())
+ t = types.NewArray(n.Type.Elem(), n.Right.Int64Val())
case OCALLPART:
t = partialCallType(n)
}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index 52b1ed351d..353f4b08c9 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -266,8 +266,8 @@ func compile(fn *Node) {
dtypesym(n.Type)
// Also make sure we allocate a linker symbol
// for the stack object data, for the same reason.
- if fn.Func.lsym.Func.StackObjects == nil {
- fn.Func.lsym.Func.StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
+ if fn.Func.lsym.Func().StackObjects == nil {
+ fn.Func.lsym.Func().StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
}
}
}
@@ -415,7 +415,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
case PAUTO:
if !n.Name.Used() {
// Text == nil -> generating abstract function
- if fnsym.Func.Text != nil {
+ if fnsym.Func().Text != nil {
Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
}
continue
@@ -425,7 +425,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
continue
}
apdecls = append(apdecls, n)
- fnsym.Func.RecordAutoType(ngotype(n).Linksym())
+ fnsym.Func().RecordAutoType(ngotype(n).Linksym())
}
decls, dwarfVars := createDwarfVars(fnsym, fn.Func, apdecls)
@@ -435,7 +435,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
// the function symbol to insure that the type included in DWARF
// processing during linking.
typesyms := []*obj.LSym{}
- for t, _ := range fnsym.Func.Autot {
+ for t, _ := range fnsym.Func().Autot {
typesyms = append(typesyms, t)
}
sort.Sort(obj.BySymName(typesyms))
@@ -444,7 +444,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
r.Sym = sym
r.Type = objabi.R_USETYPE
}
- fnsym.Func.Autot = nil
+ fnsym.Func().Autot = nil
var varScopes []ScopeID
for _, decl := range decls {
@@ -522,7 +522,7 @@ func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
}
typename := dwarf.InfoPrefix + typesymname(n.Type)
- delete(fnsym.Func.Autot, ngotype(n).Linksym())
+ delete(fnsym.Func().Autot, ngotype(n).Linksym())
inlIndex := 0
if genDwarfInline > 1 {
if n.Name.InlFormal() || n.Name.InlLocal() {
@@ -667,7 +667,7 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, apDecls []*Node) ([]*Node, []*dw
ChildIndex: -1,
})
// Record go type of to insure that it gets emitted by the linker.
- fnsym.Func.RecordAutoType(ngotype(n).Linksym())
+ fnsym.Func().RecordAutoType(ngotype(n).Linksym())
}
return decls, vars
@@ -731,7 +731,7 @@ func createComplexVar(fnsym *obj.LSym, fn *Func, varID ssa.VarID) *dwarf.Var {
}
gotype := ngotype(n).Linksym()
- delete(fnsym.Func.Autot, gotype)
+ delete(fnsym.Func().Autot, gotype)
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
inlIndex := 0
if genDwarfInline > 1 {
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index a9ea37701e..b471accb65 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -1552,26 +1552,27 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
// Emit the live pointer map data structures
ls := e.curfn.Func.lsym
- ls.Func.GCArgs, ls.Func.GCLocals, ls.Func.GCRegs = lv.emit()
+ fninfo := ls.Func()
+ fninfo.GCArgs, fninfo.GCLocals, fninfo.GCRegs = lv.emit()
p := pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
- p.To.Sym = ls.Func.GCArgs
+ p.To.Sym = fninfo.GCArgs
p = pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
- p.To.Sym = ls.Func.GCLocals
+ p.To.Sym = fninfo.GCLocals
if !go115ReduceLiveness {
p = pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
- p.To.Sym = ls.Func.GCRegs
+ p.To.Sym = fninfo.GCRegs
}
return lv.livenessMap
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 5434b0167a..1b4d765d42 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -112,12 +112,13 @@ func typecheckrangeExpr(n *Node) {
v2 = nil
}
- var why string
if v1 != nil {
if v1.Name != nil && v1.Name.Defn == n {
v1.Type = t1
- } else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
- yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
+ } else if v1.Type != nil {
+ if op, why := assignop(t1, v1.Type); op == OXXX {
+ yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
+ }
}
checkassign(n, v1)
}
@@ -125,8 +126,10 @@ func typecheckrangeExpr(n *Node) {
if v2 != nil {
if v2.Name != nil && v2.Name.Defn == n {
v2.Type = t2
- } else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
- yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
+ } else if v2.Type != nil {
+ if op, why := assignop(t2, v2.Type); op == OXXX {
+ yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
+ }
}
checkassign(n, v2)
}
@@ -463,7 +466,7 @@ func walkrange(n *Node) *Node {
//
// where == for keys of map m is reflexive.
func isMapClear(n *Node) bool {
- if Debug['N'] != 0 || instrumenting {
+ if Debug.N != 0 || instrumenting {
return false
}
@@ -530,7 +533,7 @@ func mapClear(m *Node) *Node {
//
// Parameters are as in walkrange: "for v1, v2 = range a".
func arrayClear(n, v1, v2, a *Node) bool {
- if Debug['N'] != 0 || instrumenting {
+ if Debug.N != 0 || instrumenting {
return false
}
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 21429af782..229fcfeaee 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -1275,8 +1275,9 @@ func dtypesym(t *types.Type) *obj.LSym {
}
ot = dgopkgpath(lsym, ot, tpkg)
+ xcount := sort.Search(n, func(i int) bool { return !types.IsExported(m[i].name.Name) })
ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
- ot = duintptr(lsym, ot, uint64(n))
+ ot = duintptr(lsym, ot, uint64(xcount))
ot = duintptr(lsym, ot, uint64(n))
dataAdd := imethodSize() * n
ot = dextratype(lsym, ot, t, dataAdd)
diff --git a/src/cmd/compile/internal/gc/scope.go b/src/cmd/compile/internal/gc/scope.go
index d7239d5693..e66b859e10 100644
--- a/src/cmd/compile/internal/gc/scope.go
+++ b/src/cmd/compile/internal/gc/scope.go
@@ -62,9 +62,9 @@ func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) {
if len(marks) == 0 {
return
}
- p0 := fnsym.Func.Text
+ p0 := fnsym.Func().Text
scope := findScope(marks, p0.Pos)
- for p := fnsym.Func.Text; p != nil; p = p.Link {
+ for p := p0; p != nil; p = p.Link {
if p.Pos == p0.Pos {
continue
}
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index af19a96bbc..212fcc022d 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -39,7 +39,7 @@ func (s *InitSchedule) append(n *Node) {
// staticInit adds an initialization statement n to the schedule.
func (s *InitSchedule) staticInit(n *Node) {
if !s.tryStaticInit(n) {
- if Debug['%'] != 0 {
+ if Debug.P != 0 {
Dump("nonstatic", n)
}
s.append(n)
@@ -128,7 +128,7 @@ func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
case OSLICELIT:
// copy slice
a := s.inittemps[r]
- slicesym(l, a, r.Right.Int64())
+ slicesym(l, a, r.Right.Int64Val())
return true
case OARRAYLIT, OSTRUCTLIT:
@@ -205,7 +205,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
case OSTR2BYTES:
if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
- sval := strlit(r.Left)
+ sval := r.Left.StringVal()
slicebytes(l, sval)
return true
}
@@ -213,7 +213,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
case OSLICELIT:
s.initplan(r)
// Init slice.
- bound := r.Right.Int64()
+ bound := r.Right.Int64Val()
ta := types.NewArray(r.Type.Elem(), bound)
ta.SetNoalg(true)
a := staticname(ta)
@@ -375,11 +375,6 @@ func readonlystaticname(t *types.Type) *Node {
return n
}
-func isLiteral(n *Node) bool {
- // Treat nils as zeros rather than literals.
- return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
-}
-
func (n *Node) isSimpleName() bool {
return n.Op == ONAME && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
}
@@ -404,7 +399,7 @@ const (
func getdyn(n *Node, top bool) initGenType {
switch n.Op {
default:
- if isLiteral(n) {
+ if n.isGoConst() {
return initConst
}
return initDynamic
@@ -413,7 +408,7 @@ func getdyn(n *Node, top bool) initGenType {
if !top {
return initDynamic
}
- if n.Right.Int64()/4 > int64(n.List.Len()) {
+ if n.Right.Int64Val()/4 > int64(n.List.Len()) {
// <25% of entries have explicit values.
// Very rough estimation, it takes 4 bytes of instructions
// to initialize 1 byte of result. So don't use a static
@@ -559,7 +554,7 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
continue
}
- islit := isLiteral(value)
+ islit := value.isGoConst()
if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
continue
}
@@ -589,12 +584,12 @@ func isSmallSliceLit(n *Node) bool {
r := n.Right
- return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64() <= smallArrayBytes/n.Type.Elem().Width)
+ return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64Val() <= smallArrayBytes/n.Type.Elem().Width)
}
func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
// make an array type corresponding the number of elements we have
- t := types.NewArray(n.Type.Elem(), n.Right.Int64())
+ t := types.NewArray(n.Type.Elem(), n.Right.Int64Val())
dowidth(t)
if ctxt == inNonInitFunction {
@@ -732,7 +727,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
continue
}
- if vstat != nil && isLiteral(value) { // already set by copy from static value
+ if vstat != nil && value.isGoConst() { // already set by copy from static value
continue
}
@@ -993,7 +988,7 @@ func oaslit(n *Node, init *Nodes) bool {
func getlit(lit *Node) int {
if smallintconst(lit) {
- return int(lit.Int64())
+ return int(lit.Int64Val())
}
return -1
}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 815ff7f99f..fb9d3e811a 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -9,8 +9,8 @@ import (
"fmt"
"html"
"os"
+ "path/filepath"
"sort"
- "strings"
"bufio"
"bytes"
@@ -27,6 +27,7 @@ var ssaConfig *ssa.Config
var ssaCaches []ssa.Cache
var ssaDump string // early copy of $GOSSAFUNC; the func name to dump output for
+var ssaDir string // optional destination for ssa dump file
var ssaDumpStdout bool // whether to dump to stdout
var ssaDumpCFG string // generate CFGs for these phases
const ssaDumpFile = "ssa.html"
@@ -49,21 +50,16 @@ func initssaconfig() {
// Caching is disabled in the backend, so generating these here avoids allocations.
_ = types.NewPtr(types.Types[TINTER]) // *interface{}
_ = types.NewPtr(types.NewPtr(types.Types[TSTRING])) // **string
- _ = types.NewPtr(types.NewPtr(types.Idealstring)) // **string
_ = types.NewPtr(types.NewSlice(types.Types[TINTER])) // *[]interface{}
_ = types.NewPtr(types.NewPtr(types.Bytetype)) // **byte
_ = types.NewPtr(types.NewSlice(types.Bytetype)) // *[]byte
_ = types.NewPtr(types.NewSlice(types.Types[TSTRING])) // *[]string
- _ = types.NewPtr(types.NewSlice(types.Idealstring)) // *[]string
_ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[TUINT8]))) // ***uint8
_ = types.NewPtr(types.Types[TINT16]) // *int16
_ = types.NewPtr(types.Types[TINT64]) // *int64
_ = types.NewPtr(types.Errortype) // *error
types.NewPtrCacheEnabled = false
- ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug['N'] == 0)
- if thearch.LinkArch.Name == "386" {
- ssaConfig.Set387(thearch.Use387)
- }
+ ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug.N == 0)
ssaConfig.SoftFloat = thearch.SoftFloat
ssaConfig.Race = flag_race
ssaCaches = make([]ssa.Cache, nBackendWorkers)
@@ -174,10 +170,6 @@ func initssaconfig() {
ExtendCheckFunc[ssa.BoundsSlice3CU] = sysvar("panicExtendSlice3CU")
}
- // GO386=387 runtime definitions
- ControlWord64trunc = sysvar("controlWord64trunc") // uint16
- ControlWord32 = sysvar("controlWord32") // uint16
-
// Wasm (all asm funcs with special ABIs)
WasmMove = sysvar("wasmMove")
WasmZero = sysvar("wasmZero")
@@ -248,7 +240,7 @@ func dvarint(x *obj.LSym, off int, v int64) int {
// - Offset of where argument should be placed in the args frame when making call
func (s *state) emitOpenDeferInfo() {
x := Ctxt.Lookup(s.curfn.Func.lsym.Name + ".opendefer")
- s.curfn.Func.lsym.Func.OpenCodedDeferInfo = x
+ s.curfn.Func.lsym.Func().OpenCodedDeferInfo = x
off := 0
// Compute maxargsize (max size of arguments for all defers)
@@ -347,7 +339,13 @@ func buildssa(fn *Node, worker int) *ssa.Func {
s.f.Entry.Pos = fn.Pos
if printssa {
- s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDumpFile, s.f, ssaDumpCFG)
+ ssaDF := ssaDumpFile
+ if ssaDir != "" {
+ ssaDF = filepath.Join(ssaDir, myimportpath+"."+name+".html")
+ ssaD := filepath.Dir(ssaDF)
+ os.MkdirAll(ssaD, 0755)
+ }
+ s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG)
// TODO: generate and print a mapping from nodes to values and blocks
dumpSourcesColumn(s.f.HTMLWriter, fn)
s.f.HTMLWriter.WriteAST("AST", astBuf)
@@ -359,7 +357,7 @@ func buildssa(fn *Node, worker int) *ssa.Func {
s.fwdVars = map[*Node]*ssa.Value{}
s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
- s.hasOpenDefers = Debug['N'] == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
+ s.hasOpenDefers = Debug.N == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
switch {
case s.hasOpenDefers && (Ctxt.Flag_shared || Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386":
// Don't support open-coded defers for 386 ONLY when using shared
@@ -743,7 +741,7 @@ func (s *state) pushLine(line src.XPos) {
// the frontend may emit node with line number missing,
// use the parent line number in this case.
line = s.peekPos()
- if Debug['K'] != 0 {
+ if Debug.K != 0 {
Warn("buildssa: unknown position (line 0)")
}
} else {
@@ -1216,7 +1214,7 @@ func (s *state) stmt(n *Node) {
// Check whether we're writing the result of an append back to the same slice.
// If so, we handle it specially to avoid write barriers on the fast
// (non-growth) path.
- if !samesafeexpr(n.Left, rhs.List.First()) || Debug['N'] != 0 {
+ if !samesafeexpr(n.Left, rhs.List.First()) || Debug.N != 0 {
break
}
// If the slice can be SSA'd, it'll be on the stack,
@@ -1273,7 +1271,7 @@ func (s *state) stmt(n *Node) {
// We're assigning a slicing operation back to its source.
// Don't write back fields we aren't changing. See issue #14855.
i, j, k := rhs.SliceBounds()
- if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
+ if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64Val() == 0) {
// [0:...] is the same as [:...]
i = nil
}
@@ -1303,7 +1301,7 @@ func (s *state) stmt(n *Node) {
case OIF:
if Isconst(n.Left, CTBOOL) {
s.stmtList(n.Left.Ninit)
- if n.Left.Bool() {
+ if n.Left.BoolVal() {
s.stmtList(n.Nbody)
} else {
s.stmtList(n.Rlist)
@@ -2474,6 +2472,11 @@ func (s *state) expr(n *Node) *ssa.Value {
a := s.expr(n.Left)
b := s.expr(n.Right)
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+ case OANDNOT:
+ a := s.expr(n.Left)
+ b := s.expr(n.Right)
+ b = s.newValue1(s.ssaOp(OBITNOT, b.Type), b.Type, b)
+ return s.newValue2(s.ssaOp(OAND, n.Type), a.Type, a, b)
case OLSH, ORSH:
a := s.expr(n.Left)
b := s.expr(n.Right)
@@ -2557,22 +2560,22 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.addr(n.Left)
case ORESULT:
- if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall {
+ if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
// Do the old thing
addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
- return s.load(n.Type, addr)
+ return s.rawLoad(n.Type, addr)
}
which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Xoffset)
if which == -1 {
// Do the old thing // TODO: Panic instead.
addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
- return s.load(n.Type, addr)
+ return s.rawLoad(n.Type, addr)
}
if canSSAType(n.Type) {
return s.newValue1I(ssa.OpSelectN, n.Type, which, s.prevCall)
} else {
addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(n.Type), which, s.prevCall)
- return s.load(n.Type, addr)
+ return s.rawLoad(n.Type, addr)
}
case ODEREF:
@@ -2612,7 +2615,7 @@ func (s *state) expr(n *Node) *ssa.Value {
// Replace "abc"[1] with 'b'.
// Delayed until now because "abc"[1] is not an ideal constant.
// See test/fixedbugs/issue11370.go.
- return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(strlit(n.Left)[n.Right.Int64()])))
+ return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(n.Left.StringVal()[n.Right.Int64Val()])))
}
a := s.expr(n.Left)
i := s.expr(n.Right)
@@ -2621,7 +2624,7 @@ func (s *state) expr(n *Node) *ssa.Value {
ptrtyp := s.f.Config.Types.BytePtr
ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
if Isconst(n.Right, CTINT) {
- ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr)
+ ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64Val(), ptr)
} else {
ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
}
@@ -3391,6 +3394,13 @@ func init() {
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
},
sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "LoadAcq64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ v := s.newValue2(ssa.OpAtomicLoadAcq64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
+ return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
+ },
+ sys.PPC64)
addF("runtime/internal/atomic", "Loadp",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
@@ -3429,6 +3439,12 @@ func init() {
return nil
},
sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "StoreRel64",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicStoreRel64, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.PPC64)
addF("runtime/internal/atomic", "Xchg",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
@@ -3530,12 +3546,24 @@ func init() {
return nil
},
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "And",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd32, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
addF("runtime/internal/atomic", "Or8",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem())
return nil
},
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
+ addF("runtime/internal/atomic", "Or",
+ func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr32, types.TypeMem, args[0], args[1], s.mem())
+ return nil
+ },
+ sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...)
alias("runtime/internal/atomic", "Xaddint64", "runtime/internal/atomic", "Xadd64", all...)
@@ -3544,9 +3572,19 @@ func init() {
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...)
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...)
alias("runtime/internal/atomic", "LoadAcq", "runtime/internal/atomic", "Load", lwatomics...)
+ alias("runtime/internal/atomic", "LoadAcq64", "runtime/internal/atomic", "Load64", lwatomics...)
+ alias("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq", p4...)
+ alias("sync", "runtime_LoadAcquintptr", "runtime/internal/atomic", "LoadAcq", p4...) // linknamed
+ alias("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...)
+ alias("sync", "runtime_LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...) // linknamed
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...)
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...)
alias("runtime/internal/atomic", "StoreRel", "runtime/internal/atomic", "Store", lwatomics...)
+ alias("runtime/internal/atomic", "StoreRel64", "runtime/internal/atomic", "Store64", lwatomics...)
+ alias("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel", p4...)
+ alias("sync", "runtime_StoreReluintptr", "runtime/internal/atomic", "StoreRel", p4...) // linknamed
+ alias("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...)
+ alias("sync", "runtime_StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...) // linknamed
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...)
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...)
alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...)
@@ -4251,6 +4289,7 @@ func (s *state) openDeferExit() {
s.lastDeferExit = deferExit
s.lastDeferCount = len(s.openDefers)
zeroval := s.constInt8(types.Types[TUINT8], 0)
+ testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
// Test for and run defers in reverse order
for i := len(s.openDefers) - 1; i >= 0; i-- {
r := s.openDefers[i]
@@ -4288,23 +4327,38 @@ func (s *state) openDeferExit() {
stksize := fn.Type.ArgWidth()
var ACArgs []ssa.Param
var ACResults []ssa.Param
+ var callArgs []*ssa.Value
if r.rcvr != nil {
// rcvr in case of OCALLINTER
v := s.load(r.rcvr.Type.Elem(), r.rcvr)
addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
- s.store(types.Types[TUINTPTR], addr, v)
+ if testLateExpansion {
+ callArgs = append(callArgs, v)
+ } else {
+ s.store(types.Types[TUINTPTR], addr, v)
+ }
}
for j, argAddrVal := range r.argVals {
f := getParam(r.n, j)
pt := types.NewPtr(f.Type)
- addr := s.constOffPtrSP(pt, argStart+f.Offset)
- ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart + f.Offset)})
- if !canSSAType(f.Type) {
- s.move(f.Type, addr, argAddrVal)
+ ACArgs = append(ACArgs, ssa.Param{Type: f.Type, Offset: int32(argStart + f.Offset)})
+ if testLateExpansion {
+ var a *ssa.Value
+ if !canSSAType(f.Type) {
+ a = s.newValue2(ssa.OpDereference, f.Type, argAddrVal, s.mem())
+ } else {
+ a = s.load(f.Type, argAddrVal)
+ }
+ callArgs = append(callArgs, a)
} else {
- argVal := s.load(f.Type, argAddrVal)
- s.storeType(f.Type, addr, argVal, 0, false)
+ addr := s.constOffPtrSP(pt, argStart+f.Offset)
+ if !canSSAType(f.Type) {
+ s.move(f.Type, addr, argAddrVal)
+ } else {
+ argVal := s.load(f.Type, argAddrVal)
+ s.storeType(f.Type, addr, argVal, 0, false)
+ }
}
}
var call *ssa.Value
@@ -4312,13 +4366,31 @@ func (s *state) openDeferExit() {
v := s.load(r.closure.Type.Elem(), r.closure)
s.maybeNilCheckClosure(v, callDefer)
codeptr := s.rawLoad(types.Types[TUINTPTR], v)
- call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, v, s.mem())
+ aux := ssa.ClosureAuxCall(ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, aux, codeptr, v, s.mem())
+ }
} else {
- // Do a static call if the original call was a static function or method
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn.Sym.Linksym(), ACArgs, ACResults), s.mem())
+ aux := ssa.StaticAuxCall(fn.Sym.Linksym(), ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ // Do a static call if the original call was a static function or method
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
}
call.AuxInt = stksize
- s.vars[&memVar] = call
+ if testLateExpansion {
+ s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
+ } else {
+ s.vars[&memVar] = call
+ }
// Make sure that the stack slots with pointers are kept live
// through the call (which is a pre-emption point). Also, we will
// use the first call of the last defer exit to compute liveness
@@ -4375,11 +4447,9 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
switch n.Op {
case OCALLFUNC:
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
if k == callNormal && fn.Op == ONAME && fn.Class() == PFUNC {
sym = fn.Sym
- if !returnResultAddr && strings.Contains(sym.Name, "testLateExpansion") {
- testLateExpansion = true
- }
break
}
closure = s.expr(fn)
@@ -4392,11 +4462,9 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
if fn.Op != ODOTMETH {
s.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
}
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
if k == callNormal {
sym = fn.Sym
- if !returnResultAddr && strings.Contains(sym.Name, "testLateExpansion") {
- testLateExpansion = true
- }
break
}
closure = s.getMethodClosure(fn)
@@ -4406,6 +4474,7 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
if fn.Op != ODOTINTER {
s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
}
+ testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
var iclosure *ssa.Value
iclosure, rcvr = s.getClosureAndRcvr(fn)
if k == callNormal {
@@ -4424,6 +4493,7 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
var call *ssa.Value
if k == callDeferStack {
+ testLateExpansion = ssa.LateCallExpansionEnabledWithin(s.f)
// Make a defer struct d on the stack.
t := deferstruct(stksize)
d := tempAt(n.Pos, s.curfn, t)
@@ -4474,10 +4544,17 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
}
// Call runtime.deferprocStack with pointer to _defer record.
- arg0 := s.constOffPtrSP(types.Types[TUINTPTR], Ctxt.FixedFrameSize())
- s.store(types.Types[TUINTPTR], arg0, addr)
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(Ctxt.FixedFrameSize())})
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults), s.mem())
+ aux := ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, addr, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ arg0 := s.constOffPtrSP(types.Types[TUINTPTR], Ctxt.FixedFrameSize())
+ s.store(types.Types[TUINTPTR], arg0, addr)
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
if stksize < int64(Widthptr) {
// We need room for both the call to deferprocStack and the call to
// the deferred function.
@@ -4544,9 +4621,21 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
// call target
switch {
case k == callDefer:
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferproc, ACArgs, ACResults), s.mem())
+ aux := ssa.StaticAuxCall(deferproc, ACArgs, ACResults)
+ if testLateExpansion {
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
case k == callGo:
- call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(newproc, ACArgs, ACResults), s.mem())
+ aux := ssa.StaticAuxCall(newproc, ACArgs, ACResults)
+ if testLateExpansion {
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ }
case closure != nil:
// rawLoad because loading the code pointer from a
// closure is always safe, but IsSanitizerSafeAddr
@@ -4554,18 +4643,25 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
// critical that we not clobber any arguments already
// stored onto the stack.
codeptr = s.rawLoad(types.Types[TUINTPTR], closure)
- call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, closure, s.mem())
+ if testLateExpansion {
+ aux := ssa.ClosureAuxCall(ACArgs, ACResults)
+ call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, closure, s.mem())
+ }
case codeptr != nil:
- call = s.newValue2A(ssa.OpInterCall, types.TypeMem, ssa.InterfaceAuxCall(ACArgs, ACResults), codeptr, s.mem())
+ if testLateExpansion {
+ aux := ssa.InterfaceAuxCall(ACArgs, ACResults)
+ call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
+ call.AddArgs(callArgs...)
+ } else {
+ call = s.newValue2A(ssa.OpInterCall, types.TypeMem, ssa.InterfaceAuxCall(ACArgs, ACResults), codeptr, s.mem())
+ }
case sym != nil:
if testLateExpansion {
- var tys []*types.Type
aux := ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults)
- for i := int64(0); i < aux.NResults(); i++ {
- tys = append(tys, aux.TypeOfResult(i))
- }
- tys = append(tys, types.TypeMem)
- call = s.newValue0A(ssa.OpStaticLECall, types.NewResults(tys), aux)
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
call.AddArgs(callArgs...)
} else {
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults), s.mem())
@@ -4606,7 +4702,11 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
}
fp := res.Field(0)
if returnResultAddr {
- return s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize())
+ pt := types.NewPtr(fp.Type)
+ if testLateExpansion {
+ return s.newValue1I(ssa.OpSelectNAddr, pt, 0, call)
+ }
+ return s.constOffPtrSP(pt, fp.Offset+Ctxt.FixedFrameSize())
}
if testLateExpansion {
@@ -4649,7 +4749,7 @@ func (s *state) getClosureAndRcvr(fn *Node) (*ssa.Value, *ssa.Value) {
s.nilCheck(itab)
itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab
closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
- rcvr := s.newValue1(ssa.OpIData, types.Types[TUINTPTR], i)
+ rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
return closure, rcvr
}
@@ -4710,7 +4810,7 @@ func (s *state) addr(n *Node) *ssa.Value {
}
case ORESULT:
// load return from callee
- if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall {
+ if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
return s.constOffPtrSP(t, n.Xoffset)
}
which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Xoffset)
@@ -4770,7 +4870,7 @@ func (s *state) addr(n *Node) *ssa.Value {
// canSSA reports whether n is SSA-able.
// n must be an ONAME (or an ODOT sequence with an ONAME base).
func (s *state) canSSA(n *Node) bool {
- if Debug['N'] != 0 {
+ if Debug.N != 0 {
return false
}
for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) {
@@ -4881,7 +4981,7 @@ func (s *state) nilCheck(ptr *ssa.Value) {
func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
idx = s.extendIndex(idx, len, kind, bounded)
- if bounded || Debug['B'] != 0 {
+ if bounded || Debug.B != 0 {
// If bounded or bounds checking is flag-disabled, then no check necessary,
// just return the extended index.
//
@@ -5013,15 +5113,22 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
s.prevCall = nil
// Write args to the stack
off := Ctxt.FixedFrameSize()
+ testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
var ACArgs []ssa.Param
var ACResults []ssa.Param
+ var callArgs []*ssa.Value
+
for _, arg := range args {
t := arg.Type
off = Rnd(off, t.Alignment())
- ptr := s.constOffPtrSP(t.PtrTo(), off)
size := t.Size()
ACArgs = append(ACArgs, ssa.Param{Type: t, Offset: int32(off)})
- s.store(t, ptr, arg)
+ if testLateExpansion {
+ callArgs = append(callArgs, arg)
+ } else {
+ ptr := s.constOffPtrSP(t.PtrTo(), off)
+ s.store(t, ptr, arg)
+ }
off += size
}
off = Rnd(off, int64(Widthreg))
@@ -5035,8 +5142,17 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
}
// Issue call
- call := s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn, ACArgs, ACResults), s.mem())
- s.vars[&memVar] = call
+ var call *ssa.Value
+ aux := ssa.StaticAuxCall(fn, ACArgs, ACResults)
+ if testLateExpansion {
+ callArgs = append(callArgs, s.mem())
+ call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
+ call.AddArgs(callArgs...)
+ s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
+ } else {
+ call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
+ s.vars[&memVar] = call
+ }
if !returns {
// Finish block
@@ -5052,11 +5168,24 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
// Load results
res := make([]*ssa.Value, len(results))
- for i, t := range results {
- off = Rnd(off, t.Alignment())
- ptr := s.constOffPtrSP(types.NewPtr(t), off)
- res[i] = s.load(t, ptr)
- off += t.Size()
+ if testLateExpansion {
+ for i, t := range results {
+ off = Rnd(off, t.Alignment())
+ if canSSAType(t) {
+ res[i] = s.newValue1I(ssa.OpSelectN, t, int64(i), call)
+ } else {
+ addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), int64(i), call)
+ res[i] = s.rawLoad(t, addr)
+ }
+ off += t.Size()
+ }
+ } else {
+ for i, t := range results {
+ off = Rnd(off, t.Alignment())
+ ptr := s.constOffPtrSP(types.NewPtr(t), off)
+ res[i] = s.load(t, ptr)
+ off += t.Size()
+ }
}
off = Rnd(off, int64(Widthptr))
@@ -5093,7 +5222,10 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski
case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
s.store(t, left, right)
case t.IsPtrShaped():
- // no scalar fields.
+ if t.IsPtr() && t.Elem().NotInHeap() {
+ s.store(t, left, right) // see issue 42032
+ }
+ // otherwise, no scalar fields.
case t.IsString():
if skip&skipLen != 0 {
return
@@ -5137,6 +5269,9 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski
func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
switch {
case t.IsPtrShaped():
+ if t.IsPtr() && t.Elem().NotInHeap() {
+ break // see issue 42032
+ }
s.store(t, left, right)
case t.IsString():
ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
@@ -5913,9 +6048,7 @@ type SSAGenState struct {
// bstart remembers where each block starts (indexed by block ID)
bstart []*obj.Prog
- // 387 port: maps from SSE registers (REG_X?) to 387 registers (REG_F?)
- SSEto387 map[int16]int16
- // Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include x86-387, PPC, and Sparc V8.
+ // Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include PPC and Sparc V8.
ScratchFpMem *Node
maxarg int64 // largest frame size for arguments to calls made by the function
@@ -6021,7 +6154,7 @@ func emitStackObjects(e *ssafn, pp *Progs) {
// Populate the stack object data.
// Format must match runtime/stack.go:stackObjectRecord.
- x := e.curfn.Func.lsym.Func.StackObjects
+ x := e.curfn.Func.lsym.Func().StackObjects
off := 0
off = duintptr(x, off, uint64(len(vars)))
for _, v := range vars {
@@ -6058,7 +6191,7 @@ func genssa(f *ssa.Func, pp *Progs) {
s.livenessMap = liveness(e, f, pp)
emitStackObjects(e, pp)
- openDeferInfo := e.curfn.Func.lsym.Func.OpenCodedDeferInfo
+ openDeferInfo := e.curfn.Func.lsym.Func().OpenCodedDeferInfo
if openDeferInfo != nil {
// This function uses open-coded defers -- write out the funcdata
// info that we computed at the end of genssa.
@@ -6082,10 +6215,6 @@ func genssa(f *ssa.Func, pp *Progs) {
progToBlock[s.pp.next] = f.Blocks[0]
}
- if thearch.Use387 {
- s.SSEto387 = map[int16]int16{}
- }
-
s.ScratchFpMem = e.scratchFpMem
if Ctxt.Flag_locationlists {
@@ -6208,7 +6337,7 @@ func genssa(f *ssa.Func, pp *Progs) {
}
// Emit control flow instructions for block
var next *ssa.Block
- if i < len(f.Blocks)-1 && Debug['N'] == 0 {
+ if i < len(f.Blocks)-1 && Debug.N == 0 {
// If -N, leave next==nil so every block with successors
// ends in a JMP (except call blocks - plive doesn't like
// select{send,recv} followed by a JMP call). Helps keep
@@ -6267,7 +6396,7 @@ func genssa(f *ssa.Func, pp *Progs) {
// some of the inline marks.
// Use this instruction instead.
p.Pos = p.Pos.WithIsStmt() // promote position to a statement
- pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[m])
+ pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[m])
// Make the inline mark a real nop, so it doesn't generate any code.
m.As = obj.ANOP
m.Pos = src.NoXPos
@@ -6279,7 +6408,7 @@ func genssa(f *ssa.Func, pp *Progs) {
// Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction).
for _, p := range inlMarkList {
if p.As != obj.ANOP {
- pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[p])
+ pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[p])
}
}
}
@@ -6516,7 +6645,7 @@ func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bo
} else {
lo = s.newValue1(ssa.OpInt64Lo, types.Types[TUINT], idx)
}
- if bounded || Debug['B'] != 0 {
+ if bounded || Debug.B != 0 {
return lo
}
bNext := s.f.NewBlock(ssa.BlockPlain)
@@ -6790,56 +6919,38 @@ func (e *ssafn) Auto(pos src.XPos, t *types.Type) ssa.GCNode {
}
func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
- n := name.N.(*Node)
ptrType := types.NewPtr(types.Types[TUINT8])
lenType := types.Types[TINT]
- if n.Class() == PAUTO && !n.Name.Addrtaken() {
- // Split this string up into two separate variables.
- p := e.splitSlot(&name, ".ptr", 0, ptrType)
- l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
- return p, l
- }
- // Return the two parts of the larger variable.
- return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
+ // Split this string up into two separate variables.
+ p := e.SplitSlot(&name, ".ptr", 0, ptrType)
+ l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
+ return p, l
}
func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node)
u := types.Types[TUINTPTR]
t := types.NewPtr(types.Types[TUINT8])
- if n.Class() == PAUTO && !n.Name.Addrtaken() {
- // Split this interface up into two separate variables.
- f := ".itab"
- if n.Type.IsEmptyInterface() {
- f = ".type"
- }
- c := e.splitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
- d := e.splitSlot(&name, ".data", u.Size(), t)
- return c, d
+ // Split this interface up into two separate variables.
+ f := ".itab"
+ if n.Type.IsEmptyInterface() {
+ f = ".type"
}
- // Return the two parts of the larger variable.
- return ssa.LocalSlot{N: n, Type: u, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
+ c := e.SplitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
+ d := e.SplitSlot(&name, ".data", u.Size(), t)
+ return c, d
}
func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
- n := name.N.(*Node)
ptrType := types.NewPtr(name.Type.Elem())
lenType := types.Types[TINT]
- if n.Class() == PAUTO && !n.Name.Addrtaken() {
- // Split this slice up into three separate variables.
- p := e.splitSlot(&name, ".ptr", 0, ptrType)
- l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
- c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
- return p, l, c
- }
- // Return the three parts of the larger variable.
- return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
- ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)},
- ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(2*Widthptr)}
+ p := e.SplitSlot(&name, ".ptr", 0, ptrType)
+ l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
+ c := e.SplitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
+ return p, l, c
}
func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
- n := name.N.(*Node)
s := name.Type.Size() / 2
var t *types.Type
if s == 8 {
@@ -6847,53 +6958,30 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot)
} else {
t = types.Types[TFLOAT32]
}
- if n.Class() == PAUTO && !n.Name.Addrtaken() {
- // Split this complex up into two separate variables.
- r := e.splitSlot(&name, ".real", 0, t)
- i := e.splitSlot(&name, ".imag", t.Size(), t)
- return r, i
- }
- // Return the two parts of the larger variable.
- return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
+ r := e.SplitSlot(&name, ".real", 0, t)
+ i := e.SplitSlot(&name, ".imag", t.Size(), t)
+ return r, i
}
func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
- n := name.N.(*Node)
var t *types.Type
if name.Type.IsSigned() {
t = types.Types[TINT32]
} else {
t = types.Types[TUINT32]
}
- if n.Class() == PAUTO && !n.Name.Addrtaken() {
- // Split this int64 up into two separate variables.
- if thearch.LinkArch.ByteOrder == binary.BigEndian {
- return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
- }
- return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32])
- }
- // Return the two parts of the larger variable.
if thearch.LinkArch.ByteOrder == binary.BigEndian {
- return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off + 4}
+ return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
}
- return ssa.LocalSlot{N: n, Type: t, Off: name.Off + 4}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off}
+ return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[TUINT32])
}
func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
- n := name.N.(*Node)
st := name.Type
- ft := st.FieldType(i)
- var offset int64
- for f := 0; f < i; f++ {
- offset += st.FieldType(f).Size()
- }
- if n.Class() == PAUTO && !n.Name.Addrtaken() {
- // Note: the _ field may appear several times. But
- // have no fear, identically-named but distinct Autos are
- // ok, albeit maybe confusing for a debugger.
- return e.splitSlot(&name, "."+st.FieldName(i), offset, ft)
- }
- return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
+ // Note: the _ field may appear several times. But
+ // have no fear, identically-named but distinct Autos are
+ // ok, albeit maybe confusing for a debugger.
+ return e.SplitSlot(&name, "."+st.FieldName(i), st.FieldOff(i), st.FieldType(i))
}
func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
@@ -6903,19 +6991,23 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
e.Fatalf(n.Pos, "bad array size")
}
et := at.Elem()
- if n.Class() == PAUTO && !n.Name.Addrtaken() {
- return e.splitSlot(&name, "[0]", 0, et)
- }
- return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
+ return e.SplitSlot(&name, "[0]", 0, et)
}
func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
return itabsym(it, offset)
}
-// splitSlot returns a slot representing the data of parent starting at offset.
-func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
- s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg}
+// SplitSlot returns a slot representing the data of parent starting at offset.
+func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
+ node := parent.N.(*Node)
+
+ if node.Class() != PAUTO || node.Name.Addrtaken() {
+ // addressed things and non-autos retain their parents (i.e., cannot truly be split)
+ return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
+ }
+
+ s := &types.Sym{Name: node.Sym.Name + suffix, Pkg: localpkg}
n := &Node{
Name: new(Name),
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 07547df36e..defefd76b3 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -96,7 +96,7 @@ func flusherrors() {
}
func hcrash() {
- if Debug['h'] != 0 {
+ if Debug.h != 0 {
flusherrors()
if outfile != "" {
os.Remove(outfile)
@@ -107,7 +107,7 @@ func hcrash() {
}
func linestr(pos src.XPos) string {
- return Ctxt.OutermostPos(pos).Format(Debug['C'] == 0, Debug['L'] == 1)
+ return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1)
}
// lasterror keeps track of the most recently issued error.
@@ -153,7 +153,7 @@ func yyerrorl(pos src.XPos, format string, args ...interface{}) {
hcrash()
nerrors++
- if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
+ if nsavederrors+nerrors >= 10 && Debug.e == 0 {
flusherrors()
fmt.Printf("%v: too many errors\n", linestr(pos))
errorexit()
@@ -175,7 +175,7 @@ func Warn(fmt_ string, args ...interface{}) {
func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args...)
- if Debug['m'] != 0 {
+ if Debug.m != 0 {
flusherrors()
}
}
@@ -222,7 +222,7 @@ func hasUniquePos(n *Node) bool {
}
if !n.Pos.IsKnown() {
- if Debug['K'] != 0 {
+ if Debug.K != 0 {
Warn("setlineno: unknown position (line 0)")
}
return false
@@ -348,7 +348,7 @@ func newname(s *types.Sym) *Node {
return n
}
-// newname returns a new ONAME Node associated with symbol s at position pos.
+// newnamel returns a new ONAME Node associated with symbol s at position pos.
// The caller is responsible for setting n.Name.Curfn.
func newnamel(pos src.XPos, s *types.Sym) *Node {
if s == nil {
@@ -546,22 +546,19 @@ func methtype(t *types.Type) *types.Type {
// Is type src assignment compatible to type dst?
// If so, return op code to use in conversion.
-// If not, return OXXX.
-func assignop(src, dst *types.Type, why *string) Op {
- if why != nil {
- *why = ""
- }
-
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
+func assignop(src, dst *types.Type) (Op, string) {
if src == dst {
- return OCONVNOP
+ return OCONVNOP, ""
}
if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil {
- return OXXX
+ return OXXX, ""
}
// 1. src type is identical to dst.
if types.Identical(src, dst) {
- return OCONVNOP
+ return OCONVNOP, ""
}
// 2. src and dst have identical underlying types
@@ -575,13 +572,13 @@ func assignop(src, dst *types.Type, why *string) Op {
if src.IsEmptyInterface() {
// Conversion between two empty interfaces
// requires no code.
- return OCONVNOP
+ return OCONVNOP, ""
}
if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() {
// Conversion between two types, at least one unnamed,
// needs no conversion. The exception is nonempty interfaces
// which need to have their itab updated.
- return OCONVNOP
+ return OCONVNOP, ""
}
}
@@ -590,49 +587,47 @@ func assignop(src, dst *types.Type, why *string) Op {
var missing, have *types.Field
var ptr int
if implements(src, dst, &missing, &have, &ptr) {
- return OCONVIFACE
+ return OCONVIFACE, ""
}
// we'll have complained about this method anyway, suppress spurious messages.
if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
- return OCONVIFACE
- }
-
- if why != nil {
- if isptrto(src, TINTER) {
- *why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
- } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
- } else if have != nil && have.Sym == missing.Sym {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
- "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else if ptr != 0 {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
- } else if have != nil {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
- "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
- }
+ return OCONVIFACE, ""
+ }
+
+ var why string
+ if isptrto(src, TINTER) {
+ why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
+ } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
+ } else if have != nil && have.Sym == missing.Sym {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
+ "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else if ptr != 0 {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
+ } else if have != nil {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
+ "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
}
- return OXXX
+ return OXXX, why
}
if isptrto(dst, TINTER) {
- if why != nil {
- *why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
- }
- return OXXX
+ why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
+ return OXXX, why
}
if src.IsInterface() && dst.Etype != TBLANK {
var missing, have *types.Field
var ptr int
- if why != nil && implements(dst, src, &missing, &have, &ptr) {
- *why = ": need type assertion"
+ var why string
+ if implements(dst, src, &missing, &have, &ptr) {
+ why = ": need type assertion"
}
- return OXXX
+ return OXXX, why
}
// 4. src is a bidirectional channel value, dst is a channel type,
@@ -640,7 +635,7 @@ func assignop(src, dst *types.Type, why *string) Op {
// either src or dst is not a named type.
if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
if types.Identical(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
- return OCONVNOP
+ return OCONVNOP, ""
}
}
@@ -653,7 +648,7 @@ func assignop(src, dst *types.Type, why *string) Op {
TCHAN,
TINTER,
TSLICE:
- return OCONVNOP
+ return OCONVNOP, ""
}
}
@@ -661,26 +656,23 @@ func assignop(src, dst *types.Type, why *string) Op {
// 7. Any typed value can be assigned to the blank identifier.
if dst.Etype == TBLANK {
- return OCONVNOP
+ return OCONVNOP, ""
}
- return OXXX
+ return OXXX, ""
}
// Can we convert a value of type src to a value of type dst?
// If so, return op code to use in conversion (maybe OCONVNOP).
-// If not, return OXXX.
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
// srcConstant indicates whether the value of type src is a constant.
-func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
- if why != nil {
- *why = ""
- }
-
+func convertop(srcConstant bool, src, dst *types.Type) (Op, string) {
if src == dst {
- return OCONVNOP
+ return OCONVNOP, ""
}
if src == nil || dst == nil {
- return OXXX
+ return OXXX, ""
}
// Conversions from regular to go:notinheap are not allowed
@@ -688,23 +680,19 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
// rules.
// (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
- if why != nil {
- *why = fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
- }
- return OXXX
+ why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
+ return OXXX, why
}
// (b) Disallow string to []T where T is go:notinheap.
if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Etype == types.Bytetype.Etype || dst.Elem().Etype == types.Runetype.Etype) {
- if why != nil {
- *why = fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
- }
- return OXXX
+ why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
+ return OXXX, why
}
// 1. src can be assigned to dst.
- op := assignop(src, dst, why)
+ op, why := assignop(src, dst)
if op != OXXX {
- return op
+ return op, why
}
// The rules for interfaces are no different in conversions
@@ -712,60 +700,57 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
// with the good message from assignop.
// Otherwise clear the error.
if src.IsInterface() || dst.IsInterface() {
- return OXXX
- }
- if why != nil {
- *why = ""
+ return OXXX, why
}
// 2. Ignoring struct tags, src and dst have identical underlying types.
if types.IdenticalIgnoreTags(src.Orig, dst.Orig) {
- return OCONVNOP
+ return OCONVNOP, ""
}
// 3. src and dst are unnamed pointer types and, ignoring struct tags,
// their base types have identical underlying types.
if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil {
if types.IdenticalIgnoreTags(src.Elem().Orig, dst.Elem().Orig) {
- return OCONVNOP
+ return OCONVNOP, ""
}
}
// 4. src and dst are both integer or floating point types.
if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
if simtype[src.Etype] == simtype[dst.Etype] {
- return OCONVNOP
+ return OCONVNOP, ""
}
- return OCONV
+ return OCONV, ""
}
// 5. src and dst are both complex types.
if src.IsComplex() && dst.IsComplex() {
if simtype[src.Etype] == simtype[dst.Etype] {
- return OCONVNOP
+ return OCONVNOP, ""
}
- return OCONV
+ return OCONV, ""
}
// Special case for constant conversions: any numeric
// conversion is potentially okay. We'll validate further
// within evconst. See #38117.
if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
- return OCONV
+ return OCONV, ""
}
// 6. src is an integer or has type []byte or []rune
// and dst is a string type.
if src.IsInteger() && dst.IsString() {
- return ORUNESTR
+ return ORUNESTR, ""
}
if src.IsSlice() && dst.IsString() {
if src.Elem().Etype == types.Bytetype.Etype {
- return OBYTES2STR
+ return OBYTES2STR, ""
}
if src.Elem().Etype == types.Runetype.Etype {
- return ORUNES2STR
+ return ORUNES2STR, ""
}
}
@@ -773,21 +758,21 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
// String to slice.
if src.IsString() && dst.IsSlice() {
if dst.Elem().Etype == types.Bytetype.Etype {
- return OSTR2BYTES
+ return OSTR2BYTES, ""
}
if dst.Elem().Etype == types.Runetype.Etype {
- return OSTR2RUNES
+ return OSTR2RUNES, ""
}
}
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
- return OCONVNOP
+ return OCONVNOP, ""
}
// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
- return OCONVNOP
+ return OCONVNOP, ""
}
// src is map and dst is a pointer to corresponding hmap.
@@ -795,10 +780,10 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
// go gc maps are implemented as a pointer to a hmap struct.
if src.Etype == TMAP && dst.IsPtr() &&
src.MapType().Hmap == dst.Elem() {
- return OCONVNOP
+ return OCONVNOP, ""
}
- return OXXX
+ return OXXX, ""
}
func assignconv(n *Node, t *types.Type, context string) *Node {
@@ -825,7 +810,7 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
// Convert ideal bool from comparison to plain bool
// if the next step is non-bool (like interface{}).
- if n.Type == types.Idealbool && !t.IsBoolean() {
+ if n.Type == types.UntypedBool && !t.IsBoolean() {
if n.Op == ONAME || n.Op == OLITERAL {
r := nod(OCONVNOP, n, nil)
r.Type = types.Types[TBOOL]
@@ -839,8 +824,7 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
return n
}
- var why string
- op := assignop(n.Type, t, &why)
+ op, why := assignop(n.Type, t)
if op == OXXX {
yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
op = OCONV
@@ -1040,25 +1024,24 @@ func calcHasCall(n *Node) bool {
return false
}
-func badtype(op Op, tl *types.Type, tr *types.Type) {
- fmt_ := ""
+func badtype(op Op, tl, tr *types.Type) {
+ var s string
if tl != nil {
- fmt_ += fmt.Sprintf("\n\t%v", tl)
+ s += fmt.Sprintf("\n\t%v", tl)
}
if tr != nil {
- fmt_ += fmt.Sprintf("\n\t%v", tr)
+ s += fmt.Sprintf("\n\t%v", tr)
}
// common mistake: *struct and *interface.
if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
- fmt_ += "\n\t(*struct vs *interface)"
+ s += "\n\t(*struct vs *interface)"
} else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
- fmt_ += "\n\t(*interface vs *struct)"
+ s += "\n\t(*interface vs *struct)"
}
}
- s := fmt_
yyerror("illegal types for operand: %v%s", op, s)
}
@@ -1523,7 +1506,7 @@ func structargs(tl *types.Type, mustname bool) []*Node {
// method - M func (t T)(), a TFIELD type struct
// newnam - the eventual mangled name of this function
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
- if false && Debug['r'] != 0 {
+ if false && Debug.r != 0 {
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
}
@@ -1596,7 +1579,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
fn.Nbody.Append(call)
}
- if false && Debug['r'] != 0 {
+ if false && Debug.r != 0 {
dumplist("genwrapper body", fn.Nbody)
}
@@ -1737,7 +1720,7 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
// the method does not exist for value types.
rcvr := tm.Type.Recv().Type
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
- if false && Debug['r'] != 0 {
+ if false && Debug.r != 0 {
yyerror("interface pointer mismatch")
}
@@ -1871,8 +1854,10 @@ func isdirectiface(t *types.Type) bool {
}
switch t.Etype {
- case TPTR,
- TCHAN,
+ case TPTR:
+ // Pointers to notinheap types must be stored indirectly. See issue 42076.
+ return !t.Elem().NotInHeap()
+ case TCHAN,
TMAP,
TFUNC,
TUNSAFEPTR:
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 138b0acc53..8d9fbe300e 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -189,16 +189,19 @@ func typecheckExprSwitch(n *Node) {
continue
}
- switch {
- case nilonly != "" && !n1.isNil():
+ if nilonly != "" && !n1.isNil() {
yyerrorl(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
- case t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type):
+ } else if t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type) {
yyerrorl(ncase.Pos, "invalid case %L in switch (incomparable type)", n1)
- case assignop(n1.Type, t, nil) == 0 && assignop(t, n1.Type, nil) == 0:
- if n.Left != nil {
- yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
- } else {
- yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
+ } else {
+ op1, _ := assignop(n1.Type, t)
+ op2, _ := assignop(t, n1.Type)
+ if op1 == OXXX && op2 == OXXX {
+ if n.Left != nil {
+ yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
+ } else {
+ yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
+ }
}
}
@@ -358,8 +361,8 @@ func (s *exprSwitch) flush() {
// all we need here is consistency. We respect this
// sorting below.
sort.Slice(cc, func(i, j int) bool {
- si := strlit(cc[i].lo)
- sj := strlit(cc[j].lo)
+ si := cc[i].lo.StringVal()
+ sj := cc[j].lo.StringVal()
if len(si) != len(sj) {
return len(si) < len(sj)
}
@@ -368,7 +371,7 @@ func (s *exprSwitch) flush() {
// runLen returns the string length associated with a
// particular run of exprClauses.
- runLen := func(run []exprClause) int64 { return int64(len(strlit(run[0].lo))) }
+ runLen := func(run []exprClause) int64 { return int64(len(run[0].lo.StringVal())) }
// Collapse runs of consecutive strings with the same length.
var runs [][]exprClause
@@ -405,7 +408,7 @@ func (s *exprSwitch) flush() {
merged := cc[:1]
for _, c := range cc[1:] {
last := &merged[len(merged)-1]
- if last.jmp == c.jmp && last.hi.Int64()+1 == c.lo.Int64() {
+ if last.jmp == c.jmp && last.hi.Int64Val()+1 == c.lo.Int64Val() {
last.hi = c.lo
} else {
merged = append(merged, c)
@@ -440,7 +443,7 @@ func (c *exprClause) test(exprname *Node) *Node {
// Optimize "switch true { ...}" and "switch false { ... }".
if Isconst(exprname, CTBOOL) && !c.lo.Type.IsInterface() {
- if exprname.Val().U.(bool) {
+ if exprname.BoolVal() {
return c.lo
} else {
return nodl(c.pos, ONOT, c.lo, nil)
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 4aa2e230ce..58de9b5e3f 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -142,7 +142,7 @@ const (
_, _ // second nodeInitorder bit
_, nodeHasBreak
_, nodeNoInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
- _, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP; or ANDNOT lowered to OAND
+ _, nodeImplicit // implicit OADDR or ODEREF; ++/-- statement represented as OASOP
_, nodeIsDDD // is the argument variadic
_, nodeDiag // already printed error about this
_, nodeColas // OAS resulting from :=
@@ -247,7 +247,7 @@ func (n *Node) Val() Val {
// SetVal sets the Val for the node, which must not have been used with SetOpt.
func (n *Node) SetVal(v Val) {
if n.HasOpt() {
- Debug['h'] = 1
+ Debug.h = 1
Dump("have Opt", n)
Fatalf("have Opt")
}
@@ -270,7 +270,7 @@ func (n *Node) SetOpt(x interface{}) {
return
}
if n.HasVal() {
- Debug['h'] = 1
+ Debug.h = 1
Dump("have Val", n)
Fatalf("have Val")
}
@@ -460,14 +460,14 @@ type Param struct {
// x1 := xN.Defn
// x1.Innermost = xN.Outer
//
- // We leave xN.Innermost set so that we can still get to the original
+ // We leave x1.Innermost set so that we can still get to the original
// variable quickly. Not shown here, but once we're
// done parsing a function and no longer need xN.Outer for the
- // lexical x reference links as described above, closurebody
+ // lexical x reference links as described above, funcLit
// recomputes xN.Outer as the semantic x reference link tree,
// even filling in x in intermediate closures that might not
// have mentioned it along the way to inner closures that did.
- // See closurebody for details.
+ // See funcLit for details.
//
// During the eventual compilation, then, for closure variables we have:
//
@@ -480,11 +480,87 @@ type Param struct {
Innermost *Node
Outer *Node
- // OTYPE
- //
- // TODO: Should Func pragmas also be stored on the Name?
- Pragma PragmaFlag
- Alias bool // node is alias for Ntype (only used when type-checking ODCLTYPE)
+ // OTYPE & ONAME //go:embed info,
+ // sharing storage to reduce gc.Param size.
+ // Extra is nil, or else *Extra is a *paramType or an *embedFileList.
+ Extra *interface{}
+}
+
+type paramType struct {
+ flag PragmaFlag
+ alias bool
+}
+
+type embedFileList []string
+
+// Pragma returns the PragmaFlag for p, which must be for an OTYPE.
+func (p *Param) Pragma() PragmaFlag {
+ if p.Extra == nil {
+ return 0
+ }
+ return (*p.Extra).(*paramType).flag
+}
+
+// SetPragma sets the PragmaFlag for p, which must be for an OTYPE.
+func (p *Param) SetPragma(flag PragmaFlag) {
+ if p.Extra == nil {
+ if flag == 0 {
+ return
+ }
+ p.Extra = new(interface{})
+ *p.Extra = &paramType{flag: flag}
+ return
+ }
+ (*p.Extra).(*paramType).flag = flag
+}
+
+// Alias reports whether p, which must be for an OTYPE, is a type alias.
+func (p *Param) Alias() bool {
+ if p.Extra == nil {
+ return false
+ }
+ t, ok := (*p.Extra).(*paramType)
+ if !ok {
+ return false
+ }
+ return t.alias
+}
+
+// SetAlias sets whether p, which must be for an OTYPE, is a type alias.
+func (p *Param) SetAlias(alias bool) {
+ if p.Extra == nil {
+ if !alias {
+ return
+ }
+ p.Extra = new(interface{})
+ *p.Extra = &paramType{alias: alias}
+ return
+ }
+ (*p.Extra).(*paramType).alias = alias
+}
+
+// EmbedFiles returns the list of embedded files for p,
+// which must be for an ONAME var.
+func (p *Param) EmbedFiles() []string {
+ if p.Extra == nil {
+ return nil
+ }
+ return *(*p.Extra).(*embedFileList)
+}
+
+// SetEmbedFiles sets the list of embedded files for p,
+// which must be for an ONAME var.
+func (p *Param) SetEmbedFiles(list []string) {
+ if p.Extra == nil {
+ if len(list) == 0 {
+ return
+ }
+ f := embedFileList(list)
+ p.Extra = new(interface{})
+ *p.Extra = &f
+ return
+ }
+ *(*p.Extra).(*embedFileList) = list
}
// Functions
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 0eb0dae373..8ebeaf1330 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -257,12 +257,12 @@ func typecheck(n *Node, top int) (res *Node) {
// are substituted.
cycle := cycleFor(n)
for _, n1 := range cycle {
- if n1.Name != nil && !n1.Name.Param.Alias {
+ if n1.Name != nil && !n1.Name.Param.Alias() {
// Cycle is ok. But if n is an alias type and doesn't
// have a type yet, we have a recursive type declaration
// with aliases that we can't handle properly yet.
// Report an error rather than crashing later.
- if n.Name != nil && n.Name.Param.Alias && n.Type == nil {
+ if n.Name != nil && n.Name.Param.Alias() && n.Type == nil {
lineno = n.Pos
Fatalf("cannot handle alias type declaration (issue #25838): %v", n)
}
@@ -361,7 +361,7 @@ func typecheck1(n *Node, top int) (res *Node) {
ok |= ctxExpr
if n.Type == nil && n.Val().Ctype() == CTSTR {
- n.Type = types.Idealstring
+ n.Type = types.UntypedString
}
case ONONAME:
@@ -623,8 +623,8 @@ func typecheck1(n *Node, top int) (res *Node) {
// no defaultlit for left
// the outer context gives the type
n.Type = l.Type
- if (l.Type == types.Idealfloat || l.Type == types.Idealcomplex) && r.Op == OLITERAL {
- n.Type = types.Idealint
+ if (l.Type == types.UntypedFloat || l.Type == types.UntypedComplex) && r.Op == OLITERAL {
+ n.Type = types.UntypedInt
}
break
@@ -674,8 +674,8 @@ func typecheck1(n *Node, top int) (res *Node) {
// The conversion allocates, so only do it if the concrete type is huge.
converted := false
if r.Type.Etype != TBLANK {
- aop = assignop(l.Type, r.Type, nil)
- if aop != 0 {
+ aop, _ = assignop(l.Type, r.Type)
+ if aop != OXXX {
if r.Type.IsInterface() && !l.Type.IsInterface() && !IsComparable(l.Type) {
yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
n.Type = nil
@@ -696,8 +696,8 @@ func typecheck1(n *Node, top int) (res *Node) {
}
if !converted && l.Type.Etype != TBLANK {
- aop = assignop(r.Type, l.Type, nil)
- if aop != 0 {
+ aop, _ = assignop(r.Type, l.Type)
+ if aop != OXXX {
if l.Type.IsInterface() && !r.Type.IsInterface() && !IsComparable(r.Type) {
yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
n.Type = nil
@@ -777,7 +777,7 @@ func typecheck1(n *Node, top int) (res *Node) {
if iscmp[n.Op] {
evconst(n)
- t = types.Idealbool
+ t = types.UntypedBool
if n.Op != OLITERAL {
l, r = defaultlit2(l, r, true)
n.Left = l
@@ -1046,13 +1046,13 @@ func typecheck1(n *Node, top int) (res *Node) {
}
if !n.Bounded() && Isconst(n.Right, CTINT) {
- x := n.Right.Int64()
+ x := n.Right.Int64Val()
if x < 0 {
yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
} else if t.IsArray() && x >= t.NumElem() {
yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem())
- } else if Isconst(n.Left, CTSTR) && x >= int64(len(strlit(n.Left))) {
- yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(strlit(n.Left)))
+ } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.StringVal())) {
+ yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.StringVal()))
} else if n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
yyerror("invalid %s index %v (index too large)", why, n.Right)
}
@@ -1148,11 +1148,11 @@ func typecheck1(n *Node, top int) (res *Node) {
l = defaultlit(l, types.Types[TINT])
c = defaultlit(c, types.Types[TINT])
- if Isconst(l, CTINT) && l.Int64() < 0 {
+ if Isconst(l, CTINT) && l.Int64Val() < 0 {
Fatalf("len for OSLICEHEADER must be non-negative")
}
- if Isconst(c, CTINT) && c.Int64() < 0 {
+ if Isconst(c, CTINT) && c.Int64Val() < 0 {
Fatalf("cap for OSLICEHEADER must be non-negative")
}
@@ -1201,7 +1201,7 @@ func typecheck1(n *Node, top int) (res *Node) {
if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
Fatalf("len for OMAKESLICECOPY too large")
}
- if n.Left.Int64() < 0 {
+ if n.Left.Int64Val() < 0 {
Fatalf("len for OMAKESLICECOPY must be non-negative")
}
}
@@ -1458,7 +1458,7 @@ func typecheck1(n *Node, top int) (res *Node) {
// Determine result type.
switch t.Etype {
case TIDEAL:
- n.Type = types.Idealfloat
+ n.Type = types.UntypedFloat
case TCOMPLEX64:
n.Type = types.Types[TFLOAT32]
case TCOMPLEX128:
@@ -1504,7 +1504,7 @@ func typecheck1(n *Node, top int) (res *Node) {
return n
case TIDEAL:
- t = types.Idealcomplex
+ t = types.UntypedComplex
case TFLOAT32:
t = types.Types[TCOMPLEX64]
@@ -1691,7 +1691,7 @@ func typecheck1(n *Node, top int) (res *Node) {
return n
}
var why string
- n.Op = convertop(n.Left.Op == OLITERAL, t, n.Type, &why)
+ n.Op, why = convertop(n.Left.Op == OLITERAL, t, n.Type)
if n.Op == OXXX {
if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() {
yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
@@ -2187,14 +2187,14 @@ func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
}
if r.Op == OLITERAL {
- if r.Int64() < 0 {
+ if r.Int64Val() < 0 {
yyerror("invalid slice index %v (index must be non-negative)", r)
return false
- } else if tp != nil && tp.NumElem() >= 0 && r.Int64() > tp.NumElem() {
+ } else if tp != nil && tp.NumElem() >= 0 && r.Int64Val() > tp.NumElem() {
yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem())
return false
- } else if Isconst(l, CTSTR) && r.Int64() > int64(len(strlit(l))) {
- yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(strlit(l)))
+ } else if Isconst(l, CTSTR) && r.Int64Val() > int64(len(l.StringVal())) {
+ yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.StringVal()))
return false
} else if r.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
yyerror("invalid slice index %v (index too large)", r)
@@ -2516,7 +2516,7 @@ func lookdot(n *Node, t *types.Type, dostrcmp int) *types.Field {
n.Left = nod(OADDR, n.Left, nil)
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxType|ctxExpr)
- } else if tt.IsPtr() && !rcvr.IsPtr() && types.Identical(tt.Elem(), rcvr) {
+ } else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
n.Left = nod(ODEREF, n.Left, nil)
n.Left.SetImplicit(true)
n.Left = typecheck(n.Left, ctxType|ctxExpr)
@@ -2724,9 +2724,9 @@ func errorDetails(nl Nodes, tstruct *types.Type, isddd bool) string {
// e.g in error messages about wrong arguments to return.
func sigrepr(t *types.Type, isddd bool) string {
switch t {
- case types.Idealstring:
+ case types.UntypedString:
return "string"
- case types.Idealbool:
+ case types.UntypedBool:
return "bool"
}
@@ -3267,9 +3267,7 @@ func typecheckas(n *Node) {
}
func checkassignto(src *types.Type, dst *Node) {
- var why string
-
- if assignop(src, dst.Type, &why) == 0 {
+ if op, why := assignop(src, dst.Type); op == OXXX {
yyerror("cannot assign %v to %L in multiple assignment%s", src, dst, why)
return
}
@@ -3450,9 +3448,8 @@ func stringtoruneslit(n *Node) *Node {
}
var l []*Node
- s := strlit(n.Left)
i := 0
- for _, r := range s {
+ for _, r := range n.Left.StringVal() {
l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(r))))
i++
}
@@ -3507,7 +3504,7 @@ func setUnderlying(t, underlying *types.Type) {
}
// Propagate go:notinheap pragma from the Name to the Type.
- if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma&NotInHeap != 0 {
+ if n.Name != nil && n.Name.Param != nil && n.Name.Param.Pragma()&NotInHeap != 0 {
t.SetNotInHeap(true)
}
@@ -3679,7 +3676,7 @@ func typecheckdef(n *Node) {
n.Name.Defn = typecheck(n.Name.Defn, ctxStmt) // fills in n.Type
case OTYPE:
- if p := n.Name.Param; p.Alias {
+ if p := n.Name.Param; p.Alias() {
// Type alias declaration: Simply use the rhs type - no need
// to create a new type.
// If we have a syntax error, p.Ntype may be nil.
@@ -3904,7 +3901,7 @@ func deadcodefn(fn *Node) {
return
}
case OFOR:
- if !Isconst(n.Left, CTBOOL) || n.Left.Bool() {
+ if !Isconst(n.Left, CTBOOL) || n.Left.BoolVal() {
return
}
default:
@@ -3934,7 +3931,7 @@ func deadcodeslice(nn Nodes) {
n.Left = deadcodeexpr(n.Left)
if Isconst(n.Left, CTBOOL) {
var body Nodes
- if n.Left.Bool() {
+ if n.Left.BoolVal() {
n.Rlist = Nodes{}
body = n.Nbody
} else {
@@ -3977,7 +3974,7 @@ func deadcodeexpr(n *Node) *Node {
n.Left = deadcodeexpr(n.Left)
n.Right = deadcodeexpr(n.Right)
if Isconst(n.Left, CTBOOL) {
- if n.Left.Bool() {
+ if n.Left.BoolVal() {
return n.Right // true && x => x
} else {
return n.Left // false && x => false
@@ -3987,7 +3984,7 @@ func deadcodeexpr(n *Node) *Node {
n.Left = deadcodeexpr(n.Left)
n.Right = deadcodeexpr(n.Right)
if Isconst(n.Left, CTBOOL) {
- if n.Left.Bool() {
+ if n.Left.BoolVal() {
return n.Left // true || x => true
} else {
return n.Right // false || x => x
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index 04861c8dd4..ff8cabd8e3 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -123,21 +123,21 @@ func lexinit() {
asNode(s2.Def).SetSubOp(s.op)
}
- types.Idealstring = types.New(TSTRING)
- types.Idealbool = types.New(TBOOL)
+ types.UntypedString = types.New(TSTRING)
+ types.UntypedBool = types.New(TBOOL)
types.Types[TANY] = types.New(TANY)
s := builtinpkg.Lookup("true")
s.Def = asTypesNode(nodbool(true))
asNode(s.Def).Sym = lookup("true")
asNode(s.Def).Name = new(Name)
- asNode(s.Def).Type = types.Idealbool
+ asNode(s.Def).Type = types.UntypedBool
s = builtinpkg.Lookup("false")
s.Def = asTypesNode(nodbool(false))
asNode(s.Def).Sym = lookup("false")
asNode(s.Def).Name = new(Name)
- asNode(s.Def).Type = types.Idealbool
+ asNode(s.Def).Type = types.UntypedBool
s = lookup("_")
s.Block = -100
@@ -351,7 +351,7 @@ func typeinit() {
sizeofString = Rnd(sliceLenOffset+int64(Widthptr), int64(Widthptr))
dowidth(types.Types[TSTRING])
- dowidth(types.Idealstring)
+ dowidth(types.UntypedString)
}
func makeErrorInterface() *types.Type {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 8e45059eab..b453e9f1d9 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -21,7 +21,7 @@ const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
func walk(fn *Node) {
Curfn = fn
- if Debug['W'] != 0 {
+ if Debug.W != 0 {
s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym)
dumplist(s, Curfn.Nbody)
}
@@ -63,14 +63,14 @@ func walk(fn *Node) {
return
}
walkstmtlist(Curfn.Nbody.Slice())
- if Debug['W'] != 0 {
+ if Debug.W != 0 {
s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
dumplist(s, Curfn.Nbody)
}
zeroResults()
heapmoves()
- if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 {
+ if Debug.W != 0 && Curfn.Func.Enter.Len() > 0 {
s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
dumplist(s, Curfn.Func.Enter)
}
@@ -336,19 +336,6 @@ func walkstmt(n *Node) *Node {
return n
}
-func isSmallMakeSlice(n *Node) bool {
- if n.Op != OMAKESLICE {
- return false
- }
- r := n.Right
- if r == nil {
- r = n.Left
- }
- t := n.Type
-
- return smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < maxImplicitStackVarSize/t.Elem().Width)
-}
-
// walk the whole tree of the body of an
// expression or simple statement.
// the types expressions are calculated.
@@ -449,7 +436,7 @@ func walkexpr(n *Node, init *Nodes) *Node {
lno := setlineno(n)
- if Debug['w'] > 1 {
+ if Debug.w > 1 {
Dump("before walk expr", n)
}
@@ -487,7 +474,7 @@ opswitch:
ODEREF, OSPTR, OITAB, OIDATA, OADDR:
n.Left = walkexpr(n.Left, init)
- case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH:
+ case OEFACE, OAND, OANDNOT, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
@@ -978,14 +965,6 @@ opswitch:
fn := basicnames[param] + "to" + basicnames[result]
n = conv(mkcall(fn, types.Types[result], init, conv(n.Left, types.Types[param])), n.Type)
- case OANDNOT:
- n.Left = walkexpr(n.Left, init)
- n.Op = OAND
- n.SetImplicit(true) // for walkCheckPtrArithmetic
- n.Right = nod(OBITNOT, n.Right, nil)
- n.Right = typecheck(n.Right, ctxExpr)
- n.Right = walkexpr(n.Right, init)
-
case ODIV, OMOD:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
@@ -1014,7 +993,7 @@ opswitch:
// The SSA backend will handle those.
switch et {
case TINT64:
- c := n.Right.Int64()
+ c := n.Right.Int64Val()
if c < 0 {
c = -c
}
@@ -1022,7 +1001,7 @@ opswitch:
break opswitch
}
case TUINT64:
- c := uint64(n.Right.Int64())
+ c := uint64(n.Right.Int64Val())
if c != 0 && c&(c-1) == 0 {
break opswitch
}
@@ -1062,15 +1041,15 @@ opswitch:
}
if t.IsArray() {
n.SetBounded(bounded(r, t.NumElem()))
- if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
+ if Debug.m != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
Warn("index bounds check elided")
}
if smallintconst(n.Right) && !n.Bounded() {
yyerror("index out of bounds")
}
} else if Isconst(n.Left, CTSTR) {
- n.SetBounded(bounded(r, int64(len(strlit(n.Left)))))
- if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
+ n.SetBounded(bounded(r, int64(len(n.Left.StringVal()))))
+ if Debug.m != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
Warn("index bounds check elided")
}
if smallintconst(n.Right) && !n.Bounded() {
@@ -1339,8 +1318,8 @@ opswitch:
yyerror("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
}
if n.Esc == EscNone {
- if !isSmallMakeSlice(n) {
- Fatalf("non-small OMAKESLICE with EscNone: %v", n)
+ if why := heapAllocReason(n); why != "" {
+ Fatalf("%v has EscNone, but %v", n, why)
}
// var arr [r]T
// n = arr[:l]
@@ -1504,7 +1483,7 @@ opswitch:
case OSTR2BYTES:
s := n.Left
if Isconst(s, CTSTR) {
- sc := strlit(s)
+ sc := s.StringVal()
// Allocate a [n]byte of the right size.
t := types.NewArray(types.Types[TUINT8], int64(len(sc)))
@@ -1612,7 +1591,7 @@ opswitch:
updateHasCall(n)
- if Debug['w'] != 0 && n != nil {
+ if Debug.w != 0 && n != nil {
Dump("after walk expr", n)
}
@@ -1932,7 +1911,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
for i := 0; i < len(s); {
var strs []string
for i < len(s) && Isconst(s[i], CTSTR) {
- strs = append(strs, strlit(s[i]))
+ strs = append(strs, s[i].StringVal())
i++
}
if len(strs) > 0 {
@@ -1978,7 +1957,17 @@ func walkprint(nn *Node, init *Nodes) *Node {
on = syslook("printiface")
}
on = substArgTypes(on, n.Type) // any-1
- case TPTR, TCHAN, TMAP, TFUNC, TUNSAFEPTR:
+ case TPTR:
+ if n.Type.Elem().NotInHeap() {
+ on = syslook("printuintptr")
+ n = nod(OCONV, n, nil)
+ n.Type = types.Types[TUNSAFEPTR]
+ n = nod(OCONV, n, nil)
+ n.Type = types.Types[TUINTPTR]
+ break
+ }
+ fallthrough
+ case TCHAN, TMAP, TFUNC, TUNSAFEPTR:
on = syslook("printpointer")
on = substArgTypes(on, n.Type) // any-1
case TSLICE:
@@ -2001,7 +1990,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
case TSTRING:
cs := ""
if Isconst(n, CTSTR) {
- cs = strlit(n)
+ cs = n.StringVal()
}
switch cs {
case " ":
@@ -2170,7 +2159,7 @@ func reorder3(all []*Node) []*Node {
// The result of reorder3save MUST be assigned back to n, e.g.
// n.Left = reorder3save(n.Left, all, i, early)
func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
- if !aliased(n, all, i) {
+ if !aliased(n, all[:i]) {
return n
}
@@ -2202,73 +2191,75 @@ func outervalue(n *Node) *Node {
}
}
-// Is it possible that the computation of n might be
-// affected by writes in as up to but not including the ith element?
-func aliased(n *Node, all []*Node, i int) bool {
- if n == nil {
+// Is it possible that the computation of r might be
+// affected by assignments in all?
+func aliased(r *Node, all []*Node) bool {
+ if r == nil {
return false
}
// Treat all fields of a struct as referring to the whole struct.
// We could do better but we would have to keep track of the fields.
- for n.Op == ODOT {
- n = n.Left
+ for r.Op == ODOT {
+ r = r.Left
}
// Look for obvious aliasing: a variable being assigned
// during the all list and appearing in n.
- // Also record whether there are any writes to main memory.
- // Also record whether there are any writes to variables
- // whose addresses have been taken.
+ // Also record whether there are any writes to addressable
+ // memory (either main memory or variables whose addresses
+ // have been taken).
memwrite := false
- varwrite := false
- for _, an := range all[:i] {
- a := outervalue(an.Left)
-
- for a.Op == ODOT {
- a = a.Left
+ for _, as := range all {
+ // We can ignore assignments to blank.
+ if as.Left.isBlank() {
+ continue
}
- if a.Op != ONAME {
+ l := outervalue(as.Left)
+ if l.Op != ONAME {
memwrite = true
continue
}
- switch n.Class() {
+ switch l.Class() {
default:
- varwrite = true
+ Fatalf("unexpected class: %v, %v", l, l.Class())
+
+ case PAUTOHEAP, PEXTERN:
+ memwrite = true
continue
case PAUTO, PPARAM, PPARAMOUT:
- if n.Name.Addrtaken() {
- varwrite = true
+ if l.Name.Addrtaken() {
+ memwrite = true
continue
}
- if vmatch2(a, n) {
- // Direct hit.
+ if vmatch2(l, r) {
+ // Direct hit: l appears in r.
return true
}
}
}
- // The variables being written do not appear in n.
- // However, n might refer to computed addresses
+ // The variables being written do not appear in r.
+ // However, r might refer to computed addresses
// that are being written.
// If no computed addresses are affected by the writes, no aliasing.
- if !memwrite && !varwrite {
+ if !memwrite {
return false
}
- // If n does not refer to computed addresses
- // (that is, if n only refers to variables whose addresses
+ // If r does not refer to computed addresses
+ // (that is, if r only refers to variables whose addresses
// have not been taken), no aliasing.
- if varexpr(n) {
+ if varexpr(r) {
return false
}
- // Otherwise, both the writes and n refer to computed memory addresses.
+ // Otherwise, both the writes and r refer to computed memory addresses.
// Assume that they might conflict.
return true
}
@@ -2656,7 +2647,7 @@ func addstr(n *Node, init *Nodes) *Node {
sz := int64(0)
for _, n1 := range n.List.Slice() {
if n1.Op == OLITERAL {
- sz += int64(len(strlit(n1)))
+ sz += int64(len(n1.StringVal()))
}
}
@@ -2830,7 +2821,7 @@ func appendslice(n *Node, init *Nodes) *Node {
// isAppendOfMake reports whether n is of the form append(x , make([]T, y)...).
// isAppendOfMake assumes n has already been typechecked.
func isAppendOfMake(n *Node) bool {
- if Debug['N'] != 0 || instrumenting {
+ if Debug.N != 0 || instrumenting {
return false
}
@@ -3450,7 +3441,7 @@ func walkcompare(n *Node, init *Nodes) *Node {
func tracecmpArg(n *Node, t *types.Type, init *Nodes) *Node {
// Ugly hack to avoid "constant -1 overflows uintptr" errors, etc.
- if n.Op == OLITERAL && n.Type.IsSigned() && n.Int64() < 0 {
+ if n.Op == OLITERAL && n.Type.IsSigned() && n.Int64Val() < 0 {
n = copyexpr(n, n.Type, init)
}
@@ -3520,7 +3511,7 @@ func walkcompareString(n *Node, init *Nodes) *Node {
// Length-only checks are ok, though.
maxRewriteLen = 0
}
- if s := strlit(cs); len(s) <= maxRewriteLen {
+ if s := cs.StringVal(); len(s) <= maxRewriteLen {
if len(s) > 0 {
ncs = safeexpr(ncs, init)
}
@@ -3615,26 +3606,32 @@ func bounded(n *Node, max int64) bool {
bits := int32(8 * n.Type.Width)
if smallintconst(n) {
- v := n.Int64()
+ v := n.Int64Val()
return 0 <= v && v < max
}
switch n.Op {
- case OAND:
+ case OAND, OANDNOT:
v := int64(-1)
- if smallintconst(n.Left) {
- v = n.Left.Int64()
- } else if smallintconst(n.Right) {
- v = n.Right.Int64()
+ switch {
+ case smallintconst(n.Left):
+ v = n.Left.Int64Val()
+ case smallintconst(n.Right):
+ v = n.Right.Int64Val()
+ if n.Op == OANDNOT {
+ v = ^v
+ if !sign {
+ v &= 1<<uint(bits) - 1
+ }
+ }
}
-
if 0 <= v && v < max {
return true
}
case OMOD:
if !sign && smallintconst(n.Right) {
- v := n.Right.Int64()
+ v := n.Right.Int64Val()
if 0 <= v && v <= max {
return true
}
@@ -3642,7 +3639,7 @@ func bounded(n *Node, max int64) bool {
case ODIV:
if !sign && smallintconst(n.Right) {
- v := n.Right.Int64()
+ v := n.Right.Int64Val()
for bits > 0 && v >= 2 {
bits--
v >>= 1
@@ -3651,7 +3648,7 @@ func bounded(n *Node, max int64) bool {
case ORSH:
if !sign && smallintconst(n.Right) {
- v := n.Right.Int64()
+ v := n.Right.Int64Val()
if v > int64(bits) {
return true
}
@@ -3892,6 +3889,16 @@ func wrapCall(n *Node, init *Nodes) *Node {
}
isBuiltinCall := n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER
+
+ // Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
+ if !isBuiltinCall && n.IsDDD() {
+ last := n.List.Len() - 1
+ if va := n.List.Index(last); va.Op == OSLICELIT {
+ n.List.Set(append(n.List.Slice()[:last], va.List.Slice()...))
+ n.SetIsDDD(false)
+ }
+ }
+
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
origArgs := make([]*Node, n.List.Len())
t := nod(OTFUNC, nil, nil)
@@ -3977,7 +3984,7 @@ func canMergeLoads() bool {
// isRuneCount reports whether n is of the form len([]rune(string)).
// These are optimized into a call to runtime.countrunes.
func isRuneCount(n *Node) bool {
- return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES
+ return Debug.N == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES
}
func walkCheckPtrAlignment(n *Node, init *Nodes, count *Node) *Node {
@@ -4046,12 +4053,8 @@ func walkCheckPtrArithmetic(n *Node, init *Nodes) *Node {
case OADD:
walk(n.Left)
walk(n.Right)
- case OSUB:
+ case OSUB, OANDNOT:
walk(n.Left)
- case OAND:
- if n.Implicit() { // was OANDNOT
- walk(n.Left)
- }
case OCONVNOP:
if n.Left.Type.IsUnsafePtr() {
n.Left = cheapexpr(n.Left, init)
diff --git a/src/cmd/compile/internal/logopt/logopt_test.go b/src/cmd/compile/internal/logopt/logopt_test.go
index b57a07f12c..fca85c10fb 100644
--- a/src/cmd/compile/internal/logopt/logopt_test.go
+++ b/src/cmd/compile/internal/logopt/logopt_test.go
@@ -208,12 +208,11 @@ func s15a8(x *[15]int64) [15]int64 {
`"relatedInformation":[{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"}]}`)
want(t, slogged, `{"range":{"start":{"line":11,"character":6},"end":{"line":11,"character":6}},"severity":3,"code":"isInBounds","source":"go compiler","message":""}`)
want(t, slogged, `{"range":{"start":{"line":7,"character":6},"end":{"line":7,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 35"}`)
- want(t, slogged, `{"range":{"start":{"line":21,"character":21},"end":{"line":21,"character":21}},"severity":3,"code":"cannotInlineCall","source":"go compiler","message":"foo cannot be inlined (escaping closure variable)"}`)
// escape analysis explanation
want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r2 with derefs=0",`+
`"relatedInformation":[`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
- `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y = \u003cN\u003e (assign-pair)"},`+
+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r1 = y:"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+
diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go
index a5fbdaffba..3888aa6527 100644
--- a/src/cmd/compile/internal/ppc64/ssa.go
+++ b/src/cmd/compile/internal/ppc64/ssa.go
@@ -166,34 +166,46 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p2.To.Reg = v.Reg1()
case ssa.OpPPC64LoweredAtomicAnd8,
- ssa.OpPPC64LoweredAtomicOr8:
+ ssa.OpPPC64LoweredAtomicAnd32,
+ ssa.OpPPC64LoweredAtomicOr8,
+ ssa.OpPPC64LoweredAtomicOr32:
// LWSYNC
- // LBAR (Rarg0), Rtmp
+ // LBAR/LWAR (Rarg0), Rtmp
// AND/OR Rarg1, Rtmp
- // STBCCC Rtmp, (Rarg0)
+ // STBCCC/STWCCC Rtmp, (Rarg0)
// BNE -3(PC)
+ ld := ppc64.ALBAR
+ st := ppc64.ASTBCCC
+ if v.Op == ssa.OpPPC64LoweredAtomicAnd32 || v.Op == ssa.OpPPC64LoweredAtomicOr32 {
+ ld = ppc64.ALWAR
+ st = ppc64.ASTWCCC
+ }
r0 := v.Args[0].Reg()
r1 := v.Args[1].Reg()
// LWSYNC - Assuming shared data not write-through-required nor
// caching-inhibited. See Appendix B.2.2.2 in the ISA 2.07b.
plwsync := s.Prog(ppc64.ALWSYNC)
plwsync.To.Type = obj.TYPE_NONE
- p := s.Prog(ppc64.ALBAR)
+ // LBAR or LWAR
+ p := s.Prog(ld)
p.From.Type = obj.TYPE_MEM
p.From.Reg = r0
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REGTMP
+ // AND/OR reg1,out
p1 := s.Prog(v.Op.Asm())
p1.From.Type = obj.TYPE_REG
p1.From.Reg = r1
p1.To.Type = obj.TYPE_REG
p1.To.Reg = ppc64.REGTMP
- p2 := s.Prog(ppc64.ASTBCCC)
+ // STBCCC or STWCCC
+ p2 := s.Prog(st)
p2.From.Type = obj.TYPE_REG
p2.From.Reg = ppc64.REGTMP
p2.To.Type = obj.TYPE_MEM
p2.To.Reg = r0
p2.RegTo2 = ppc64.REGTMP
+ // BNE retry
p3 := s.Prog(ppc64.ABNE)
p3.To.Type = obj.TYPE_BRANCH
gc.Patch(p3, p)
@@ -570,9 +582,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
r1 := v.Args[0].Reg()
shifts := v.AuxInt
p := s.Prog(v.Op.Asm())
- // clrlslwi ra,rs,sh,mb will become rlwinm ra,rs,sh,mb-sh,31-n as described in ISA
- p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)}
- p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)})
+ // clrlslwi ra,rs,mb,sh will become rlwinm ra,rs,sh,mb-sh,31-sh as described in ISA
+ p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)})
p.Reg = r1
p.To.Type = obj.TYPE_REG
p.To.Reg = r
@@ -582,9 +594,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
r1 := v.Args[0].Reg()
shifts := v.AuxInt
p := s.Prog(v.Op.Asm())
- // clrlsldi ra,rs,sh,mb will become rldic ra,rs,sh,mb-sh
- p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)}
- p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)})
+ // clrlsldi ra,rs,mb,sh will become rldic ra,rs,sh,mb-sh
+ p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftmb(shifts)}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: ssa.GetPPC64Shiftsh(shifts)})
p.Reg = r1
p.To.Type = obj.TYPE_REG
p.To.Reg = r
@@ -637,6 +649,24 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ // Auxint holds encoded rotate + mask
+ case ssa.OpPPC64RLWINM, ssa.OpPPC64RLWMI:
+ rot, _, _, mask := ssa.DecodePPC64RotateMask(v.AuxInt)
+ p := s.Prog(v.Op.Asm())
+ p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()}
+ p.Reg = v.Args[0].Reg()
+ p.From = obj.Addr{Type: obj.TYPE_CONST, Offset: int64(rot)}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(mask)})
+
+ // Auxint holds mask
+ case ssa.OpPPC64RLWNM:
+ _, _, _, mask := ssa.DecodePPC64RotateMask(v.AuxInt)
+ p := s.Prog(v.Op.Asm())
+ p.To = obj.Addr{Type: obj.TYPE_REG, Reg: v.Reg()}
+ p.Reg = v.Args[0].Reg()
+ p.From = obj.Addr{Type: obj.TYPE_REG, Reg: v.Args[1].Reg()}
+ p.SetFrom3(obj.Addr{Type: obj.TYPE_CONST, Offset: int64(mask)})
+
case ssa.OpPPC64MADDLD:
r := v.Reg()
r1 := v.Args[0].Reg()
@@ -677,7 +707,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Reg = v.Args[0].Reg()
case ssa.OpPPC64ADDconst, ssa.OpPPC64ANDconst, ssa.OpPPC64ORconst, ssa.OpPPC64XORconst,
- ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst, ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst, ssa.OpPPC64EXTSWSLconst:
+ ssa.OpPPC64SRADconst, ssa.OpPPC64SRAWconst, ssa.OpPPC64SRDconst, ssa.OpPPC64SRWconst,
+ ssa.OpPPC64SLDconst, ssa.OpPPC64SLWconst, ssa.OpPPC64EXTSWSLconst, ssa.OpPPC64MULLWconst, ssa.OpPPC64MULLDconst:
p := s.Prog(v.Op.Asm())
p.Reg = v.Args[0].Reg()
p.From.Type = obj.TYPE_CONST
diff --git a/src/cmd/compile/internal/riscv64/ggen.go b/src/cmd/compile/internal/riscv64/ggen.go
index be31fad441..f7c03fe7c2 100644
--- a/src/cmd/compile/internal/riscv64/ggen.go
+++ b/src/cmd/compile/internal/riscv64/ggen.go
@@ -25,7 +25,15 @@ func zeroRange(pp *gc.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog {
return p
}
- // TODO(jsing): Add a duff zero implementation for medium sized ranges.
+ if cnt <= int64(128*gc.Widthptr) {
+ p = pp.Appendpp(p, riscv.AADDI, obj.TYPE_CONST, 0, off, obj.TYPE_REG, riscv.REG_A0, 0)
+ p.Reg = riscv.REG_SP
+ p = pp.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Duffzero
+ p.To.Offset = 8 * (128 - cnt/int64(gc.Widthptr))
+ return p
+ }
// Loop, zeroing pointer width bytes at a time.
// ADD $(off), SP, T0
diff --git a/src/cmd/compile/internal/riscv64/ssa.go b/src/cmd/compile/internal/riscv64/ssa.go
index 73f0dbc195..0beb5b4bd1 100644
--- a/src/cmd/compile/internal/riscv64/ssa.go
+++ b/src/cmd/compile/internal/riscv64/ssa.go
@@ -190,7 +190,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
// input args need no code
case ssa.OpPhi:
gc.CheckLoweredPhi(v)
- case ssa.OpCopy, ssa.OpRISCV64MOVconvert:
+ case ssa.OpCopy, ssa.OpRISCV64MOVconvert, ssa.OpRISCV64MOVDreg:
if v.Type.IsMemory() {
return
}
@@ -208,6 +208,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Reg = rs
p.To.Type = obj.TYPE_REG
p.To.Reg = rd
+ case ssa.OpRISCV64MOVDnop:
+ if v.Reg() != v.Args[0].Reg() {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
+ }
+ // nothing to do
case ssa.OpLoadReg:
if v.Type.IsFlags() {
v.Fatalf("load flags not implemented: %v", v.LongString())
@@ -228,6 +233,37 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.AddrAuto(&p.To, v)
case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
// nothing to do
+ case ssa.OpRISCV64MOVBreg, ssa.OpRISCV64MOVHreg, ssa.OpRISCV64MOVWreg,
+ ssa.OpRISCV64MOVBUreg, ssa.OpRISCV64MOVHUreg, ssa.OpRISCV64MOVWUreg:
+ a := v.Args[0]
+ for a.Op == ssa.OpCopy || a.Op == ssa.OpRISCV64MOVDreg {
+ a = a.Args[0]
+ }
+ as := v.Op.Asm()
+ rs := v.Args[0].Reg()
+ rd := v.Reg()
+ if a.Op == ssa.OpLoadReg {
+ t := a.Type
+ switch {
+ case v.Op == ssa.OpRISCV64MOVBreg && t.Size() == 1 && t.IsSigned(),
+ v.Op == ssa.OpRISCV64MOVHreg && t.Size() == 2 && t.IsSigned(),
+ v.Op == ssa.OpRISCV64MOVWreg && t.Size() == 4 && t.IsSigned(),
+ v.Op == ssa.OpRISCV64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
+ v.Op == ssa.OpRISCV64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
+ v.Op == ssa.OpRISCV64MOVWUreg && t.Size() == 4 && !t.IsSigned():
+ // arg is a proper-typed load and already sign/zero-extended
+ if rs == rd {
+ return
+ }
+ as = riscv.AMOV
+ default:
+ }
+ }
+ p := s.Prog(as)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = rs
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = rd
case ssa.OpRISCV64ADD, ssa.OpRISCV64SUB, ssa.OpRISCV64SUBW, ssa.OpRISCV64XOR, ssa.OpRISCV64OR, ssa.OpRISCV64AND,
ssa.OpRISCV64SLL, ssa.OpRISCV64SRA, ssa.OpRISCV64SRL,
ssa.OpRISCV64SLT, ssa.OpRISCV64SLTU, ssa.OpRISCV64MUL, ssa.OpRISCV64MULW, ssa.OpRISCV64MULH,
@@ -572,6 +608,20 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
+ case ssa.OpRISCV64DUFFZERO:
+ p := s.Prog(obj.ADUFFZERO)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Duffzero
+ p.To.Offset = v.AuxInt
+
+ case ssa.OpRISCV64DUFFCOPY:
+ p := s.Prog(obj.ADUFFCOPY)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Duffcopy
+ p.To.Offset = v.AuxInt
+
default:
v.Fatalf("Unhandled op %v", v.Op)
}
diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go
index 00d253c95a..e23b31f385 100644
--- a/src/cmd/compile/internal/s390x/ssa.go
+++ b/src/cmd/compile/internal/s390x/ssa.go
@@ -761,6 +761,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM
p.To.Reg = v.Args[0].Reg()
gc.AddAux(&p.To, v)
+ case ssa.OpS390XLAN, ssa.OpS390XLAO:
+ // LA(N|O) Ry, TMP, 0(Rx)
+ op := s.Prog(v.Op.Asm())
+ op.From.Type = obj.TYPE_REG
+ op.From.Reg = v.Args[1].Reg()
+ op.Reg = s390x.REGTMP
+ op.To.Type = obj.TYPE_MEM
+ op.To.Reg = v.Args[0].Reg()
case ssa.OpS390XLANfloor, ssa.OpS390XLAOfloor:
r := v.Args[0].Reg() // clobbered, assumed R1 in comments
diff --git a/src/cmd/compile/internal/ssa/addressingmodes.go b/src/cmd/compile/internal/ssa/addressingmodes.go
index aae0def27f..1baf143869 100644
--- a/src/cmd/compile/internal/ssa/addressingmodes.go
+++ b/src/cmd/compile/internal/ssa/addressingmodes.go
@@ -59,22 +59,22 @@ func addressingModes(f *Func) {
v.AuxInt += p.AuxInt
case [2]auxType{auxSymValAndOff, auxInt32}:
vo := ValAndOff(v.AuxInt)
- if !vo.canAdd(p.AuxInt) {
+ if !vo.canAdd64(p.AuxInt) {
continue
}
- v.AuxInt = vo.add(p.AuxInt)
+ v.AuxInt = int64(vo.addOffset64(p.AuxInt))
case [2]auxType{auxSymValAndOff, auxSymOff}:
vo := ValAndOff(v.AuxInt)
if v.Aux != nil && p.Aux != nil {
continue
}
- if !vo.canAdd(p.AuxInt) {
+ if !vo.canAdd64(p.AuxInt) {
continue
}
if p.Aux != nil {
v.Aux = p.Aux
}
- v.AuxInt = vo.add(p.AuxInt)
+ v.AuxInt = int64(vo.addOffset64(p.AuxInt))
case [2]auxType{auxSymOff, auxNone}:
// nothing to do
case [2]auxType{auxSymValAndOff, auxNone}:
diff --git a/src/cmd/compile/internal/ssa/branchelim.go b/src/cmd/compile/internal/ssa/branchelim.go
index 4f9fd8e22e..1d34f8160b 100644
--- a/src/cmd/compile/internal/ssa/branchelim.go
+++ b/src/cmd/compile/internal/ssa/branchelim.go
@@ -35,7 +35,7 @@ func branchelim(f *Func) {
for _, b := range f.Blocks {
for _, v := range b.Values {
switch v.Op {
- case OpLoad, OpAtomicLoad8, OpAtomicLoad32, OpAtomicLoad64, OpAtomicLoadPtr, OpAtomicLoadAcq32:
+ case OpLoad, OpAtomicLoad8, OpAtomicLoad32, OpAtomicLoad64, OpAtomicLoadPtr, OpAtomicLoadAcq32, OpAtomicLoadAcq64:
loadAddr.add(v.Args[0].ID)
case OpMove:
loadAddr.add(v.Args[1].ID)
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index 4eed612977..bddd271273 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -47,6 +47,9 @@ func Compile(f *Func) {
stack := make([]byte, 16384)
n := runtime.Stack(stack, false)
stack = stack[:n]
+ if f.HTMLWriter != nil {
+ f.HTMLWriter.flushPhases()
+ }
f.Fatalf("panic during %s while compiling %s:\n\n%v\n\n%s\n", phaseName, f.Name, err, stack)
}
}()
@@ -201,6 +204,13 @@ func (p *pass) addDump(s string) {
p.dump[s] = true
}
+func (p *pass) String() string {
+ if p == nil {
+ return "nil pass"
+ }
+ return p.name
+}
+
// Run consistency checker between each phase
var (
checkEnabled = false
@@ -432,8 +442,8 @@ var passes = [...]pass{
{name: "prove", fn: prove},
{name: "early fuse", fn: fuseEarly},
{name: "decompose builtin", fn: decomposeBuiltIn, required: true},
+ {name: "expand calls", fn: expandCalls, required: true},
{name: "softfloat", fn: softfloat, required: true},
- {name: "expand calls", fn:expandCalls, required: true},
{name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
{name: "dead auto elim", fn: elimDeadAutosGeneric},
{name: "generic deadcode", fn: deadcode, required: true}, // remove dead stores, which otherwise mess up store chain
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 7f01f8047f..cb6f6fe7a1 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -38,7 +38,6 @@ type Config struct {
useSSE bool // Use SSE for non-float operations
useAvg bool // Use optimizations that need Avg* operations
useHmul bool // Use optimizations that need Hmul* operations
- use387 bool // GO386=387
SoftFloat bool //
Race bool // race detector enabled
NeedsFpScratch bool // No direct move between GP and FP register sets
@@ -150,6 +149,7 @@ type Frontend interface {
SplitStruct(LocalSlot, int) LocalSlot
SplitArray(LocalSlot) LocalSlot // array must be length 1
SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
+ SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot
// DerefItab dereferences an itab function
// entry, given the symbol of the itab and
@@ -196,6 +196,14 @@ const (
ClassParamOut // return value
)
+const go116lateCallExpansion = true
+
+// LateCallExpansionEnabledWithin returns true if late call expansion should be tested
+// within compilation of a function/method triggered by GOSSAHASH (defaults to "yes").
+func LateCallExpansionEnabledWithin(f *Func) bool {
+ return go116lateCallExpansion && f.DebugTest // Currently set up for GOSSAHASH bug searches
+}
+
// NewConfig returns a new configuration object for the given architecture.
func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config {
c := &Config{arch: arch, Types: types}
@@ -379,9 +387,4 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config
return c
}
-func (c *Config) Set387(b bool) {
- c.NeedsFpScratch = b
- c.use387 = b
-}
-
func (c *Config) Ctxt() *obj.Link { return c.ctxt }
diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go
index ab27ba85ae..bf7f1e826b 100644
--- a/src/cmd/compile/internal/ssa/decompose.go
+++ b/src/cmd/compile/internal/ssa/decompose.go
@@ -6,6 +6,7 @@ package ssa
import (
"cmd/compile/internal/types"
+ "sort"
)
// decompose converts phi ops on compound builtin types into phi
@@ -31,77 +32,79 @@ func decomposeBuiltIn(f *Func) {
}
// Split up named values into their components.
+ // accumulate old names for aggregates (that are decomposed) in toDelete for efficient bulk deletion,
+ // accumulate new LocalSlots in newNames for addition after the iteration. This decomposition is for
+ // builtin types with leaf components, and thus there is no need to reprocess the newly create LocalSlots.
+ var toDelete []namedVal
var newNames []LocalSlot
- for _, name := range f.Names {
+ for i, name := range f.Names {
t := name.Type
switch {
case t.IsInteger() && t.Size() > f.Config.RegSize:
hiName, loName := f.fe.SplitInt64(name)
newNames = append(newNames, hiName, loName)
- for _, v := range f.NamedValues[name] {
+ for j, v := range f.NamedValues[name] {
if v.Op != OpInt64Make {
continue
}
f.NamedValues[hiName] = append(f.NamedValues[hiName], v.Args[0])
f.NamedValues[loName] = append(f.NamedValues[loName], v.Args[1])
+ toDelete = append(toDelete, namedVal{i, j})
}
- delete(f.NamedValues, name)
case t.IsComplex():
rName, iName := f.fe.SplitComplex(name)
newNames = append(newNames, rName, iName)
- for _, v := range f.NamedValues[name] {
+ for j, v := range f.NamedValues[name] {
if v.Op != OpComplexMake {
continue
}
f.NamedValues[rName] = append(f.NamedValues[rName], v.Args[0])
f.NamedValues[iName] = append(f.NamedValues[iName], v.Args[1])
-
+ toDelete = append(toDelete, namedVal{i, j})
}
- delete(f.NamedValues, name)
case t.IsString():
ptrName, lenName := f.fe.SplitString(name)
newNames = append(newNames, ptrName, lenName)
- for _, v := range f.NamedValues[name] {
+ for j, v := range f.NamedValues[name] {
if v.Op != OpStringMake {
continue
}
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
+ toDelete = append(toDelete, namedVal{i, j})
}
- delete(f.NamedValues, name)
case t.IsSlice():
ptrName, lenName, capName := f.fe.SplitSlice(name)
newNames = append(newNames, ptrName, lenName, capName)
- for _, v := range f.NamedValues[name] {
+ for j, v := range f.NamedValues[name] {
if v.Op != OpSliceMake {
continue
}
f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
f.NamedValues[capName] = append(f.NamedValues[capName], v.Args[2])
+ toDelete = append(toDelete, namedVal{i, j})
}
- delete(f.NamedValues, name)
case t.IsInterface():
typeName, dataName := f.fe.SplitInterface(name)
newNames = append(newNames, typeName, dataName)
- for _, v := range f.NamedValues[name] {
+ for j, v := range f.NamedValues[name] {
if v.Op != OpIMake {
continue
}
f.NamedValues[typeName] = append(f.NamedValues[typeName], v.Args[0])
f.NamedValues[dataName] = append(f.NamedValues[dataName], v.Args[1])
+ toDelete = append(toDelete, namedVal{i, j})
}
- delete(f.NamedValues, name)
case t.IsFloat():
// floats are never decomposed, even ones bigger than RegSize
- newNames = append(newNames, name)
case t.Size() > f.Config.RegSize:
f.Fatalf("undecomposed named type %s %v", name, t)
- default:
- newNames = append(newNames, name)
}
}
- f.Names = newNames
+
+ deleteNamedVals(f, toDelete)
+ f.Names = append(f.Names, newNames...)
}
func decomposeBuiltInPhi(v *Value) {
@@ -263,14 +266,20 @@ func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalS
f.Fatalf("array not of size 1")
}
elemName := f.fe.SplitArray(name)
+ var keep []*Value
for _, v := range f.NamedValues[name] {
if v.Op != OpArrayMake1 {
+ keep = append(keep, v)
continue
}
f.NamedValues[elemName] = append(f.NamedValues[elemName], v.Args[0])
}
- // delete the name for the array as a whole
- delete(f.NamedValues, name)
+ if len(keep) == 0 {
+ // delete the name for the array as a whole
+ delete(f.NamedValues, name)
+ } else {
+ f.NamedValues[name] = keep
+ }
if t.Elem().IsArray() {
return decomposeUserArrayInto(f, elemName, slots)
@@ -300,17 +309,23 @@ func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []Local
}
makeOp := StructMakeOp(n)
+ var keep []*Value
// create named values for each struct field
for _, v := range f.NamedValues[name] {
if v.Op != makeOp {
+ keep = append(keep, v)
continue
}
for i := 0; i < len(fnames); i++ {
f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], v.Args[i])
}
}
- // remove the name of the struct as a whole
- delete(f.NamedValues, name)
+ if len(keep) == 0 {
+ // delete the name for the struct as a whole
+ delete(f.NamedValues, name)
+ } else {
+ f.NamedValues[name] = keep
+ }
// now that this f.NamedValues contains values for the struct
// fields, recurse into nested structs
@@ -400,3 +415,35 @@ func StructMakeOp(nf int) Op {
}
panic("too many fields in an SSAable struct")
}
+
+type namedVal struct {
+ locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key
+}
+
+// deleteNamedVals removes particular values with debugger names from f's naming data structures
+func deleteNamedVals(f *Func, toDelete []namedVal) {
+ // Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalid pending indices.
+ sort.Slice(toDelete, func(i, j int) bool {
+ if toDelete[i].locIndex != toDelete[j].locIndex {
+ return toDelete[i].locIndex > toDelete[j].locIndex
+ }
+ return toDelete[i].valIndex > toDelete[j].valIndex
+
+ })
+
+ // Get rid of obsolete names
+ for _, d := range toDelete {
+ loc := f.Names[d.locIndex]
+ vals := f.NamedValues[loc]
+ l := len(vals) - 1
+ if l > 0 {
+ vals[d.valIndex] = vals[l]
+ f.NamedValues[loc] = vals[:l]
+ } else {
+ delete(f.NamedValues, loc)
+ l = len(f.Names) - 1
+ f.Names[d.locIndex] = f.Names[l]
+ f.Names = f.Names[:l]
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go
index 34cff51c00..3e3573ff39 100644
--- a/src/cmd/compile/internal/ssa/expand_calls.go
+++ b/src/cmd/compile/internal/ssa/expand_calls.go
@@ -4,14 +4,140 @@
package ssa
-import "cmd/compile/internal/types"
+import (
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+ "fmt"
+ "sort"
+)
+
+type selKey struct {
+ from *Value
+ offset int64
+ size int64
+ typ types.EType
+}
+
+type offsetKey struct {
+ from *Value
+ offset int64
+ pt *types.Type
+}
// expandCalls converts LE (Late Expansion) calls that act like they receive value args into a lower-level form
-// that is more oriented to a platform's ABI. The SelectN operations that extract results are also rewritten into
-// more appropriate forms.
+// that is more oriented to a platform's ABI. The SelectN operations that extract results are rewritten into
+// more appropriate forms, and any StructMake or ArrayMake inputs are decomposed until non-struct values are
+// reached.
func expandCalls(f *Func) {
+ // Calls that need lowering have some number of inputs, including a memory input,
+ // and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able.
+
+ // With the current ABI those inputs need to be converted into stores to memory,
+ // rethreading the call's memory input to the first, and the new call now receiving the last.
+
+ // With the current ABI, the outputs need to be converted to loads, which will all use the call's
+ // memory output as their input.
+ if !LateCallExpansionEnabledWithin(f) {
+ return
+ }
+ debug := f.pass.debug > 0
+
canSSAType := f.fe.CanSSA
+ regSize := f.Config.RegSize
sp, _ := f.spSb()
+ typ := &f.Config.Types
+ ptrSize := f.Config.PtrSize
+
+ // For 32-bit, need to deal with decomposition of 64-bit integers, which depends on endianness.
+ var hiOffset, lowOffset int64
+ if f.Config.BigEndian {
+ lowOffset = 4
+ } else {
+ hiOffset = 4
+ }
+
+ namedSelects := make(map[*Value][]namedVal)
+
+ // intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target
+ // that has no 64-bit integer registers.
+ intPairTypes := func(et types.EType) (tHi, tLo *types.Type) {
+ tHi = typ.UInt32
+ if et == types.TINT64 {
+ tHi = typ.Int32
+ }
+ tLo = typ.UInt32
+ return
+ }
+
+ // isAlreadyExpandedAggregateType returns whether a type is an SSA-able "aggregate" (multiple register) type
+ // that was expanded in an earlier phase (currently, expand_calls is intended to run after decomposeBuiltin,
+ // so this is all aggregate types -- small struct and array, complex, interface, string, slice, and 64-bit
+ // integer on 32-bit).
+ isAlreadyExpandedAggregateType := func(t *types.Type) bool {
+ if !canSSAType(t) {
+ return false
+ }
+ return t.IsStruct() || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice() ||
+ t.Size() > regSize && t.IsInteger()
+ }
+
+ offsets := make(map[offsetKey]*Value)
+
+ // offsetFrom creates an offset from a pointer, simplifying chained offsets and offsets from SP
+ // TODO should also optimize offsets from SB?
+ offsetFrom := func(from *Value, offset int64, pt *types.Type) *Value {
+ if offset == 0 && from.Type == pt { // this is not actually likely
+ return from
+ }
+ // Simplify, canonicalize
+ for from.Op == OpOffPtr {
+ offset += from.AuxInt
+ from = from.Args[0]
+ }
+ if from == sp {
+ return f.ConstOffPtrSP(pt, offset, sp)
+ }
+ key := offsetKey{from, offset, pt}
+ v := offsets[key]
+ if v != nil {
+ return v
+ }
+ v = from.Block.NewValue1I(from.Pos.WithNotStmt(), OpOffPtr, pt, offset, from)
+ offsets[key] = v
+ return v
+ }
+
+ splitSlots := func(ls []LocalSlot, sfx string, offset int64, ty *types.Type) []LocalSlot {
+ var locs []LocalSlot
+ for i := range ls {
+ locs = append(locs, f.fe.SplitSlot(&ls[i], sfx, offset, ty))
+ }
+ return locs
+ }
+
+ // removeTrivialWrapperTypes unwraps layers of
+ // struct { singleField SomeType } and [1]SomeType
+ // until a non-wrapper type is reached. This is useful
+ // for working with assignments to/from interface data
+ // fields (either second operand to OpIMake or OpIData)
+ // where the wrapping or type conversion can be elided
+ // because of type conversions/assertions in source code
+ // that do not appear in SSA.
+ removeTrivialWrapperTypes := func(t *types.Type) *types.Type {
+ for {
+ if t.IsStruct() && t.NumFields() == 1 {
+ t = t.Field(0).Type
+ continue
+ }
+ if t.IsArray() && t.NumElem() == 1 {
+ t = t.Elem()
+ continue
+ }
+ break
+ }
+ return t
+ }
+
// Calls that need lowering have some number of inputs, including a memory input,
// and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able.
@@ -21,79 +147,631 @@ func expandCalls(f *Func) {
// With the current ABI, the outputs need to be converted to loads, which will all use the call's
// memory output as their input.
- // Step 1: find all references to calls as values and rewrite those.
+ // rewriteSelect recursively walks leaf selector to a root (OpSelectN) through
+ // a chain of Struct/Array Select operations. If the chain of selectors does not
+ // end in OpSelectN, it does nothing (this can happen depending on compiler phase ordering).
+ // It emits the code necessary to implement the leaf select operation that leads to the call.
+ // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
+ var rewriteSelect func(leaf *Value, selector *Value, offset int64) []LocalSlot
+ rewriteSelect = func(leaf *Value, selector *Value, offset int64) []LocalSlot {
+ var locs []LocalSlot
+ leafType := leaf.Type
+ switch selector.Op {
+ case OpSelectN:
+ // TODO these may be duplicated. Should memoize. Intermediate selectors will go dead, no worries there.
+ for _, s := range namedSelects[selector] {
+ locs = append(locs, f.Names[s.locIndex])
+ }
+ call := selector.Args[0]
+ aux := call.Aux.(*AuxCall)
+ which := selector.AuxInt
+ if which == aux.NResults() { // mem is after the results.
+ // rewrite v as a Copy of call -- the replacement call will produce a mem.
+ leaf.copyOf(call)
+ } else {
+ leafType := removeTrivialWrapperTypes(leaf.Type)
+ if canSSAType(leafType) {
+ for leafType.Etype == types.TSTRUCT && leafType.NumFields() == 1 {
+ // This may not be adequately general -- consider [1]etc but this is caused by immediate IDATA
+ leafType = leafType.Field(0).Type
+ }
+ pt := types.NewPtr(leafType)
+ off := offsetFrom(sp, offset+aux.OffsetOfResult(which), pt)
+ // Any selection right out of the arg area/registers has to be same Block as call, use call as mem input.
+ if leaf.Block == call.Block {
+ leaf.reset(OpLoad)
+ leaf.SetArgs2(off, call)
+ leaf.Type = leafType
+ } else {
+ w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call)
+ leaf.copyOf(w)
+ }
+ } else {
+ f.Fatalf("Should not have non-SSA-able OpSelectN, selector=%s", selector.LongString())
+ }
+ }
+ case OpStructSelect:
+ w := selector.Args[0]
+ var ls []LocalSlot
+ if w.Type.Etype != types.TSTRUCT {
+ f.Fatalf("Bad type for w: v=%v; sel=%v; w=%v; ,f=%s\n", leaf.LongString(), selector.LongString(), w.LongString(), f.Name)
+ // Artifact of immediate interface idata
+ ls = rewriteSelect(leaf, w, offset)
+ } else {
+ ls = rewriteSelect(leaf, w, offset+w.Type.FieldOff(int(selector.AuxInt)))
+ for _, l := range ls {
+ locs = append(locs, f.fe.SplitStruct(l, int(selector.AuxInt)))
+ }
+ }
+
+ case OpArraySelect:
+ w := selector.Args[0]
+ rewriteSelect(leaf, w, offset+selector.Type.Size()*selector.AuxInt)
+
+ case OpInt64Hi:
+ w := selector.Args[0]
+ ls := rewriteSelect(leaf, w, offset+hiOffset)
+ locs = splitSlots(ls, ".hi", hiOffset, leafType)
+
+ case OpInt64Lo:
+ w := selector.Args[0]
+ ls := rewriteSelect(leaf, w, offset+lowOffset)
+ locs = splitSlots(ls, ".lo", lowOffset, leafType)
+
+ case OpStringPtr:
+ ls := rewriteSelect(leaf, selector.Args[0], offset)
+ locs = splitSlots(ls, ".ptr", 0, typ.BytePtr)
+ //for i := range ls {
+ // locs = append(locs, f.fe.SplitSlot(&ls[i], ".ptr", 0, typ.BytePtr))
+ //}
+ case OpSlicePtr:
+ w := selector.Args[0]
+ ls := rewriteSelect(leaf, w, offset)
+ locs = splitSlots(ls, ".ptr", 0, types.NewPtr(w.Type.Elem()))
+
+ case OpITab:
+ w := selector.Args[0]
+ ls := rewriteSelect(leaf, w, offset)
+ sfx := ".itab"
+ if w.Type.IsEmptyInterface() {
+ sfx = ".type"
+ }
+ locs = splitSlots(ls, sfx, 0, typ.Uintptr)
+
+ case OpComplexReal:
+ ls := rewriteSelect(leaf, selector.Args[0], offset)
+ locs = splitSlots(ls, ".real", 0, leafType)
+
+ case OpComplexImag:
+ ls := rewriteSelect(leaf, selector.Args[0], offset+leafType.Width) // result is FloatNN, width of result is offset of imaginary part.
+ locs = splitSlots(ls, ".imag", leafType.Width, leafType)
+
+ case OpStringLen, OpSliceLen:
+ ls := rewriteSelect(leaf, selector.Args[0], offset+ptrSize)
+ locs = splitSlots(ls, ".len", ptrSize, leafType)
+
+ case OpIData:
+ ls := rewriteSelect(leaf, selector.Args[0], offset+ptrSize)
+ locs = splitSlots(ls, ".data", ptrSize, leafType)
+
+ case OpSliceCap:
+ ls := rewriteSelect(leaf, selector.Args[0], offset+2*ptrSize)
+ locs = splitSlots(ls, ".cap", 2*ptrSize, leafType)
+
+ case OpCopy: // If it's an intermediate result, recurse
+ locs = rewriteSelect(leaf, selector.Args[0], offset)
+ for _, s := range namedSelects[selector] {
+ // this copy may have had its own name, preserve that, too.
+ locs = append(locs, f.Names[s.locIndex])
+ }
+
+ default:
+ // Ignore dead ends. These can occur if this phase is run before decompose builtin (which is not intended, but allowed).
+ }
+
+ return locs
+ }
+
+ // storeArg converts stores of SSA-able aggregate arguments (passed to a call) into a series of stores of
+ // smaller types into individual parameter slots.
+ var storeArg func(pos src.XPos, b *Block, a *Value, t *types.Type, offset int64, mem *Value) *Value
+ storeArg = func(pos src.XPos, b *Block, a *Value, t *types.Type, offset int64, mem *Value) *Value {
+ if debug {
+ fmt.Printf("\tstoreArg(%s; %s; %v; %d; %s)\n", b, a.LongString(), t, offset, mem.String())
+ }
+
+ switch a.Op {
+ case OpArrayMake0, OpStructMake0:
+ return mem
+
+ case OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4:
+ for i := 0; i < t.NumFields(); i++ {
+ fld := t.Field(i)
+ mem = storeArg(pos, b, a.Args[i], fld.Type, offset+fld.Offset, mem)
+ }
+ return mem
+
+ case OpArrayMake1:
+ return storeArg(pos, b, a.Args[0], t.Elem(), offset, mem)
+
+ case OpInt64Make:
+ tHi, tLo := intPairTypes(t.Etype)
+ mem = storeArg(pos, b, a.Args[0], tHi, offset+hiOffset, mem)
+ return storeArg(pos, b, a.Args[1], tLo, offset+lowOffset, mem)
+
+ case OpComplexMake:
+ tPart := typ.Float32
+ wPart := t.Width / 2
+ if wPart == 8 {
+ tPart = typ.Float64
+ }
+ mem = storeArg(pos, b, a.Args[0], tPart, offset, mem)
+ return storeArg(pos, b, a.Args[1], tPart, offset+wPart, mem)
+
+ case OpIMake:
+ mem = storeArg(pos, b, a.Args[0], typ.Uintptr, offset, mem)
+ return storeArg(pos, b, a.Args[1], typ.BytePtr, offset+ptrSize, mem)
+
+ case OpStringMake:
+ mem = storeArg(pos, b, a.Args[0], typ.BytePtr, offset, mem)
+ return storeArg(pos, b, a.Args[1], typ.Int, offset+ptrSize, mem)
+
+ case OpSliceMake:
+ mem = storeArg(pos, b, a.Args[0], typ.BytePtr, offset, mem)
+ mem = storeArg(pos, b, a.Args[1], typ.Int, offset+ptrSize, mem)
+ return storeArg(pos, b, a.Args[2], typ.Int, offset+2*ptrSize, mem)
+ }
+
+ dst := offsetFrom(sp, offset, types.NewPtr(t))
+ x := b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, a, mem)
+ if debug {
+ fmt.Printf("\t\tstoreArg returns %s\n", x.LongString())
+ }
+ return x
+ }
+
+ // splitStore converts a store of an SSA-able aggregate into a series of smaller stores, emitting
+ // appropriate Struct/Array Select operations (which will soon go dead) to obtain the parts.
+ // This has to handle aggregate types that have already been lowered by an earlier phase.
+ var splitStore func(dest, source, mem, v *Value, t *types.Type, offset int64, firstStorePos src.XPos) *Value
+ splitStore = func(dest, source, mem, v *Value, t *types.Type, offset int64, firstStorePos src.XPos) *Value {
+ if debug {
+ fmt.Printf("\tsplitStore(%s; %s; %s; %s; %v; %d; %v)\n", dest.LongString(), source.LongString(), mem.String(), v.LongString(), t, offset, firstStorePos)
+ }
+ pos := v.Pos.WithNotStmt()
+ switch t.Etype {
+ case types.TARRAY:
+ elt := t.Elem()
+ if t.NumElem() == 1 && t.Width == regSize && elt.Width == regSize {
+ t = removeTrivialWrapperTypes(t)
+ if t.Etype == types.TSTRUCT || t.Etype == types.TARRAY {
+ f.Fatalf("Did not expect to find IDATA-immediate with non-trivial struct/array in it")
+ }
+ break // handle the leaf type.
+ }
+ for i := int64(0); i < t.NumElem(); i++ {
+ sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source)
+ mem = splitStore(dest, sel, mem, v, elt, offset+i*elt.Width, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ }
+ return mem
+
+ case types.TSTRUCT:
+ if t.NumFields() == 1 && t.Field(0).Type.Width == t.Width && t.Width == regSize {
+ // This peculiar test deals with accesses to immediate interface data.
+ // It works okay because everything is the same size.
+ // Example code that triggers this can be found in go/constant/value.go, function ToComplex
+ // v119 (+881) = IData <intVal> v6
+ // v121 (+882) = StaticLECall <floatVal,mem> {AuxCall{"".itof([intVal,0])[floatVal,8]}} [16] v119 v1
+ // This corresponds to the generic rewrite rule "(StructSelect [0] (IData x)) => (IData x)"
+ // Guard against "struct{struct{*foo}}"
+ // Other rewriting phases create minor glitches when they transform IData, for instance the
+ // interface-typed Arg "x" of ToFloat in go/constant/value.go
+ // v6 (858) = Arg <Value> {x} (x[Value], x[Value])
+ // is rewritten by decomposeArgs into
+ // v141 (858) = Arg <uintptr> {x}
+ // v139 (858) = Arg <*uint8> {x} [8]
+ // because of a type case clause on line 862 of go/constant/value.go
+ // case intVal:
+ // return itof(x)
+ // v139 is later stored as an intVal == struct{val *big.Int} which naively requires the fields of
+ // of a *uint8, which does not succeed.
+ t = removeTrivialWrapperTypes(t)
+
+ // it could be a leaf type, but the "leaf" could be complex64 (for example)
+ return splitStore(dest, source, mem, v, t, offset, firstStorePos)
+ }
+
+ for i := 0; i < t.NumFields(); i++ {
+ fld := t.Field(i)
+ sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source)
+ mem = splitStore(dest, sel, mem, v, fld.Type, offset+fld.Offset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ }
+ return mem
+
+ case types.TINT64, types.TUINT64:
+ if t.Width == regSize {
+ break
+ }
+ tHi, tLo := intPairTypes(t.Etype)
+ sel := source.Block.NewValue1(pos, OpInt64Hi, tHi, source)
+ mem = splitStore(dest, sel, mem, v, tHi, offset+hiOffset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ sel = source.Block.NewValue1(pos, OpInt64Lo, tLo, source)
+ return splitStore(dest, sel, mem, v, tLo, offset+lowOffset, firstStorePos)
+
+ case types.TINTER:
+ sel := source.Block.NewValue1(pos, OpITab, typ.BytePtr, source)
+ mem = splitStore(dest, sel, mem, v, typ.BytePtr, offset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ sel = source.Block.NewValue1(pos, OpIData, typ.BytePtr, source)
+ return splitStore(dest, sel, mem, v, typ.BytePtr, offset+ptrSize, firstStorePos)
+
+ case types.TSTRING:
+ sel := source.Block.NewValue1(pos, OpStringPtr, typ.BytePtr, source)
+ mem = splitStore(dest, sel, mem, v, typ.BytePtr, offset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ sel = source.Block.NewValue1(pos, OpStringLen, typ.Int, source)
+ return splitStore(dest, sel, mem, v, typ.Int, offset+ptrSize, firstStorePos)
+
+ case types.TSLICE:
+ et := types.NewPtr(t.Elem())
+ sel := source.Block.NewValue1(pos, OpSlicePtr, et, source)
+ mem = splitStore(dest, sel, mem, v, et, offset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ sel = source.Block.NewValue1(pos, OpSliceLen, typ.Int, source)
+ mem = splitStore(dest, sel, mem, v, typ.Int, offset+ptrSize, firstStorePos)
+ sel = source.Block.NewValue1(pos, OpSliceCap, typ.Int, source)
+ return splitStore(dest, sel, mem, v, typ.Int, offset+2*ptrSize, firstStorePos)
+
+ case types.TCOMPLEX64:
+ sel := source.Block.NewValue1(pos, OpComplexReal, typ.Float32, source)
+ mem = splitStore(dest, sel, mem, v, typ.Float32, offset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ sel = source.Block.NewValue1(pos, OpComplexImag, typ.Float32, source)
+ return splitStore(dest, sel, mem, v, typ.Float32, offset+4, firstStorePos)
+
+ case types.TCOMPLEX128:
+ sel := source.Block.NewValue1(pos, OpComplexReal, typ.Float64, source)
+ mem = splitStore(dest, sel, mem, v, typ.Float64, offset, firstStorePos)
+ firstStorePos = firstStorePos.WithNotStmt()
+ sel = source.Block.NewValue1(pos, OpComplexImag, typ.Float64, source)
+ return splitStore(dest, sel, mem, v, typ.Float64, offset+8, firstStorePos)
+ }
+ // Default, including for aggregates whose single element exactly fills their container
+ // TODO this will be a problem for cast interfaces containing floats when we move to registers.
+ x := v.Block.NewValue3A(firstStorePos, OpStore, types.TypeMem, t, offsetFrom(dest, offset, types.NewPtr(t)), source, mem)
+ if debug {
+ fmt.Printf("\t\tsplitStore returns %s\n", x.LongString())
+ }
+
+ return x
+ }
+
+ // rewriteArgs removes all the Args from a call and converts the call args into appropriate
+ // stores (or later, register movement). Extra args for interface and closure calls are ignored,
+ // but removed.
+ rewriteArgs := func(v *Value, firstArg int) *Value {
+ // Thread the stores on the memory arg
+ aux := v.Aux.(*AuxCall)
+ pos := v.Pos.WithNotStmt()
+ m0 := v.Args[len(v.Args)-1]
+ mem := m0
+ for i, a := range v.Args {
+ if i < firstArg {
+ continue
+ }
+ if a == m0 { // mem is last.
+ break
+ }
+ auxI := int64(i - firstArg)
+ if a.Op == OpDereference {
+ if a.MemoryArg() != m0 {
+ f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString())
+ }
+ // "Dereference" of addressed (probably not-SSA-eligible) value becomes Move
+ // TODO this will be more complicated with registers in the picture.
+ source := a.Args[0]
+ dst := f.ConstOffPtrSP(source.Type, aux.OffsetOfArg(auxI), sp)
+ if a.Uses == 1 && a.Block == v.Block {
+ a.reset(OpMove)
+ a.Pos = pos
+ a.Type = types.TypeMem
+ a.Aux = aux.TypeOfArg(auxI)
+ a.AuxInt = aux.SizeOfArg(auxI)
+ a.SetArgs3(dst, source, mem)
+ mem = a
+ } else {
+ mem = v.Block.NewValue3A(pos, OpMove, types.TypeMem, aux.TypeOfArg(auxI), dst, source, mem)
+ mem.AuxInt = aux.SizeOfArg(auxI)
+ }
+ } else {
+ if debug {
+ fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aux.TypeOfArg(auxI), aux.OffsetOfArg(auxI))
+ }
+ mem = storeArg(pos, v.Block, a, aux.TypeOfArg(auxI), aux.OffsetOfArg(auxI), mem)
+ }
+ }
+ v.resetArgs()
+ return mem
+ }
+
+ // TODO if too slow, whole program iteration can be replaced w/ slices of appropriate values, accumulated in first loop here.
+
+ // Step 0: rewrite the calls to convert incoming args to stores.
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ switch v.Op {
+ case OpStaticLECall:
+ mem := rewriteArgs(v, 0)
+ v.SetArgs1(mem)
+ case OpClosureLECall:
+ code := v.Args[0]
+ context := v.Args[1]
+ mem := rewriteArgs(v, 2)
+ v.SetArgs3(code, context, mem)
+ case OpInterLECall:
+ code := v.Args[0]
+ mem := rewriteArgs(v, 1)
+ v.SetArgs2(code, mem)
+ }
+ }
+ }
+
+ for i, name := range f.Names {
+ t := name.Type
+ if isAlreadyExpandedAggregateType(t) {
+ for j, v := range f.NamedValues[name] {
+ if v.Op == OpSelectN {
+ ns := namedSelects[v]
+ namedSelects[v] = append(ns, namedVal{locIndex: i, valIndex: j})
+ }
+ }
+ }
+ }
+
+ // Step 1: any stores of aggregates remaining are believed to be sourced from call results.
+ // Decompose those stores into a series of smaller stores, adding selection ops as necessary.
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ if v.Op == OpStore {
+ t := v.Aux.(*types.Type)
+ iAEATt := isAlreadyExpandedAggregateType(t)
+ if !iAEATt {
+ // guarding against store immediate struct into interface data field -- store type is *uint8
+ // TODO can this happen recursively?
+ tSrc := v.Args[1].Type
+ iAEATt = isAlreadyExpandedAggregateType(tSrc)
+ if iAEATt {
+ t = tSrc
+ }
+ }
+ if iAEATt {
+ if debug {
+ fmt.Printf("Splitting store %s\n", v.LongString())
+ }
+ dst, source, mem := v.Args[0], v.Args[1], v.Args[2]
+ mem = splitStore(dst, source, mem, v, t, 0, v.Pos)
+ v.copyOf(mem)
+ }
+ }
+ }
+ }
+
+ val2Preds := make(map[*Value]int32) // Used to accumulate dependency graph of selection operations for topological ordering.
+
+ // Step 2: transform or accumulate selection operations for rewrite in topological order.
+ //
+ // Aggregate types that have already (in earlier phases) been transformed must be lowered comprehensively to finish
+ // the transformation (user-defined structs and arrays, slices, strings, interfaces, complex, 64-bit on 32-bit architectures),
+ //
+ // Any select-for-addressing applied to call results can be transformed directly.
for _, b := range f.Blocks {
for _, v := range b.Values {
+ // Accumulate chains of selectors for processing in topological order
switch v.Op {
+ case OpStructSelect, OpArraySelect,
+ OpIData, OpITab,
+ OpStringPtr, OpStringLen,
+ OpSlicePtr, OpSliceLen, OpSliceCap,
+ OpComplexReal, OpComplexImag,
+ OpInt64Hi, OpInt64Lo:
+ w := v.Args[0]
+ switch w.Op {
+ case OpStructSelect, OpArraySelect, OpSelectN:
+ val2Preds[w] += 1
+ if debug {
+ fmt.Printf("v2p[%s] = %d\n", w.LongString(), val2Preds[w])
+ }
+ }
+ fallthrough
+
case OpSelectN:
- call := v.Args[0]
- aux := call.Aux.(*AuxCall)
- which := v.AuxInt
- t := v.Type
- if which == aux.NResults() { // mem is after the results.
- // rewrite v as a Copy of call -- the replacement call will produce a mem.
- v.copyOf(call)
- } else {
- pt := types.NewPtr(t)
- if canSSAType(t) {
- off := f.ConstOffPtrSP(pt, aux.OffsetOfResult(which), sp)
- v.reset(OpLoad)
- v.SetArgs2(off, call)
- } else {
- panic("Should not have non-SSA-able OpSelectN")
+ if _, ok := val2Preds[v]; !ok {
+ val2Preds[v] = 0
+ if debug {
+ fmt.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v])
}
}
- v.Type = t // not right for the mem operand yet, but will be when call is rewritten.
case OpSelectNAddr:
+ // Do these directly, there are no chains of selectors.
call := v.Args[0]
which := v.AuxInt
aux := call.Aux.(*AuxCall)
pt := v.Type
- off := f.ConstOffPtrSP(pt, aux.OffsetOfResult(which), sp)
+ off := offsetFrom(sp, aux.OffsetOfResult(which), pt)
v.copyOf(off)
}
}
}
- // Step 2: rewrite the calls
+ // Step 3: Compute topological order of selectors,
+ // then process it in reverse to eliminate duplicates,
+ // then forwards to rewrite selectors.
+ //
+ // All chains of selectors end up in same block as the call.
+ sdom := f.Sdom()
+
+ // Compilation must be deterministic, so sort after extracting first zeroes from map.
+ // Sorting allows dominators-last order within each batch,
+ // so that the backwards scan for duplicates will most often find copies from dominating blocks (it is best-effort).
+ var toProcess []*Value
+ less := func(i, j int) bool {
+ vi, vj := toProcess[i], toProcess[j]
+ bi, bj := vi.Block, vj.Block
+ if bi == bj {
+ return vi.ID < vj.ID
+ }
+ return sdom.domorder(bi) > sdom.domorder(bj) // reverse the order to put dominators last.
+ }
+
+ // Accumulate order in allOrdered
+ var allOrdered []*Value
+ for v, n := range val2Preds {
+ if n == 0 {
+ allOrdered = append(allOrdered, v)
+ }
+ }
+ last := 0 // allOrdered[0:last] has been top-sorted and processed
+ for len(val2Preds) > 0 {
+ toProcess = allOrdered[last:]
+ last = len(allOrdered)
+ sort.SliceStable(toProcess, less)
+ for _, v := range toProcess {
+ w := v.Args[0]
+ delete(val2Preds, v)
+ n, ok := val2Preds[w]
+ if !ok {
+ continue
+ }
+ if n == 1 {
+ allOrdered = append(allOrdered, w)
+ delete(val2Preds, w)
+ continue
+ }
+ val2Preds[w] = n - 1
+ }
+ }
+
+ common := make(map[selKey]*Value)
+ // Rewrite duplicate selectors as copies where possible.
+ for i := len(allOrdered) - 1; i >= 0; i-- {
+ v := allOrdered[i]
+ w := v.Args[0]
+ for w.Op == OpCopy {
+ w = w.Args[0]
+ }
+ typ := v.Type
+ if typ.IsMemory() {
+ continue // handled elsewhere, not an indexable result
+ }
+ size := typ.Width
+ offset := int64(0)
+ switch v.Op {
+ case OpStructSelect:
+ if w.Type.Etype == types.TSTRUCT {
+ offset = w.Type.FieldOff(int(v.AuxInt))
+ } else { // Immediate interface data artifact, offset is zero.
+ f.Fatalf("Expand calls interface data problem, func %s, v=%s, w=%s\n", f.Name, v.LongString(), w.LongString())
+ }
+ case OpArraySelect:
+ offset = size * v.AuxInt
+ case OpSelectN:
+ offset = w.Aux.(*AuxCall).OffsetOfResult(v.AuxInt)
+ case OpInt64Hi:
+ offset = hiOffset
+ case OpInt64Lo:
+ offset = lowOffset
+ case OpStringLen, OpSliceLen, OpIData:
+ offset = ptrSize
+ case OpSliceCap:
+ offset = 2 * ptrSize
+ case OpComplexImag:
+ offset = size
+ }
+ sk := selKey{from: w, size: size, offset: offset, typ: typ.Etype}
+ dupe := common[sk]
+ if dupe == nil {
+ common[sk] = v
+ } else if sdom.IsAncestorEq(dupe.Block, v.Block) {
+ v.copyOf(dupe)
+ } else {
+ // Because values are processed in dominator order, the old common[s] will never dominate after a miss is seen.
+ // Installing the new value might match some future values.
+ common[sk] = v
+ }
+ }
+
+ // Indices of entries in f.Names that need to be deleted.
+ var toDelete []namedVal
+
+ // Rewrite selectors.
+ for i, v := range allOrdered {
+ if debug {
+ b := v.Block
+ fmt.Printf("allOrdered[%d] = b%d, %s, uses=%d\n", i, b.ID, v.LongString(), v.Uses)
+ }
+ if v.Uses == 0 {
+ v.reset(OpInvalid)
+ continue
+ }
+ if v.Op == OpCopy {
+ continue
+ }
+ locs := rewriteSelect(v, v, 0)
+ // Install new names.
+ if v.Type.IsMemory() {
+ continue
+ }
+ // Leaf types may have debug locations
+ if !isAlreadyExpandedAggregateType(v.Type) {
+ for _, l := range locs {
+ f.NamedValues[l] = append(f.NamedValues[l], v)
+ }
+ f.Names = append(f.Names, locs...)
+ continue
+ }
+ // Not-leaf types that had debug locations need to lose them.
+ if ns, ok := namedSelects[v]; ok {
+ toDelete = append(toDelete, ns...)
+ }
+ }
+
+ deleteNamedVals(f, toDelete)
+
+ // Step 4: rewrite the calls themselves, correcting the type
for _, b := range f.Blocks {
for _, v := range b.Values {
switch v.Op {
case OpStaticLECall:
- // Thread the stores on the memory arg
- m0 := v.Args[len(v.Args)-1]
- mem := m0
- pos := v.Pos.WithNotStmt()
- aux := v.Aux.(*AuxCall)
- auxInt := v.AuxInt
- for i, a := range v.Args {
- if a == m0 {
- break
- }
- if a.Op == OpDereference {
- // "Dereference" of addressed (probably not-SSA-eligible) value becomes Move
- src := a.Args[0]
- dst := f.ConstOffPtrSP(src.Type, aux.OffsetOfArg(int64(i)), sp)
- a.reset(OpMove)
- a.Pos = pos
- a.Type = types.TypeMem
- a.Aux = aux.TypeOfArg(int64(i))
- a.AuxInt = aux.SizeOfArg(int64(i))
- a.SetArgs3(dst, src, mem)
- mem = a
- } else {
- // Add a new store.
- t := aux.TypeOfArg(int64(i))
- dst := f.ConstOffPtrSP(types.NewPtr(t), aux.OffsetOfArg(int64(i)), sp)
- mem = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, a, mem)
- }
- }
- v.reset(OpStaticCall)
+ v.Op = OpStaticCall
v.Type = types.TypeMem
- v.Aux = aux
- v.AuxInt = auxInt
- v.SetArgs1(mem)
+ case OpClosureLECall:
+ v.Op = OpClosureCall
+ v.Type = types.TypeMem
+ case OpInterLECall:
+ v.Op = OpInterCall
+ v.Type = types.TypeMem
+ }
+ }
+ }
+
+ // Step 5: elide any copies introduced.
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ for i, a := range v.Args {
+ if a.Op != OpCopy {
+ continue
+ }
+ aa := copySource(a)
+ v.SetArg(i, aa)
+ for a.Uses == 0 {
+ b := a.Args[0]
+ a.reset(OpInvalid)
+ a = b
+ }
}
}
}
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index 51665c60e2..b4c3e5cfdf 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -125,6 +125,10 @@ func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
return LocalSlot{N: s.N, Type: s.Type.Elem(), Off: s.Off}
}
+
+func (d DummyFrontend) SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot {
+ return LocalSlot{N: parent.N, Type: t, Off: offset}
+}
func (DummyFrontend) Line(_ src.XPos) string {
return "unknown.go:0"
}
diff --git a/src/cmd/compile/internal/ssa/flagalloc.go b/src/cmd/compile/internal/ssa/flagalloc.go
index d50b615912..61c45a6be7 100644
--- a/src/cmd/compile/internal/ssa/flagalloc.go
+++ b/src/cmd/compile/internal/ssa/flagalloc.go
@@ -191,11 +191,6 @@ func flagalloc(f *Func) {
b.FlagsLiveAtEnd = end[b.ID] != nil
}
- const go115flagallocdeadcode = true
- if !go115flagallocdeadcode {
- return
- }
-
// Remove any now-dead values.
// The number of values to remove is likely small,
// and removing them requires processing all values in a block,
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index 0df7b4a5d7..ec2c67c1fa 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -672,7 +672,7 @@ func (f *Func) Idom() []*Block {
return f.cachedIdom
}
-// sdom returns a sparse tree representing the dominator relationships
+// Sdom returns a sparse tree representing the dominator relationships
// among the blocks of f.
func (f *Func) Sdom() SparseTree {
if f.cachedSdom == nil {
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
index 4a8244eb27..4e6cc8c692 100644
--- a/src/cmd/compile/internal/ssa/gen/386.rules
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -38,10 +38,8 @@
(Xor(32|16|8) ...) => (XORL ...)
(Neg(32|16|8) ...) => (NEGL ...)
-(Neg32F x) && !config.use387 => (PXOR x (MOVSSconst <typ.Float32> [float32(math.Copysign(0, -1))]))
-(Neg64F x) && !config.use387 => (PXOR x (MOVSDconst <typ.Float64> [math.Copysign(0, -1)]))
-(Neg32F x) && config.use387 => (FCHS x)
-(Neg64F x) && config.use387 => (FCHS x)
+(Neg32F x) => (PXOR x (MOVSSconst <typ.Float32> [float32(math.Copysign(0, -1))]))
+(Neg64F x) => (PXOR x (MOVSDconst <typ.Float64> [math.Copysign(0, -1)]))
(Com(32|16|8) ...) => (NOTL ...)
@@ -312,7 +310,7 @@
(Const32 ...) => (MOVLconst ...)
(Const(32|64)F ...) => (MOVS(S|D)const ...)
(ConstNil) => (MOVLconst [0])
-(ConstBool [c]) => (MOVLconst [int32(b2i(c))])
+(ConstBool [c]) => (MOVLconst [b2i32(c)])
// Lowering calls
(StaticCall ...) => (CALLstatic ...)
@@ -670,8 +668,8 @@
// Merge load/store to op
((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem)
-((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) => ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
-((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l) => ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
+((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem)
+((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoadClobber(v, l, x) && clobber(l) => ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem)
(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) => ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y, l) =>
((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem)
diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go
index ddabde7d3d..737b99c371 100644
--- a/src/cmd/compile/internal/ssa/gen/386Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/386Ops.go
@@ -51,17 +51,6 @@ var regNames386 = []string{
"SB",
}
-// Notes on 387 support.
-// - The 387 has a weird stack-register setup for floating-point registers.
-// We use these registers when SSE registers are not available (when GO386=387).
-// - We use the same register names (X0-X7) but they refer to the 387
-// floating-point registers. That way, most of the SSA backend is unchanged.
-// - The instruction generation pass maintains an SSE->387 register mapping.
-// This mapping is updated whenever the FP stack is pushed or popped so that
-// we can always find a given SSE register even when the TOS pointer has changed.
-// - To facilitate the mapping from SSE to 387, we enforce that
-// every basic block starts and ends with an empty floating-point stack.
-
func init() {
// Make map from reg names to reg integers.
if len(regNames386) > 64 {
@@ -552,9 +541,6 @@ func init() {
{name: "FlagGT_UGT"}, // signed > and unsigned <
{name: "FlagGT_ULT"}, // signed > and unsigned >
- // Special op for -x on 387
- {name: "FCHS", argLength: 1, reg: fp11},
-
// Special ops for PIC floating-point constants.
// MOVSXconst1 loads the address of the constant-pool entry into a register.
// MOVSXconst2 loads the constant from that address.
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index 408678f054..934e7dfdb6 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -401,7 +401,7 @@
(Const32F ...) => (MOVSSconst ...)
(Const64F ...) => (MOVSDconst ...)
(ConstNil ) => (MOVQconst [0])
-(ConstBool [c]) => (MOVLconst [int32(b2i(c))])
+(ConstBool [c]) => (MOVLconst [b2i32(c)])
// Lowering calls
(StaticCall ...) => (CALLstatic ...)
@@ -530,8 +530,10 @@
(AtomicCompareAndSwap64 ptr old new_ mem) => (CMPXCHGQlock ptr old new_ mem)
// Atomic memory updates.
-(AtomicAnd8 ptr val mem) => (ANDBlock ptr val mem)
-(AtomicOr8 ptr val mem) => (ORBlock ptr val mem)
+(AtomicAnd8 ptr val mem) => (ANDBlock ptr val mem)
+(AtomicAnd32 ptr val mem) => (ANDLlock ptr val mem)
+(AtomicOr8 ptr val mem) => (ORBlock ptr val mem)
+(AtomicOr32 ptr val mem) => (ORLlock ptr val mem)
// Write barrier.
(WB ...) => (LoweredWB ...)
@@ -957,7 +959,7 @@
(MUL(Q|L)const [73] x) => (LEA(Q|L)8 x (LEA(Q|L)8 <v.Type> x x))
(MUL(Q|L)const [81] x) => (LEA(Q|L)8 (LEA(Q|L)8 <v.Type> x x) (LEA(Q|L)8 <v.Type> x x))
-(MUL(Q|L)const [c] x) && isPowerOfTwo(int64(c)+1) && c >= 15 => (SUB(Q|L) (SHL(Q|L)const <v.Type> [int8(log2(int64(c)+1))] x) x)
+(MUL(Q|L)const [c] x) && isPowerOfTwo64(int64(c)+1) && c >= 15 => (SUB(Q|L) (SHL(Q|L)const <v.Type> [int8(log2(int64(c)+1))] x) x)
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-1) && c >= 17 => (LEA(Q|L)1 (SHL(Q|L)const <v.Type> [int8(log32(c-1))] x) x)
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-2) && c >= 34 => (LEA(Q|L)2 (SHL(Q|L)const <v.Type> [int8(log32(c-2))] x) x)
(MUL(Q|L)const [c] x) && isPowerOfTwo32(c-4) && c >= 68 => (LEA(Q|L)4 (SHL(Q|L)const <v.Type> [int8(log32(c-4))] x) x)
@@ -1274,8 +1276,8 @@
(CMPQconst (ANDQconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT)
(CMPQconst (ANDLconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT)
(CMPLconst (ANDLconst _ [m]) [n]) && 0 <= m && m < n => (FlagLT_ULT)
-(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= m && int16(m) < n => (FlagLT_ULT)
-(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= m && int8(m) < n => (FlagLT_ULT)
+(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < n => (FlagLT_ULT)
+(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < n => (FlagLT_ULT)
// TESTQ c c sets flags like CMPQ c 0.
(TESTQconst [c] (MOVQconst [d])) && int64(c) == d && c == 0 => (FlagEQ)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index 2df5016d59..de5372670b 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -902,7 +902,9 @@ func init() {
// Atomic memory updates.
{name: "ANDBlock", argLength: 3, reg: gpstore, asm: "ANDB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) &= arg1
+ {name: "ANDLlock", argLength: 3, reg: gpstore, asm: "ANDL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) &= arg1
{name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) |= arg1
+ {name: "ORLlock", argLength: 3, reg: gpstore, asm: "ORL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr"}, // *(arg0+auxint+aux) |= arg1
}
var AMD64blocks = []blockData{
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index 9490805f46..f48abcd202 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -169,10 +169,10 @@
(Rsh8x64 x (Const64 [c])) && uint64(c) >= 8 => (SRAconst (SLLconst <typ.UInt32> x [24]) [31])
// constants
-(Const(8|16|32) ...) -> (MOVWconst ...)
-(Const(32F|64F) ...) -> (MOV(F|D)const ...)
+(Const(8|16|32) [val]) => (MOVWconst [int32(val)])
+(Const(32|64)F [val]) => (MOV(F|D)const [float64(val)])
(ConstNil) => (MOVWconst [0])
-(ConstBool ...) -> (MOVWconst ...)
+(ConstBool [b]) => (MOVWconst [b2i32(b)])
// truncations
// Because we ignore high parts of registers, truncates are just copies.
@@ -243,10 +243,10 @@
(Leq16U x y) => (LessEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
(Leq32U x y) => (LessEqualU (CMP x y))
-(OffPtr [off] ptr:(SP)) -> (MOVWaddr [off] ptr)
-(OffPtr [off] ptr) -> (ADDconst [off] ptr)
+(OffPtr [off] ptr:(SP)) => (MOVWaddr [int32(off)] ptr)
+(OffPtr [off] ptr) => (ADDconst [int32(off)] ptr)
-(Addr ...) -> (MOVWaddr ...)
+(Addr {sym} base) => (MOVWaddr {sym} base)
(LocalAddr {sym} base _) => (MOVWaddr {sym} base)
// loads
@@ -1052,8 +1052,8 @@
(BICshiftRL x (MOVWconst [c]) [d]) => (BICconst x [int32(uint32(c)>>uint64(d))])
(BICshiftRA x (MOVWconst [c]) [d]) => (BICconst x [c>>uint64(d)])
(MVNshiftLL (MOVWconst [c]) [d]) => (MOVWconst [^(c<<uint64(d))])
-(MVNshiftRL (MOVWconst [c]) [d]) -> (MOVWconst [^int64(uint32(c)>>uint64(d))])
-(MVNshiftRA (MOVWconst [c]) [d]) -> (MOVWconst [^int64(int32(c)>>uint64(d))])
+(MVNshiftRL (MOVWconst [c]) [d]) => (MOVWconst [^int32(uint32(c)>>uint64(d))])
+(MVNshiftRA (MOVWconst [c]) [d]) => (MOVWconst [int32(c)>>uint64(d)])
(CMPshiftLL x (MOVWconst [c]) [d]) => (CMPconst x [c<<uint64(d)])
(CMPshiftRL x (MOVWconst [c]) [d]) => (CMPconst x [int32(uint32(c)>>uint64(d))])
(CMPshiftRA x (MOVWconst [c]) [d]) => (CMPconst x [c>>uint64(d)])
@@ -1190,12 +1190,12 @@
(MOVWstoreidx ptr (SRAconst idx [c]) val mem) => (MOVWstoreshiftRA ptr idx [c] val mem)
(MOVWstoreidx (SRAconst idx [c]) ptr val mem) => (MOVWstoreshiftRA ptr idx [c] val mem)
-(MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem)
-(MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem)
+(MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) => (MOVWload [int32(uint32(c)<<uint64(d))] ptr mem)
+(MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) => (MOVWload [int32(uint32(c)>>uint64(d))] ptr mem)
(MOVWloadshiftRA ptr (MOVWconst [c]) [d] mem) => (MOVWload [c>>uint64(d)] ptr mem)
-(MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem)
-(MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem)
+(MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [int32(uint32(c)<<uint64(d))] ptr val mem)
+(MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [int32(uint32(c)>>uint64(d))] ptr val mem)
(MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [c>>uint64(d)] ptr val mem)
// generic simplifications
@@ -1263,8 +1263,8 @@
(SRLconst (SLLconst x [c]) [d]) && objabi.GOARM==7 && uint64(d)>=uint64(c) && uint64(d)<=31 => (BFXU [(d-c)|(32-d)<<8] x)
// comparison simplification
-(CMP x (RSBconst [0] y)) => (CMN x y)
-(CMN x (RSBconst [0] y)) => (CMP x y)
+((LT|LE|EQ|NE|GE|GT) (CMP x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMN x y)) // sense of carry bit not preserved
+((LT|LE|EQ|NE|GE|GT) (CMN x (RSBconst [0] y))) => ((LT|LE|EQ|NE|GE|GT) (CMP x y)) // sense of carry bit not preserved
(EQ (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 => (EQ (CMP x y) yes no)
(EQ (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 => (EQ (CMP a (MUL <x.Type> x y)) yes no)
(EQ (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 => (EQ (CMPconst [c] x) yes no)
@@ -1470,6 +1470,6 @@
(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRLreg x y z) yes no)
(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 => (GE (TEQshiftRAreg x y z) yes no)
-(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(read8(sym, off))])
-(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(read16(sym, off, config.ctxt.Arch.ByteOrder))])
-(MOVWload [off] {sym} (SB) _) && symIsRO(sym) -> (MOVWconst [int64(int32(read32(sym, off, config.ctxt.Arch.ByteOrder)))])
+(MOVBUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read8(sym, int64(off)))])
+(MOVHUload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])
+(MOVWload [off] {sym} (SB) _) && symIsRO(sym) => (MOVWconst [int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))])
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index c4a3532632..c50a8c7778 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -548,8 +548,10 @@
(AtomicCompareAndSwap(32|64) ...) => (LoweredAtomicCas(32|64) ...)
// Currently the updated value is not used, but we need a register to temporarily hold it.
-(AtomicAnd8 ptr val mem) => (Select1 (LoweredAtomicAnd8 ptr val mem))
-(AtomicOr8 ptr val mem) => (Select1 (LoweredAtomicOr8 ptr val mem))
+(AtomicAnd8 ptr val mem) => (Select1 (LoweredAtomicAnd8 ptr val mem))
+(AtomicAnd32 ptr val mem) => (Select1 (LoweredAtomicAnd32 ptr val mem))
+(AtomicOr8 ptr val mem) => (Select1 (LoweredAtomicOr8 ptr val mem))
+(AtomicOr32 ptr val mem) => (Select1 (LoweredAtomicOr32 ptr val mem))
(AtomicAdd(32|64)Variant ...) => (LoweredAtomicAdd(32|64)Variant ...)
@@ -1171,145 +1173,145 @@
(MUL x (MOVDconst [-1])) => (NEG x)
(MUL _ (MOVDconst [0])) => (MOVDconst [0])
(MUL x (MOVDconst [1])) => x
-(MUL x (MOVDconst [c])) && isPowerOfTwo(c) => (SLLconst [log2(c)] x)
-(MUL x (MOVDconst [c])) && isPowerOfTwo(c-1) && c >= 3 => (ADDshiftLL x x [log2(c-1)])
-(MUL x (MOVDconst [c])) && isPowerOfTwo(c+1) && c >= 7 => (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
-(MUL x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) => (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
-(MUL x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) => (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
-(MUL x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) => (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
-(MUL x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) => (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
+(MUL x (MOVDconst [c])) && isPowerOfTwo64(c) => (SLLconst [log2(c)] x)
+(MUL x (MOVDconst [c])) && isPowerOfTwo64(c-1) && c >= 3 => (ADDshiftLL x x [log2(c-1)])
+(MUL x (MOVDconst [c])) && isPowerOfTwo64(c+1) && c >= 7 => (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
+(MUL x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) => (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+(MUL x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) => (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+(MUL x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) => (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
+(MUL x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) => (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
(MULW x (MOVDconst [c])) && int32(c)==-1 => (NEG x)
(MULW _ (MOVDconst [c])) && int32(c)==0 => (MOVDconst [0])
(MULW x (MOVDconst [c])) && int32(c)==1 => x
-(MULW x (MOVDconst [c])) && isPowerOfTwo(c) => (SLLconst [log2(c)] x)
-(MULW x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c) >= 3 => (ADDshiftLL x x [log2(c-1)])
-(MULW x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c) >= 7 => (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
-(MULW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
-(MULW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
-(MULW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
-(MULW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
+(MULW x (MOVDconst [c])) && isPowerOfTwo64(c) => (SLLconst [log2(c)] x)
+(MULW x (MOVDconst [c])) && isPowerOfTwo64(c-1) && int32(c) >= 3 => (ADDshiftLL x x [log2(c-1)])
+(MULW x (MOVDconst [c])) && isPowerOfTwo64(c+1) && int32(c) >= 7 => (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
+(MULW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+(MULW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+(MULW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
+(MULW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
// mneg by constant
(MNEG x (MOVDconst [-1])) => x
(MNEG _ (MOVDconst [0])) => (MOVDconst [0])
(MNEG x (MOVDconst [1])) => (NEG x)
-(MNEG x (MOVDconst [c])) && isPowerOfTwo(c) => (NEG (SLLconst <x.Type> [log2(c)] x))
-(MNEG x (MOVDconst [c])) && isPowerOfTwo(c-1) && c >= 3 => (NEG (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MNEG x (MOVDconst [c])) && isPowerOfTwo(c+1) && c >= 7 => (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log2(c+1)]))
-(MNEG x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) => (SLLconst <x.Type> [log2(c/3)] (SUBshiftLL <x.Type> x x [2]))
-(MNEG x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) => (NEG (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])))
-(MNEG x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) => (SLLconst <x.Type> [log2(c/7)] (SUBshiftLL <x.Type> x x [3]))
-(MNEG x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) => (NEG (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])))
+(MNEG x (MOVDconst [c])) && isPowerOfTwo64(c) => (NEG (SLLconst <x.Type> [log2(c)] x))
+(MNEG x (MOVDconst [c])) && isPowerOfTwo64(c-1) && c >= 3 => (NEG (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MNEG x (MOVDconst [c])) && isPowerOfTwo64(c+1) && c >= 7 => (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log2(c+1)]))
+(MNEG x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) => (SLLconst <x.Type> [log2(c/3)] (SUBshiftLL <x.Type> x x [2]))
+(MNEG x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) => (NEG (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])))
+(MNEG x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) => (SLLconst <x.Type> [log2(c/7)] (SUBshiftLL <x.Type> x x [3]))
+(MNEG x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) => (NEG (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])))
(MNEGW x (MOVDconst [c])) && int32(c)==-1 => x
(MNEGW _ (MOVDconst [c])) && int32(c)==0 => (MOVDconst [0])
(MNEGW x (MOVDconst [c])) && int32(c)==1 => (NEG x)
-(MNEGW x (MOVDconst [c])) && isPowerOfTwo(c) => (NEG (SLLconst <x.Type> [log2(c)] x))
-(MNEGW x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c) >= 3 => (NEG (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MNEGW x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c) >= 7 => (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log2(c+1)]))
-(MNEGW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (SLLconst <x.Type> [log2(c/3)] (SUBshiftLL <x.Type> x x [2]))
-(MNEGW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (NEG (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])))
-(MNEGW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (SLLconst <x.Type> [log2(c/7)] (SUBshiftLL <x.Type> x x [3]))
-(MNEGW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (NEG (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])))
+(MNEGW x (MOVDconst [c])) && isPowerOfTwo64(c) => (NEG (SLLconst <x.Type> [log2(c)] x))
+(MNEGW x (MOVDconst [c])) && isPowerOfTwo64(c-1) && int32(c) >= 3 => (NEG (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MNEGW x (MOVDconst [c])) && isPowerOfTwo64(c+1) && int32(c) >= 7 => (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log2(c+1)]))
+(MNEGW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (SLLconst <x.Type> [log2(c/3)] (SUBshiftLL <x.Type> x x [2]))
+(MNEGW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (NEG (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])))
+(MNEGW x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (SLLconst <x.Type> [log2(c/7)] (SUBshiftLL <x.Type> x x [3]))
+(MNEGW x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (NEG (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])))
(MADD a x (MOVDconst [-1])) => (SUB a x)
(MADD a _ (MOVDconst [0])) => a
(MADD a x (MOVDconst [1])) => (ADD a x)
-(MADD a x (MOVDconst [c])) && isPowerOfTwo(c) => (ADDshiftLL a x [log2(c)])
-(MADD a x (MOVDconst [c])) && isPowerOfTwo(c-1) && c>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MADD a x (MOVDconst [c])) && isPowerOfTwo(c+1) && c>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
-(MADD a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
-(MADD a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
-(MADD a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
-(MADD a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
+(MADD a x (MOVDconst [c])) && isPowerOfTwo64(c) => (ADDshiftLL a x [log2(c)])
+(MADD a x (MOVDconst [c])) && isPowerOfTwo64(c-1) && c>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MADD a x (MOVDconst [c])) && isPowerOfTwo64(c+1) && c>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
+(MADD a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
+(MADD a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
+(MADD a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
+(MADD a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
(MADD a (MOVDconst [-1]) x) => (SUB a x)
(MADD a (MOVDconst [0]) _) => a
(MADD a (MOVDconst [1]) x) => (ADD a x)
-(MADD a (MOVDconst [c]) x) && isPowerOfTwo(c) => (ADDshiftLL a x [log2(c)])
-(MADD a (MOVDconst [c]) x) && isPowerOfTwo(c-1) && c>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MADD a (MOVDconst [c]) x) && isPowerOfTwo(c+1) && c>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
-(MADD a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
-(MADD a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
-(MADD a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
-(MADD a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
+(MADD a (MOVDconst [c]) x) && isPowerOfTwo64(c) => (ADDshiftLL a x [log2(c)])
+(MADD a (MOVDconst [c]) x) && isPowerOfTwo64(c-1) && c>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MADD a (MOVDconst [c]) x) && isPowerOfTwo64(c+1) && c>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
+(MADD a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo64(c/3) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
+(MADD a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo64(c/5) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
+(MADD a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo64(c/7) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
+(MADD a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo64(c/9) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
(MADDW a x (MOVDconst [c])) && int32(c)==-1 => (SUB a x)
(MADDW a _ (MOVDconst [c])) && int32(c)==0 => a
(MADDW a x (MOVDconst [c])) && int32(c)==1 => (ADD a x)
-(MADDW a x (MOVDconst [c])) && isPowerOfTwo(c) => (ADDshiftLL a x [log2(c)])
-(MADDW a x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c)>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MADDW a x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c)>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
-(MADDW a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
-(MADDW a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
-(MADDW a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
-(MADDW a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
+(MADDW a x (MOVDconst [c])) && isPowerOfTwo64(c) => (ADDshiftLL a x [log2(c)])
+(MADDW a x (MOVDconst [c])) && isPowerOfTwo64(c-1) && int32(c)>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MADDW a x (MOVDconst [c])) && isPowerOfTwo64(c+1) && int32(c)>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
+(MADDW a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
+(MADDW a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
+(MADDW a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
+(MADDW a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
(MADDW a (MOVDconst [c]) x) && int32(c)==-1 => (SUB a x)
(MADDW a (MOVDconst [c]) _) && int32(c)==0 => a
(MADDW a (MOVDconst [c]) x) && int32(c)==1 => (ADD a x)
-(MADDW a (MOVDconst [c]) x) && isPowerOfTwo(c) => (ADDshiftLL a x [log2(c)])
-(MADDW a (MOVDconst [c]) x) && isPowerOfTwo(c-1) && int32(c)>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MADDW a (MOVDconst [c]) x) && isPowerOfTwo(c+1) && int32(c)>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
-(MADDW a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
-(MADDW a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
-(MADDW a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
-(MADDW a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
+(MADDW a (MOVDconst [c]) x) && isPowerOfTwo64(c) => (ADDshiftLL a x [log2(c)])
+(MADDW a (MOVDconst [c]) x) && isPowerOfTwo64(c-1) && int32(c)>=3 => (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MADDW a (MOVDconst [c]) x) && isPowerOfTwo64(c+1) && int32(c)>=7 => (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
+(MADDW a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
+(MADDW a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
+(MADDW a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
+(MADDW a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
(MSUB a x (MOVDconst [-1])) => (ADD a x)
(MSUB a _ (MOVDconst [0])) => a
(MSUB a x (MOVDconst [1])) => (SUB a x)
-(MSUB a x (MOVDconst [c])) && isPowerOfTwo(c) => (SUBshiftLL a x [log2(c)])
-(MSUB a x (MOVDconst [c])) && isPowerOfTwo(c-1) && c>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MSUB a x (MOVDconst [c])) && isPowerOfTwo(c+1) && c>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
-(MSUB a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
-(MSUB a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
-(MSUB a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
-(MSUB a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
+(MSUB a x (MOVDconst [c])) && isPowerOfTwo64(c) => (SUBshiftLL a x [log2(c)])
+(MSUB a x (MOVDconst [c])) && isPowerOfTwo64(c-1) && c>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MSUB a x (MOVDconst [c])) && isPowerOfTwo64(c+1) && c>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
+(MSUB a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
+(MSUB a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
+(MSUB a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
+(MSUB a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
(MSUB a (MOVDconst [-1]) x) => (ADD a x)
(MSUB a (MOVDconst [0]) _) => a
(MSUB a (MOVDconst [1]) x) => (SUB a x)
-(MSUB a (MOVDconst [c]) x) && isPowerOfTwo(c) => (SUBshiftLL a x [log2(c)])
-(MSUB a (MOVDconst [c]) x) && isPowerOfTwo(c-1) && c>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MSUB a (MOVDconst [c]) x) && isPowerOfTwo(c+1) && c>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
-(MSUB a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
-(MSUB a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
-(MSUB a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
-(MSUB a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
+(MSUB a (MOVDconst [c]) x) && isPowerOfTwo64(c) => (SUBshiftLL a x [log2(c)])
+(MSUB a (MOVDconst [c]) x) && isPowerOfTwo64(c-1) && c>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MSUB a (MOVDconst [c]) x) && isPowerOfTwo64(c+1) && c>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
+(MSUB a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo64(c/3) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
+(MSUB a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo64(c/5) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
+(MSUB a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo64(c/7) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
+(MSUB a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo64(c/9) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
(MSUBW a x (MOVDconst [c])) && int32(c)==-1 => (ADD a x)
(MSUBW a _ (MOVDconst [c])) && int32(c)==0 => a
(MSUBW a x (MOVDconst [c])) && int32(c)==1 => (SUB a x)
-(MSUBW a x (MOVDconst [c])) && isPowerOfTwo(c) => (SUBshiftLL a x [log2(c)])
-(MSUBW a x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c)>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MSUBW a x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c)>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
-(MSUBW a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
-(MSUBW a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
-(MSUBW a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
-(MSUBW a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
+(MSUBW a x (MOVDconst [c])) && isPowerOfTwo64(c) => (SUBshiftLL a x [log2(c)])
+(MSUBW a x (MOVDconst [c])) && isPowerOfTwo64(c-1) && int32(c)>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MSUBW a x (MOVDconst [c])) && isPowerOfTwo64(c+1) && int32(c)>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
+(MSUBW a x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
+(MSUBW a x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
+(MSUBW a x (MOVDconst [c])) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
+(MSUBW a x (MOVDconst [c])) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
(MSUBW a (MOVDconst [c]) x) && int32(c)==-1 => (ADD a x)
(MSUBW a (MOVDconst [c]) _) && int32(c)==0 => a
(MSUBW a (MOVDconst [c]) x) && int32(c)==1 => (SUB a x)
-(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo(c) => (SUBshiftLL a x [log2(c)])
-(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo(c-1) && int32(c)>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
-(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo(c+1) && int32(c)>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
-(MSUBW a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
-(MSUBW a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
-(MSUBW a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
-(MSUBW a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
+(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo64(c) => (SUBshiftLL a x [log2(c)])
+(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo64(c-1) && int32(c)>=3 => (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
+(MSUBW a (MOVDconst [c]) x) && isPowerOfTwo64(c+1) && int32(c)>=7 => (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
+(MSUBW a (MOVDconst [c]) x) && c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
+(MSUBW a (MOVDconst [c]) x) && c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
+(MSUBW a (MOVDconst [c]) x) && c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c) => (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
+(MSUBW a (MOVDconst [c]) x) && c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c) => (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
// div by constant
(UDIV x (MOVDconst [1])) => x
-(UDIV x (MOVDconst [c])) && isPowerOfTwo(c) => (SRLconst [log2(c)] x)
+(UDIV x (MOVDconst [c])) && isPowerOfTwo64(c) => (SRLconst [log2(c)] x)
(UDIVW x (MOVDconst [c])) && uint32(c)==1 => x
-(UDIVW x (MOVDconst [c])) && isPowerOfTwo(c) && is32Bit(c) => (SRLconst [log2(c)] x)
+(UDIVW x (MOVDconst [c])) && isPowerOfTwo64(c) && is32Bit(c) => (SRLconst [log2(c)] x)
(UMOD _ (MOVDconst [1])) => (MOVDconst [0])
-(UMOD x (MOVDconst [c])) && isPowerOfTwo(c) => (ANDconst [c-1] x)
+(UMOD x (MOVDconst [c])) && isPowerOfTwo64(c) => (ANDconst [c-1] x)
(UMODW _ (MOVDconst [c])) && uint32(c)==1 => (MOVDconst [0])
-(UMODW x (MOVDconst [c])) && isPowerOfTwo(c) && is32Bit(c) => (ANDconst [c-1] x)
+(UMODW x (MOVDconst [c])) && isPowerOfTwo64(c) && is32Bit(c) => (ANDconst [c-1] x)
// generic simplifications
(ADD x (NEG y)) => (SUB x y)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
index 9ff53f7e4e..fe9edbf933 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
@@ -656,12 +656,14 @@ func init() {
// atomic and/or.
// *arg0 &= (|=) arg1. arg2=mem. returns <new content of *arg0, memory>. auxint must be zero.
- // LDAXRB (Rarg0), Rout
+ // LDAXR (Rarg0), Rout
// AND/OR Rarg1, Rout
- // STLXRB Rout, (Rarg0), Rtmp
+ // STLXR Rout, (Rarg0), Rtmp
// CBNZ Rtmp, -3(PC)
{name: "LoweredAtomicAnd8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", typ: "(UInt8,Mem)", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
+ {name: "LoweredAtomicAnd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", typ: "(UInt32,Mem)", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
{name: "LoweredAtomicOr8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", typ: "(UInt8,Mem)", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
+ {name: "LoweredAtomicOr32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", typ: "(UInt32,Mem)", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true},
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
// It saves all GP registers if necessary,
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules
index 96feaf9234..b6e5312224 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS.rules
+++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules
@@ -143,7 +143,7 @@
(Const(32|16|8) [val]) => (MOVWconst [int32(val)])
(Const(32|64)F ...) => (MOV(F|D)const ...)
(ConstNil) => (MOVWconst [0])
-(ConstBool [b]) => (MOVWconst [int32(b2i(b))])
+(ConstBool [b]) => (MOVWconst [b2i32(b)])
// truncations
// Because we ignore high parts of registers, truncates are just copies.
@@ -383,6 +383,9 @@
(ANDconst <typ.UInt32> [3]
(XORconst <typ.UInt32> [3] ptr)))))) mem)
+(AtomicAnd32 ...) => (LoweredAtomicAnd ...)
+(AtomicOr32 ...) => (LoweredAtomicOr ...)
+
// checks
(NilCheck ...) => (LoweredNilCheck ...)
@@ -581,13 +584,13 @@
(Select0 (MULTU (MOVWconst [1]) _ )) => (MOVWconst [0])
(Select1 (MULTU (MOVWconst [-1]) x )) => (NEG <x.Type> x)
(Select0 (MULTU (MOVWconst [-1]) x )) => (CMOVZ (ADDconst <x.Type> [-1] x) (MOVWconst [0]) x)
-(Select1 (MULTU (MOVWconst [c]) x )) && isPowerOfTwo(int64(uint32(c))) => (SLLconst [int32(log2uint32(int64(c)))] x)
-(Select0 (MULTU (MOVWconst [c]) x )) && isPowerOfTwo(int64(uint32(c))) => (SRLconst [int32(32-log2uint32(int64(c)))] x)
+(Select1 (MULTU (MOVWconst [c]) x )) && isPowerOfTwo64(int64(uint32(c))) => (SLLconst [int32(log2uint32(int64(c)))] x)
+(Select0 (MULTU (MOVWconst [c]) x )) && isPowerOfTwo64(int64(uint32(c))) => (SRLconst [int32(32-log2uint32(int64(c)))] x)
(MUL (MOVWconst [0]) _ ) => (MOVWconst [0])
(MUL (MOVWconst [1]) x ) => x
(MUL (MOVWconst [-1]) x ) => (NEG x)
-(MUL (MOVWconst [c]) x ) && isPowerOfTwo(int64(uint32(c))) => (SLLconst [int32(log2uint32(int64(c)))] x)
+(MUL (MOVWconst [c]) x ) && isPowerOfTwo64(int64(uint32(c))) => (SLLconst [int32(log2uint32(int64(c)))] x)
// generic simplifications
(ADD x (NEG y)) => (SUB x y)
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
index e008ec8703..8e4c3a07c8 100644
--- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules
+++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
@@ -580,13 +580,13 @@
(Select1 (MULVU x (MOVVconst [-1]))) => (NEGV x)
(Select1 (MULVU _ (MOVVconst [0]))) => (MOVVconst [0])
(Select1 (MULVU x (MOVVconst [1]))) => x
-(Select1 (MULVU x (MOVVconst [c]))) && isPowerOfTwo(c) => (SLLVconst [log2(c)] x)
+(Select1 (MULVU x (MOVVconst [c]))) && isPowerOfTwo64(c) => (SLLVconst [log2(c)] x)
// div by constant
(Select1 (DIVVU x (MOVVconst [1]))) => x
-(Select1 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo(c) => (SRLVconst [log2(c)] x)
+(Select1 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo64(c) => (SRLVconst [log2(c)] x)
(Select0 (DIVVU _ (MOVVconst [1]))) => (MOVVconst [0]) // mod
-(Select0 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo(c) => (ANDconst [c-1] x) // mod
+(Select0 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo64(c) => (ANDconst [c-1] x) // mod
// generic simplifications
(ADDV x (NEGV y)) => (SUBV x y)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index de30d003e6..558b09c9f2 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -150,6 +150,31 @@
(ROTLW x (MOVDconst [c])) => (ROTLWconst x [c&31])
(ROTL x (MOVDconst [c])) => (ROTLconst x [c&63])
+// Combine rotate and mask operations
+(ANDconst [m] (ROTLWconst [r] x)) && isPPC64WordRotateMask(m) => (RLWINM [encodePPC64RotateMask(r,m,32)] x)
+(AND (MOVDconst [m]) (ROTLWconst [r] x)) && isPPC64WordRotateMask(m) => (RLWINM [encodePPC64RotateMask(r,m,32)] x)
+(ANDconst [m] (ROTLW x r)) && isPPC64WordRotateMask(m) => (RLWNM [encodePPC64RotateMask(0,m,32)] x r)
+(AND (MOVDconst [m]) (ROTLW x r)) && isPPC64WordRotateMask(m) => (RLWNM [encodePPC64RotateMask(0,m,32)] x r)
+
+// Note, any rotated word bitmask is still a valid word bitmask.
+(ROTLWconst [r] (AND (MOVDconst [m]) x)) && isPPC64WordRotateMask(m) => (RLWINM [encodePPC64RotateMask(r,rotateLeft32(m,r),32)] x)
+(ROTLWconst [r] (ANDconst [m] x)) && isPPC64WordRotateMask(m) => (RLWINM [encodePPC64RotateMask(r,rotateLeft32(m,r),32)] x)
+
+(ANDconst [m] (SRWconst x [s])) && mergePPC64RShiftMask(m,s,32) == 0 => (MOVDconst [0])
+(ANDconst [m] (SRWconst x [s])) && mergePPC64AndSrwi(m,s) != 0 => (RLWINM [mergePPC64AndSrwi(m,s)] x)
+(AND (MOVDconst [m]) (SRWconst x [s])) && mergePPC64RShiftMask(m,s,32) == 0 => (MOVDconst [0])
+(AND (MOVDconst [m]) (SRWconst x [s])) && mergePPC64AndSrwi(m,s) != 0 => (RLWINM [mergePPC64AndSrwi(m,s)] x)
+
+(SRWconst (ANDconst [m] x) [s]) && mergePPC64RShiftMask(m>>uint(s),s,32) == 0 => (MOVDconst [0])
+(SRWconst (ANDconst [m] x) [s]) && mergePPC64AndSrwi(m>>uint(s),s) != 0 => (RLWINM [mergePPC64AndSrwi(m>>uint(s),s)] x)
+(SRWconst (AND (MOVDconst [m]) x) [s]) && mergePPC64RShiftMask(m>>uint(s),s,32) == 0 => (MOVDconst [0])
+(SRWconst (AND (MOVDconst [m]) x) [s]) && mergePPC64AndSrwi(m>>uint(s),s) != 0 => (RLWINM [mergePPC64AndSrwi(m>>uint(s),s)] x)
+
+// Merge shift right + shift left and clear left (e.g for a table lookup)
+(CLRLSLDI [c] (SRWconst [s] x)) && mergePPC64ClrlsldiSrw(int64(c),s) != 0 => (RLWINM [mergePPC64ClrlsldiSrw(int64(c),s)] x)
+(SLDconst [l] (SRWconst [r] x)) && mergePPC64SldiSrw(l,r) != 0 => (RLWINM [mergePPC64SldiSrw(l,r)] x)
+// The following reduction shows up frequently too. e.g b[(x>>14)&0xFF]
+(CLRLSLDI [c] i:(RLWINM [s] x)) && mergePPC64ClrlsldiRlwinm(c,s) != 0 => (RLWINM [mergePPC64ClrlsldiRlwinm(c,s)] x)
// large constant shifts
(Lsh64x64 _ (MOVDconst [c])) && uint64(c) >= 64 => (MOVDconst [0])
@@ -821,6 +846,8 @@
(ADDconst [c] (MOVDaddr [d] {sym} x)) && is32Bit(c+int64(d)) => (MOVDaddr [int32(c+int64(d))] {sym} x)
+(MULL(W|D) x (MOVDconst [c])) && is16Bit(c) => (MULL(W|D)const [int32(c)] x)
+
// Subtract from (with carry, but ignored) constant.
// Note, these clobber the carry bit.
(SUB (MOVDconst [c]) x) && is32Bit(c) => (SUBFCconst [c] x)
@@ -965,10 +992,10 @@
// atomic intrinsics
(AtomicLoad(8|32|64|Ptr) ptr mem) => (LoweredAtomicLoad(8|32|64|Ptr) [1] ptr mem)
-(AtomicLoadAcq32 ptr mem) => (LoweredAtomicLoad32 [0] ptr mem)
+(AtomicLoadAcq(32|64) ptr mem) => (LoweredAtomicLoad(32|64) [0] ptr mem)
(AtomicStore(8|32|64) ptr val mem) => (LoweredAtomicStore(8|32|64) [1] ptr val mem)
-(AtomicStoreRel32 ptr val mem) => (LoweredAtomicStore32 [0] ptr val mem)
+(AtomicStoreRel(32|64) ptr val mem) => (LoweredAtomicStore(32|64) [0] ptr val mem)
//(AtomicStorePtrNoWB ptr val mem) => (STLR ptr val mem)
(AtomicExchange(32|64) ...) => (LoweredAtomicExchange(32|64) ...)
@@ -978,8 +1005,10 @@
(AtomicCompareAndSwap(32|64) ptr old new_ mem) => (LoweredAtomicCas(32|64) [1] ptr old new_ mem)
(AtomicCompareAndSwapRel32 ptr old new_ mem) => (LoweredAtomicCas32 [0] ptr old new_ mem)
-(AtomicAnd8 ...) => (LoweredAtomicAnd8 ...)
-(AtomicOr8 ...) => (LoweredAtomicOr8 ...)
+(AtomicAnd8 ...) => (LoweredAtomicAnd8 ...)
+(AtomicAnd32 ...) => (LoweredAtomicAnd32 ...)
+(AtomicOr8 ...) => (LoweredAtomicOr8 ...)
+(AtomicOr32 ...) => (LoweredAtomicOr32 ...)
(Slicemask <t> x) => (SRADconst (NEG <t> x) [63])
@@ -1018,13 +1047,12 @@
(SLDconst [c] z:(MOVHZreg x)) && c < 16 && z.Uses == 1 => (CLRLSLDI [newPPC64ShiftAuxInt(c,48,63,64)] x)
(SLDconst [c] z:(MOVWZreg x)) && c < 32 && z.Uses == 1 => (CLRLSLDI [newPPC64ShiftAuxInt(c,32,63,64)] x)
-(SLDconst [c] z:(ANDconst [d] x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) => (CLRLSLDI [newPPC64ShiftAuxInt(c,64-getPPC64ShiftMaskLength(d),63,64)] x)
-(SLDconst [c] z:(AND (MOVDconst [d]) x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) => (CLRLSLDI [newPPC64ShiftAuxInt(c,64-getPPC64ShiftMaskLength(d),63,64)] x)
+(SLDconst [c] z:(ANDconst [d] x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) && c <= (64-getPPC64ShiftMaskLength(d)) => (CLRLSLDI [newPPC64ShiftAuxInt(c,64-getPPC64ShiftMaskLength(d),63,64)] x)
+(SLDconst [c] z:(AND (MOVDconst [d]) x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(64-getPPC64ShiftMaskLength(d)) => (CLRLSLDI [newPPC64ShiftAuxInt(c,64-getPPC64ShiftMaskLength(d),63,64)] x)
(SLWconst [c] z:(MOVBZreg x)) && z.Uses == 1 && c < 8 => (CLRLSLWI [newPPC64ShiftAuxInt(c,24,31,32)] x)
(SLWconst [c] z:(MOVHZreg x)) && z.Uses == 1 && c < 16 => (CLRLSLWI [newPPC64ShiftAuxInt(c,16,31,32)] x)
-(SLWconst [c] z:(MOVWZreg x)) && z.Uses == 1 && c < 24 => (CLRLSLWI [newPPC64ShiftAuxInt(c,8,31,32)] x)
-(SLWconst [c] z:(ANDconst [d] x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) => (CLRLSLWI [newPPC64ShiftAuxInt(c,32-getPPC64ShiftMaskLength(d),31,32)] x)
-(SLWconst [c] z:(AND (MOVDconst [d]) x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) => (CLRLSLWI [newPPC64ShiftAuxInt(c,32-getPPC64ShiftMaskLength(d),31,32)] x)
+(SLWconst [c] z:(ANDconst [d] x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(32-getPPC64ShiftMaskLength(d)) => (CLRLSLWI [newPPC64ShiftAuxInt(c,32-getPPC64ShiftMaskLength(d),31,32)] x)
+(SLWconst [c] z:(AND (MOVDconst [d]) x)) && z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(32-getPPC64ShiftMaskLength(d)) => (CLRLSLWI [newPPC64ShiftAuxInt(c,32-getPPC64ShiftMaskLength(d),31,32)] x)
// special case for power9
(SL(W|D)const [c] z:(MOVWreg x)) && c < 32 && objabi.GOPPC64 >= 9 => (EXTSWSLconst [c] x)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
index 28317928a8..f7198b90c3 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
@@ -137,6 +137,7 @@ func init() {
gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
gp11 = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
gp21 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
+ gp21a0 = regInfo{inputs: []regMask{gp, gp | sp | sb}, outputs: []regMask{gp}}
gp31 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
gp22 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, gp}}
gp32 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp, gp}}
@@ -181,6 +182,8 @@ func init() {
{name: "MULLD", argLength: 2, reg: gp21, asm: "MULLD", typ: "Int64", commutative: true}, // arg0*arg1 (signed 64-bit)
{name: "MULLW", argLength: 2, reg: gp21, asm: "MULLW", typ: "Int32", commutative: true}, // arg0*arg1 (signed 32-bit)
+ {name: "MULLDconst", argLength: 1, reg: gp11, asm: "MULLD", aux: "Int32", typ: "Int64"}, // arg0*auxInt (signed 64-bit)
+ {name: "MULLWconst", argLength: 1, reg: gp11, asm: "MULLW", aux: "Int32", typ: "Int64"}, // arg0*auxInt (signed 64-bit)
{name: "MADDLD", argLength: 3, reg: gp31, asm: "MADDLD", typ: "Int64"}, // (arg0*arg1)+arg2 (signed 64-bit)
{name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", commutative: true}, // (arg0 * arg1) >> 64, signed
@@ -225,6 +228,10 @@ func init() {
{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits
{name: "EXTSWSLconst", argLength: 1, reg: gp11, asm: "EXTSWSLI", aux: "Int64"},
+ {name: "RLWINM", argLength: 1, reg: gp11, asm: "RLWNM", aux: "Int64"}, // Rotate and mask by immediate "rlwinm". encodePPC64RotateMask describes aux
+ {name: "RLWNM", argLength: 2, reg: gp21, asm: "RLWNM", aux: "Int64"}, // Rotate and mask by "rlwnm". encodePPC64RotateMask describes aux
+ {name: "RLWMI", argLength: 2, reg: gp21a0, asm: "RLWMI", aux: "Int64", resultInArg0: true}, // "rlwimi" similar aux encoding as above
+
{name: "CNTLZD", argLength: 1, reg: gp11, asm: "CNTLZD", clobberFlags: true}, // count leading zeros
{name: "CNTLZW", argLength: 1, reg: gp11, asm: "CNTLZW", clobberFlags: true}, // count leading zeros (32 bit)
@@ -600,25 +607,22 @@ func init() {
{name: "LoweredAtomicLoadPtr", argLength: 2, reg: gpload, typ: "Int64", aux: "Int64", clobberFlags: true, faultOnNilArg0: true},
// atomic add32, 64
- // SYNC
+ // LWSYNC
// LDAR (Rarg0), Rout
// ADD Rarg1, Rout
// STDCCC Rout, (Rarg0)
// BNE -3(PC)
- // ISYNC
// return new sum
-
{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
// atomic exchange32, 64
- // SYNC
+ // LWSYNC
// LDAR (Rarg0), Rout
// STDCCC Rarg1, (Rarg0)
// BNE -2(PC)
// ISYNC
// return old val
-
{name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
@@ -641,15 +645,16 @@ func init() {
{name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, aux: "Int64", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
- // atomic 8 and/or.
+ // atomic 8/32 and/or.
// *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
- // LBAR (Rarg0), Rtmp
+ // LBAR/LWAT (Rarg0), Rtmp
// AND/OR Rarg1, Rtmp
- // STBCCC Rtmp, (Rarg0), Rtmp
+ // STBCCC/STWCCC Rtmp, (Rarg0), Rtmp
// BNE Rtmp, -3(PC)
-
{name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicAnd32", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicOr32", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true, hasSideEffects: true},
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
// It preserves R0 through R17 (except special registers R1, R2, R11, R12, R13), g, and its arguments R20 and R21,
diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules
index 9437c8e9d4..325cbeb825 100644
--- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules
+++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules
@@ -3,11 +3,7 @@
// license that can be found in the LICENSE file.
// Optimizations TODO:
-// * Somehow track when values are already zero/signed-extended, avoid re-extending.
// * Use SLTI and SLTIU for comparisons to constants, instead of SLT/SLTU with constants in registers
-// * Find a more efficient way to do zero/sign extension than left+right shift.
-// There are many other options (store then load-extend, LUI+ANDI for zero extend, special case 32->64, ...),
-// but left+right shift is simple and uniform, and we don't have real hardware to do perf testing on anyway.
// * Use the zero register instead of moving 0 into a register.
// * Add rules to avoid generating a temp bool value for (If (SLT[U] ...) ...).
// * Optimize left and right shift by simplifying SLTIU, Neg, and ADD for constants.
@@ -66,8 +62,8 @@
(Mod32u ...) => (REMUW ...)
(Mod16 x y [false]) => (REMW (SignExt16to32 x) (SignExt16to32 y))
(Mod16u x y) => (REMUW (ZeroExt16to32 x) (ZeroExt16to32 y))
-(Mod8 x y) => (REMW (SignExt8to32 x) (SignExt8to32 y))
-(Mod8u x y) => (REMUW (ZeroExt8to32 x) (ZeroExt8to32 y))
+(Mod8 x y) => (REMW (SignExt8to32 x) (SignExt8to32 y))
+(Mod8u x y) => (REMUW (ZeroExt8to32 x) (ZeroExt8to32 y))
(And64 ...) => (AND ...)
(And32 ...) => (AND ...)
@@ -98,25 +94,21 @@
(Sqrt ...) => (FSQRTD ...)
-// Zero and sign extension
-// Shift left until the bits we want are at the top of the register.
-// Then logical/arithmetic shift right for zero/sign extend.
-// We always extend to 64 bits; there's no reason not to,
-// and optimization rules can then collapse some extensions.
-
-(SignExt8to16 <t> x) => (SRAI [56] (SLLI <t> [56] x))
-(SignExt8to32 <t> x) => (SRAI [56] (SLLI <t> [56] x))
-(SignExt8to64 <t> x) => (SRAI [56] (SLLI <t> [56] x))
-(SignExt16to32 <t> x) => (SRAI [48] (SLLI <t> [48] x))
-(SignExt16to64 <t> x) => (SRAI [48] (SLLI <t> [48] x))
-(SignExt32to64 <t> x) => (ADDIW [0] x)
-
-(ZeroExt8to16 <t> x) => (SRLI [56] (SLLI <t> [56] x))
-(ZeroExt8to32 <t> x) => (SRLI [56] (SLLI <t> [56] x))
-(ZeroExt8to64 <t> x) => (SRLI [56] (SLLI <t> [56] x))
-(ZeroExt16to32 <t> x) => (SRLI [48] (SLLI <t> [48] x))
-(ZeroExt16to64 <t> x) => (SRLI [48] (SLLI <t> [48] x))
-(ZeroExt32to64 <t> x) => (SRLI [32] (SLLI <t> [32] x))
+// Sign and zero extension.
+
+(SignExt8to16 ...) => (MOVBreg ...)
+(SignExt8to32 ...) => (MOVBreg ...)
+(SignExt8to64 ...) => (MOVBreg ...)
+(SignExt16to32 ...) => (MOVHreg ...)
+(SignExt16to64 ...) => (MOVHreg ...)
+(SignExt32to64 ...) => (MOVWreg ...)
+
+(ZeroExt8to16 ...) => (MOVBUreg ...)
+(ZeroExt8to32 ...) => (MOVBUreg ...)
+(ZeroExt8to64 ...) => (MOVBUreg ...)
+(ZeroExt16to32 ...) => (MOVHUreg ...)
+(ZeroExt16to64 ...) => (MOVHUreg ...)
+(ZeroExt32to64 ...) => (MOVWUreg ...)
(Cvt32to32F ...) => (FCVTSW ...)
(Cvt32to64F ...) => (FCVTDW ...)
@@ -261,16 +253,16 @@
(EqPtr x y) => (SEQZ (SUB <x.Type> x y))
(Eq64 x y) => (SEQZ (SUB <x.Type> x y))
(Eq32 x y) => (SEQZ (SUBW <x.Type> x y))
-(Eq16 x y) => (SEQZ (ZeroExt16to64 (SUB <x.Type> x y)))
-(Eq8 x y) => (SEQZ (ZeroExt8to64 (SUB <x.Type> x y)))
+(Eq16 x y) => (SEQZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
+(Eq8 x y) => (SEQZ (SUB <x.Type> (ZeroExt8to64 x) (ZeroExt8to64 y)))
(Eq64F ...) => (FEQD ...)
(Eq32F ...) => (FEQS ...)
(NeqPtr x y) => (SNEZ (SUB <x.Type> x y))
(Neq64 x y) => (SNEZ (SUB <x.Type> x y))
(Neq32 x y) => (SNEZ (SUBW <x.Type> x y))
-(Neq16 x y) => (SNEZ (ZeroExt16to64 (SUB <x.Type> x y)))
-(Neq8 x y) => (SNEZ (ZeroExt8to64 (SUB <x.Type> x y)))
+(Neq16 x y) => (SNEZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
+(Neq8 x y) => (SNEZ (SUB <x.Type> (ZeroExt8to64 x) (ZeroExt8to64 y)))
(Neq64F ...) => (FNED ...)
(Neq32F ...) => (FNES ...)
@@ -291,8 +283,8 @@
(Store {t} ptr val mem) && t.Size() == 2 => (MOVHstore ptr val mem)
(Store {t} ptr val mem) && t.Size() == 4 && !is32BitFloat(val.Type) => (MOVWstore ptr val mem)
(Store {t} ptr val mem) && t.Size() == 8 && !is64BitFloat(val.Type) => (MOVDstore ptr val mem)
-(Store {t} ptr val mem) && t.Size() == 4 && is32BitFloat(val.Type) => (FMOVWstore ptr val mem)
-(Store {t} ptr val mem) && t.Size() == 8 && is64BitFloat(val.Type) => (FMOVDstore ptr val mem)
+(Store {t} ptr val mem) && t.Size() == 4 && is32BitFloat(val.Type) => (FMOVWstore ptr val mem)
+(Store {t} ptr val mem) && t.Size() == 8 && is64BitFloat(val.Type) => (FMOVDstore ptr val mem)
// We need to fold MOVaddr into the LD/MOVDstore ops so that the live variable analysis
// knows what variables are being read/written by the ops.
@@ -368,6 +360,13 @@
(Zero [4] ptr mem) => (MOVWstore ptr (MOVWconst) mem)
(Zero [8] ptr mem) => (MOVDstore ptr (MOVDconst) mem)
+// Medium zeroing uses a Duff's device
+// 8 and 128 are magic constants, see runtime/mkduff.go
+(Zero [s] {t} ptr mem)
+ && s%8 == 0 && s >= 16 && s <= 8*128
+ && t.Alignment()%8 == 0 && !config.noDuffDevice =>
+ (DUFFZERO [8 * (128 - s/8)] ptr mem)
+
// Generic zeroing uses a loop
(Zero [s] {t} ptr mem) =>
(LoweredZero [t.Alignment()]
@@ -403,6 +402,13 @@
(Move [4] dst src mem) => (MOVWstore dst (MOVWload src mem) mem)
(Move [8] dst src mem) => (MOVDstore dst (MOVDload src mem) mem)
+// Medium move uses a Duff's device
+// 16 and 128 are magic constants, see runtime/mkduff.go
+(Move [s] {t} dst src mem)
+ && s%8 == 0 && s >= 16 && s <= 8*128 && t.Alignment()%8 == 0
+ && !config.noDuffDevice && logLargeCopy(v, s) =>
+ (DUFFCOPY [16 * (128 - s/8)] dst src mem)
+
// Generic move uses a loop
(Move [s] {t} dst src mem) && (s <= 16 || logLargeCopy(v, s)) =>
(LoweredMove [t.Alignment()]
@@ -501,6 +507,65 @@
(MOVWstore [off] {sym} ptr (MOVWconst [0]) mem) => (MOVWstorezero [off] {sym} ptr mem)
(MOVDstore [off] {sym} ptr (MOVDconst [0]) mem) => (MOVDstorezero [off] {sym} ptr mem)
+// Avoid sign/zero extension after properly typed load.
+(MOVBreg x:(MOVBload _ _)) => (MOVDreg x)
+(MOVHreg x:(MOVBload _ _)) => (MOVDreg x)
+(MOVHreg x:(MOVBUload _ _)) => (MOVDreg x)
+(MOVHreg x:(MOVHload _ _)) => (MOVDreg x)
+(MOVWreg x:(MOVBload _ _)) => (MOVDreg x)
+(MOVWreg x:(MOVBUload _ _)) => (MOVDreg x)
+(MOVWreg x:(MOVHload _ _)) => (MOVDreg x)
+(MOVWreg x:(MOVHUload _ _)) => (MOVDreg x)
+(MOVWreg x:(MOVWload _ _)) => (MOVDreg x)
+(MOVBUreg x:(MOVBUload _ _)) => (MOVDreg x)
+(MOVHUreg x:(MOVBUload _ _)) => (MOVDreg x)
+(MOVHUreg x:(MOVHUload _ _)) => (MOVDreg x)
+(MOVWUreg x:(MOVBUload _ _)) => (MOVDreg x)
+(MOVWUreg x:(MOVHUload _ _)) => (MOVDreg x)
+(MOVWUreg x:(MOVWUload _ _)) => (MOVDreg x)
+
+// Fold double extensions.
+(MOVBreg x:(MOVBreg _)) => (MOVDreg x)
+(MOVHreg x:(MOVBreg _)) => (MOVDreg x)
+(MOVHreg x:(MOVBUreg _)) => (MOVDreg x)
+(MOVHreg x:(MOVHreg _)) => (MOVDreg x)
+(MOVWreg x:(MOVBreg _)) => (MOVDreg x)
+(MOVWreg x:(MOVBUreg _)) => (MOVDreg x)
+(MOVWreg x:(MOVHreg _)) => (MOVDreg x)
+(MOVWreg x:(MOVWreg _)) => (MOVDreg x)
+(MOVBUreg x:(MOVBUreg _)) => (MOVDreg x)
+(MOVHUreg x:(MOVBUreg _)) => (MOVDreg x)
+(MOVHUreg x:(MOVHUreg _)) => (MOVDreg x)
+(MOVWUreg x:(MOVBUreg _)) => (MOVDreg x)
+(MOVWUreg x:(MOVHUreg _)) => (MOVDreg x)
+(MOVWUreg x:(MOVWUreg _)) => (MOVDreg x)
+
+// Do not extend before store.
+(MOVBstore [off] {sym} ptr (MOVBreg x) mem) => (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHreg x) mem) => (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVWreg x) mem) => (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBUreg x) mem) => (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHUreg x) mem) => (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVWUreg x) mem) => (MOVBstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHreg x) mem) => (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVWreg x) mem) => (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHUreg x) mem) => (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVWUreg x) mem) => (MOVHstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWreg x) mem) => (MOVWstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWUreg x) mem) => (MOVWstore [off] {sym} ptr x mem)
+
+// Replace extend after load with alternate load where possible.
+(MOVBreg <t> x:(MOVBUload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVBload <t> [off] {sym} ptr mem)
+(MOVHreg <t> x:(MOVHUload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVHload <t> [off] {sym} ptr mem)
+(MOVWreg <t> x:(MOVWUload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVWload <t> [off] {sym} ptr mem)
+(MOVBUreg <t> x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVBUload <t> [off] {sym} ptr mem)
+(MOVHUreg <t> x:(MOVHload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVHUload <t> [off] {sym} ptr mem)
+(MOVWUreg <t> x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (MOVWUload <t> [off] {sym} ptr mem)
+
+// If a register move has only 1 use, just use the same register without emitting instruction
+// MOVnop does not emit an instruction, only for ensuring the type.
+(MOVDreg x) && x.Uses == 1 => (MOVDnop x)
+
// Fold constant into immediate instructions where possible.
(ADD (MOVBconst [val]) x) => (ADDI [int64(val)] x)
(ADD (MOVHconst [val]) x) => (ADDI [int64(val)] x)
diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go b/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go
index b06b86075e..f64319230b 100644
--- a/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go
@@ -24,10 +24,11 @@ import (
// L = 64 bit int, used when the opcode starts with F
const (
- riscv64REG_G = 4
+ riscv64REG_G = 27
riscv64REG_CTXT = 20
riscv64REG_LR = 1
riscv64REG_SP = 2
+ riscv64REG_TP = 4
riscv64REG_TMP = 31
riscv64REG_ZERO = 0
)
@@ -78,8 +79,8 @@ func init() {
// Add general purpose registers to gpMask.
switch r {
- // ZERO, and TMP are not in any gp mask.
- case riscv64REG_ZERO, riscv64REG_TMP:
+ // ZERO, TP and TMP are not in any gp mask.
+ case riscv64REG_ZERO, riscv64REG_TP, riscv64REG_TMP:
case riscv64REG_G:
gpgMask |= mask
gpspsbgMask |= mask
@@ -192,6 +193,17 @@ func init() {
{name: "MOVWstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOVW", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 32 bits
{name: "MOVDstorezero", argLength: 2, reg: gpstore0, aux: "SymOff", asm: "MOV", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // 64 bits
+ // Conversions
+ {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte
+ {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half
+ {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word
+ {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOV"}, // move from arg0
+ {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
+ {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
+ {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
+
+ {name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gpMask}, outputs: []regMask{gpMask}}, resultInArg0: true}, // nop, return arg0 in same register
+
// Shift ops
{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << (aux1 & 63)
{name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> (aux1 & 63), signed
@@ -228,6 +240,44 @@ func init() {
{name: "CALLclosure", argLength: 3, reg: callClosure, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
{name: "CALLinter", argLength: 2, reg: callInter, aux: "CallOff", call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
+ // duffzero
+ // arg0 = address of memory to zero (in X10, changed as side effect)
+ // arg1 = mem
+ // auxint = offset into duffzero code to start executing
+ // X1 (link register) changed because of function call
+ // returns mem
+ {
+ name: "DUFFZERO",
+ aux: "Int64",
+ argLength: 2,
+ reg: regInfo{
+ inputs: []regMask{regNamed["X10"]},
+ clobbers: regNamed["X1"] | regNamed["X10"],
+ },
+ typ: "Mem",
+ faultOnNilArg0: true,
+ },
+
+ // duffcopy
+ // arg0 = address of dst memory (in X11, changed as side effect)
+ // arg1 = address of src memory (in X10, changed as side effect)
+ // arg2 = mem
+ // auxint = offset into duffcopy code to start executing
+ // X1 (link register) changed because of function call
+ // returns mem
+ {
+ name: "DUFFCOPY",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{regNamed["X11"], regNamed["X10"]},
+ clobbers: regNamed["X1"] | regNamed["X10"] | regNamed["X11"],
+ },
+ typ: "Mem",
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ },
+
// Generic moves and zeros
// general unaligned zeroing
diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules
index e564f638d3..2d6f091a4e 100644
--- a/src/cmd/compile/internal/ssa/gen/S390X.rules
+++ b/src/cmd/compile/internal/ssa/gen/S390X.rules
@@ -198,6 +198,9 @@
(RXSBG <typ.UInt32> {s390x.NewRotateParams(59, 60, 3)} (MOVDconst [3<<3]) ptr))
mem)
+(AtomicAnd32 ...) => (LAN ...)
+(AtomicOr32 ...) => (LAO ...)
+
// Lowering extension
// Note: we always extend to 64 bits even though some ops don't need that many result bits.
(SignExt8to(16|32|64) ...) => (MOVBreg ...)
diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go
index 417b33cf91..728cfb5508 100644
--- a/src/cmd/compile/internal/ssa/gen/S390XOps.go
+++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go
@@ -547,8 +547,10 @@ func init() {
// Atomic bitwise operations.
// Note: 'floor' operations round the pointer down to the nearest word boundary
// which reflects how they are used in the runtime.
- {name: "LAOfloor", argLength: 3, reg: gpstorelab, asm: "LAO", typ: "Mem", clobberFlags: true, hasSideEffects: true}, // *(floor(arg0, 4)) |= arg1. arg2 = mem.
+ {name: "LAN", argLength: 3, reg: gpstore, asm: "LAN", typ: "Mem", clobberFlags: true, hasSideEffects: true}, // *arg0 &= arg1. arg2 = mem.
{name: "LANfloor", argLength: 3, reg: gpstorelab, asm: "LAN", typ: "Mem", clobberFlags: true, hasSideEffects: true}, // *(floor(arg0, 4)) &= arg1. arg2 = mem.
+ {name: "LAO", argLength: 3, reg: gpstore, asm: "LAO", typ: "Mem", clobberFlags: true, hasSideEffects: true}, // *arg0 |= arg1. arg2 = mem.
+ {name: "LAOfloor", argLength: 3, reg: gpstorelab, asm: "LAO", typ: "Mem", clobberFlags: true, hasSideEffects: true}, // *(floor(arg0, 4)) |= arg1. arg2 = mem.
// Compare and swap.
// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
diff --git a/src/cmd/compile/internal/ssa/gen/dec64.rules b/src/cmd/compile/internal/ssa/gen/dec64.rules
index 4f9e863f90..07607960fa 100644
--- a/src/cmd/compile/internal/ssa/gen/dec64.rules
+++ b/src/cmd/compile/internal/ssa/gen/dec64.rules
@@ -9,7 +9,6 @@
(Int64Hi (Int64Make hi _)) => hi
(Int64Lo (Int64Make _ lo)) => lo
-
(Load <t> ptr mem) && is64BitInt(t) && !config.BigEndian && t.IsSigned() =>
(Int64Make
(Load <typ.Int32> (OffPtr <typ.Int32Ptr> [4] ptr) mem)
@@ -143,6 +142,10 @@
(Trunc64to32 (Int64Make _ lo)) => lo
(Trunc64to16 (Int64Make _ lo)) => (Trunc32to16 lo)
(Trunc64to8 (Int64Make _ lo)) => (Trunc32to8 lo)
+// Most general
+(Trunc64to32 x) => (Int64Lo x)
+(Trunc64to16 x) => (Trunc32to16 (Int64Lo x))
+(Trunc64to8 x) => (Trunc32to8 (Int64Lo x))
(Lsh32x64 _ (Int64Make (Const32 [c]) _)) && c != 0 => (Const32 [0])
(Rsh32x64 x (Int64Make (Const32 [c]) _)) && c != 0 => (Signmask x)
@@ -175,156 +178,174 @@
// turn x64 non-constant shifts to x32 shifts
// if high 32-bit of the shift is nonzero, make a huge shift
(Lsh64x64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Lsh64x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Lsh64x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Rsh64x64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Rsh64x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Rsh64x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Rsh64Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Rsh64Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Rsh64Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Lsh32x64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Lsh32x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Lsh32x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Rsh32x64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Rsh32x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Rsh32x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Rsh32Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Rsh32Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Rsh32Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Lsh16x64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Lsh16x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Lsh16x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Rsh16x64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Rsh16x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Rsh16x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Rsh16Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Rsh16Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Rsh16Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Lsh8x64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Lsh8x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Lsh8x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Rsh8x64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Rsh8x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Rsh8x32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
(Rsh8Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 =>
- (Rsh8Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+ (Rsh8Ux32 x (Or32 <typ.UInt32> (Zeromask hi) lo))
+
+// Most general
+(Lsh64x64 x y) => (Lsh64x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Rsh64x64 x y) => (Rsh64x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Rsh64Ux64 x y) => (Rsh64Ux32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Lsh32x64 x y) => (Lsh32x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Rsh32x64 x y) => (Rsh32x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Rsh32Ux64 x y) => (Rsh32Ux32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Lsh16x64 x y) => (Lsh16x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Rsh16x64 x y) => (Rsh16x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Rsh16Ux64 x y) => (Rsh16Ux32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Lsh8x64 x y) => (Lsh8x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Rsh8x64 x y) => (Rsh8x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+(Rsh8Ux64 x y) => (Rsh8Ux32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+
+// Clean up constants a little
+(Or32 <typ.UInt32> (Zeromask (Const32 [c])) y) && c == 0 => y
+(Or32 <typ.UInt32> (Zeromask (Const32 [c])) y) && c != 0 => (Const32 <typ.UInt32> [-1])
// 64x left shift
// result.hi = hi<<s | lo>>(32-s) | lo<<(s-32) // >> is unsigned, large shifts result 0
// result.lo = lo<<s
-(Lsh64x32 (Int64Make hi lo) s) =>
+(Lsh64x32 x s) =>
(Int64Make
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Lsh32x32 <typ.UInt32> hi s)
+ (Lsh32x32 <typ.UInt32> (Int64Hi x) s)
(Rsh32Ux32 <typ.UInt32>
- lo
+ (Int64Lo x)
(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s)))
(Lsh32x32 <typ.UInt32>
- lo
+ (Int64Lo x)
(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32]))))
- (Lsh32x32 <typ.UInt32> lo s))
-(Lsh64x16 (Int64Make hi lo) s) =>
+ (Lsh32x32 <typ.UInt32> (Int64Lo x) s))
+(Lsh64x16 x s) =>
(Int64Make
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Lsh32x16 <typ.UInt32> hi s)
+ (Lsh32x16 <typ.UInt32> (Int64Hi x) s)
(Rsh32Ux16 <typ.UInt32>
- lo
+ (Int64Lo x)
(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s)))
(Lsh32x16 <typ.UInt32>
- lo
+ (Int64Lo x)
(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32]))))
- (Lsh32x16 <typ.UInt32> lo s))
-(Lsh64x8 (Int64Make hi lo) s) =>
+ (Lsh32x16 <typ.UInt32> (Int64Lo x) s))
+(Lsh64x8 x s) =>
(Int64Make
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Lsh32x8 <typ.UInt32> hi s)
+ (Lsh32x8 <typ.UInt32> (Int64Hi x) s)
(Rsh32Ux8 <typ.UInt32>
- lo
+ (Int64Lo x)
(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s)))
(Lsh32x8 <typ.UInt32>
- lo
+ (Int64Lo x)
(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32]))))
- (Lsh32x8 <typ.UInt32> lo s))
+ (Lsh32x8 <typ.UInt32> (Int64Lo x) s))
// 64x unsigned right shift
// result.hi = hi>>s
// result.lo = lo>>s | hi<<(32-s) | hi>>(s-32) // >> is unsigned, large shifts result 0
-(Rsh64Ux32 (Int64Make hi lo) s) =>
+(Rsh64Ux32 x s) =>
(Int64Make
- (Rsh32Ux32 <typ.UInt32> hi s)
+ (Rsh32Ux32 <typ.UInt32> (Int64Hi x) s)
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Rsh32Ux32 <typ.UInt32> lo s)
+ (Rsh32Ux32 <typ.UInt32> (Int64Lo x) s)
(Lsh32x32 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s)))
(Rsh32Ux32 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))))
-(Rsh64Ux16 (Int64Make hi lo) s) =>
+(Rsh64Ux16 x s) =>
(Int64Make
- (Rsh32Ux16 <typ.UInt32> hi s)
+ (Rsh32Ux16 <typ.UInt32> (Int64Hi x) s)
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Rsh32Ux16 <typ.UInt32> lo s)
+ (Rsh32Ux16 <typ.UInt32> (Int64Lo x) s)
(Lsh32x16 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s)))
(Rsh32Ux16 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))))
-(Rsh64Ux8 (Int64Make hi lo) s) =>
+(Rsh64Ux8 x s) =>
(Int64Make
- (Rsh32Ux8 <typ.UInt32> hi s)
+ (Rsh32Ux8 <typ.UInt32> (Int64Hi x) s)
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Rsh32Ux8 <typ.UInt32> lo s)
+ (Rsh32Ux8 <typ.UInt32> (Int64Lo x) s)
(Lsh32x8 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s)))
(Rsh32Ux8 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))))
// 64x signed right shift
// result.hi = hi>>s
// result.lo = lo>>s | hi<<(32-s) | (hi>>(s-32))&zeromask(s>>5) // hi>>(s-32) is signed, large shifts result 0/-1
-(Rsh64x32 (Int64Make hi lo) s) =>
+(Rsh64x32 x s) =>
(Int64Make
- (Rsh32x32 <typ.UInt32> hi s)
+ (Rsh32x32 <typ.UInt32> (Int64Hi x) s)
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Rsh32Ux32 <typ.UInt32> lo s)
+ (Rsh32Ux32 <typ.UInt32> (Int64Lo x) s)
(Lsh32x32 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s)))
(And32 <typ.UInt32>
(Rsh32x32 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))
(Zeromask
(Rsh32Ux32 <typ.UInt32> s (Const32 <typ.UInt32> [5]))))))
-(Rsh64x16 (Int64Make hi lo) s) =>
+(Rsh64x16 x s) =>
(Int64Make
- (Rsh32x16 <typ.UInt32> hi s)
+ (Rsh32x16 <typ.UInt32> (Int64Hi x) s)
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Rsh32Ux16 <typ.UInt32> lo s)
+ (Rsh32Ux16 <typ.UInt32> (Int64Lo x) s)
(Lsh32x16 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s)))
(And32 <typ.UInt32>
(Rsh32x16 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))
(Zeromask
(ZeroExt16to32
(Rsh16Ux32 <typ.UInt16> s (Const32 <typ.UInt32> [5])))))))
-(Rsh64x8 (Int64Make hi lo) s) =>
+(Rsh64x8 x s) =>
(Int64Make
- (Rsh32x8 <typ.UInt32> hi s)
+ (Rsh32x8 <typ.UInt32> (Int64Hi x) s)
(Or32 <typ.UInt32>
(Or32 <typ.UInt32>
- (Rsh32Ux8 <typ.UInt32> lo s)
+ (Rsh32Ux8 <typ.UInt32> (Int64Lo x) s)
(Lsh32x8 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s)))
(And32 <typ.UInt32>
(Rsh32x8 <typ.UInt32>
- hi
+ (Int64Hi x)
(Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))
(Zeromask
(ZeroExt8to32
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index 39f8cc8889..4351ef5bdd 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -1961,6 +1961,31 @@
&& warnRule(fe.Debug_checknil(), v, "removed nil check")
=> (Invalid)
+// for late-expanded calls
+(Zero (SelectN [0] call:(StaticLECall _ _)) mem:(SelectN [1] call))
+ && isSameCall(call.Aux, "runtime.newobject")
+ => mem
+
+(Store (SelectN [0] call:(StaticLECall _ _)) x mem:(SelectN [1] call))
+ && isConstZero(x)
+ && isSameCall(call.Aux, "runtime.newobject")
+ => mem
+
+(Store (OffPtr (SelectN [0] call:(StaticLECall _ _))) x mem:(SelectN [1] call))
+ && isConstZero(x)
+ && isSameCall(call.Aux, "runtime.newobject")
+ => mem
+
+(NilCheck (SelectN [0] call:(StaticLECall _ _)) (SelectN [1] call))
+ && isSameCall(call.Aux, "runtime.newobject")
+ && warnRule(fe.Debug_checknil(), v, "removed nil check")
+ => (Invalid)
+
+(NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) (SelectN [1] call))
+ && isSameCall(call.Aux, "runtime.newobject")
+ && warnRule(fe.Debug_checknil(), v, "removed nil check")
+ => (Invalid)
+
// Evaluate constant address comparisons.
(EqPtr x x) => (ConstBool [true])
(NeqPtr x x) => (ConstBool [false])
@@ -2017,6 +2042,17 @@
&& clobber(s1, s2, s3)
=> (Move {t.Elem()} [int64(sz)] dst src mem)
+// Inline small or disjoint runtime.memmove calls with constant length.
+// See the comment in op Move in genericOps.go for discussion of the type.
+(SelectN [0] call:(StaticLECall {sym} dst src (Const(64|32) [sz]) mem))
+ && sz >= 0
+ && call.Uses == 1 // this will exclude all calls with results
+ && isSameCall(sym, "runtime.memmove")
+ && dst.Type.IsPtr() // avoids TUINTPTR, see issue 30061
+ && isInlinableMemmove(dst, src, int64(sz), config)
+ && clobber(call)
+ => (Move {dst.Type.Elem()} [int64(sz)] dst src mem)
+
// De-virtualize interface calls into static calls.
// Note that (ITab (IMake)) doesn't get
// rewritten until after the first opt pass,
@@ -2024,6 +2060,13 @@
(InterCall [argsize] {auxCall} (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) mem) && devirt(v, auxCall, itab, off) != nil =>
(StaticCall [int32(argsize)] {devirt(v, auxCall, itab, off)} mem)
+// De-virtualize late-expanded interface calls into late-expanded static calls.
+// Note that (ITab (IMake)) doesn't get rewritten until after the first opt pass,
+// so this rule should trigger reliably.
+// devirtLECall removes the first argument, adds the devirtualized symbol to the AuxCall, and changes the opcode
+(InterLECall [argsize] {auxCall} (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) ___) && devirtLESym(v, auxCall, itab, off) !=
+ nil => devirtLECall(v, devirtLESym(v, auxCall, itab, off))
+
// Move and Zero optimizations.
// Move source and destination may overlap.
@@ -2404,6 +2447,7 @@
(Store {t5} (OffPtr <tt5> [o5] dst) d4
(Zero {t1} [n] dst mem)))))
+// TODO this does not fire before call expansion; is that acceptable?
(StaticCall {sym} x) && needRaceCleanup(sym, v) => x
// Collapse moving A -> B -> C into just A -> C.
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index 95edff4c8c..23bd4af2cd 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -389,10 +389,12 @@ var genericOps = []opData{
// TODO(josharian): ClosureCall and InterCall should have Int32 aux
// to match StaticCall's 32 bit arg size limit.
// TODO(drchase,josharian): could the arg size limit be bundled into the rules for CallOff?
- {name: "ClosureCall", argLength: 3, aux: "CallOff", call: true}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory.
- {name: "StaticCall", argLength: 1, aux: "CallOff", call: true}, // call function aux.(*obj.LSym), arg0=memory. auxint=arg size. Returns memory.
- {name: "InterCall", argLength: 2, aux: "CallOff", call: true}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory.
- {name: "StaticLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded static call function aux.(*ssa.AuxCall.Fn). arg0..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem.
+ {name: "ClosureCall", argLength: 3, aux: "CallOff", call: true}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory.
+ {name: "StaticCall", argLength: 1, aux: "CallOff", call: true}, // call function aux.(*obj.LSym), arg0=memory. auxint=arg size. Returns memory.
+ {name: "InterCall", argLength: 2, aux: "CallOff", call: true}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory.
+ {name: "ClosureLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded closure call. arg0=code pointer, arg1=context ptr, arg2..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem.
+ {name: "StaticLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded static call function aux.(*ssa.AuxCall.Fn). arg0..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem.
+ {name: "InterLECall", argLength: -1, aux: "CallOff", call: true}, // late-expanded interface call. arg0=code pointer, arg1..argN-1 are inputs, argN is mem. auxint = arg size. Result is tuple of result(s), plus mem.
// Conversions: signed extensions, zero (unsigned) extensions, truncations
{name: "SignExt8to16", argLength: 1, typ: "Int16"},
@@ -539,20 +541,22 @@ var genericOps = []opData{
{name: "SelectN", argLength: 1, aux: "Int64"}, // arg0=tuple, auxint=field index. Returns the auxint'th member.
{name: "SelectNAddr", argLength: 1, aux: "Int64"}, // arg0=tuple, auxint=field index. Returns the address of auxint'th member. Used for un-SSA-able result types.
- // Atomic operations used for semantically inlining runtime/internal/atomic.
- // Atomic loads return a new memory so that the loads are properly ordered
- // with respect to other loads and stores.
- // TODO: use for sync/atomic at some point.
+ // Atomic operations used for semantically inlining sync/atomic and
+ // runtime/internal/atomic. Atomic loads return a new memory so that
+ // the loads are properly ordered with respect to other loads and
+ // stores.
{name: "AtomicLoad8", argLength: 2, typ: "(UInt8,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
{name: "AtomicLoad32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
{name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
{name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
{name: "AtomicLoadAcq32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Lock acquisition, returns loaded value and new memory.
+ {name: "AtomicLoadAcq64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Lock acquisition, returns loaded value and new memory.
{name: "AtomicStore8", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStore32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStore64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStoreRel32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Lock release, returns memory.
+ {name: "AtomicStoreRel64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Lock release, returns memory.
{name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
{name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
{name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
@@ -561,7 +565,9 @@ var genericOps = []opData{
{name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Returns true if store happens and new memory.
{name: "AtomicCompareAndSwapRel32", argLength: 4, typ: "(Bool,Mem)", hasSideEffects: true}, // if *arg0==arg1, then set *arg0=arg2. Lock release, reports whether store happens and new memory.
{name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory.
+ {name: "AtomicAnd32", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory.
{name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.
+ {name: "AtomicOr32", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.
// Atomic operation variants
// These variants have the same semantics as above atomic operations.
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
index be51a7c5f8..120ccbbdb3 100644
--- a/src/cmd/compile/internal/ssa/gen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -35,8 +35,7 @@ import (
)
// rule syntax:
-// sexpr [&& extra conditions] -> [@block] sexpr (untyped)
-// sexpr [&& extra conditions] => [@block] sexpr (typed)
+// sexpr [&& extra conditions] => [@block] sexpr
//
// sexpr are s-expressions (lisp-like parenthesized groupings)
// sexpr ::= [variable:](opcode sexpr*)
@@ -50,8 +49,12 @@ import (
// variable ::= some token
// opcode ::= one of the opcodes from the *Ops.go files
+// special rules: trailing ellipsis "..." (in the outermost sexpr?) must match on both sides of a rule.
+// trailing three underscore "___" in the outermost match sexpr indicate the presence of
+// extra ignored args that need not appear in the replacement
+
// extra conditions is just a chunk of Go that evaluates to a boolean. It may use
-// variables declared in the matching sexpr. The variable "v" is predefined to be
+// variables declared in the matching tsexpr. The variable "v" is predefined to be
// the value matched by the entire rule.
// If multiple rules match, the first one in file order is selected.
@@ -75,14 +78,8 @@ func normalizeSpaces(s string) string {
}
// parse returns the matching part of the rule, additional conditions, and the result.
-// parse also reports whether the generated code should use strongly typed aux and auxint fields.
-func (r Rule) parse() (match, cond, result string, typed bool) {
- arrow := "->"
- if strings.Contains(r.Rule, "=>") {
- arrow = "=>"
- typed = true
- }
- s := strings.Split(r.Rule, arrow)
+func (r Rule) parse() (match, cond, result string) {
+ s := strings.Split(r.Rule, "=>")
match = normalizeSpaces(s[0])
result = normalizeSpaces(s[1])
cond = ""
@@ -90,7 +87,7 @@ func (r Rule) parse() (match, cond, result string, typed bool) {
cond = normalizeSpaces(match[i+2:])
match = normalizeSpaces(match[:i])
}
- return match, cond, result, typed
+ return match, cond, result
}
func genRules(arch arch) { genRulesSuffix(arch, "") }
@@ -116,7 +113,7 @@ func genRulesSuffix(arch arch, suff string) {
scanner := bufio.NewScanner(text)
rule := ""
var lineno int
- var ruleLineno int // line number of "->" or "=>"
+ var ruleLineno int // line number of "=>"
for scanner.Scan() {
lineno++
line := scanner.Text()
@@ -130,13 +127,13 @@ func genRulesSuffix(arch arch, suff string) {
if rule == "" {
continue
}
- if !strings.Contains(rule, "->") && !strings.Contains(rule, "=>") {
+ if !strings.Contains(rule, "=>") {
continue
}
if ruleLineno == 0 {
ruleLineno = lineno
}
- if strings.HasSuffix(rule, "->") || strings.HasSuffix(rule, "=>") {
+ if strings.HasSuffix(rule, "=>") {
continue // continue on the next line
}
if n := balance(rule); n > 0 {
@@ -153,7 +150,7 @@ func genRulesSuffix(arch arch, suff string) {
continue
}
// Do fancier value op matching.
- match, _, _, _ := r.parse()
+ match, _, _ := r.parse()
op, oparch, _, _, _, _ := parseValue(match, arch, loc)
opname := fmt.Sprintf("Op%s%s", oparch, op.name)
oprules[opname] = append(oprules[opname], r)
@@ -227,7 +224,7 @@ func genRulesSuffix(arch arch, suff string) {
log.Fatalf("unconditional rule %s is followed by other rules", rr.Match)
}
rr = &RuleRewrite{Loc: rule.Loc}
- rr.Match, rr.Cond, rr.Result, rr.Typed = rule.parse()
+ rr.Match, rr.Cond, rr.Result = rule.parse()
pos, _ := genMatch(rr, arch, rr.Match, fn.ArgLen >= 0)
if pos == "" {
pos = "v.Pos"
@@ -786,7 +783,6 @@ type (
Alloc int // for unique var names
Loc string // file name & line number of the original rule
CommuteDepth int // used to track depth of commute loops
- Typed bool // aux and auxint fields should be strongly typed
}
Declare struct {
Name string
@@ -840,7 +836,7 @@ func breakf(format string, a ...interface{}) *CondBreak {
func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
rr := &RuleRewrite{Loc: rule.Loc}
- rr.Match, rr.Cond, rr.Result, rr.Typed = rule.parse()
+ rr.Match, rr.Cond, rr.Result = rule.parse()
_, _, auxint, aux, s := extract(rr.Match) // remove parens, then split
// check match of control values
@@ -884,15 +880,6 @@ func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
if e.name == "" {
continue
}
- if !rr.Typed {
- if !token.IsIdentifier(e.name) || rr.declared(e.name) {
- // code or variable
- rr.add(breakf("b.%s != %s", e.field, e.name))
- } else {
- rr.add(declf(e.name, "b.%s", e.field))
- }
- continue
- }
if e.dclType == "" {
log.Fatalf("op %s has no declared type for %s", data.name, e.field)
@@ -961,20 +948,12 @@ func genBlockRewrite(rule Rule, arch arch, data blockData) *RuleRewrite {
}
if auxint != "" {
- if rr.Typed {
- // Make sure auxint value has the right type.
- rr.add(stmtf("b.AuxInt = %sToAuxInt(%s)", unTitle(outdata.auxIntType()), auxint))
- } else {
- rr.add(stmtf("b.AuxInt = %s", auxint))
- }
+ // Make sure auxint value has the right type.
+ rr.add(stmtf("b.AuxInt = %sToAuxInt(%s)", unTitle(outdata.auxIntType()), auxint))
}
if aux != "" {
- if rr.Typed {
- // Make sure aux value has the right type.
- rr.add(stmtf("b.Aux = %sToAux(%s)", unTitle(outdata.auxType()), aux))
- } else {
- rr.add(stmtf("b.Aux = %s", aux))
- }
+ // Make sure aux value has the right type.
+ rr.add(stmtf("b.Aux = %sToAux(%s)", unTitle(outdata.auxType()), aux))
}
succChanged := false
@@ -1019,6 +998,19 @@ func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int,
pos = v + ".Pos"
}
+ // If the last argument is ___, it means "don't care about trailing arguments, really"
+ // The likely/intended use is for rewrites that are too tricky to express in the existing pattern language
+ // Do a length check early because long patterns fed short (ultimately not-matching) inputs will
+ // do an indexing error in pattern-matching.
+ if op.argLength == -1 {
+ l := len(args)
+ if l == 0 || args[l-1] != "___" {
+ rr.add(breakf("len(%s.Args) != %d", v, l))
+ } else if l > 1 && args[l-1] == "___" {
+ rr.add(breakf("len(%s.Args) < %d", v, l-1))
+ }
+ }
+
for _, e := range []struct {
name, field, dclType string
}{
@@ -1029,15 +1021,6 @@ func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int,
if e.name == "" {
continue
}
- if !rr.Typed {
- if !token.IsIdentifier(e.name) || rr.declared(e.name) {
- // code or variable
- rr.add(breakf("%s.%s != %s", v, e.field, e.name))
- } else {
- rr.add(declf(e.name, "%s.%s", v, e.field))
- }
- continue
- }
if e.dclType == "" {
log.Fatalf("op %s has no declared type for %s", op.name, e.field)
@@ -1159,9 +1142,6 @@ func genMatch0(rr *RuleRewrite, arch arch, match, v string, cnt map[string]int,
}
}
- if op.argLength == -1 {
- rr.add(breakf("len(%s.Args) != %d", v, len(args)))
- }
return pos, checkOp
}
@@ -1230,20 +1210,12 @@ func genResult0(rr *RuleRewrite, arch arch, result string, top, move bool, pos s
}
if auxint != "" {
- if rr.Typed {
- // Make sure auxint value has the right type.
- rr.add(stmtf("%s.AuxInt = %sToAuxInt(%s)", v, unTitle(op.auxIntType()), auxint))
- } else {
- rr.add(stmtf("%s.AuxInt = %s", v, auxint))
- }
+ // Make sure auxint value has the right type.
+ rr.add(stmtf("%s.AuxInt = %sToAuxInt(%s)", v, unTitle(op.auxIntType()), auxint))
}
if aux != "" {
- if rr.Typed {
- // Make sure aux value has the right type.
- rr.add(stmtf("%s.Aux = %sToAux(%s)", v, unTitle(op.auxType()), aux))
- } else {
- rr.add(stmtf("%s.Aux = %s", v, aux))
- }
+ // Make sure aux value has the right type.
+ rr.add(stmtf("%s.Aux = %sToAux(%s)", v, unTitle(op.auxType()), aux))
}
all := new(strings.Builder)
for i, arg := range args {
@@ -1524,7 +1496,7 @@ func excludeFromExpansion(s string, idx []int) bool {
return true
}
right := s[idx[1]:]
- if strings.Contains(left, "&&") && (strings.Contains(right, "->") || strings.Contains(right, "=>")) {
+ if strings.Contains(left, "&&") && strings.Contains(right, "=>") {
// Inside && conditions.
return true
}
@@ -1626,7 +1598,6 @@ func normalizeWhitespace(x string) string {
x = strings.Replace(x, " )", ")", -1)
x = strings.Replace(x, "[ ", "[", -1)
x = strings.Replace(x, " ]", "]", -1)
- x = strings.Replace(x, ")->", ") ->", -1)
x = strings.Replace(x, ")=>", ") =>", -1)
return x
}
@@ -1683,7 +1654,7 @@ func parseEllipsisRules(rules []Rule, arch arch) (newop string, ok bool) {
return "", false
}
rule := rules[0]
- match, cond, result, _ := rule.parse()
+ match, cond, result := rule.parse()
if cond != "" || !isEllipsisValue(match) || !isEllipsisValue(result) {
if strings.Contains(rule.Rule, "...") {
log.Fatalf("%s: found ellipsis in non-ellipsis rule", rule.Loc)
@@ -1708,7 +1679,7 @@ func isEllipsisValue(s string) bool {
}
func checkEllipsisRuleCandidate(rule Rule, arch arch) {
- match, cond, result, _ := rule.parse()
+ match, cond, result := rule.parse()
if cond != "" {
return
}
@@ -1718,7 +1689,7 @@ func checkEllipsisRuleCandidate(rule Rule, arch arch) {
var usingCopy string
var eop opData
if result[0] != '(' {
- // Check for (Foo x) -> x, which can be converted to (Foo ...) -> (Copy ...).
+ // Check for (Foo x) => x, which can be converted to (Foo ...) => (Copy ...).
args2 = []string{result}
usingCopy = " using Copy"
} else {
diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go
index c781ca92cc..a9d52fa4ee 100644
--- a/src/cmd/compile/internal/ssa/html.go
+++ b/src/cmd/compile/internal/ssa/html.go
@@ -28,18 +28,23 @@ type HTMLWriter struct {
}
func NewHTMLWriter(path string, f *Func, cfgMask string) *HTMLWriter {
+ path = strings.Replace(path, "/", string(filepath.Separator), -1)
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
f.Fatalf("%v", err)
}
- pwd, err := os.Getwd()
- if err != nil {
- f.Fatalf("%v", err)
+ reportPath := path
+ if !filepath.IsAbs(reportPath) {
+ pwd, err := os.Getwd()
+ if err != nil {
+ f.Fatalf("%v", err)
+ }
+ reportPath = filepath.Join(pwd, path)
}
html := HTMLWriter{
w: out,
Func: f,
- path: filepath.Join(pwd, path),
+ path: reportPath,
dot: newDotWriter(cfgMask),
}
html.start()
diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
index 9b45dd53c7..6f029a421e 100644
--- a/src/cmd/compile/internal/ssa/op.go
+++ b/src/cmd/compile/internal/ssa/op.go
@@ -127,6 +127,17 @@ func (a *AuxCall) NResults() int64 {
return int64(len(a.results))
}
+// LateExpansionResultType returns the result type (including trailing mem)
+// for a call that will be expanded later in the SSA phase.
+func (a *AuxCall) LateExpansionResultType() *types.Type {
+ var tys []*types.Type
+ for i := int64(0); i < a.NResults(); i++ {
+ tys = append(tys, a.TypeOfResult(i))
+ }
+ tys = append(tys, types.TypeMem)
+ return types.NewResults(tys)
+}
+
// NArgs returns the number of arguments
func (a *AuxCall) NArgs() int64 {
return int64(len(a.args))
@@ -255,9 +266,6 @@ func (x ValAndOff) Val8() int8 { return int8(int64(x) >> 32) }
func (x ValAndOff) Off() int64 { return int64(int32(x)) }
func (x ValAndOff) Off32() int32 { return int32(x) }
-func (x ValAndOff) Int64() int64 {
- return int64(x)
-}
func (x ValAndOff) String() string {
return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
}
@@ -286,17 +294,9 @@ func validValAndOff(val, off int64) bool {
return true
}
-// makeValAndOff encodes a ValAndOff into an int64 suitable for storing in an AuxInt field.
-func makeValAndOff(val, off int64) int64 {
- if !validValAndOff(val, off) {
- panic("invalid makeValAndOff")
- }
- return ValAndOff(val<<32 + int64(uint32(off))).Int64()
-}
func makeValAndOff32(val, off int32) ValAndOff {
return ValAndOff(int64(val)<<32 + int64(uint32(off)))
}
-
func makeValAndOff64(val, off int64) ValAndOff {
if !validValAndOff(val, off) {
panic("invalid makeValAndOff64")
@@ -304,35 +304,26 @@ func makeValAndOff64(val, off int64) ValAndOff {
return ValAndOff(val<<32 + int64(uint32(off)))
}
-func (x ValAndOff) canAdd(off int64) bool {
- newoff := x.Off() + off
- return newoff == int64(int32(newoff))
-}
-
func (x ValAndOff) canAdd32(off int32) bool {
newoff := x.Off() + int64(off)
return newoff == int64(int32(newoff))
}
-
-func (x ValAndOff) add(off int64) int64 {
- if !x.canAdd(off) {
- panic("invalid ValAndOff.add")
- }
- return makeValAndOff(x.Val(), x.Off()+off)
+func (x ValAndOff) canAdd64(off int64) bool {
+ newoff := x.Off() + off
+ return newoff == int64(int32(newoff))
}
func (x ValAndOff) addOffset32(off int32) ValAndOff {
if !x.canAdd32(off) {
- panic("invalid ValAndOff.add")
+ panic("invalid ValAndOff.addOffset32")
}
- return ValAndOff(makeValAndOff(x.Val(), x.Off()+int64(off)))
+ return makeValAndOff64(x.Val(), x.Off()+int64(off))
}
-
func (x ValAndOff) addOffset64(off int64) ValAndOff {
- if !x.canAdd(off) {
- panic("invalid ValAndOff.add")
+ if !x.canAdd64(off) {
+ panic("invalid ValAndOff.addOffset64")
}
- return ValAndOff(makeValAndOff(x.Val(), x.Off()+off))
+ return makeValAndOff64(x.Val(), x.Off()+off)
}
// int128 is a type that stores a 128-bit constant.
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 1fe00c7026..96aa3adedd 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -536,7 +536,6 @@ const (
Op386FlagLT_UGT
Op386FlagGT_UGT
Op386FlagGT_ULT
- Op386FCHS
Op386MOVSSconst1
Op386MOVSDconst1
Op386MOVSSconst2
@@ -1035,7 +1034,9 @@ const (
OpAMD64CMPXCHGLlock
OpAMD64CMPXCHGQlock
OpAMD64ANDBlock
+ OpAMD64ANDLlock
OpAMD64ORBlock
+ OpAMD64ORLlock
OpARMADD
OpARMADDconst
@@ -1587,7 +1588,9 @@ const (
OpARM64LoweredAtomicCas64
OpARM64LoweredAtomicCas32
OpARM64LoweredAtomicAnd8
+ OpARM64LoweredAtomicAnd32
OpARM64LoweredAtomicOr8
+ OpARM64LoweredAtomicOr32
OpARM64LoweredWB
OpARM64LoweredPanicBoundsA
OpARM64LoweredPanicBoundsB
@@ -1833,6 +1836,8 @@ const (
OpPPC64FSUBS
OpPPC64MULLD
OpPPC64MULLW
+ OpPPC64MULLDconst
+ OpPPC64MULLWconst
OpPPC64MADDLD
OpPPC64MULHD
OpPPC64MULHW
@@ -1866,6 +1871,9 @@ const (
OpPPC64ROTLconst
OpPPC64ROTLWconst
OpPPC64EXTSWSLconst
+ OpPPC64RLWINM
+ OpPPC64RLWNM
+ OpPPC64RLWMI
OpPPC64CNTLZD
OpPPC64CNTLZW
OpPPC64CNTTZD
@@ -2021,7 +2029,9 @@ const (
OpPPC64LoweredAtomicCas64
OpPPC64LoweredAtomicCas32
OpPPC64LoweredAtomicAnd8
+ OpPPC64LoweredAtomicAnd32
OpPPC64LoweredAtomicOr8
+ OpPPC64LoweredAtomicOr32
OpPPC64LoweredWB
OpPPC64LoweredPanicBoundsA
OpPPC64LoweredPanicBoundsB
@@ -2070,6 +2080,14 @@ const (
OpRISCV64MOVHstorezero
OpRISCV64MOVWstorezero
OpRISCV64MOVDstorezero
+ OpRISCV64MOVBreg
+ OpRISCV64MOVHreg
+ OpRISCV64MOVWreg
+ OpRISCV64MOVDreg
+ OpRISCV64MOVBUreg
+ OpRISCV64MOVHUreg
+ OpRISCV64MOVWUreg
+ OpRISCV64MOVDnop
OpRISCV64SLL
OpRISCV64SRA
OpRISCV64SRL
@@ -2093,6 +2111,8 @@ const (
OpRISCV64CALLstatic
OpRISCV64CALLclosure
OpRISCV64CALLinter
+ OpRISCV64DUFFZERO
+ OpRISCV64DUFFCOPY
OpRISCV64LoweredZero
OpRISCV64LoweredMove
OpRISCV64LoweredAtomicLoad8
@@ -2367,8 +2387,10 @@ const (
OpS390XLAAG
OpS390XAddTupleFirst32
OpS390XAddTupleFirst64
- OpS390XLAOfloor
+ OpS390XLAN
OpS390XLANfloor
+ OpS390XLAO
+ OpS390XLAOfloor
OpS390XLoweredAtomicCas32
OpS390XLoweredAtomicCas64
OpS390XLoweredAtomicExchange32
@@ -2732,7 +2754,9 @@ const (
OpClosureCall
OpStaticCall
OpInterCall
+ OpClosureLECall
OpStaticLECall
+ OpInterLECall
OpSignExt8to16
OpSignExt8to32
OpSignExt8to64
@@ -2836,11 +2860,13 @@ const (
OpAtomicLoad64
OpAtomicLoadPtr
OpAtomicLoadAcq32
+ OpAtomicLoadAcq64
OpAtomicStore8
OpAtomicStore32
OpAtomicStore64
OpAtomicStorePtrNoWB
OpAtomicStoreRel32
+ OpAtomicStoreRel64
OpAtomicExchange32
OpAtomicExchange64
OpAtomicAdd32
@@ -2849,7 +2875,9 @@ const (
OpAtomicCompareAndSwap64
OpAtomicCompareAndSwapRel32
OpAtomicAnd8
+ OpAtomicAnd32
OpAtomicOr8
+ OpAtomicOr32
OpAtomicAdd32Variant
OpAtomicAdd64Variant
OpClobber
@@ -6059,18 +6087,6 @@ var opcodeTable = [...]opInfo{
reg: regInfo{},
},
{
- name: "FCHS",
- argLen: 1,
- reg: regInfo{
- inputs: []inputInfo{
- {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
- },
- outputs: []outputInfo{
- {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
- },
- },
- },
- {
name: "MOVSSconst1",
auxType: auxFloat32,
argLen: 0,
@@ -13583,6 +13599,22 @@ var opcodeTable = [...]opInfo{
},
},
{
+ name: "ANDLlock",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ symEffect: SymRdWr,
+ asm: x86.AANDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
name: "ORBlock",
auxType: auxSymOff,
argLen: 3,
@@ -13598,6 +13630,22 @@ var opcodeTable = [...]opInfo{
},
},
},
+ {
+ name: "ORLlock",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ symEffect: SymRdWr,
+ asm: x86.AORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
{
name: "ADD",
@@ -21068,6 +21116,24 @@ var opcodeTable = [...]opInfo{
},
},
{
+ name: "LoweredAtomicAnd32",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ unsafePoint: true,
+ asm: arm64.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+ },
+ },
+ },
+ {
name: "LoweredAtomicOr8",
argLen: 3,
resultNotInArgs: true,
@@ -21086,6 +21152,24 @@ var opcodeTable = [...]opInfo{
},
},
{
+ name: "LoweredAtomicOr32",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ unsafePoint: true,
+ asm: arm64.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+ },
+ },
+ },
+ {
name: "LoweredWB",
auxType: auxSym,
argLen: 3,
@@ -24389,6 +24473,34 @@ var opcodeTable = [...]opInfo{
},
},
{
+ name: "MULLDconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: ppc64.AMULLD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
+ {
+ name: "MULLWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: ppc64.AMULLW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
+ {
name: "MADDLD",
argLen: 3,
asm: ppc64.AMADDLD,
@@ -24865,6 +24977,51 @@ var opcodeTable = [...]opInfo{
},
},
{
+ name: "RLWINM",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ARLWNM,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
+ {
+ name: "RLWNM",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: ppc64.ARLWNM,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
+ {
+ name: "RLWMI",
+ auxType: auxInt64,
+ argLen: 2,
+ resultInArg0: true,
+ asm: ppc64.ARLWMI,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ outputs: []outputInfo{
+ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
+ {
name: "CNTLZD",
argLen: 1,
clobberFlags: true,
@@ -26928,6 +27085,19 @@ var opcodeTable = [...]opInfo{
},
},
{
+ name: "LoweredAtomicAnd32",
+ argLen: 3,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ asm: ppc64.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
+ {
name: "LoweredAtomicOr8",
argLen: 3,
faultOnNilArg0: true,
@@ -26941,6 +27111,19 @@ var opcodeTable = [...]opInfo{
},
},
{
+ name: "LoweredAtomicOr32",
+ argLen: 3,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ asm: ppc64.AOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29
+ },
+ },
+ },
+ {
name: "LoweredWB",
auxType: auxSym,
argLen: 3,
@@ -27018,11 +27201,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AADD,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27033,10 +27216,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AADDI,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27047,10 +27230,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AADDIW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27060,10 +27243,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ANEG,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27073,10 +27256,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ANEGW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27086,11 +27269,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASUB,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27100,11 +27283,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASUBW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27115,11 +27298,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMUL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27130,11 +27313,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMULW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27145,11 +27328,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMULH,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27160,11 +27343,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMULHU,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27174,11 +27357,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ADIV,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27188,11 +27371,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ADIVU,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27202,11 +27385,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ADIVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27216,11 +27399,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ADIVUW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27230,11 +27413,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AREM,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27244,11 +27427,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AREMU,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27258,11 +27441,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AREMW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27272,11 +27455,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AREMUW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27289,10 +27472,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27304,7 +27487,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27316,7 +27499,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27328,7 +27511,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27340,7 +27523,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27353,10 +27536,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVB,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27369,10 +27552,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVH,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27385,10 +27568,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27401,10 +27584,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27417,10 +27600,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVBU,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27433,10 +27616,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVHU,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27449,10 +27632,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVWU,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27465,8 +27648,8 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVB,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27479,8 +27662,8 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVH,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27493,8 +27676,8 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVW,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27507,8 +27690,8 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27521,7 +27704,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVB,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27534,7 +27717,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVH,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27547,7 +27730,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27560,7 +27743,111 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
+ },
+ },
+ },
+ {
+ name: "MOVBreg",
+ argLen: 1,
+ asm: riscv.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ outputs: []outputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ },
+ },
+ {
+ name: "MOVHreg",
+ argLen: 1,
+ asm: riscv.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ outputs: []outputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ },
+ },
+ {
+ name: "MOVWreg",
+ argLen: 1,
+ asm: riscv.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ outputs: []outputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ },
+ },
+ {
+ name: "MOVDreg",
+ argLen: 1,
+ asm: riscv.AMOV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ outputs: []outputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ },
+ },
+ {
+ name: "MOVBUreg",
+ argLen: 1,
+ asm: riscv.AMOVBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ outputs: []outputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ },
+ },
+ {
+ name: "MOVHUreg",
+ argLen: 1,
+ asm: riscv.AMOVHU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ outputs: []outputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ },
+ },
+ {
+ name: "MOVWUreg",
+ argLen: 1,
+ asm: riscv.AMOVWU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ outputs: []outputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ },
+ },
+ {
+ name: "MOVDnop",
+ argLen: 1,
+ resultInArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ },
+ outputs: []outputInfo{
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27570,11 +27857,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASLL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27584,11 +27871,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASRA,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27598,11 +27885,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASRL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27613,10 +27900,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASLLI,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27627,10 +27914,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASRAI,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27641,10 +27928,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASRLI,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27655,11 +27942,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AXOR,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27670,10 +27957,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AXORI,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27684,11 +27971,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AOR,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27699,10 +27986,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AORI,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27713,11 +28000,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.AAND,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27728,10 +28015,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AANDI,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27741,10 +28028,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ANOT,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27754,10 +28041,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASEQZ,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27767,10 +28054,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASNEZ,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27780,11 +28067,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASLT,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27795,10 +28082,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASLTI,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27808,11 +28095,11 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASLTU,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27823,10 +28110,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.ASLTIU,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27836,10 +28123,10 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOV,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27849,7 +28136,7 @@ var opcodeTable = [...]opInfo{
argLen: 1,
call: true,
reg: regInfo{
- clobbers: 9223372035781033980, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 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
+ clobbers: 9223372035781033972, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 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
},
},
{
@@ -27860,9 +28147,9 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{1, 524288}, // X20
- {0, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
- clobbers: 9223372035781033980, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 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
+ clobbers: 9223372035781033972, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 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
},
},
{
@@ -27872,9 +28159,35 @@ var opcodeTable = [...]opInfo{
call: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
- clobbers: 9223372035781033980, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 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
+ clobbers: 9223372035781033972, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 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
+ },
+ },
+ {
+ name: "DUFFZERO",
+ auxType: auxInt64,
+ argLen: 2,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 512}, // X10
+ },
+ clobbers: 512, // X10
+ },
+ },
+ {
+ name: "DUFFCOPY",
+ auxType: auxInt64,
+ argLen: 3,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1024}, // X11
+ {1, 512}, // X10
+ },
+ clobbers: 1536, // X10 X11
},
},
{
@@ -27885,7 +28198,7 @@ var opcodeTable = [...]opInfo{
reg: regInfo{
inputs: []inputInfo{
{0, 16}, // X5
- {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {1, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
clobbers: 16, // X5
},
@@ -27900,7 +28213,7 @@ var opcodeTable = [...]opInfo{
inputs: []inputInfo{
{0, 16}, // X5
{1, 32}, // X6
- {2, 1073741748}, // X3 X5 X6 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {2, 1006632884}, // X3 X5 X6 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
clobbers: 112, // X5 X6 X7
},
@@ -27911,10 +28224,10 @@ var opcodeTable = [...]opInfo{
faultOnNilArg0: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27924,10 +28237,10 @@ var opcodeTable = [...]opInfo{
faultOnNilArg0: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27937,10 +28250,10 @@ var opcodeTable = [...]opInfo{
faultOnNilArg0: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -27951,8 +28264,8 @@ var opcodeTable = [...]opInfo{
hasSideEffects: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27963,8 +28276,8 @@ var opcodeTable = [...]opInfo{
hasSideEffects: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27975,8 +28288,8 @@ var opcodeTable = [...]opInfo{
hasSideEffects: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
},
},
@@ -27988,11 +28301,11 @@ var opcodeTable = [...]opInfo{
hasSideEffects: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741820}, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517630}, // SP X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+ {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28004,11 +28317,11 @@ var opcodeTable = [...]opInfo{
hasSideEffects: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741820}, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517630}, // SP X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+ {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28021,11 +28334,11 @@ var opcodeTable = [...]opInfo{
unsafePoint: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741820}, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517630}, // SP X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+ {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28038,11 +28351,11 @@ var opcodeTable = [...]opInfo{
unsafePoint: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741820}, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517630}, // SP X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+ {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28055,12 +28368,12 @@ var opcodeTable = [...]opInfo{
unsafePoint: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741820}, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {2, 1073741820}, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517630}, // SP X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+ {2, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+ {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28073,12 +28386,12 @@ var opcodeTable = [...]opInfo{
unsafePoint: true,
reg: regInfo{
inputs: []inputInfo{
- {1, 1073741820}, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {2, 1073741820}, // X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
- {0, 9223372037928517630}, // SP X3 g X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {1, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+ {2, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30
+ {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 SB
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28089,7 +28402,7 @@ var opcodeTable = [...]opInfo{
faultOnNilArg0: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741814}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632950}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28108,7 +28421,7 @@ var opcodeTable = [...]opInfo{
rematerializeable: true,
reg: regInfo{
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28118,7 +28431,7 @@ var opcodeTable = [...]opInfo{
rematerializeable: true,
reg: regInfo{
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28262,7 +28575,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AFMVSX,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 9223372034707292160}, // 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
@@ -28275,7 +28588,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AFCVTSW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 9223372034707292160}, // 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
@@ -28288,7 +28601,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AFCVTSL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 9223372034707292160}, // 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
@@ -28304,7 +28617,7 @@ var opcodeTable = [...]opInfo{
{0, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28317,7 +28630,7 @@ var opcodeTable = [...]opInfo{
{0, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28330,7 +28643,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVF,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
{0, 9223372034707292160}, // 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
@@ -28346,7 +28659,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVF,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
{1, 9223372034707292160}, // 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
},
},
@@ -28362,7 +28675,7 @@ var opcodeTable = [...]opInfo{
{1, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28377,7 +28690,7 @@ var opcodeTable = [...]opInfo{
{1, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28391,7 +28704,7 @@ var opcodeTable = [...]opInfo{
{1, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28405,7 +28718,7 @@ var opcodeTable = [...]opInfo{
{1, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28499,7 +28812,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AFMVDX,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 9223372034707292160}, // 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
@@ -28512,7 +28825,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AFCVTDW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 9223372034707292160}, // 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
@@ -28525,7 +28838,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AFCVTDL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
outputs: []outputInfo{
{0, 9223372034707292160}, // 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
@@ -28541,7 +28854,7 @@ var opcodeTable = [...]opInfo{
{0, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28554,7 +28867,7 @@ var opcodeTable = [...]opInfo{
{0, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28593,7 +28906,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVD,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
},
outputs: []outputInfo{
{0, 9223372034707292160}, // 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
@@ -28609,7 +28922,7 @@ var opcodeTable = [...]opInfo{
asm: riscv.AMOVD,
reg: regInfo{
inputs: []inputInfo{
- {0, 9223372037928517622}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 SB
+ {0, 9223372037861408758}, // SP X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 SB
{1, 9223372034707292160}, // 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
},
},
@@ -28625,7 +28938,7 @@ var opcodeTable = [...]opInfo{
{1, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28640,7 +28953,7 @@ var opcodeTable = [...]opInfo{
{1, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28654,7 +28967,7 @@ var opcodeTable = [...]opInfo{
{1, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -28668,7 +28981,7 @@ var opcodeTable = [...]opInfo{
{1, 9223372034707292160}, // 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
},
outputs: []outputInfo{
- {0, 1073741812}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30
+ {0, 1006632948}, // X3 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30
},
},
},
@@ -31782,11 +32095,24 @@ var opcodeTable = [...]opInfo{
reg: regInfo{},
},
{
- name: "LAOfloor",
+ name: "LAN",
argLen: 3,
clobberFlags: true,
hasSideEffects: true,
- asm: s390x.ALAO,
+ asm: s390x.ALAN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295023614}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 SP SB
+ {1, 56319}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 SP
+ },
+ },
+ },
+ {
+ name: "LANfloor",
+ argLen: 3,
+ clobberFlags: true,
+ hasSideEffects: true,
+ asm: s390x.ALAN,
reg: regInfo{
inputs: []inputInfo{
{0, 2}, // R1
@@ -31796,11 +32122,24 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "LANfloor",
+ name: "LAO",
argLen: 3,
clobberFlags: true,
hasSideEffects: true,
- asm: s390x.ALAN,
+ asm: s390x.ALAO,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295023614}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 SP SB
+ {1, 56319}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 SP
+ },
+ },
+ },
+ {
+ name: "LAOfloor",
+ argLen: 3,
+ clobberFlags: true,
+ hasSideEffects: true,
+ asm: s390x.ALAO,
reg: regInfo{
inputs: []inputInfo{
{0, 2}, // R1
@@ -34852,6 +35191,13 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "ClosureLECall",
+ auxType: auxCallOff,
+ argLen: -1,
+ call: true,
+ generic: true,
+ },
+ {
name: "StaticLECall",
auxType: auxCallOff,
argLen: -1,
@@ -34859,6 +35205,13 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "InterLECall",
+ auxType: auxCallOff,
+ argLen: -1,
+ call: true,
+ generic: true,
+ },
+ {
name: "SignExt8to16",
argLen: 1,
generic: true,
@@ -35397,6 +35750,11 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "AtomicLoadAcq64",
+ argLen: 2,
+ generic: true,
+ },
+ {
name: "AtomicStore8",
argLen: 3,
hasSideEffects: true,
@@ -35427,6 +35785,12 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "AtomicStoreRel64",
+ argLen: 3,
+ hasSideEffects: true,
+ generic: true,
+ },
+ {
name: "AtomicExchange32",
argLen: 3,
hasSideEffects: true,
@@ -35475,12 +35839,24 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "AtomicAnd32",
+ argLen: 3,
+ hasSideEffects: true,
+ generic: true,
+ },
+ {
name: "AtomicOr8",
argLen: 3,
hasSideEffects: true,
generic: true,
},
{
+ name: "AtomicOr32",
+ argLen: 3,
+ hasSideEffects: true,
+ generic: true,
+ },
+ {
name: "AtomicAdd32Variant",
argLen: 3,
hasSideEffects: true,
@@ -35885,7 +36261,7 @@ var registersRISCV64 = [...]Register{
{0, riscv.REG_X0, -1, "X0"},
{1, riscv.REGSP, -1, "SP"},
{2, riscv.REG_X3, 0, "X3"},
- {3, riscv.REGG, -1, "g"},
+ {3, riscv.REG_X4, -1, "X4"},
{4, riscv.REG_X5, 1, "X5"},
{5, riscv.REG_X6, 2, "X6"},
{6, riscv.REG_X7, 3, "X7"},
@@ -35908,10 +36284,10 @@ var registersRISCV64 = [...]Register{
{23, riscv.REG_X24, 20, "X24"},
{24, riscv.REG_X25, 21, "X25"},
{25, riscv.REG_X26, 22, "X26"},
- {26, riscv.REG_X27, 23, "X27"},
- {27, riscv.REG_X28, 24, "X28"},
- {28, riscv.REG_X29, 25, "X29"},
- {29, riscv.REG_X30, 26, "X30"},
+ {26, riscv.REGG, -1, "g"},
+ {27, riscv.REG_X28, 23, "X28"},
+ {28, riscv.REG_X29, 24, "X29"},
+ {29, riscv.REG_X30, 25, "X30"},
{30, riscv.REG_X31, -1, "X31"},
{31, riscv.REG_F0, -1, "F0"},
{32, riscv.REG_F1, -1, "F1"},
@@ -35947,7 +36323,7 @@ var registersRISCV64 = [...]Register{
{62, riscv.REG_F31, -1, "F31"},
{63, 0, -1, "SB"},
}
-var gpRegMaskRISCV64 = regMask(1073741812)
+var gpRegMaskRISCV64 = regMask(1006632948)
var fpRegMaskRISCV64 = regMask(9223372034707292160)
var specialRegMaskRISCV64 = regMask(0)
var framepointerRegRISCV64 = int8(-1)
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
index 64c6aed3e7..0339b073ae 100644
--- a/src/cmd/compile/internal/ssa/regalloc.go
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -625,9 +625,6 @@ func (s *regAllocState) init(f *Func) {
s.f.fe.Fatalf(src.NoXPos, "arch %s not implemented", s.f.Config.arch)
}
}
- if s.f.Config.use387 {
- s.allocatable &^= 1 << 15 // X7 disallowed (one 387 register is used as scratch space during SSE->387 generation in ../x86/387.go)
- }
// Linear scan register allocation can be influenced by the order in which blocks appear.
// Decouple the register allocation order from the generated block order.
@@ -1015,8 +1012,8 @@ func (s *regAllocState) regalloc(f *Func) {
// Copy phi ops into new schedule.
b.Values = append(b.Values, phis...)
- // Third pass - pick registers for phis whose inputs
- // were not in a register.
+ // Third pass - pick registers for phis whose input
+ // was not in a register in the primary predecessor.
for i, v := range phis {
if !s.values[v.ID].needReg {
continue
@@ -1024,10 +1021,25 @@ func (s *regAllocState) regalloc(f *Func) {
if phiRegs[i] != noRegister {
continue
}
- if s.f.Config.use387 && v.Type.IsFloat() {
- continue // 387 can't handle floats in registers between blocks
- }
m := s.compatRegs(v.Type) &^ phiUsed &^ s.used
+ // If one of the other inputs of v is in a register, and the register is available,
+ // select this register, which can save some unnecessary copies.
+ for i, pe := range b.Preds {
+ if int32(i) == idx {
+ continue
+ }
+ ri := noRegister
+ for _, er := range s.endRegs[pe.b.ID] {
+ if er.v == s.orig[v.Args[i].ID] {
+ ri = er.r
+ break
+ }
+ }
+ if ri != noRegister && m>>ri&1 != 0 {
+ m = regMask(1) << ri
+ break
+ }
+ }
if m != 0 {
r := pickReg(m)
phiRegs[i] = r
@@ -1125,7 +1137,19 @@ func (s *regAllocState) regalloc(f *Func) {
}
rp, ok := s.f.getHome(v.ID).(*Register)
if !ok {
- continue
+ // If v is not assigned a register, pick a register assigned to one of v's inputs.
+ // Hopefully v will get assigned that register later.
+ // If the inputs have allocated register information, add it to desired,
+ // which may reduce spill or copy operations when the register is available.
+ for _, a := range v.Args {
+ rp, ok = s.f.getHome(a.ID).(*Register)
+ if ok {
+ break
+ }
+ }
+ if !ok {
+ continue
+ }
}
desired.add(v.Args[pidx].ID, register(rp.num))
}
@@ -1528,11 +1552,6 @@ func (s *regAllocState) regalloc(f *Func) {
s.freeUseRecords = u
}
- // Spill any values that can't live across basic block boundaries.
- if s.f.Config.use387 {
- s.freeRegs(s.f.Config.fpRegMask)
- }
-
// If we are approaching a merge point and we are the primary
// predecessor of it, find live values that we use soon after
// the merge point and promote them to registers now.
@@ -1562,10 +1581,20 @@ func (s *regAllocState) regalloc(f *Func) {
continue
}
v := s.orig[vid]
- if s.f.Config.use387 && v.Type.IsFloat() {
- continue // 387 can't handle floats in registers between blocks
- }
m := s.compatRegs(v.Type) &^ s.used
+ // Used desired register if available.
+ outerloop:
+ for _, e := range desired.entries {
+ if e.ID != v.ID {
+ continue
+ }
+ for _, r := range e.regs {
+ if r != noRegister && m>>r&1 != 0 {
+ m = regMask(1) << r
+ break outerloop
+ }
+ }
+ }
if m&^desired.avoid != 0 {
m &^= desired.avoid
}
@@ -1627,7 +1656,9 @@ func (s *regAllocState) regalloc(f *Func) {
// we'll rematerialize during the merge.
continue
}
- //fmt.Printf("live-at-end spill for %s at %s\n", s.orig[e.ID], b)
+ if s.f.pass.debug > regDebug {
+ fmt.Printf("live-at-end spill for %s at %s\n", s.orig[e.ID], b)
+ }
spill := s.makeSpill(s.orig[e.ID], b)
s.spillLive[b.ID] = append(s.spillLive[b.ID], spill.ID)
}
@@ -2498,7 +2529,7 @@ func (s *regAllocState) computeLive() {
for _, b := range f.Blocks {
fmt.Printf(" %s:", b)
for _, x := range s.live[b.ID] {
- fmt.Printf(" v%d", x.ID)
+ fmt.Printf(" v%d(%d)", x.ID, x.dist)
for _, e := range s.desired[b.ID].entries {
if e.ID != x.ID {
continue
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index d9c3e455a0..ab6d020942 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -395,7 +395,8 @@ func canMergeLoad(target, load *Value) bool {
// isSameCall reports whether sym is the same as the given named symbol
func isSameCall(sym interface{}, name string) bool {
- return sym.(*AuxCall).Fn.String() == name
+ fn := sym.(*AuxCall).Fn
+ return fn != nil && fn.String() == name
}
// nlz returns the number of leading zeros.
@@ -448,10 +449,7 @@ func log2uint32(n int64) int64 {
return int64(bits.Len32(uint32(n))) - 1
}
-// isPowerOfTwo reports whether n is a power of 2.
-func isPowerOfTwo(n int64) bool {
- return n > 0 && n&(n-1) == 0
-}
+// isPowerOfTwo functions report whether n is a power of 2.
func isPowerOfTwo8(n int8) bool {
return n > 0 && n&(n-1) == 0
}
@@ -764,6 +762,36 @@ func devirt(v *Value, aux interface{}, sym Sym, offset int64) *AuxCall {
return StaticAuxCall(lsym, va.args, va.results)
}
+// de-virtualize an InterLECall
+// 'sym' is the symbol for the itab
+func devirtLESym(v *Value, aux interface{}, sym Sym, offset int64) *obj.LSym {
+ n, ok := sym.(*obj.LSym)
+ if !ok {
+ return nil
+ }
+
+ f := v.Block.Func
+ lsym := f.fe.DerefItab(n, offset)
+ if f.pass.debug > 0 {
+ if lsym != nil {
+ f.Warnl(v.Pos, "de-virtualizing call")
+ } else {
+ f.Warnl(v.Pos, "couldn't de-virtualize call")
+ }
+ }
+ if lsym == nil {
+ return nil
+ }
+ return lsym
+}
+
+func devirtLECall(v *Value, sym *obj.LSym) *Value {
+ v.Op = OpStaticLECall
+ v.Aux.(*AuxCall).Fn = sym
+ v.RemoveArg(0)
+ return v
+}
+
// isSamePtr reports whether p1 and p2 point to the same address.
func isSamePtr(p1, p2 *Value) bool {
if p1 == p2 {
@@ -1350,8 +1378,73 @@ func GetPPC64Shiftme(auxint int64) int64 {
return int64(int8(auxint))
}
-// Catch the simple ones first
-// TODO: Later catch more cases
+// Test if this value can encoded as a mask for a rlwinm like
+// operation. Masks can also extend from the msb and wrap to
+// the lsb too. That is, the valid masks are 32 bit strings
+// of the form: 0..01..10..0 or 1..10..01..1 or 1...1
+func isPPC64WordRotateMask(v64 int64) bool {
+ // Isolate rightmost 1 (if none 0) and add.
+ v := uint32(v64)
+ vp := (v & -v) + v
+ // Likewise, for the wrapping case.
+ vn := ^v
+ vpn := (vn & -vn) + vn
+ return (v&vp == 0 || vn&vpn == 0) && v != 0
+}
+
+// Compress mask and and shift into single value of the form
+// me | mb<<8 | rotate<<16 | nbits<<24 where me and mb can
+// be used to regenerate the input mask.
+func encodePPC64RotateMask(rotate, mask, nbits int64) int64 {
+ var mb, me, mbn, men int
+
+ // Determine boundaries and then decode them
+ if mask == 0 || ^mask == 0 || rotate >= nbits {
+ panic("Invalid PPC64 rotate mask")
+ } else if nbits == 32 {
+ mb = bits.LeadingZeros32(uint32(mask))
+ me = 32 - bits.TrailingZeros32(uint32(mask))
+ mbn = bits.LeadingZeros32(^uint32(mask))
+ men = 32 - bits.TrailingZeros32(^uint32(mask))
+ } else {
+ mb = bits.LeadingZeros64(uint64(mask))
+ me = 64 - bits.TrailingZeros64(uint64(mask))
+ mbn = bits.LeadingZeros64(^uint64(mask))
+ men = 64 - bits.TrailingZeros64(^uint64(mask))
+ }
+ // Check for a wrapping mask (e.g bits at 0 and 63)
+ if mb == 0 && me == int(nbits) {
+ // swap the inverted values
+ mb, me = men, mbn
+ }
+
+ return int64(me) | int64(mb<<8) | int64(rotate<<16) | int64(nbits<<24)
+}
+
+// The inverse operation of encodePPC64RotateMask. The values returned as
+// mb and me satisfy the POWER ISA definition of MASK(x,y) where MASK(mb,me) = mask.
+func DecodePPC64RotateMask(sauxint int64) (rotate, mb, me int64, mask uint64) {
+ auxint := uint64(sauxint)
+ rotate = int64((auxint >> 16) & 0xFF)
+ mb = int64((auxint >> 8) & 0xFF)
+ me = int64((auxint >> 0) & 0xFF)
+ nbits := int64((auxint >> 24) & 0xFF)
+ mask = ((1 << uint(nbits-mb)) - 1) ^ ((1 << uint(nbits-me)) - 1)
+ if mb > me {
+ mask = ^mask
+ }
+ if nbits == 32 {
+ mask = uint64(uint32(mask))
+ }
+
+ // Fixup ME to match ISA definition. The second argument to MASK(..,me)
+ // is inclusive.
+ me = (me - 1) & (nbits - 1)
+ return
+}
+
+// This verifies that the mask occupies the
+// rightmost bits.
func isPPC64ValidShiftMask(v int64) bool {
if ((v + 1) & v) == 0 {
return true
@@ -1363,6 +1456,78 @@ func getPPC64ShiftMaskLength(v int64) int64 {
return int64(bits.Len64(uint64(v)))
}
+// Decompose a shift right into an equivalent rotate/mask,
+// and return mask & m.
+func mergePPC64RShiftMask(m, s, nbits int64) int64 {
+ smask := uint64((1<<uint(nbits))-1) >> uint(s)
+ return m & int64(smask)
+}
+
+// Combine (ANDconst [m] (SRWconst [s])) into (RLWINM [y]) or return 0
+func mergePPC64AndSrwi(m, s int64) int64 {
+ mask := mergePPC64RShiftMask(m, s, 32)
+ if !isPPC64WordRotateMask(mask) {
+ return 0
+ }
+ return encodePPC64RotateMask(32-s, mask, 32)
+}
+
+// Test if a shift right feeding into a CLRLSLDI can be merged into RLWINM.
+// Return the encoded RLWINM constant, or 0 if they cannot be merged.
+func mergePPC64ClrlsldiSrw(sld, srw int64) int64 {
+ mask_1 := uint64(0xFFFFFFFF >> uint(srw))
+ // for CLRLSLDI, it's more convient to think of it as a mask left bits then rotate left.
+ mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))
+
+ // Rewrite mask to apply after the final left shift.
+ mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(sld))
+
+ r_1 := 32 - srw
+ r_2 := GetPPC64Shiftsh(sld)
+ r_3 := (r_1 + r_2) & 31 // This can wrap.
+
+ if uint64(uint32(mask_3)) != mask_3 || mask_3 == 0 {
+ return 0
+ }
+ return encodePPC64RotateMask(int64(r_3), int64(mask_3), 32)
+}
+
+// Test if a RLWINM feeding into a CLRLSLDI can be merged into RLWINM. Return
+// the encoded RLWINM constant, or 0 if they cannot be merged.
+func mergePPC64ClrlsldiRlwinm(sld int32, rlw int64) int64 {
+ r_1, _, _, mask_1 := DecodePPC64RotateMask(rlw)
+ // for CLRLSLDI, it's more convient to think of it as a mask left bits then rotate left.
+ mask_2 := uint64(0xFFFFFFFFFFFFFFFF) >> uint(GetPPC64Shiftmb(int64(sld)))
+
+ // combine the masks, and adjust for the final left shift.
+ mask_3 := (mask_1 & mask_2) << uint(GetPPC64Shiftsh(int64(sld)))
+ r_2 := GetPPC64Shiftsh(int64(sld))
+ r_3 := (r_1 + r_2) & 31 // This can wrap.
+
+ // Verify the result is still a valid bitmask of <= 32 bits.
+ if !isPPC64WordRotateMask(int64(mask_3)) || uint64(uint32(mask_3)) != mask_3 {
+ return 0
+ }
+ return encodePPC64RotateMask(r_3, int64(mask_3), 32)
+}
+
+// Compute the encoded RLWINM constant from combining (SLDconst [sld] (SRWconst [srw] x)),
+// or return 0 if they cannot be combined.
+func mergePPC64SldiSrw(sld, srw int64) int64 {
+ if sld > srw || srw >= 32 {
+ return 0
+ }
+ mask_r := uint32(0xFFFFFFFF) >> uint(srw)
+ mask_l := uint32(0xFFFFFFFF) >> uint(sld)
+ mask := (mask_r & mask_l) << uint(sld)
+ return encodePPC64RotateMask((32-srw+sld)&31, int64(mask), 32)
+}
+
+// Convenience function to rotate a 32 bit constant value by another constant.
+func rotateLeft32(v, rotate int64) int64 {
+ return int64(bits.RotateLeft32(uint32(v), int(rotate)))
+}
+
// encodes the lsb and width for arm(64) bitfield ops into the expected auxInt format.
func armBFAuxInt(lsb, width int64) arm64BitField {
if lsb < 0 || lsb > 63 {
@@ -1387,7 +1552,7 @@ func (bfc arm64BitField) getARM64BFwidth() int64 {
// checks if mask >> rshift applied at lsb is a valid arm64 bitfield op mask.
func isARM64BFMask(lsb, mask, rshift int64) bool {
shiftedMask := int64(uint64(mask) >> uint64(rshift))
- return shiftedMask != 0 && isPowerOfTwo(shiftedMask+1) && nto(shiftedMask)+lsb < 64
+ return shiftedMask != 0 && isPowerOfTwo64(shiftedMask+1) && nto(shiftedMask)+lsb < 64
}
// returns the bitfield width of mask >> rshift for arm64 bitfield ops
diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go
index fc1e0541b2..afce14fa76 100644
--- a/src/cmd/compile/internal/ssa/rewrite386.go
+++ b/src/cmd/compile/internal/ssa/rewrite386.go
@@ -1310,10 +1310,8 @@ func rewriteValue386_Op386ADDLmodify(v *Value) bool {
func rewriteValue386_Op386ADDSD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- b := v.Block
- config := b.Func.Config
// match: (ADDSD x l:(MOVSDload [off] {sym} ptr mem))
- // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
+ // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ADDSDload x [off] {sym} ptr mem)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -1326,7 +1324,7 @@ func rewriteValue386_Op386ADDSD(v *Value) bool {
sym := auxToSym(l.Aux)
mem := l.Args[1]
ptr := l.Args[0]
- if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
+ if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
continue
}
v.reset(Op386ADDSDload)
@@ -1395,10 +1393,8 @@ func rewriteValue386_Op386ADDSDload(v *Value) bool {
func rewriteValue386_Op386ADDSS(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- b := v.Block
- config := b.Func.Config
// match: (ADDSS x l:(MOVSSload [off] {sym} ptr mem))
- // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
+ // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (ADDSSload x [off] {sym} ptr mem)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -1411,7 +1407,7 @@ func rewriteValue386_Op386ADDSS(v *Value) bool {
sym := auxToSym(l.Aux)
mem := l.Args[1]
ptr := l.Args[0]
- if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
+ if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
continue
}
v.reset(Op386ADDSSload)
@@ -2640,10 +2636,8 @@ func rewriteValue386_Op386CMPWload(v *Value) bool {
func rewriteValue386_Op386DIVSD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- b := v.Block
- config := b.Func.Config
// match: (DIVSD x l:(MOVSDload [off] {sym} ptr mem))
- // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
+ // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (DIVSDload x [off] {sym} ptr mem)
for {
x := v_0
@@ -2655,7 +2649,7 @@ func rewriteValue386_Op386DIVSD(v *Value) bool {
sym := auxToSym(l.Aux)
mem := l.Args[1]
ptr := l.Args[0]
- if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
+ if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break
}
v.reset(Op386DIVSDload)
@@ -2722,10 +2716,8 @@ func rewriteValue386_Op386DIVSDload(v *Value) bool {
func rewriteValue386_Op386DIVSS(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- b := v.Block
- config := b.Func.Config
// match: (DIVSS x l:(MOVSSload [off] {sym} ptr mem))
- // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
+ // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (DIVSSload x [off] {sym} ptr mem)
for {
x := v_0
@@ -2737,7 +2729,7 @@ func rewriteValue386_Op386DIVSS(v *Value) bool {
sym := auxToSym(l.Aux)
mem := l.Args[1]
ptr := l.Args[0]
- if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
+ if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break
}
v.reset(Op386DIVSSload)
@@ -6104,10 +6096,8 @@ func rewriteValue386_Op386MULLload(v *Value) bool {
func rewriteValue386_Op386MULSD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- b := v.Block
- config := b.Func.Config
// match: (MULSD x l:(MOVSDload [off] {sym} ptr mem))
- // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
+ // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (MULSDload x [off] {sym} ptr mem)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -6120,7 +6110,7 @@ func rewriteValue386_Op386MULSD(v *Value) bool {
sym := auxToSym(l.Aux)
mem := l.Args[1]
ptr := l.Args[0]
- if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
+ if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
continue
}
v.reset(Op386MULSDload)
@@ -6189,10 +6179,8 @@ func rewriteValue386_Op386MULSDload(v *Value) bool {
func rewriteValue386_Op386MULSS(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- b := v.Block
- config := b.Func.Config
// match: (MULSS x l:(MOVSSload [off] {sym} ptr mem))
- // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
+ // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (MULSSload x [off] {sym} ptr mem)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -6205,7 +6193,7 @@ func rewriteValue386_Op386MULSS(v *Value) bool {
sym := auxToSym(l.Aux)
mem := l.Args[1]
ptr := l.Args[0]
- if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
+ if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
continue
}
v.reset(Op386MULSSload)
@@ -8187,10 +8175,8 @@ func rewriteValue386_Op386SUBLmodify(v *Value) bool {
func rewriteValue386_Op386SUBSD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- b := v.Block
- config := b.Func.Config
// match: (SUBSD x l:(MOVSDload [off] {sym} ptr mem))
- // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
+ // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (SUBSDload x [off] {sym} ptr mem)
for {
x := v_0
@@ -8202,7 +8188,7 @@ func rewriteValue386_Op386SUBSD(v *Value) bool {
sym := auxToSym(l.Aux)
mem := l.Args[1]
ptr := l.Args[0]
- if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
+ if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break
}
v.reset(Op386SUBSDload)
@@ -8269,10 +8255,8 @@ func rewriteValue386_Op386SUBSDload(v *Value) bool {
func rewriteValue386_Op386SUBSS(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- b := v.Block
- config := b.Func.Config
// match: (SUBSS x l:(MOVSSload [off] {sym} ptr mem))
- // cond: canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)
+ // cond: canMergeLoadClobber(v, l, x) && clobber(l)
// result: (SUBSSload x [off] {sym} ptr mem)
for {
x := v_0
@@ -8284,7 +8268,7 @@ func rewriteValue386_Op386SUBSS(v *Value) bool {
sym := auxToSym(l.Aux)
mem := l.Args[1]
ptr := l.Args[0]
- if !(canMergeLoadClobber(v, l, x) && !config.use387 && clobber(l)) {
+ if !(canMergeLoadClobber(v, l, x) && clobber(l)) {
break
}
v.reset(Op386SUBSSload)
@@ -8712,11 +8696,11 @@ func rewriteValue386_OpConst8(v *Value) bool {
}
func rewriteValue386_OpConstBool(v *Value) bool {
// match: (ConstBool [c])
- // result: (MOVLconst [int32(b2i(c))])
+ // result: (MOVLconst [b2i32(c)])
for {
c := auxIntToBool(v.AuxInt)
v.reset(Op386MOVLconst)
- v.AuxInt = int32ToAuxInt(int32(b2i(c)))
+ v.AuxInt = int32ToAuxInt(b2i32(c))
return true
}
}
@@ -10043,68 +10027,32 @@ func rewriteValue386_OpMove(v *Value) bool {
func rewriteValue386_OpNeg32F(v *Value) bool {
v_0 := v.Args[0]
b := v.Block
- config := b.Func.Config
typ := &b.Func.Config.Types
// match: (Neg32F x)
- // cond: !config.use387
// result: (PXOR x (MOVSSconst <typ.Float32> [float32(math.Copysign(0, -1))]))
for {
x := v_0
- if !(!config.use387) {
- break
- }
v.reset(Op386PXOR)
v0 := b.NewValue0(v.Pos, Op386MOVSSconst, typ.Float32)
v0.AuxInt = float32ToAuxInt(float32(math.Copysign(0, -1)))
v.AddArg2(x, v0)
return true
}
- // match: (Neg32F x)
- // cond: config.use387
- // result: (FCHS x)
- for {
- x := v_0
- if !(config.use387) {
- break
- }
- v.reset(Op386FCHS)
- v.AddArg(x)
- return true
- }
- return false
}
func rewriteValue386_OpNeg64F(v *Value) bool {
v_0 := v.Args[0]
b := v.Block
- config := b.Func.Config
typ := &b.Func.Config.Types
// match: (Neg64F x)
- // cond: !config.use387
// result: (PXOR x (MOVSDconst <typ.Float64> [math.Copysign(0, -1)]))
for {
x := v_0
- if !(!config.use387) {
- break
- }
v.reset(Op386PXOR)
v0 := b.NewValue0(v.Pos, Op386MOVSDconst, typ.Float64)
v0.AuxInt = float64ToAuxInt(math.Copysign(0, -1))
v.AddArg2(x, v0)
return true
}
- // match: (Neg64F x)
- // cond: config.use387
- // result: (FCHS x)
- for {
- x := v_0
- if !(config.use387) {
- break
- }
- v.reset(Op386FCHS)
- v.AddArg(x)
- return true
- }
- return false
}
func rewriteValue386_OpNeq16(v *Value) bool {
v_1 := v.Args[1]
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index 3d7eb8c9a4..ed84812a03 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -572,6 +572,8 @@ func rewriteValueAMD64(v *Value) bool {
return rewriteValueAMD64_OpAtomicAdd32(v)
case OpAtomicAdd64:
return rewriteValueAMD64_OpAtomicAdd64(v)
+ case OpAtomicAnd32:
+ return rewriteValueAMD64_OpAtomicAnd32(v)
case OpAtomicAnd8:
return rewriteValueAMD64_OpAtomicAnd8(v)
case OpAtomicCompareAndSwap32:
@@ -590,6 +592,8 @@ func rewriteValueAMD64(v *Value) bool {
return rewriteValueAMD64_OpAtomicLoad8(v)
case OpAtomicLoadPtr:
return rewriteValueAMD64_OpAtomicLoadPtr(v)
+ case OpAtomicOr32:
+ return rewriteValueAMD64_OpAtomicOr32(v)
case OpAtomicOr8:
return rewriteValueAMD64_OpAtomicOr8(v)
case OpAtomicStore32:
@@ -6886,7 +6890,7 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value) bool {
return true
}
// match: (CMPBconst (ANDLconst _ [m]) [n])
- // cond: 0 <= m && int8(m) < n
+ // cond: 0 <= int8(m) && int8(m) < n
// result: (FlagLT_ULT)
for {
n := auxIntToInt8(v.AuxInt)
@@ -6894,7 +6898,7 @@ func rewriteValueAMD64_OpAMD64CMPBconst(v *Value) bool {
break
}
m := auxIntToInt32(v_0.AuxInt)
- if !(0 <= m && int8(m) < n) {
+ if !(0 <= int8(m) && int8(m) < n) {
break
}
v.reset(OpAMD64FlagLT_ULT)
@@ -8243,7 +8247,7 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value) bool {
return true
}
// match: (CMPWconst (ANDLconst _ [m]) [n])
- // cond: 0 <= m && int16(m) < n
+ // cond: 0 <= int16(m) && int16(m) < n
// result: (FlagLT_ULT)
for {
n := auxIntToInt16(v.AuxInt)
@@ -8251,7 +8255,7 @@ func rewriteValueAMD64_OpAMD64CMPWconst(v *Value) bool {
break
}
m := auxIntToInt32(v_0.AuxInt)
- if !(0 <= m && int16(m) < n) {
+ if !(0 <= int16(m) && int16(m) < n) {
break
}
v.reset(OpAMD64FlagLT_ULT)
@@ -15830,12 +15834,12 @@ func rewriteValueAMD64_OpAMD64MULLconst(v *Value) bool {
return true
}
// match: (MULLconst [c] x)
- // cond: isPowerOfTwo(int64(c)+1) && c >= 15
+ // cond: isPowerOfTwo64(int64(c)+1) && c >= 15
// result: (SUBL (SHLLconst <v.Type> [int8(log2(int64(c)+1))] x) x)
for {
c := auxIntToInt32(v.AuxInt)
x := v_0
- if !(isPowerOfTwo(int64(c)+1) && c >= 15) {
+ if !(isPowerOfTwo64(int64(c)+1) && c >= 15) {
break
}
v.reset(OpAMD64SUBL)
@@ -16277,12 +16281,12 @@ func rewriteValueAMD64_OpAMD64MULQconst(v *Value) bool {
return true
}
// match: (MULQconst [c] x)
- // cond: isPowerOfTwo(int64(c)+1) && c >= 15
+ // cond: isPowerOfTwo64(int64(c)+1) && c >= 15
// result: (SUBQ (SHLQconst <v.Type> [int8(log2(int64(c)+1))] x) x)
for {
c := auxIntToInt32(v.AuxInt)
x := v_0
- if !(isPowerOfTwo(int64(c)+1) && c >= 15) {
+ if !(isPowerOfTwo64(int64(c)+1) && c >= 15) {
break
}
v.reset(OpAMD64SUBQ)
@@ -28476,6 +28480,21 @@ func rewriteValueAMD64_OpAtomicAdd64(v *Value) bool {
return true
}
}
+func rewriteValueAMD64_OpAtomicAnd32(v *Value) bool {
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ // match: (AtomicAnd32 ptr val mem)
+ // result: (ANDLlock ptr val mem)
+ for {
+ ptr := v_0
+ val := v_1
+ mem := v_2
+ v.reset(OpAMD64ANDLlock)
+ v.AddArg3(ptr, val, mem)
+ return true
+ }
+}
func rewriteValueAMD64_OpAtomicAnd8(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
@@ -28607,6 +28626,21 @@ func rewriteValueAMD64_OpAtomicLoadPtr(v *Value) bool {
return true
}
}
+func rewriteValueAMD64_OpAtomicOr32(v *Value) bool {
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ // match: (AtomicOr32 ptr val mem)
+ // result: (ORLlock ptr val mem)
+ for {
+ ptr := v_0
+ val := v_1
+ mem := v_2
+ v.reset(OpAMD64ORLlock)
+ v.AddArg3(ptr, val, mem)
+ return true
+ }
+}
func rewriteValueAMD64_OpAtomicOr8(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
@@ -29685,11 +29719,11 @@ func rewriteValueAMD64_OpConst8(v *Value) bool {
}
func rewriteValueAMD64_OpConstBool(v *Value) bool {
// match: (ConstBool [c])
- // result: (MOVLconst [int32(b2i(c))])
+ // result: (MOVLconst [b2i32(c)])
for {
c := auxIntToBool(v.AuxInt)
v.reset(OpAMD64MOVLconst)
- v.AuxInt = int32ToAuxInt(int32(b2i(c)))
+ v.AuxInt = int32ToAuxInt(b2i32(c))
return true
}
}
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 4e44165169..6ade8283d6 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -448,8 +448,7 @@ func rewriteValueARM(v *Value) bool {
v.Op = OpARMADD
return true
case OpAddr:
- v.Op = OpARMMOVWaddr
- return true
+ return rewriteValueARM_OpAddr(v)
case OpAnd16:
v.Op = OpARMAND
return true
@@ -481,23 +480,17 @@ func rewriteValueARM(v *Value) bool {
v.Op = OpARMMVN
return true
case OpConst16:
- v.Op = OpARMMOVWconst
- return true
+ return rewriteValueARM_OpConst16(v)
case OpConst32:
- v.Op = OpARMMOVWconst
- return true
+ return rewriteValueARM_OpConst32(v)
case OpConst32F:
- v.Op = OpARMMOVFconst
- return true
+ return rewriteValueARM_OpConst32F(v)
case OpConst64F:
- v.Op = OpARMMOVDconst
- return true
+ return rewriteValueARM_OpConst64F(v)
case OpConst8:
- v.Op = OpARMMOVWconst
- return true
+ return rewriteValueARM_OpConst8(v)
case OpConstBool:
- v.Op = OpARMMOVWconst
- return true
+ return rewriteValueARM_OpConstBool(v)
case OpConstNil:
return rewriteValueARM_OpConstNil(v)
case OpCtz16:
@@ -3362,21 +3355,6 @@ func rewriteValueARM_OpARMCMN(v *Value) bool {
}
break
}
- // match: (CMN x (RSBconst [0] y))
- // result: (CMP x y)
- for {
- for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
- x := v_0
- if v_1.Op != OpARMRSBconst || auxIntToInt32(v_1.AuxInt) != 0 {
- continue
- }
- y := v_1.Args[0]
- v.reset(OpARMCMP)
- v.AddArg2(x, y)
- return true
- }
- break
- }
return false
}
func rewriteValueARM_OpARMCMNconst(v *Value) bool {
@@ -3938,18 +3916,6 @@ func rewriteValueARM_OpARMCMP(v *Value) bool {
v.AddArg(v0)
return true
}
- // match: (CMP x (RSBconst [0] y))
- // result: (CMN x y)
- for {
- x := v_0
- if v_1.Op != OpARMRSBconst || auxIntToInt32(v_1.AuxInt) != 0 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpARMCMN)
- v.AddArg2(x, y)
- return true
- }
return false
}
func rewriteValueARM_OpARMCMPD(v *Value) bool {
@@ -4627,15 +4593,15 @@ func rewriteValueARM_OpARMMOVBUload(v *Value) bool {
}
// match: (MOVBUload [off] {sym} (SB) _)
// cond: symIsRO(sym)
- // result: (MOVWconst [int64(read8(sym, off))])
+ // result: (MOVWconst [int32(read8(sym, int64(off)))])
for {
- off := v.AuxInt
- sym := v.Aux
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
if v_0.Op != OpSB || !(symIsRO(sym)) {
break
}
v.reset(OpARMMOVWconst)
- v.AuxInt = int64(read8(sym, off))
+ v.AuxInt = int32ToAuxInt(int32(read8(sym, int64(off))))
return true
}
return false
@@ -5540,15 +5506,15 @@ func rewriteValueARM_OpARMMOVHUload(v *Value) bool {
}
// match: (MOVHUload [off] {sym} (SB) _)
// cond: symIsRO(sym)
- // result: (MOVWconst [int64(read16(sym, off, config.ctxt.Arch.ByteOrder))])
+ // result: (MOVWconst [int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder))])
for {
- off := v.AuxInt
- sym := v.Aux
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
if v_0.Op != OpSB || !(symIsRO(sym)) {
break
}
v.reset(OpARMMOVWconst)
- v.AuxInt = int64(read16(sym, off, config.ctxt.Arch.ByteOrder))
+ v.AuxInt = int32ToAuxInt(int32(read16(sym, int64(off), config.ctxt.Arch.ByteOrder)))
return true
}
return false
@@ -6261,15 +6227,15 @@ func rewriteValueARM_OpARMMOVWload(v *Value) bool {
}
// match: (MOVWload [off] {sym} (SB) _)
// cond: symIsRO(sym)
- // result: (MOVWconst [int64(int32(read32(sym, off, config.ctxt.Arch.ByteOrder)))])
+ // result: (MOVWconst [int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder))])
for {
- off := v.AuxInt
- sym := v.Aux
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
if v_0.Op != OpSB || !(symIsRO(sym)) {
break
}
v.reset(OpARMMOVWconst)
- v.AuxInt = int64(int32(read32(sym, off, config.ctxt.Arch.ByteOrder)))
+ v.AuxInt = int32ToAuxInt(int32(read32(sym, int64(off), config.ctxt.Arch.ByteOrder)))
return true
}
return false
@@ -6439,17 +6405,17 @@ func rewriteValueARM_OpARMMOVWloadshiftLL(v *Value) bool {
return true
}
// match: (MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem)
- // result: (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem)
+ // result: (MOVWload [int32(uint32(c)<<uint64(d))] ptr mem)
for {
- d := v.AuxInt
+ d := auxIntToInt32(v.AuxInt)
ptr := v_0
if v_1.Op != OpARMMOVWconst {
break
}
- c := v_1.AuxInt
+ c := auxIntToInt32(v_1.AuxInt)
mem := v_2
v.reset(OpARMMOVWload)
- v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AuxInt = int32ToAuxInt(int32(uint32(c) << uint64(d)))
v.AddArg2(ptr, mem)
return true
}
@@ -6519,17 +6485,17 @@ func rewriteValueARM_OpARMMOVWloadshiftRL(v *Value) bool {
return true
}
// match: (MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem)
- // result: (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem)
+ // result: (MOVWload [int32(uint32(c)>>uint64(d))] ptr mem)
for {
- d := v.AuxInt
+ d := auxIntToInt32(v.AuxInt)
ptr := v_0
if v_1.Op != OpARMMOVWconst {
break
}
- c := v_1.AuxInt
+ c := auxIntToInt32(v_1.AuxInt)
mem := v_2
v.reset(OpARMMOVWload)
- v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AuxInt = int32ToAuxInt(int32(uint32(c) >> uint64(d)))
v.AddArg2(ptr, mem)
return true
}
@@ -6860,18 +6826,18 @@ func rewriteValueARM_OpARMMOVWstoreshiftLL(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem)
- // result: (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem)
+ // result: (MOVWstore [int32(uint32(c)<<uint64(d))] ptr val mem)
for {
- d := v.AuxInt
+ d := auxIntToInt32(v.AuxInt)
ptr := v_0
if v_1.Op != OpARMMOVWconst {
break
}
- c := v_1.AuxInt
+ c := auxIntToInt32(v_1.AuxInt)
val := v_2
mem := v_3
v.reset(OpARMMOVWstore)
- v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AuxInt = int32ToAuxInt(int32(uint32(c) << uint64(d)))
v.AddArg3(ptr, val, mem)
return true
}
@@ -6906,18 +6872,18 @@ func rewriteValueARM_OpARMMOVWstoreshiftRL(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem)
- // result: (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem)
+ // result: (MOVWstore [int32(uint32(c)>>uint64(d))] ptr val mem)
for {
- d := v.AuxInt
+ d := auxIntToInt32(v.AuxInt)
ptr := v_0
if v_1.Op != OpARMMOVWconst {
break
}
- c := v_1.AuxInt
+ c := auxIntToInt32(v_1.AuxInt)
val := v_2
mem := v_3
v.reset(OpARMMOVWstore)
- v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AuxInt = int32ToAuxInt(int32(uint32(c) >> uint64(d)))
v.AddArg3(ptr, val, mem)
return true
}
@@ -8132,15 +8098,15 @@ func rewriteValueARM_OpARMMVNshiftLLreg(v *Value) bool {
func rewriteValueARM_OpARMMVNshiftRA(v *Value) bool {
v_0 := v.Args[0]
// match: (MVNshiftRA (MOVWconst [c]) [d])
- // result: (MOVWconst [^int64(int32(c)>>uint64(d))])
+ // result: (MOVWconst [int32(c)>>uint64(d)])
for {
- d := v.AuxInt
+ d := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVWconst {
break
}
- c := v_0.AuxInt
+ c := auxIntToInt32(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = ^int64(int32(c) >> uint64(d))
+ v.AuxInt = int32ToAuxInt(int32(c) >> uint64(d))
return true
}
return false
@@ -8166,15 +8132,15 @@ func rewriteValueARM_OpARMMVNshiftRAreg(v *Value) bool {
func rewriteValueARM_OpARMMVNshiftRL(v *Value) bool {
v_0 := v.Args[0]
// match: (MVNshiftRL (MOVWconst [c]) [d])
- // result: (MOVWconst [^int64(uint32(c)>>uint64(d))])
+ // result: (MOVWconst [^int32(uint32(c)>>uint64(d))])
for {
- d := v.AuxInt
+ d := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVWconst {
break
}
- c := v_0.AuxInt
+ c := auxIntToInt32(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = ^int64(uint32(c) >> uint64(d))
+ v.AuxInt = int32ToAuxInt(^int32(uint32(c) >> uint64(d)))
return true
}
return false
@@ -12900,6 +12866,19 @@ func rewriteValueARM_OpARMXORshiftRR(v *Value) bool {
}
return false
}
+func rewriteValueARM_OpAddr(v *Value) bool {
+ v_0 := v.Args[0]
+ // match: (Addr {sym} base)
+ // result: (MOVWaddr {sym} base)
+ for {
+ sym := auxToSym(v.Aux)
+ base := v_0
+ v.reset(OpARMMOVWaddr)
+ v.Aux = symToAux(sym)
+ v.AddArg(base)
+ return true
+ }
+}
func rewriteValueARM_OpAvg32u(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -12981,6 +12960,66 @@ func rewriteValueARM_OpBswap32(v *Value) bool {
}
return false
}
+func rewriteValueARM_OpConst16(v *Value) bool {
+ // match: (Const16 [val])
+ // result: (MOVWconst [int32(val)])
+ for {
+ val := auxIntToInt16(v.AuxInt)
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int32ToAuxInt(int32(val))
+ return true
+ }
+}
+func rewriteValueARM_OpConst32(v *Value) bool {
+ // match: (Const32 [val])
+ // result: (MOVWconst [int32(val)])
+ for {
+ val := auxIntToInt32(v.AuxInt)
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int32ToAuxInt(int32(val))
+ return true
+ }
+}
+func rewriteValueARM_OpConst32F(v *Value) bool {
+ // match: (Const32F [val])
+ // result: (MOVFconst [float64(val)])
+ for {
+ val := auxIntToFloat32(v.AuxInt)
+ v.reset(OpARMMOVFconst)
+ v.AuxInt = float64ToAuxInt(float64(val))
+ return true
+ }
+}
+func rewriteValueARM_OpConst64F(v *Value) bool {
+ // match: (Const64F [val])
+ // result: (MOVDconst [float64(val)])
+ for {
+ val := auxIntToFloat64(v.AuxInt)
+ v.reset(OpARMMOVDconst)
+ v.AuxInt = float64ToAuxInt(float64(val))
+ return true
+ }
+}
+func rewriteValueARM_OpConst8(v *Value) bool {
+ // match: (Const8 [val])
+ // result: (MOVWconst [int32(val)])
+ for {
+ val := auxIntToInt8(v.AuxInt)
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int32ToAuxInt(int32(val))
+ return true
+ }
+}
+func rewriteValueARM_OpConstBool(v *Value) bool {
+ // match: (ConstBool [b])
+ // result: (MOVWconst [b2i32(b)])
+ for {
+ b := auxIntToBool(v.AuxInt)
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int32ToAuxInt(b2i32(b))
+ return true
+ }
+}
func rewriteValueARM_OpConstNil(v *Value) bool {
// match: (ConstNil)
// result: (MOVWconst [0])
@@ -14675,25 +14714,25 @@ func rewriteValueARM_OpNot(v *Value) bool {
func rewriteValueARM_OpOffPtr(v *Value) bool {
v_0 := v.Args[0]
// match: (OffPtr [off] ptr:(SP))
- // result: (MOVWaddr [off] ptr)
+ // result: (MOVWaddr [int32(off)] ptr)
for {
- off := v.AuxInt
+ off := auxIntToInt64(v.AuxInt)
ptr := v_0
if ptr.Op != OpSP {
break
}
v.reset(OpARMMOVWaddr)
- v.AuxInt = off
+ v.AuxInt = int32ToAuxInt(int32(off))
v.AddArg(ptr)
return true
}
// match: (OffPtr [off] ptr)
- // result: (ADDconst [off] ptr)
+ // result: (ADDconst [int32(off)] ptr)
for {
- off := v.AuxInt
+ off := auxIntToInt64(v.AuxInt)
ptr := v_0
v.reset(OpARMADDconst)
- v.AuxInt = off
+ v.AuxInt = int32ToAuxInt(int32(off))
v.AddArg(ptr)
return true
}
@@ -16002,6 +16041,42 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMEQ, cmp)
return true
}
+ // match: (EQ (CMP x (RSBconst [0] y)))
+ // result: (EQ (CMN x y))
+ for b.Controls[0].Op == OpARMCMP {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ break
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMEQ, v0)
+ return true
+ }
+ // match: (EQ (CMN x (RSBconst [0] y)))
+ // result: (EQ (CMP x y))
+ for b.Controls[0].Op == OpARMCMN {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ x := v_0_0
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ continue
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMEQ, v0)
+ return true
+ }
+ break
+ }
// match: (EQ (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (EQ (CMP x y) yes no)
@@ -16848,6 +16923,42 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMLE, cmp)
return true
}
+ // match: (GE (CMP x (RSBconst [0] y)))
+ // result: (GE (CMN x y))
+ for b.Controls[0].Op == OpARMCMP {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ break
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMGE, v0)
+ return true
+ }
+ // match: (GE (CMN x (RSBconst [0] y)))
+ // result: (GE (CMP x y))
+ for b.Controls[0].Op == OpARMCMN {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ x := v_0_0
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ continue
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMGE, v0)
+ return true
+ }
+ break
+ }
// match: (GE (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (GEnoov (CMP x y) yes no)
@@ -17728,6 +17839,42 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMLT, cmp)
return true
}
+ // match: (GT (CMP x (RSBconst [0] y)))
+ // result: (GT (CMN x y))
+ for b.Controls[0].Op == OpARMCMP {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ break
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMGT, v0)
+ return true
+ }
+ // match: (GT (CMN x (RSBconst [0] y)))
+ // result: (GT (CMP x y))
+ for b.Controls[0].Op == OpARMCMN {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ x := v_0_0
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ continue
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMGT, v0)
+ return true
+ }
+ break
+ }
// match: (GT (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (GTnoov (CMP x y) yes no)
@@ -18699,6 +18846,42 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGE, cmp)
return true
}
+ // match: (LE (CMP x (RSBconst [0] y)))
+ // result: (LE (CMN x y))
+ for b.Controls[0].Op == OpARMCMP {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ break
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMLE, v0)
+ return true
+ }
+ // match: (LE (CMN x (RSBconst [0] y)))
+ // result: (LE (CMP x y))
+ for b.Controls[0].Op == OpARMCMN {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ x := v_0_0
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ continue
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMLE, v0)
+ return true
+ }
+ break
+ }
// match: (LE (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (LEnoov (CMP x y) yes no)
@@ -19579,6 +19762,42 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGT, cmp)
return true
}
+ // match: (LT (CMP x (RSBconst [0] y)))
+ // result: (LT (CMN x y))
+ for b.Controls[0].Op == OpARMCMP {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ break
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMLT, v0)
+ return true
+ }
+ // match: (LT (CMN x (RSBconst [0] y)))
+ // result: (LT (CMP x y))
+ for b.Controls[0].Op == OpARMCMN {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ x := v_0_0
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ continue
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMLT, v0)
+ return true
+ }
+ break
+ }
// match: (LT (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (LTnoov (CMP x y) yes no)
@@ -20609,6 +20828,42 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMNE, cmp)
return true
}
+ // match: (NE (CMP x (RSBconst [0] y)))
+ // result: (NE (CMN x y))
+ for b.Controls[0].Op == OpARMCMP {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ break
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMNE, v0)
+ return true
+ }
+ // match: (NE (CMN x (RSBconst [0] y)))
+ // result: (NE (CMP x y))
+ for b.Controls[0].Op == OpARMCMN {
+ v_0 := b.Controls[0]
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ x := v_0_0
+ if v_0_1.Op != OpARMRSBconst || auxIntToInt32(v_0_1.AuxInt) != 0 {
+ continue
+ }
+ y := v_0_1.Args[0]
+ v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
+ v0.AddArg2(x, y)
+ b.resetWithControl(BlockARMNE, v0)
+ return true
+ }
+ break
+ }
// match: (NE (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
// result: (NE (CMP x y) yes no)
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index 6c48812121..774e2ead68 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -424,6 +424,8 @@ func rewriteValueARM64(v *Value) bool {
case OpAtomicAdd64Variant:
v.Op = OpARM64LoweredAtomicAdd64Variant
return true
+ case OpAtomicAnd32:
+ return rewriteValueARM64_OpAtomicAnd32(v)
case OpAtomicAnd8:
return rewriteValueARM64_OpAtomicAnd8(v)
case OpAtomicCompareAndSwap32:
@@ -450,6 +452,8 @@ func rewriteValueARM64(v *Value) bool {
case OpAtomicLoadPtr:
v.Op = OpARM64LDAR
return true
+ case OpAtomicOr32:
+ return rewriteValueARM64_OpAtomicOr32(v)
case OpAtomicOr8:
return rewriteValueARM64_OpAtomicOr8(v)
case OpAtomicStore32:
@@ -4888,7 +4892,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (ADDshiftLL a x [log2(c)])
for {
a := v_0
@@ -4897,7 +4901,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -4906,7 +4910,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c-1) && c>=3
+ // cond: isPowerOfTwo64(c-1) && c>=3
// result: (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
a := v_0
@@ -4915,7 +4919,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c-1) && c >= 3) {
+ if !(isPowerOfTwo64(c-1) && c >= 3) {
break
}
v.reset(OpARM64ADD)
@@ -4926,7 +4930,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c+1) && c>=7
+ // cond: isPowerOfTwo64(c+1) && c>=7
// result: (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
for {
a := v_0
@@ -4935,7 +4939,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c+1) && c >= 7) {
+ if !(isPowerOfTwo64(c+1) && c >= 7) {
break
}
v.reset(OpARM64SUB)
@@ -4946,7 +4950,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a x (MOVDconst [c]))
- // cond: c%3 == 0 && isPowerOfTwo(c/3)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3)
// result: (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
for {
a := v_0
@@ -4955,7 +4959,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -4967,7 +4971,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a x (MOVDconst [c]))
- // cond: c%5 == 0 && isPowerOfTwo(c/5)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5)
// result: (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
for {
a := v_0
@@ -4976,7 +4980,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -4988,7 +4992,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a x (MOVDconst [c]))
- // cond: c%7 == 0 && isPowerOfTwo(c/7)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7)
// result: (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
for {
a := v_0
@@ -4997,7 +5001,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -5009,7 +5013,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a x (MOVDconst [c]))
- // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9)
// result: (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
for {
a := v_0
@@ -5018,7 +5022,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5064,7 +5068,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (ADDshiftLL a x [log2(c)])
for {
a := v_0
@@ -5073,7 +5077,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5082,7 +5086,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c-1) && c>=3
+ // cond: isPowerOfTwo64(c-1) && c>=3
// result: (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
a := v_0
@@ -5091,7 +5095,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c-1) && c >= 3) {
+ if !(isPowerOfTwo64(c-1) && c >= 3) {
break
}
v.reset(OpARM64ADD)
@@ -5102,7 +5106,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c+1) && c>=7
+ // cond: isPowerOfTwo64(c+1) && c>=7
// result: (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
for {
a := v_0
@@ -5111,7 +5115,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c+1) && c >= 7) {
+ if !(isPowerOfTwo64(c+1) && c >= 7) {
break
}
v.reset(OpARM64SUB)
@@ -5122,7 +5126,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a (MOVDconst [c]) x)
- // cond: c%3 == 0 && isPowerOfTwo(c/3)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3)
// result: (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
for {
a := v_0
@@ -5131,7 +5135,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -5143,7 +5147,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a (MOVDconst [c]) x)
- // cond: c%5 == 0 && isPowerOfTwo(c/5)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5)
// result: (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
for {
a := v_0
@@ -5152,7 +5156,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5164,7 +5168,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a (MOVDconst [c]) x)
- // cond: c%7 == 0 && isPowerOfTwo(c/7)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7)
// result: (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
for {
a := v_0
@@ -5173,7 +5177,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -5185,7 +5189,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
return true
}
// match: (MADD a (MOVDconst [c]) x)
- // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9)
// result: (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
for {
a := v_0
@@ -5194,7 +5198,7 @@ func rewriteValueARM64_OpARM64MADD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5295,7 +5299,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (ADDshiftLL a x [log2(c)])
for {
a := v_0
@@ -5304,7 +5308,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5313,7 +5317,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c-1) && int32(c)>=3
+ // cond: isPowerOfTwo64(c-1) && int32(c)>=3
// result: (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
a := v_0
@@ -5322,7 +5326,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+ if !(isPowerOfTwo64(c-1) && int32(c) >= 3) {
break
}
v.reset(OpARM64ADD)
@@ -5333,7 +5337,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c+1) && int32(c)>=7
+ // cond: isPowerOfTwo64(c+1) && int32(c)>=7
// result: (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
for {
a := v_0
@@ -5342,7 +5346,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ if !(isPowerOfTwo64(c+1) && int32(c) >= 7) {
break
}
v.reset(OpARM64SUB)
@@ -5353,7 +5357,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a x (MOVDconst [c]))
- // cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)
// result: (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
for {
a := v_0
@@ -5362,7 +5366,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -5374,7 +5378,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a x (MOVDconst [c]))
- // cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)
// result: (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
for {
a := v_0
@@ -5383,7 +5387,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5395,7 +5399,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a x (MOVDconst [c]))
- // cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)
// result: (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
for {
a := v_0
@@ -5404,7 +5408,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -5416,7 +5420,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a x (MOVDconst [c]))
- // cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)
// result: (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
for {
a := v_0
@@ -5425,7 +5429,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5486,7 +5490,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (ADDshiftLL a x [log2(c)])
for {
a := v_0
@@ -5495,7 +5499,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5504,7 +5508,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c-1) && int32(c)>=3
+ // cond: isPowerOfTwo64(c-1) && int32(c)>=3
// result: (ADD a (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
a := v_0
@@ -5513,7 +5517,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+ if !(isPowerOfTwo64(c-1) && int32(c) >= 3) {
break
}
v.reset(OpARM64ADD)
@@ -5524,7 +5528,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c+1) && int32(c)>=7
+ // cond: isPowerOfTwo64(c+1) && int32(c)>=7
// result: (SUB a (SUBshiftLL <x.Type> x x [log2(c+1)]))
for {
a := v_0
@@ -5533,7 +5537,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ if !(isPowerOfTwo64(c+1) && int32(c) >= 7) {
break
}
v.reset(OpARM64SUB)
@@ -5544,7 +5548,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a (MOVDconst [c]) x)
- // cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)
// result: (SUBshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
for {
a := v_0
@@ -5553,7 +5557,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -5565,7 +5569,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a (MOVDconst [c]) x)
- // cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)
// result: (ADDshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
for {
a := v_0
@@ -5574,7 +5578,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5586,7 +5590,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a (MOVDconst [c]) x)
- // cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)
// result: (SUBshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
for {
a := v_0
@@ -5595,7 +5599,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -5607,7 +5611,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
return true
}
// match: (MADDW a (MOVDconst [c]) x)
- // cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)
// result: (ADDshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
for {
a := v_0
@@ -5616,7 +5620,7 @@ func rewriteValueARM64_OpARM64MADDW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -5707,7 +5711,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
break
}
// match: (MNEG x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (NEG (SLLconst <x.Type> [log2(c)] x))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5716,7 +5720,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
continue
}
v.reset(OpARM64NEG)
@@ -5729,7 +5733,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
break
}
// match: (MNEG x (MOVDconst [c]))
- // cond: isPowerOfTwo(c-1) && c >= 3
+ // cond: isPowerOfTwo64(c-1) && c >= 3
// result: (NEG (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5738,7 +5742,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c-1) && c >= 3) {
+ if !(isPowerOfTwo64(c-1) && c >= 3) {
continue
}
v.reset(OpARM64NEG)
@@ -5751,7 +5755,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
break
}
// match: (MNEG x (MOVDconst [c]))
- // cond: isPowerOfTwo(c+1) && c >= 7
+ // cond: isPowerOfTwo64(c+1) && c >= 7
// result: (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log2(c+1)]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5760,7 +5764,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c+1) && c >= 7) {
+ if !(isPowerOfTwo64(c+1) && c >= 7) {
continue
}
v.reset(OpARM64NEG)
@@ -5775,7 +5779,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
break
}
// match: (MNEG x (MOVDconst [c]))
- // cond: c%3 == 0 && isPowerOfTwo(c/3)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3)
// result: (SLLconst <x.Type> [log2(c/3)] (SUBshiftLL <x.Type> x x [2]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5784,7 +5788,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -5799,7 +5803,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
break
}
// match: (MNEG x (MOVDconst [c]))
- // cond: c%5 == 0 && isPowerOfTwo(c/5)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5)
// result: (NEG (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5808,7 +5812,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5)) {
continue
}
v.reset(OpARM64NEG)
@@ -5824,7 +5828,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
break
}
// match: (MNEG x (MOVDconst [c]))
- // cond: c%7 == 0 && isPowerOfTwo(c/7)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7)
// result: (SLLconst <x.Type> [log2(c/7)] (SUBshiftLL <x.Type> x x [3]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5833,7 +5837,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -5848,7 +5852,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
break
}
// match: (MNEG x (MOVDconst [c]))
- // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9)
// result: (NEG (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5857,7 +5861,7 @@ func rewriteValueARM64_OpARM64MNEG(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9)) {
continue
}
v.reset(OpARM64NEG)
@@ -5952,7 +5956,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
break
}
// match: (MNEGW x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (NEG (SLLconst <x.Type> [log2(c)] x))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5961,7 +5965,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
continue
}
v.reset(OpARM64NEG)
@@ -5974,7 +5978,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
break
}
// match: (MNEGW x (MOVDconst [c]))
- // cond: isPowerOfTwo(c-1) && int32(c) >= 3
+ // cond: isPowerOfTwo64(c-1) && int32(c) >= 3
// result: (NEG (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -5983,7 +5987,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+ if !(isPowerOfTwo64(c-1) && int32(c) >= 3) {
continue
}
v.reset(OpARM64NEG)
@@ -5996,7 +6000,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
break
}
// match: (MNEGW x (MOVDconst [c]))
- // cond: isPowerOfTwo(c+1) && int32(c) >= 7
+ // cond: isPowerOfTwo64(c+1) && int32(c) >= 7
// result: (NEG (ADDshiftLL <x.Type> (NEG <x.Type> x) x [log2(c+1)]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -6005,7 +6009,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ if !(isPowerOfTwo64(c+1) && int32(c) >= 7) {
continue
}
v.reset(OpARM64NEG)
@@ -6020,7 +6024,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
break
}
// match: (MNEGW x (MOVDconst [c]))
- // cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)
// result: (SLLconst <x.Type> [log2(c/3)] (SUBshiftLL <x.Type> x x [2]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -6029,7 +6033,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -6044,7 +6048,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
break
}
// match: (MNEGW x (MOVDconst [c]))
- // cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)
// result: (NEG (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -6053,7 +6057,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)) {
continue
}
v.reset(OpARM64NEG)
@@ -6069,7 +6073,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
break
}
// match: (MNEGW x (MOVDconst [c]))
- // cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)
// result: (SLLconst <x.Type> [log2(c/7)] (SUBshiftLL <x.Type> x x [3]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -6078,7 +6082,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -6093,7 +6097,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
break
}
// match: (MNEGW x (MOVDconst [c]))
- // cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)
// result: (NEG (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -6102,7 +6106,7 @@ func rewriteValueARM64_OpARM64MNEGW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)) {
continue
}
v.reset(OpARM64NEG)
@@ -13376,7 +13380,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SUBshiftLL a x [log2(c)])
for {
a := v_0
@@ -13385,7 +13389,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13394,7 +13398,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c-1) && c>=3
+ // cond: isPowerOfTwo64(c-1) && c>=3
// result: (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
a := v_0
@@ -13403,7 +13407,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c-1) && c >= 3) {
+ if !(isPowerOfTwo64(c-1) && c >= 3) {
break
}
v.reset(OpARM64SUB)
@@ -13414,7 +13418,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c+1) && c>=7
+ // cond: isPowerOfTwo64(c+1) && c>=7
// result: (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
for {
a := v_0
@@ -13423,7 +13427,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c+1) && c >= 7) {
+ if !(isPowerOfTwo64(c+1) && c >= 7) {
break
}
v.reset(OpARM64ADD)
@@ -13434,7 +13438,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a x (MOVDconst [c]))
- // cond: c%3 == 0 && isPowerOfTwo(c/3)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3)
// result: (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
for {
a := v_0
@@ -13443,7 +13447,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -13455,7 +13459,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a x (MOVDconst [c]))
- // cond: c%5 == 0 && isPowerOfTwo(c/5)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5)
// result: (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
for {
a := v_0
@@ -13464,7 +13468,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13476,7 +13480,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a x (MOVDconst [c]))
- // cond: c%7 == 0 && isPowerOfTwo(c/7)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7)
// result: (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
for {
a := v_0
@@ -13485,7 +13489,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -13497,7 +13501,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a x (MOVDconst [c]))
- // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9)
// result: (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
for {
a := v_0
@@ -13506,7 +13510,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13552,7 +13556,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SUBshiftLL a x [log2(c)])
for {
a := v_0
@@ -13561,7 +13565,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13570,7 +13574,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c-1) && c>=3
+ // cond: isPowerOfTwo64(c-1) && c>=3
// result: (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
a := v_0
@@ -13579,7 +13583,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c-1) && c >= 3) {
+ if !(isPowerOfTwo64(c-1) && c >= 3) {
break
}
v.reset(OpARM64SUB)
@@ -13590,7 +13594,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c+1) && c>=7
+ // cond: isPowerOfTwo64(c+1) && c>=7
// result: (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
for {
a := v_0
@@ -13599,7 +13603,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c+1) && c >= 7) {
+ if !(isPowerOfTwo64(c+1) && c >= 7) {
break
}
v.reset(OpARM64ADD)
@@ -13610,7 +13614,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a (MOVDconst [c]) x)
- // cond: c%3 == 0 && isPowerOfTwo(c/3)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3)
// result: (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
for {
a := v_0
@@ -13619,7 +13623,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -13631,7 +13635,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a (MOVDconst [c]) x)
- // cond: c%5 == 0 && isPowerOfTwo(c/5)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5)
// result: (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
for {
a := v_0
@@ -13640,7 +13644,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13652,7 +13656,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a (MOVDconst [c]) x)
- // cond: c%7 == 0 && isPowerOfTwo(c/7)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7)
// result: (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
for {
a := v_0
@@ -13661,7 +13665,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -13673,7 +13677,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
return true
}
// match: (MSUB a (MOVDconst [c]) x)
- // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9)
// result: (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
for {
a := v_0
@@ -13682,7 +13686,7 @@ func rewriteValueARM64_OpARM64MSUB(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13783,7 +13787,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SUBshiftLL a x [log2(c)])
for {
a := v_0
@@ -13792,7 +13796,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13801,7 +13805,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c-1) && int32(c)>=3
+ // cond: isPowerOfTwo64(c-1) && int32(c)>=3
// result: (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
a := v_0
@@ -13810,7 +13814,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+ if !(isPowerOfTwo64(c-1) && int32(c) >= 3) {
break
}
v.reset(OpARM64SUB)
@@ -13821,7 +13825,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a x (MOVDconst [c]))
- // cond: isPowerOfTwo(c+1) && int32(c)>=7
+ // cond: isPowerOfTwo64(c+1) && int32(c)>=7
// result: (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
for {
a := v_0
@@ -13830,7 +13834,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ if !(isPowerOfTwo64(c+1) && int32(c) >= 7) {
break
}
v.reset(OpARM64ADD)
@@ -13841,7 +13845,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a x (MOVDconst [c]))
- // cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)
// result: (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
for {
a := v_0
@@ -13850,7 +13854,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -13862,7 +13866,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a x (MOVDconst [c]))
- // cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)
// result: (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
for {
a := v_0
@@ -13871,7 +13875,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13883,7 +13887,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a x (MOVDconst [c]))
- // cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)
// result: (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
for {
a := v_0
@@ -13892,7 +13896,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -13904,7 +13908,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a x (MOVDconst [c]))
- // cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)
// result: (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
for {
a := v_0
@@ -13913,7 +13917,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
break
}
c := auxIntToInt64(v_2.AuxInt)
- if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13974,7 +13978,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SUBshiftLL a x [log2(c)])
for {
a := v_0
@@ -13983,7 +13987,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -13992,7 +13996,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c-1) && int32(c)>=3
+ // cond: isPowerOfTwo64(c-1) && int32(c)>=3
// result: (SUB a (ADDshiftLL <x.Type> x x [log2(c-1)]))
for {
a := v_0
@@ -14001,7 +14005,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+ if !(isPowerOfTwo64(c-1) && int32(c) >= 3) {
break
}
v.reset(OpARM64SUB)
@@ -14012,7 +14016,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a (MOVDconst [c]) x)
- // cond: isPowerOfTwo(c+1) && int32(c)>=7
+ // cond: isPowerOfTwo64(c+1) && int32(c)>=7
// result: (ADD a (SUBshiftLL <x.Type> x x [log2(c+1)]))
for {
a := v_0
@@ -14021,7 +14025,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ if !(isPowerOfTwo64(c+1) && int32(c) >= 7) {
break
}
v.reset(OpARM64ADD)
@@ -14032,7 +14036,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a (MOVDconst [c]) x)
- // cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)
// result: (ADDshiftLL a (SUBshiftLL <x.Type> x x [2]) [log2(c/3)])
for {
a := v_0
@@ -14041,7 +14045,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -14053,7 +14057,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a (MOVDconst [c]) x)
- // cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)
// result: (SUBshiftLL a (ADDshiftLL <x.Type> x x [2]) [log2(c/5)])
for {
a := v_0
@@ -14062,7 +14066,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -14074,7 +14078,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a (MOVDconst [c]) x)
- // cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)
// result: (ADDshiftLL a (SUBshiftLL <x.Type> x x [3]) [log2(c/7)])
for {
a := v_0
@@ -14083,7 +14087,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)) {
break
}
v.reset(OpARM64ADDshiftLL)
@@ -14095,7 +14099,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
return true
}
// match: (MSUBW a (MOVDconst [c]) x)
- // cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)
// result: (SUBshiftLL a (ADDshiftLL <x.Type> x x [3]) [log2(c/9)])
for {
a := v_0
@@ -14104,7 +14108,7 @@ func rewriteValueARM64_OpARM64MSUBW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
x := v_2
- if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)) {
break
}
v.reset(OpARM64SUBshiftLL)
@@ -14210,7 +14214,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
break
}
// match: (MUL x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SLLconst [log2(c)] x)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14219,7 +14223,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14230,7 +14234,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
break
}
// match: (MUL x (MOVDconst [c]))
- // cond: isPowerOfTwo(c-1) && c >= 3
+ // cond: isPowerOfTwo64(c-1) && c >= 3
// result: (ADDshiftLL x x [log2(c-1)])
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14239,7 +14243,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c-1) && c >= 3) {
+ if !(isPowerOfTwo64(c-1) && c >= 3) {
continue
}
v.reset(OpARM64ADDshiftLL)
@@ -14250,7 +14254,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
break
}
// match: (MUL x (MOVDconst [c]))
- // cond: isPowerOfTwo(c+1) && c >= 7
+ // cond: isPowerOfTwo64(c+1) && c >= 7
// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14259,7 +14263,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c+1) && c >= 7) {
+ if !(isPowerOfTwo64(c+1) && c >= 7) {
continue
}
v.reset(OpARM64ADDshiftLL)
@@ -14272,7 +14276,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
break
}
// match: (MUL x (MOVDconst [c]))
- // cond: c%3 == 0 && isPowerOfTwo(c/3)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3)
// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14281,7 +14285,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14295,7 +14299,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
break
}
// match: (MUL x (MOVDconst [c]))
- // cond: c%5 == 0 && isPowerOfTwo(c/5)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5)
// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14304,7 +14308,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14318,7 +14322,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
break
}
// match: (MUL x (MOVDconst [c]))
- // cond: c%7 == 0 && isPowerOfTwo(c/7)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7)
// result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14327,7 +14331,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14343,7 +14347,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
break
}
// match: (MUL x (MOVDconst [c]))
- // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9)
// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14352,7 +14356,7 @@ func rewriteValueARM64_OpARM64MUL(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14460,7 +14464,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
break
}
// match: (MULW x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SLLconst [log2(c)] x)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14469,7 +14473,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14480,7 +14484,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
break
}
// match: (MULW x (MOVDconst [c]))
- // cond: isPowerOfTwo(c-1) && int32(c) >= 3
+ // cond: isPowerOfTwo64(c-1) && int32(c) >= 3
// result: (ADDshiftLL x x [log2(c-1)])
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14489,7 +14493,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+ if !(isPowerOfTwo64(c-1) && int32(c) >= 3) {
continue
}
v.reset(OpARM64ADDshiftLL)
@@ -14500,7 +14504,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
break
}
// match: (MULW x (MOVDconst [c]))
- // cond: isPowerOfTwo(c+1) && int32(c) >= 7
+ // cond: isPowerOfTwo64(c+1) && int32(c) >= 7
// result: (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14509,7 +14513,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ if !(isPowerOfTwo64(c+1) && int32(c) >= 7) {
continue
}
v.reset(OpARM64ADDshiftLL)
@@ -14522,7 +14526,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
break
}
// match: (MULW x (MOVDconst [c]))
- // cond: c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)
+ // cond: c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)
// result: (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14531,7 +14535,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ if !(c%3 == 0 && isPowerOfTwo64(c/3) && is32Bit(c)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14545,7 +14549,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
break
}
// match: (MULW x (MOVDconst [c]))
- // cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+ // cond: c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)
// result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14554,7 +14558,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+ if !(c%5 == 0 && isPowerOfTwo64(c/5) && is32Bit(c)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14568,7 +14572,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
break
}
// match: (MULW x (MOVDconst [c]))
- // cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+ // cond: c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)
// result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14577,7 +14581,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ if !(c%7 == 0 && isPowerOfTwo64(c/7) && is32Bit(c)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -14593,7 +14597,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
break
}
// match: (MULW x (MOVDconst [c]))
- // cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+ // cond: c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)
// result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -14602,7 +14606,7 @@ func rewriteValueARM64_OpARM64MULW(v *Value) bool {
continue
}
c := auxIntToInt64(v_1.AuxInt)
- if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ if !(c%9 == 0 && isPowerOfTwo64(c/9) && is32Bit(c)) {
continue
}
v.reset(OpARM64SLLconst)
@@ -20382,7 +20386,7 @@ func rewriteValueARM64_OpARM64UDIV(v *Value) bool {
return true
}
// match: (UDIV x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SRLconst [log2(c)] x)
for {
x := v_0
@@ -20390,7 +20394,7 @@ func rewriteValueARM64_OpARM64UDIV(v *Value) bool {
break
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64SRLconst)
@@ -20434,7 +20438,7 @@ func rewriteValueARM64_OpARM64UDIVW(v *Value) bool {
return true
}
// match: (UDIVW x (MOVDconst [c]))
- // cond: isPowerOfTwo(c) && is32Bit(c)
+ // cond: isPowerOfTwo64(c) && is32Bit(c)
// result: (SRLconst [log2(c)] x)
for {
x := v_0
@@ -20442,7 +20446,7 @@ func rewriteValueARM64_OpARM64UDIVW(v *Value) bool {
break
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c) && is32Bit(c)) {
+ if !(isPowerOfTwo64(c) && is32Bit(c)) {
break
}
v.reset(OpARM64SRLconst)
@@ -20498,7 +20502,7 @@ func rewriteValueARM64_OpARM64UMOD(v *Value) bool {
return true
}
// match: (UMOD x (MOVDconst [c]))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (ANDconst [c-1] x)
for {
x := v_0
@@ -20506,7 +20510,7 @@ func rewriteValueARM64_OpARM64UMOD(v *Value) bool {
break
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpARM64ANDconst)
@@ -20567,7 +20571,7 @@ func rewriteValueARM64_OpARM64UMODW(v *Value) bool {
return true
}
// match: (UMODW x (MOVDconst [c]))
- // cond: isPowerOfTwo(c) && is32Bit(c)
+ // cond: isPowerOfTwo64(c) && is32Bit(c)
// result: (ANDconst [c-1] x)
for {
x := v_0
@@ -20575,7 +20579,7 @@ func rewriteValueARM64_OpARM64UMODW(v *Value) bool {
break
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c) && is32Bit(c)) {
+ if !(isPowerOfTwo64(c) && is32Bit(c)) {
break
}
v.reset(OpARM64ANDconst)
@@ -21340,6 +21344,25 @@ func rewriteValueARM64_OpAddr(v *Value) bool {
return true
}
}
+func rewriteValueARM64_OpAtomicAnd32(v *Value) bool {
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (AtomicAnd32 ptr val mem)
+ // result: (Select1 (LoweredAtomicAnd32 ptr val mem))
+ for {
+ ptr := v_0
+ val := v_1
+ mem := v_2
+ v.reset(OpSelect1)
+ v0 := b.NewValue0(v.Pos, OpARM64LoweredAtomicAnd32, types.NewTuple(typ.UInt32, types.TypeMem))
+ v0.AddArg3(ptr, val, mem)
+ v.AddArg(v0)
+ return true
+ }
+}
func rewriteValueARM64_OpAtomicAnd8(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
@@ -21359,6 +21382,25 @@ func rewriteValueARM64_OpAtomicAnd8(v *Value) bool {
return true
}
}
+func rewriteValueARM64_OpAtomicOr32(v *Value) bool {
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (AtomicOr32 ptr val mem)
+ // result: (Select1 (LoweredAtomicOr32 ptr val mem))
+ for {
+ ptr := v_0
+ val := v_1
+ mem := v_2
+ v.reset(OpSelect1)
+ v0 := b.NewValue0(v.Pos, OpARM64LoweredAtomicOr32, types.NewTuple(typ.UInt32, types.TypeMem))
+ v0.AddArg3(ptr, val, mem)
+ v.AddArg(v0)
+ return true
+ }
+}
func rewriteValueARM64_OpAtomicOr8(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go
index bdafa9a957..0f0954fb83 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go
@@ -44,6 +44,9 @@ func rewriteValueMIPS(v *Value) bool {
case OpAtomicAdd32:
v.Op = OpMIPSLoweredAtomicAdd
return true
+ case OpAtomicAnd32:
+ v.Op = OpMIPSLoweredAtomicAnd
+ return true
case OpAtomicAnd8:
return rewriteValueMIPS_OpAtomicAnd8(v)
case OpAtomicCompareAndSwap32:
@@ -61,6 +64,9 @@ func rewriteValueMIPS(v *Value) bool {
case OpAtomicLoadPtr:
v.Op = OpMIPSLoweredAtomicLoad32
return true
+ case OpAtomicOr32:
+ v.Op = OpMIPSLoweredAtomicOr
+ return true
case OpAtomicOr8:
return rewriteValueMIPS_OpAtomicOr8(v)
case OpAtomicStore32:
@@ -862,11 +868,11 @@ func rewriteValueMIPS_OpConst8(v *Value) bool {
}
func rewriteValueMIPS_OpConstBool(v *Value) bool {
// match: (ConstBool [b])
- // result: (MOVWconst [int32(b2i(b))])
+ // result: (MOVWconst [b2i32(b)])
for {
b := auxIntToBool(v.AuxInt)
v.reset(OpMIPSMOVWconst)
- v.AuxInt = int32ToAuxInt(int32(b2i(b)))
+ v.AuxInt = int32ToAuxInt(b2i32(b))
return true
}
}
@@ -3846,7 +3852,7 @@ func rewriteValueMIPS_OpMIPSMUL(v *Value) bool {
break
}
// match: (MUL (MOVWconst [c]) x )
- // cond: isPowerOfTwo(int64(uint32(c)))
+ // cond: isPowerOfTwo64(int64(uint32(c)))
// result: (SLLconst [int32(log2uint32(int64(c)))] x)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
@@ -3855,7 +3861,7 @@ func rewriteValueMIPS_OpMIPSMUL(v *Value) bool {
}
c := auxIntToInt32(v_0.AuxInt)
x := v_1
- if !(isPowerOfTwo(int64(uint32(c)))) {
+ if !(isPowerOfTwo64(int64(uint32(c)))) {
continue
}
v.reset(OpMIPSSLLconst)
@@ -6382,7 +6388,7 @@ func rewriteValueMIPS_OpSelect0(v *Value) bool {
break
}
// match: (Select0 (MULTU (MOVWconst [c]) x ))
- // cond: isPowerOfTwo(int64(uint32(c)))
+ // cond: isPowerOfTwo64(int64(uint32(c)))
// result: (SRLconst [int32(32-log2uint32(int64(c)))] x)
for {
if v_0.Op != OpMIPSMULTU {
@@ -6397,7 +6403,7 @@ func rewriteValueMIPS_OpSelect0(v *Value) bool {
}
c := auxIntToInt32(v_0_0.AuxInt)
x := v_0_1
- if !(isPowerOfTwo(int64(uint32(c)))) {
+ if !(isPowerOfTwo64(int64(uint32(c)))) {
continue
}
v.reset(OpMIPSSRLconst)
@@ -6570,7 +6576,7 @@ func rewriteValueMIPS_OpSelect1(v *Value) bool {
break
}
// match: (Select1 (MULTU (MOVWconst [c]) x ))
- // cond: isPowerOfTwo(int64(uint32(c)))
+ // cond: isPowerOfTwo64(int64(uint32(c)))
// result: (SLLconst [int32(log2uint32(int64(c)))] x)
for {
if v_0.Op != OpMIPSMULTU {
@@ -6585,7 +6591,7 @@ func rewriteValueMIPS_OpSelect1(v *Value) bool {
}
c := auxIntToInt32(v_0_0.AuxInt)
x := v_0_1
- if !(isPowerOfTwo(int64(uint32(c)))) {
+ if !(isPowerOfTwo64(int64(uint32(c)))) {
continue
}
v.reset(OpMIPSSLLconst)
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
index dfff1c03b7..d0751ee5c3 100644
--- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
@@ -6865,7 +6865,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value) bool {
return true
}
// match: (Select0 (DIVVU x (MOVVconst [c])))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (ANDconst [c-1] x)
for {
if v_0.Op != OpMIPS64DIVVU {
@@ -6878,7 +6878,7 @@ func rewriteValueMIPS64_OpSelect0(v *Value) bool {
break
}
c := auxIntToInt64(v_0_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpMIPS64ANDconst)
@@ -7012,7 +7012,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value) bool {
break
}
// match: (Select1 (MULVU x (MOVVconst [c])))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SLLVconst [log2(c)] x)
for {
if v_0.Op != OpMIPS64MULVU {
@@ -7027,7 +7027,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value) bool {
continue
}
c := auxIntToInt64(v_0_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
continue
}
v.reset(OpMIPS64SLLVconst)
@@ -7053,7 +7053,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value) bool {
return true
}
// match: (Select1 (DIVVU x (MOVVconst [c])))
- // cond: isPowerOfTwo(c)
+ // cond: isPowerOfTwo64(c)
// result: (SRLVconst [log2(c)] x)
for {
if v_0.Op != OpMIPS64DIVVU {
@@ -7066,7 +7066,7 @@ func rewriteValueMIPS64_OpSelect1(v *Value) bool {
break
}
c := auxIntToInt64(v_0_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isPowerOfTwo64(c)) {
break
}
v.reset(OpMIPS64SRLVconst)
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 29ec3992f2..e5a23e8625 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -59,6 +59,9 @@ func rewriteValuePPC64(v *Value) bool {
case OpAtomicAdd64:
v.Op = OpPPC64LoweredAtomicAdd64
return true
+ case OpAtomicAnd32:
+ v.Op = OpPPC64LoweredAtomicAnd32
+ return true
case OpAtomicAnd8:
v.Op = OpPPC64LoweredAtomicAnd8
return true
@@ -82,8 +85,13 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpAtomicLoad8(v)
case OpAtomicLoadAcq32:
return rewriteValuePPC64_OpAtomicLoadAcq32(v)
+ case OpAtomicLoadAcq64:
+ return rewriteValuePPC64_OpAtomicLoadAcq64(v)
case OpAtomicLoadPtr:
return rewriteValuePPC64_OpAtomicLoadPtr(v)
+ case OpAtomicOr32:
+ v.Op = OpPPC64LoweredAtomicOr32
+ return true
case OpAtomicOr8:
v.Op = OpPPC64LoweredAtomicOr8
return true
@@ -95,6 +103,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpAtomicStore8(v)
case OpAtomicStoreRel32:
return rewriteValuePPC64_OpAtomicStoreRel32(v)
+ case OpAtomicStoreRel64:
+ return rewriteValuePPC64_OpAtomicStoreRel64(v)
case OpAvg64u:
return rewriteValuePPC64_OpAvg64u(v)
case OpBitLen32:
@@ -434,6 +444,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpPPC64ANDN(v)
case OpPPC64ANDconst:
return rewriteValuePPC64_OpPPC64ANDconst(v)
+ case OpPPC64CLRLSLDI:
+ return rewriteValuePPC64_OpPPC64CLRLSLDI(v)
case OpPPC64CMP:
return rewriteValuePPC64_OpPPC64CMP(v)
case OpPPC64CMPU:
@@ -568,6 +580,10 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpPPC64MOVWstorezero(v)
case OpPPC64MTVSRD:
return rewriteValuePPC64_OpPPC64MTVSRD(v)
+ case OpPPC64MULLD:
+ return rewriteValuePPC64_OpPPC64MULLD(v)
+ case OpPPC64MULLW:
+ return rewriteValuePPC64_OpPPC64MULLW(v)
case OpPPC64NEG:
return rewriteValuePPC64_OpPPC64NEG(v)
case OpPPC64NOR:
@@ -584,6 +600,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpPPC64ROTL(v)
case OpPPC64ROTLW:
return rewriteValuePPC64_OpPPC64ROTLW(v)
+ case OpPPC64ROTLWconst:
+ return rewriteValuePPC64_OpPPC64ROTLWconst(v)
case OpPPC64SLD:
return rewriteValuePPC64_OpPPC64SLD(v)
case OpPPC64SLDconst:
@@ -600,6 +618,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpPPC64SRD(v)
case OpPPC64SRW:
return rewriteValuePPC64_OpPPC64SRW(v)
+ case OpPPC64SRWconst:
+ return rewriteValuePPC64_OpPPC64SRWconst(v)
case OpPPC64SUB:
return rewriteValuePPC64_OpPPC64SUB(v)
case OpPPC64SUBFCconst:
@@ -926,6 +946,20 @@ func rewriteValuePPC64_OpAtomicLoadAcq32(v *Value) bool {
return true
}
}
+func rewriteValuePPC64_OpAtomicLoadAcq64(v *Value) bool {
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ // match: (AtomicLoadAcq64 ptr mem)
+ // result: (LoweredAtomicLoad64 [0] ptr mem)
+ for {
+ ptr := v_0
+ mem := v_1
+ v.reset(OpPPC64LoweredAtomicLoad64)
+ v.AuxInt = int64ToAuxInt(0)
+ v.AddArg2(ptr, mem)
+ return true
+ }
+}
func rewriteValuePPC64_OpAtomicLoadPtr(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -1004,6 +1038,22 @@ func rewriteValuePPC64_OpAtomicStoreRel32(v *Value) bool {
return true
}
}
+func rewriteValuePPC64_OpAtomicStoreRel64(v *Value) bool {
+ v_2 := v.Args[2]
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ // match: (AtomicStoreRel64 ptr val mem)
+ // result: (LoweredAtomicStore64 [0] ptr val mem)
+ for {
+ ptr := v_0
+ val := v_1
+ mem := v_2
+ v.reset(OpPPC64LoweredAtomicStore64)
+ v.AuxInt = int64ToAuxInt(0)
+ v.AddArg3(ptr, val, mem)
+ return true
+ }
+}
func rewriteValuePPC64_OpAvg64u(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -4168,6 +4218,100 @@ func rewriteValuePPC64_OpPPC64ADDconst(v *Value) bool {
func rewriteValuePPC64_OpPPC64AND(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
+ // match: (AND (MOVDconst [m]) (ROTLWconst [r] x))
+ // cond: isPPC64WordRotateMask(m)
+ // result: (RLWINM [encodePPC64RotateMask(r,m,32)] x)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpPPC64MOVDconst {
+ continue
+ }
+ m := auxIntToInt64(v_0.AuxInt)
+ if v_1.Op != OpPPC64ROTLWconst {
+ continue
+ }
+ r := auxIntToInt64(v_1.AuxInt)
+ x := v_1.Args[0]
+ if !(isPPC64WordRotateMask(m)) {
+ continue
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(encodePPC64RotateMask(r, m, 32))
+ v.AddArg(x)
+ return true
+ }
+ break
+ }
+ // match: (AND (MOVDconst [m]) (ROTLW x r))
+ // cond: isPPC64WordRotateMask(m)
+ // result: (RLWNM [encodePPC64RotateMask(0,m,32)] x r)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpPPC64MOVDconst {
+ continue
+ }
+ m := auxIntToInt64(v_0.AuxInt)
+ if v_1.Op != OpPPC64ROTLW {
+ continue
+ }
+ r := v_1.Args[1]
+ x := v_1.Args[0]
+ if !(isPPC64WordRotateMask(m)) {
+ continue
+ }
+ v.reset(OpPPC64RLWNM)
+ v.AuxInt = int64ToAuxInt(encodePPC64RotateMask(0, m, 32))
+ v.AddArg2(x, r)
+ return true
+ }
+ break
+ }
+ // match: (AND (MOVDconst [m]) (SRWconst x [s]))
+ // cond: mergePPC64RShiftMask(m,s,32) == 0
+ // result: (MOVDconst [0])
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpPPC64MOVDconst {
+ continue
+ }
+ m := auxIntToInt64(v_0.AuxInt)
+ if v_1.Op != OpPPC64SRWconst {
+ continue
+ }
+ s := auxIntToInt64(v_1.AuxInt)
+ if !(mergePPC64RShiftMask(m, s, 32) == 0) {
+ continue
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = int64ToAuxInt(0)
+ return true
+ }
+ break
+ }
+ // match: (AND (MOVDconst [m]) (SRWconst x [s]))
+ // cond: mergePPC64AndSrwi(m,s) != 0
+ // result: (RLWINM [mergePPC64AndSrwi(m,s)] x)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpPPC64MOVDconst {
+ continue
+ }
+ m := auxIntToInt64(v_0.AuxInt)
+ if v_1.Op != OpPPC64SRWconst {
+ continue
+ }
+ s := auxIntToInt64(v_1.AuxInt)
+ x := v_1.Args[0]
+ if !(mergePPC64AndSrwi(m, s) != 0) {
+ continue
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(mergePPC64AndSrwi(m, s))
+ v.AddArg(x)
+ return true
+ }
+ break
+ }
// match: (AND x (NOR y y))
// result: (ANDN x y)
for {
@@ -4303,6 +4447,76 @@ func rewriteValuePPC64_OpPPC64ANDN(v *Value) bool {
}
func rewriteValuePPC64_OpPPC64ANDconst(v *Value) bool {
v_0 := v.Args[0]
+ // match: (ANDconst [m] (ROTLWconst [r] x))
+ // cond: isPPC64WordRotateMask(m)
+ // result: (RLWINM [encodePPC64RotateMask(r,m,32)] x)
+ for {
+ m := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64ROTLWconst {
+ break
+ }
+ r := auxIntToInt64(v_0.AuxInt)
+ x := v_0.Args[0]
+ if !(isPPC64WordRotateMask(m)) {
+ break
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(encodePPC64RotateMask(r, m, 32))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDconst [m] (ROTLW x r))
+ // cond: isPPC64WordRotateMask(m)
+ // result: (RLWNM [encodePPC64RotateMask(0,m,32)] x r)
+ for {
+ m := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64ROTLW {
+ break
+ }
+ r := v_0.Args[1]
+ x := v_0.Args[0]
+ if !(isPPC64WordRotateMask(m)) {
+ break
+ }
+ v.reset(OpPPC64RLWNM)
+ v.AuxInt = int64ToAuxInt(encodePPC64RotateMask(0, m, 32))
+ v.AddArg2(x, r)
+ return true
+ }
+ // match: (ANDconst [m] (SRWconst x [s]))
+ // cond: mergePPC64RShiftMask(m,s,32) == 0
+ // result: (MOVDconst [0])
+ for {
+ m := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64SRWconst {
+ break
+ }
+ s := auxIntToInt64(v_0.AuxInt)
+ if !(mergePPC64RShiftMask(m, s, 32) == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = int64ToAuxInt(0)
+ return true
+ }
+ // match: (ANDconst [m] (SRWconst x [s]))
+ // cond: mergePPC64AndSrwi(m,s) != 0
+ // result: (RLWINM [mergePPC64AndSrwi(m,s)] x)
+ for {
+ m := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64SRWconst {
+ break
+ }
+ s := auxIntToInt64(v_0.AuxInt)
+ x := v_0.Args[0]
+ if !(mergePPC64AndSrwi(m, s) != 0) {
+ break
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(mergePPC64AndSrwi(m, s))
+ v.AddArg(x)
+ return true
+ }
// match: (ANDconst [c] (ANDconst [d] x))
// result: (ANDconst [c&d] x)
for {
@@ -4467,6 +4681,47 @@ func rewriteValuePPC64_OpPPC64ANDconst(v *Value) bool {
}
return false
}
+func rewriteValuePPC64_OpPPC64CLRLSLDI(v *Value) bool {
+ v_0 := v.Args[0]
+ // match: (CLRLSLDI [c] (SRWconst [s] x))
+ // cond: mergePPC64ClrlsldiSrw(int64(c),s) != 0
+ // result: (RLWINM [mergePPC64ClrlsldiSrw(int64(c),s)] x)
+ for {
+ c := auxIntToInt32(v.AuxInt)
+ if v_0.Op != OpPPC64SRWconst {
+ break
+ }
+ s := auxIntToInt64(v_0.AuxInt)
+ x := v_0.Args[0]
+ if !(mergePPC64ClrlsldiSrw(int64(c), s) != 0) {
+ break
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(mergePPC64ClrlsldiSrw(int64(c), s))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CLRLSLDI [c] i:(RLWINM [s] x))
+ // cond: mergePPC64ClrlsldiRlwinm(c,s) != 0
+ // result: (RLWINM [mergePPC64ClrlsldiRlwinm(c,s)] x)
+ for {
+ c := auxIntToInt32(v.AuxInt)
+ i := v_0
+ if i.Op != OpPPC64RLWINM {
+ break
+ }
+ s := auxIntToInt64(i.AuxInt)
+ x := i.Args[0]
+ if !(mergePPC64ClrlsldiRlwinm(c, s) != 0) {
+ break
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(mergePPC64ClrlsldiRlwinm(c, s))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
func rewriteValuePPC64_OpPPC64CMP(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -11003,6 +11258,56 @@ func rewriteValuePPC64_OpPPC64MTVSRD(v *Value) bool {
}
return false
}
+func rewriteValuePPC64_OpPPC64MULLD(v *Value) bool {
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ // match: (MULLD x (MOVDconst [c]))
+ // cond: is16Bit(c)
+ // result: (MULLDconst [int32(c)] x)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ x := v_0
+ if v_1.Op != OpPPC64MOVDconst {
+ continue
+ }
+ c := auxIntToInt64(v_1.AuxInt)
+ if !(is16Bit(c)) {
+ continue
+ }
+ v.reset(OpPPC64MULLDconst)
+ v.AuxInt = int32ToAuxInt(int32(c))
+ v.AddArg(x)
+ return true
+ }
+ break
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MULLW(v *Value) bool {
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ // match: (MULLW x (MOVDconst [c]))
+ // cond: is16Bit(c)
+ // result: (MULLWconst [int32(c)] x)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ x := v_0
+ if v_1.Op != OpPPC64MOVDconst {
+ continue
+ }
+ c := auxIntToInt64(v_1.AuxInt)
+ if !(is16Bit(c)) {
+ continue
+ }
+ v.reset(OpPPC64MULLWconst)
+ v.AuxInt = int32ToAuxInt(int32(c))
+ v.AddArg(x)
+ return true
+ }
+ break
+ }
+ return false
+}
func rewriteValuePPC64_OpPPC64NEG(v *Value) bool {
v_0 := v.Args[0]
// match: (NEG (ADDconst [c] x))
@@ -12756,6 +13061,55 @@ func rewriteValuePPC64_OpPPC64ROTLW(v *Value) bool {
}
return false
}
+func rewriteValuePPC64_OpPPC64ROTLWconst(v *Value) bool {
+ v_0 := v.Args[0]
+ // match: (ROTLWconst [r] (AND (MOVDconst [m]) x))
+ // cond: isPPC64WordRotateMask(m)
+ // result: (RLWINM [encodePPC64RotateMask(r,rotateLeft32(m,r),32)] x)
+ for {
+ r := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64AND {
+ break
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ if v_0_0.Op != OpPPC64MOVDconst {
+ continue
+ }
+ m := auxIntToInt64(v_0_0.AuxInt)
+ x := v_0_1
+ if !(isPPC64WordRotateMask(m)) {
+ continue
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(encodePPC64RotateMask(r, rotateLeft32(m, r), 32))
+ v.AddArg(x)
+ return true
+ }
+ break
+ }
+ // match: (ROTLWconst [r] (ANDconst [m] x))
+ // cond: isPPC64WordRotateMask(m)
+ // result: (RLWINM [encodePPC64RotateMask(r,rotateLeft32(m,r),32)] x)
+ for {
+ r := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64ANDconst {
+ break
+ }
+ m := auxIntToInt64(v_0.AuxInt)
+ x := v_0.Args[0]
+ if !(isPPC64WordRotateMask(m)) {
+ break
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(encodePPC64RotateMask(r, rotateLeft32(m, r), 32))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
func rewriteValuePPC64_OpPPC64SLD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -12776,6 +13130,24 @@ func rewriteValuePPC64_OpPPC64SLD(v *Value) bool {
}
func rewriteValuePPC64_OpPPC64SLDconst(v *Value) bool {
v_0 := v.Args[0]
+ // match: (SLDconst [l] (SRWconst [r] x))
+ // cond: mergePPC64SldiSrw(l,r) != 0
+ // result: (RLWINM [mergePPC64SldiSrw(l,r)] x)
+ for {
+ l := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64SRWconst {
+ break
+ }
+ r := auxIntToInt64(v_0.AuxInt)
+ x := v_0.Args[0]
+ if !(mergePPC64SldiSrw(l, r) != 0) {
+ break
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(mergePPC64SldiSrw(l, r))
+ v.AddArg(x)
+ return true
+ }
// match: (SLDconst [c] z:(MOVBZreg x))
// cond: c < 8 && z.Uses == 1
// result: (CLRLSLDI [newPPC64ShiftAuxInt(c,56,63,64)] x)
@@ -12831,7 +13203,7 @@ func rewriteValuePPC64_OpPPC64SLDconst(v *Value) bool {
return true
}
// match: (SLDconst [c] z:(ANDconst [d] x))
- // cond: z.Uses == 1 && isPPC64ValidShiftMask(d)
+ // cond: z.Uses == 1 && isPPC64ValidShiftMask(d) && c <= (64-getPPC64ShiftMaskLength(d))
// result: (CLRLSLDI [newPPC64ShiftAuxInt(c,64-getPPC64ShiftMaskLength(d),63,64)] x)
for {
c := auxIntToInt64(v.AuxInt)
@@ -12841,7 +13213,7 @@ func rewriteValuePPC64_OpPPC64SLDconst(v *Value) bool {
}
d := auxIntToInt64(z.AuxInt)
x := z.Args[0]
- if !(z.Uses == 1 && isPPC64ValidShiftMask(d)) {
+ if !(z.Uses == 1 && isPPC64ValidShiftMask(d) && c <= (64-getPPC64ShiftMaskLength(d))) {
break
}
v.reset(OpPPC64CLRLSLDI)
@@ -12850,7 +13222,7 @@ func rewriteValuePPC64_OpPPC64SLDconst(v *Value) bool {
return true
}
// match: (SLDconst [c] z:(AND (MOVDconst [d]) x))
- // cond: z.Uses == 1 && isPPC64ValidShiftMask(d)
+ // cond: z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(64-getPPC64ShiftMaskLength(d))
// result: (CLRLSLDI [newPPC64ShiftAuxInt(c,64-getPPC64ShiftMaskLength(d),63,64)] x)
for {
c := auxIntToInt64(v.AuxInt)
@@ -12867,7 +13239,7 @@ func rewriteValuePPC64_OpPPC64SLDconst(v *Value) bool {
}
d := auxIntToInt64(z_0.AuxInt)
x := z_1
- if !(z.Uses == 1 && isPPC64ValidShiftMask(d)) {
+ if !(z.Uses == 1 && isPPC64ValidShiftMask(d) && c <= (64-getPPC64ShiftMaskLength(d))) {
continue
}
v.reset(OpPPC64CLRLSLDI)
@@ -12953,26 +13325,8 @@ func rewriteValuePPC64_OpPPC64SLWconst(v *Value) bool {
v.AddArg(x)
return true
}
- // match: (SLWconst [c] z:(MOVWZreg x))
- // cond: z.Uses == 1 && c < 24
- // result: (CLRLSLWI [newPPC64ShiftAuxInt(c,8,31,32)] x)
- for {
- c := auxIntToInt64(v.AuxInt)
- z := v_0
- if z.Op != OpPPC64MOVWZreg {
- break
- }
- x := z.Args[0]
- if !(z.Uses == 1 && c < 24) {
- break
- }
- v.reset(OpPPC64CLRLSLWI)
- v.AuxInt = int32ToAuxInt(newPPC64ShiftAuxInt(c, 8, 31, 32))
- v.AddArg(x)
- return true
- }
// match: (SLWconst [c] z:(ANDconst [d] x))
- // cond: z.Uses == 1 && isPPC64ValidShiftMask(d)
+ // cond: z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(32-getPPC64ShiftMaskLength(d))
// result: (CLRLSLWI [newPPC64ShiftAuxInt(c,32-getPPC64ShiftMaskLength(d),31,32)] x)
for {
c := auxIntToInt64(v.AuxInt)
@@ -12982,7 +13336,7 @@ func rewriteValuePPC64_OpPPC64SLWconst(v *Value) bool {
}
d := auxIntToInt64(z.AuxInt)
x := z.Args[0]
- if !(z.Uses == 1 && isPPC64ValidShiftMask(d)) {
+ if !(z.Uses == 1 && isPPC64ValidShiftMask(d) && c <= (32-getPPC64ShiftMaskLength(d))) {
break
}
v.reset(OpPPC64CLRLSLWI)
@@ -12991,7 +13345,7 @@ func rewriteValuePPC64_OpPPC64SLWconst(v *Value) bool {
return true
}
// match: (SLWconst [c] z:(AND (MOVDconst [d]) x))
- // cond: z.Uses == 1 && isPPC64ValidShiftMask(d)
+ // cond: z.Uses == 1 && isPPC64ValidShiftMask(d) && c<=(32-getPPC64ShiftMaskLength(d))
// result: (CLRLSLWI [newPPC64ShiftAuxInt(c,32-getPPC64ShiftMaskLength(d),31,32)] x)
for {
c := auxIntToInt64(v.AuxInt)
@@ -13008,7 +13362,7 @@ func rewriteValuePPC64_OpPPC64SLWconst(v *Value) bool {
}
d := auxIntToInt64(z_0.AuxInt)
x := z_1
- if !(z.Uses == 1 && isPPC64ValidShiftMask(d)) {
+ if !(z.Uses == 1 && isPPC64ValidShiftMask(d) && c <= (32-getPPC64ShiftMaskLength(d))) {
continue
}
v.reset(OpPPC64CLRLSLWI)
@@ -13110,6 +13464,96 @@ func rewriteValuePPC64_OpPPC64SRW(v *Value) bool {
}
return false
}
+func rewriteValuePPC64_OpPPC64SRWconst(v *Value) bool {
+ v_0 := v.Args[0]
+ // match: (SRWconst (ANDconst [m] x) [s])
+ // cond: mergePPC64RShiftMask(m>>uint(s),s,32) == 0
+ // result: (MOVDconst [0])
+ for {
+ s := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64ANDconst {
+ break
+ }
+ m := auxIntToInt64(v_0.AuxInt)
+ if !(mergePPC64RShiftMask(m>>uint(s), s, 32) == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = int64ToAuxInt(0)
+ return true
+ }
+ // match: (SRWconst (ANDconst [m] x) [s])
+ // cond: mergePPC64AndSrwi(m>>uint(s),s) != 0
+ // result: (RLWINM [mergePPC64AndSrwi(m>>uint(s),s)] x)
+ for {
+ s := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64ANDconst {
+ break
+ }
+ m := auxIntToInt64(v_0.AuxInt)
+ x := v_0.Args[0]
+ if !(mergePPC64AndSrwi(m>>uint(s), s) != 0) {
+ break
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(mergePPC64AndSrwi(m>>uint(s), s))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRWconst (AND (MOVDconst [m]) x) [s])
+ // cond: mergePPC64RShiftMask(m>>uint(s),s,32) == 0
+ // result: (MOVDconst [0])
+ for {
+ s := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64AND {
+ break
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ if v_0_0.Op != OpPPC64MOVDconst {
+ continue
+ }
+ m := auxIntToInt64(v_0_0.AuxInt)
+ if !(mergePPC64RShiftMask(m>>uint(s), s, 32) == 0) {
+ continue
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = int64ToAuxInt(0)
+ return true
+ }
+ break
+ }
+ // match: (SRWconst (AND (MOVDconst [m]) x) [s])
+ // cond: mergePPC64AndSrwi(m>>uint(s),s) != 0
+ // result: (RLWINM [mergePPC64AndSrwi(m>>uint(s),s)] x)
+ for {
+ s := auxIntToInt64(v.AuxInt)
+ if v_0.Op != OpPPC64AND {
+ break
+ }
+ _ = v_0.Args[1]
+ v_0_0 := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 {
+ if v_0_0.Op != OpPPC64MOVDconst {
+ continue
+ }
+ m := auxIntToInt64(v_0_0.AuxInt)
+ x := v_0_1
+ if !(mergePPC64AndSrwi(m>>uint(s), s) != 0) {
+ continue
+ }
+ v.reset(OpPPC64RLWINM)
+ v.AuxInt = int64ToAuxInt(mergePPC64AndSrwi(m>>uint(s), s))
+ v.AddArg(x)
+ return true
+ }
+ break
+ }
+ return false
+}
func rewriteValuePPC64_OpPPC64SUB(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
index c178290343..c337ffbfe7 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -420,8 +420,12 @@ func rewriteValueRISCV64(v *Value) bool {
return rewriteValueRISCV64_OpRISCV64AND(v)
case OpRISCV64MOVBUload:
return rewriteValueRISCV64_OpRISCV64MOVBUload(v)
+ case OpRISCV64MOVBUreg:
+ return rewriteValueRISCV64_OpRISCV64MOVBUreg(v)
case OpRISCV64MOVBload:
return rewriteValueRISCV64_OpRISCV64MOVBload(v)
+ case OpRISCV64MOVBreg:
+ return rewriteValueRISCV64_OpRISCV64MOVBreg(v)
case OpRISCV64MOVBstore:
return rewriteValueRISCV64_OpRISCV64MOVBstore(v)
case OpRISCV64MOVBstorezero:
@@ -430,22 +434,32 @@ func rewriteValueRISCV64(v *Value) bool {
return rewriteValueRISCV64_OpRISCV64MOVDconst(v)
case OpRISCV64MOVDload:
return rewriteValueRISCV64_OpRISCV64MOVDload(v)
+ case OpRISCV64MOVDreg:
+ return rewriteValueRISCV64_OpRISCV64MOVDreg(v)
case OpRISCV64MOVDstore:
return rewriteValueRISCV64_OpRISCV64MOVDstore(v)
case OpRISCV64MOVDstorezero:
return rewriteValueRISCV64_OpRISCV64MOVDstorezero(v)
case OpRISCV64MOVHUload:
return rewriteValueRISCV64_OpRISCV64MOVHUload(v)
+ case OpRISCV64MOVHUreg:
+ return rewriteValueRISCV64_OpRISCV64MOVHUreg(v)
case OpRISCV64MOVHload:
return rewriteValueRISCV64_OpRISCV64MOVHload(v)
+ case OpRISCV64MOVHreg:
+ return rewriteValueRISCV64_OpRISCV64MOVHreg(v)
case OpRISCV64MOVHstore:
return rewriteValueRISCV64_OpRISCV64MOVHstore(v)
case OpRISCV64MOVHstorezero:
return rewriteValueRISCV64_OpRISCV64MOVHstorezero(v)
case OpRISCV64MOVWUload:
return rewriteValueRISCV64_OpRISCV64MOVWUload(v)
+ case OpRISCV64MOVWUreg:
+ return rewriteValueRISCV64_OpRISCV64MOVWUreg(v)
case OpRISCV64MOVWload:
return rewriteValueRISCV64_OpRISCV64MOVWload(v)
+ case OpRISCV64MOVWreg:
+ return rewriteValueRISCV64_OpRISCV64MOVWreg(v)
case OpRISCV64MOVWstore:
return rewriteValueRISCV64_OpRISCV64MOVWstore(v)
case OpRISCV64MOVWstorezero:
@@ -543,17 +557,23 @@ func rewriteValueRISCV64(v *Value) bool {
case OpRsh8x8:
return rewriteValueRISCV64_OpRsh8x8(v)
case OpSignExt16to32:
- return rewriteValueRISCV64_OpSignExt16to32(v)
+ v.Op = OpRISCV64MOVHreg
+ return true
case OpSignExt16to64:
- return rewriteValueRISCV64_OpSignExt16to64(v)
+ v.Op = OpRISCV64MOVHreg
+ return true
case OpSignExt32to64:
- return rewriteValueRISCV64_OpSignExt32to64(v)
+ v.Op = OpRISCV64MOVWreg
+ return true
case OpSignExt8to16:
- return rewriteValueRISCV64_OpSignExt8to16(v)
+ v.Op = OpRISCV64MOVBreg
+ return true
case OpSignExt8to32:
- return rewriteValueRISCV64_OpSignExt8to32(v)
+ v.Op = OpRISCV64MOVBreg
+ return true
case OpSignExt8to64:
- return rewriteValueRISCV64_OpSignExt8to64(v)
+ v.Op = OpRISCV64MOVBreg
+ return true
case OpSlicemask:
return rewriteValueRISCV64_OpSlicemask(v)
case OpSqrt:
@@ -621,17 +641,23 @@ func rewriteValueRISCV64(v *Value) bool {
case OpZero:
return rewriteValueRISCV64_OpZero(v)
case OpZeroExt16to32:
- return rewriteValueRISCV64_OpZeroExt16to32(v)
+ v.Op = OpRISCV64MOVHUreg
+ return true
case OpZeroExt16to64:
- return rewriteValueRISCV64_OpZeroExt16to64(v)
+ v.Op = OpRISCV64MOVHUreg
+ return true
case OpZeroExt32to64:
- return rewriteValueRISCV64_OpZeroExt32to64(v)
+ v.Op = OpRISCV64MOVWUreg
+ return true
case OpZeroExt8to16:
- return rewriteValueRISCV64_OpZeroExt8to16(v)
+ v.Op = OpRISCV64MOVBUreg
+ return true
case OpZeroExt8to32:
- return rewriteValueRISCV64_OpZeroExt8to32(v)
+ v.Op = OpRISCV64MOVBUreg
+ return true
case OpZeroExt8to64:
- return rewriteValueRISCV64_OpZeroExt8to64(v)
+ v.Op = OpRISCV64MOVBUreg
+ return true
}
return false
}
@@ -844,15 +870,17 @@ func rewriteValueRISCV64_OpEq16(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq16 x y)
- // result: (SEQZ (ZeroExt16to64 (SUB <x.Type> x y)))
+ // result: (SEQZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SEQZ)
- v0 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
- v1 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
- v1.AddArg2(x, y)
- v0.AddArg(v1)
+ v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
+ v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
+ v1.AddArg(x)
+ v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
+ v2.AddArg(y)
+ v0.AddArg2(v1, v2)
v.AddArg(v0)
return true
}
@@ -895,15 +923,17 @@ func rewriteValueRISCV64_OpEq8(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Eq8 x y)
- // result: (SEQZ (ZeroExt8to64 (SUB <x.Type> x y)))
+ // result: (SEQZ (SUB <x.Type> (ZeroExt8to64 x) (ZeroExt8to64 y)))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SEQZ)
- v0 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
- v1 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
- v1.AddArg2(x, y)
- v0.AddArg(v1)
+ v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
+ v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
+ v1.AddArg(x)
+ v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
+ v2.AddArg(y)
+ v0.AddArg2(v1, v2)
v.AddArg(v0)
return true
}
@@ -1987,6 +2017,23 @@ func rewriteValueRISCV64_OpMove(v *Value) bool {
return true
}
// match: (Move [s] {t} dst src mem)
+ // cond: s%8 == 0 && s >= 16 && s <= 8*128 && t.Alignment()%8 == 0 && !config.noDuffDevice && logLargeCopy(v, s)
+ // result: (DUFFCOPY [16 * (128 - s/8)] dst src mem)
+ for {
+ s := auxIntToInt64(v.AuxInt)
+ t := auxToType(v.Aux)
+ dst := v_0
+ src := v_1
+ mem := v_2
+ if !(s%8 == 0 && s >= 16 && s <= 8*128 && t.Alignment()%8 == 0 && !config.noDuffDevice && logLargeCopy(v, s)) {
+ break
+ }
+ v.reset(OpRISCV64DUFFCOPY)
+ v.AuxInt = int64ToAuxInt(16 * (128 - s/8))
+ v.AddArg3(dst, src, mem)
+ return true
+ }
+ // match: (Move [s] {t} dst src mem)
// cond: (s <= 16 || logLargeCopy(v, s))
// result: (LoweredMove [t.Alignment()] dst src (ADDI <src.Type> [s-moveSize(t.Alignment(), config)] src) mem)
for {
@@ -2052,15 +2099,17 @@ func rewriteValueRISCV64_OpNeq16(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Neq16 x y)
- // result: (SNEZ (ZeroExt16to64 (SUB <x.Type> x y)))
+ // result: (SNEZ (SUB <x.Type> (ZeroExt16to64 x) (ZeroExt16to64 y)))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SNEZ)
- v0 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
- v1 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
- v1.AddArg2(x, y)
- v0.AddArg(v1)
+ v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
+ v1 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
+ v1.AddArg(x)
+ v2 := b.NewValue0(v.Pos, OpZeroExt16to64, typ.UInt64)
+ v2.AddArg(y)
+ v0.AddArg2(v1, v2)
v.AddArg(v0)
return true
}
@@ -2103,15 +2152,17 @@ func rewriteValueRISCV64_OpNeq8(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (Neq8 x y)
- // result: (SNEZ (ZeroExt8to64 (SUB <x.Type> x y)))
+ // result: (SNEZ (SUB <x.Type> (ZeroExt8to64 x) (ZeroExt8to64 y)))
for {
x := v_0
y := v_1
v.reset(OpRISCV64SNEZ)
- v0 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
- v1 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
- v1.AddArg2(x, y)
- v0.AddArg(v1)
+ v0 := b.NewValue0(v.Pos, OpRISCV64SUB, x.Type)
+ v1 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
+ v1.AddArg(x)
+ v2 := b.NewValue0(v.Pos, OpZeroExt8to64, typ.UInt64)
+ v2.AddArg(y)
+ v0.AddArg2(v1, v2)
v.AddArg(v0)
return true
}
@@ -2458,6 +2509,57 @@ func rewriteValueRISCV64_OpRISCV64MOVBUload(v *Value) bool {
}
return false
}
+func rewriteValueRISCV64_OpRISCV64MOVBUreg(v *Value) bool {
+ v_0 := v.Args[0]
+ b := v.Block
+ // match: (MOVBUreg x:(MOVBUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg x:(MOVBUreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg <t> x:(MOVBload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBUload <t> [off] {sym} ptr mem)
+ for {
+ t := v.Type
+ x := v_0
+ if x.Op != OpRISCV64MOVBload {
+ break
+ }
+ off := auxIntToInt32(x.AuxInt)
+ sym := auxToSym(x.Aux)
+ mem := x.Args[1]
+ ptr := x.Args[0]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(x.Pos, OpRISCV64MOVBUload, t)
+ v.copyOf(v0)
+ v0.AuxInt = int32ToAuxInt(off)
+ v0.Aux = symToAux(sym)
+ v0.AddArg2(ptr, mem)
+ return true
+ }
+ return false
+}
func rewriteValueRISCV64_OpRISCV64MOVBload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -2506,6 +2608,57 @@ func rewriteValueRISCV64_OpRISCV64MOVBload(v *Value) bool {
}
return false
}
+func rewriteValueRISCV64_OpRISCV64MOVBreg(v *Value) bool {
+ v_0 := v.Args[0]
+ b := v.Block
+ // match: (MOVBreg x:(MOVBload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg x:(MOVBreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg <t> x:(MOVBUload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBload <t> [off] {sym} ptr mem)
+ for {
+ t := v.Type
+ x := v_0
+ if x.Op != OpRISCV64MOVBUload {
+ break
+ }
+ off := auxIntToInt32(x.AuxInt)
+ sym := auxToSym(x.Aux)
+ mem := x.Args[1]
+ ptr := x.Args[0]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(x.Pos, OpRISCV64MOVBload, t)
+ v.copyOf(v0)
+ v0.AuxInt = int32ToAuxInt(off)
+ v0.Aux = symToAux(sym)
+ v0.AddArg2(ptr, mem)
+ return true
+ }
+ return false
+}
func rewriteValueRISCV64_OpRISCV64MOVBstore(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
@@ -2571,6 +2724,108 @@ func rewriteValueRISCV64_OpRISCV64MOVBstore(v *Value) bool {
v.AddArg2(ptr, mem)
return true
}
+ // match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVBreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVBstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHreg x) mem)
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVBstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVWreg x) mem)
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVBstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBUreg x) mem)
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVBUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVBstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHUreg x) mem)
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVBstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVWUreg x) mem)
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVBstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
return false
}
func rewriteValueRISCV64_OpRISCV64MOVBstorezero(v *Value) bool {
@@ -2714,6 +2969,22 @@ func rewriteValueRISCV64_OpRISCV64MOVDload(v *Value) bool {
}
return false
}
+func rewriteValueRISCV64_OpRISCV64MOVDreg(v *Value) bool {
+ v_0 := v.Args[0]
+ // match: (MOVDreg x)
+ // cond: x.Uses == 1
+ // result: (MOVDnop x)
+ for {
+ x := v_0
+ if !(x.Uses == 1) {
+ break
+ }
+ v.reset(OpRISCV64MOVDnop)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
func rewriteValueRISCV64_OpRISCV64MOVDstore(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
@@ -2877,6 +3148,79 @@ func rewriteValueRISCV64_OpRISCV64MOVHUload(v *Value) bool {
}
return false
}
+func rewriteValueRISCV64_OpRISCV64MOVHUreg(v *Value) bool {
+ v_0 := v.Args[0]
+ b := v.Block
+ // match: (MOVHUreg x:(MOVBUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVBUreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHUreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg <t> x:(MOVHload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVHUload <t> [off] {sym} ptr mem)
+ for {
+ t := v.Type
+ x := v_0
+ if x.Op != OpRISCV64MOVHload {
+ break
+ }
+ off := auxIntToInt32(x.AuxInt)
+ sym := auxToSym(x.Aux)
+ mem := x.Args[1]
+ ptr := x.Args[0]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(x.Pos, OpRISCV64MOVHUload, t)
+ v.copyOf(v0)
+ v0.AuxInt = int32ToAuxInt(off)
+ v0.Aux = symToAux(sym)
+ v0.AddArg2(ptr, mem)
+ return true
+ }
+ return false
+}
func rewriteValueRISCV64_OpRISCV64MOVHload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -2925,6 +3269,101 @@ func rewriteValueRISCV64_OpRISCV64MOVHload(v *Value) bool {
}
return false
}
+func rewriteValueRISCV64_OpRISCV64MOVHreg(v *Value) bool {
+ v_0 := v.Args[0]
+ b := v.Block
+ // match: (MOVHreg x:(MOVBload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg <t> x:(MOVHUload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVHload <t> [off] {sym} ptr mem)
+ for {
+ t := v.Type
+ x := v_0
+ if x.Op != OpRISCV64MOVHUload {
+ break
+ }
+ off := auxIntToInt32(x.AuxInt)
+ sym := auxToSym(x.Aux)
+ mem := x.Args[1]
+ ptr := x.Args[0]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(x.Pos, OpRISCV64MOVHload, t)
+ v.copyOf(v0)
+ v0.AuxInt = int32ToAuxInt(off)
+ v0.Aux = symToAux(sym)
+ v0.AddArg2(ptr, mem)
+ return true
+ }
+ return false
+}
func rewriteValueRISCV64_OpRISCV64MOVHstore(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
@@ -2990,6 +3429,74 @@ func rewriteValueRISCV64_OpRISCV64MOVHstore(v *Value) bool {
v.AddArg2(ptr, mem)
return true
}
+ // match: (MOVHstore [off] {sym} ptr (MOVHreg x) mem)
+ // result: (MOVHstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVHstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVWreg x) mem)
+ // result: (MOVHstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVHstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHUreg x) mem)
+ // result: (MOVHstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVHstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVWUreg x) mem)
+ // result: (MOVHstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVHstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
return false
}
func rewriteValueRISCV64_OpRISCV64MOVHstorezero(v *Value) bool {
@@ -3088,6 +3595,101 @@ func rewriteValueRISCV64_OpRISCV64MOVWUload(v *Value) bool {
}
return false
}
+func rewriteValueRISCV64_OpRISCV64MOVWUreg(v *Value) bool {
+ v_0 := v.Args[0]
+ b := v.Block
+ // match: (MOVWUreg x:(MOVBUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVHUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVWUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVWUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVBUreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVHUreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHUreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVWUreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVWUreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg <t> x:(MOVWload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVWUload <t> [off] {sym} ptr mem)
+ for {
+ t := v.Type
+ x := v_0
+ if x.Op != OpRISCV64MOVWload {
+ break
+ }
+ off := auxIntToInt32(x.AuxInt)
+ sym := auxToSym(x.Aux)
+ mem := x.Args[1]
+ ptr := x.Args[0]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(x.Pos, OpRISCV64MOVWUload, t)
+ v.copyOf(v0)
+ v0.AuxInt = int32ToAuxInt(off)
+ v0.Aux = symToAux(sym)
+ v0.AddArg2(ptr, mem)
+ return true
+ }
+ return false
+}
func rewriteValueRISCV64_OpRISCV64MOVWload(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -3136,6 +3738,134 @@ func rewriteValueRISCV64_OpRISCV64MOVWload(v *Value) bool {
}
return false
}
+func rewriteValueRISCV64_OpRISCV64MOVWreg(v *Value) bool {
+ v_0 := v.Args[0]
+ b := v.Block
+ // match: (MOVWreg x:(MOVBload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHUload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHUload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVWload _ _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVWload {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBUreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVBUreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVHreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVWreg _))
+ // result: (MOVDreg x)
+ for {
+ x := v_0
+ if x.Op != OpRISCV64MOVWreg {
+ break
+ }
+ v.reset(OpRISCV64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg <t> x:(MOVWUload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVWload <t> [off] {sym} ptr mem)
+ for {
+ t := v.Type
+ x := v_0
+ if x.Op != OpRISCV64MOVWUload {
+ break
+ }
+ off := auxIntToInt32(x.AuxInt)
+ sym := auxToSym(x.Aux)
+ mem := x.Args[1]
+ ptr := x.Args[0]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(x.Pos, OpRISCV64MOVWload, t)
+ v.copyOf(v0)
+ v0.AuxInt = int32ToAuxInt(off)
+ v0.Aux = symToAux(sym)
+ v0.AddArg2(ptr, mem)
+ return true
+ }
+ return false
+}
func rewriteValueRISCV64_OpRISCV64MOVWstore(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
@@ -3201,6 +3931,40 @@ func rewriteValueRISCV64_OpRISCV64MOVWstore(v *Value) bool {
v.AddArg2(ptr, mem)
return true
}
+ // match: (MOVWstore [off] {sym} ptr (MOVWreg x) mem)
+ // result: (MOVWstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVWstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVWUreg x) mem)
+ // result: (MOVWstore [off] {sym} ptr x mem)
+ for {
+ off := auxIntToInt32(v.AuxInt)
+ sym := auxToSym(v.Aux)
+ ptr := v_0
+ if v_1.Op != OpRISCV64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v_2
+ v.reset(OpRISCV64MOVWstore)
+ v.AuxInt = int32ToAuxInt(off)
+ v.Aux = symToAux(sym)
+ v.AddArg3(ptr, x, mem)
+ return true
+ }
return false
}
func rewriteValueRISCV64_OpRISCV64MOVWstorezero(v *Value) bool {
@@ -4719,103 +5483,6 @@ func rewriteValueRISCV64_OpRsh8x8(v *Value) bool {
return true
}
}
-func rewriteValueRISCV64_OpSignExt16to32(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (SignExt16to32 <t> x)
- // result: (SRAI [48] (SLLI <t> [48] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRAI)
- v.AuxInt = int64ToAuxInt(48)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(48)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpSignExt16to64(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (SignExt16to64 <t> x)
- // result: (SRAI [48] (SLLI <t> [48] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRAI)
- v.AuxInt = int64ToAuxInt(48)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(48)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpSignExt32to64(v *Value) bool {
- v_0 := v.Args[0]
- // match: (SignExt32to64 <t> x)
- // result: (ADDIW [0] x)
- for {
- x := v_0
- v.reset(OpRISCV64ADDIW)
- v.AuxInt = int64ToAuxInt(0)
- v.AddArg(x)
- return true
- }
-}
-func rewriteValueRISCV64_OpSignExt8to16(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (SignExt8to16 <t> x)
- // result: (SRAI [56] (SLLI <t> [56] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRAI)
- v.AuxInt = int64ToAuxInt(56)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(56)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpSignExt8to32(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (SignExt8to32 <t> x)
- // result: (SRAI [56] (SLLI <t> [56] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRAI)
- v.AuxInt = int64ToAuxInt(56)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(56)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpSignExt8to64(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (SignExt8to64 <t> x)
- // result: (SRAI [56] (SLLI <t> [56] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRAI)
- v.AuxInt = int64ToAuxInt(56)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(56)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
func rewriteValueRISCV64_OpSlicemask(v *Value) bool {
v_0 := v.Args[0]
b := v.Block
@@ -5000,6 +5667,22 @@ func rewriteValueRISCV64_OpZero(v *Value) bool {
return true
}
// match: (Zero [s] {t} ptr mem)
+ // cond: s%8 == 0 && s >= 16 && s <= 8*128 && t.Alignment()%8 == 0 && !config.noDuffDevice
+ // result: (DUFFZERO [8 * (128 - s/8)] ptr mem)
+ for {
+ s := auxIntToInt64(v.AuxInt)
+ t := auxToType(v.Aux)
+ ptr := v_0
+ mem := v_1
+ if !(s%8 == 0 && s >= 16 && s <= 8*128 && t.Alignment()%8 == 0 && !config.noDuffDevice) {
+ break
+ }
+ v.reset(OpRISCV64DUFFZERO)
+ v.AuxInt = int64ToAuxInt(8 * (128 - s/8))
+ v.AddArg2(ptr, mem)
+ return true
+ }
+ // match: (Zero [s] {t} ptr mem)
// result: (LoweredZero [t.Alignment()] ptr (ADD <ptr.Type> ptr (MOVDconst [s-moveSize(t.Alignment(), config)])) mem)
for {
s := auxIntToInt64(v.AuxInt)
@@ -5016,108 +5699,6 @@ func rewriteValueRISCV64_OpZero(v *Value) bool {
return true
}
}
-func rewriteValueRISCV64_OpZeroExt16to32(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (ZeroExt16to32 <t> x)
- // result: (SRLI [48] (SLLI <t> [48] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRLI)
- v.AuxInt = int64ToAuxInt(48)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(48)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpZeroExt16to64(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (ZeroExt16to64 <t> x)
- // result: (SRLI [48] (SLLI <t> [48] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRLI)
- v.AuxInt = int64ToAuxInt(48)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(48)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpZeroExt32to64(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (ZeroExt32to64 <t> x)
- // result: (SRLI [32] (SLLI <t> [32] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRLI)
- v.AuxInt = int64ToAuxInt(32)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(32)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpZeroExt8to16(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (ZeroExt8to16 <t> x)
- // result: (SRLI [56] (SLLI <t> [56] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRLI)
- v.AuxInt = int64ToAuxInt(56)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(56)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpZeroExt8to32(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (ZeroExt8to32 <t> x)
- // result: (SRLI [56] (SLLI <t> [56] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRLI)
- v.AuxInt = int64ToAuxInt(56)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(56)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueRISCV64_OpZeroExt8to64(v *Value) bool {
- v_0 := v.Args[0]
- b := v.Block
- // match: (ZeroExt8to64 <t> x)
- // result: (SRLI [56] (SLLI <t> [56] x))
- for {
- t := v.Type
- x := v_0
- v.reset(OpRISCV64SRLI)
- v.AuxInt = int64ToAuxInt(56)
- v0 := b.NewValue0(v.Pos, OpRISCV64SLLI, t)
- v0.AuxInt = int64ToAuxInt(56)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
-}
func rewriteBlockRISCV64(b *Block) bool {
switch b.Kind {
case BlockRISCV64BEQ:
diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go
index 78a57c2388..35b691c12d 100644
--- a/src/cmd/compile/internal/ssa/rewriteS390X.go
+++ b/src/cmd/compile/internal/ssa/rewriteS390X.go
@@ -49,6 +49,9 @@ func rewriteValueS390X(v *Value) bool {
return rewriteValueS390X_OpAtomicAdd32(v)
case OpAtomicAdd64:
return rewriteValueS390X_OpAtomicAdd64(v)
+ case OpAtomicAnd32:
+ v.Op = OpS390XLAN
+ return true
case OpAtomicAnd8:
return rewriteValueS390X_OpAtomicAnd8(v)
case OpAtomicCompareAndSwap32:
@@ -69,6 +72,9 @@ func rewriteValueS390X(v *Value) bool {
return rewriteValueS390X_OpAtomicLoadAcq32(v)
case OpAtomicLoadPtr:
return rewriteValueS390X_OpAtomicLoadPtr(v)
+ case OpAtomicOr32:
+ v.Op = OpS390XLAO
+ return true
case OpAtomicOr8:
return rewriteValueS390X_OpAtomicOr8(v)
case OpAtomicStore32:
diff --git a/src/cmd/compile/internal/ssa/rewrite_test.go b/src/cmd/compile/internal/ssa/rewrite_test.go
index 1a15d8c940..6fe429e85a 100644
--- a/src/cmd/compile/internal/ssa/rewrite_test.go
+++ b/src/cmd/compile/internal/ssa/rewrite_test.go
@@ -36,3 +36,184 @@ func TestSubFlags(t *testing.T) {
t.Errorf("subFlags32(0,1).ult() returned false")
}
}
+
+func TestIsPPC64WordRotateMask(t *testing.T) {
+ tests := []struct {
+ input int64
+ expected bool
+ }{
+ {0x00000001, true},
+ {0x80000001, true},
+ {0x80010001, false},
+ {0xFFFFFFFA, false},
+ {0xF0F0F0F0, false},
+ {0xFFFFFFFD, true},
+ {0x80000000, true},
+ {0x00000000, false},
+ {0xFFFFFFFF, true},
+ {0x0000FFFF, true},
+ {0xFF0000FF, true},
+ {0x00FFFF00, true},
+ }
+
+ for _, v := range tests {
+ if v.expected != isPPC64WordRotateMask(v.input) {
+ t.Errorf("isPPC64WordRotateMask(0x%x) failed", v.input)
+ }
+ }
+}
+
+func TestEncodeDecodePPC64WordRotateMask(t *testing.T) {
+ tests := []struct {
+ rotate int64
+ mask uint64
+ nbits,
+ mb,
+ me,
+ encoded int64
+ }{
+ {1, 0x00000001, 32, 31, 31, 0x20011f20},
+ {2, 0x80000001, 32, 31, 0, 0x20021f01},
+ {3, 0xFFFFFFFD, 32, 31, 29, 0x20031f1e},
+ {4, 0x80000000, 32, 0, 0, 0x20040001},
+ {5, 0xFFFFFFFF, 32, 0, 31, 0x20050020},
+ {6, 0x0000FFFF, 32, 16, 31, 0x20061020},
+ {7, 0xFF0000FF, 32, 24, 7, 0x20071808},
+ {8, 0x00FFFF00, 32, 8, 23, 0x20080818},
+
+ {9, 0x0000000000FFFF00, 64, 40, 55, 0x40092838},
+ {10, 0xFFFF000000000000, 64, 0, 15, 0x400A0010},
+ {10, 0xFFFF000000000001, 64, 63, 15, 0x400A3f10},
+ }
+
+ for i, v := range tests {
+ result := encodePPC64RotateMask(v.rotate, int64(v.mask), v.nbits)
+ if result != v.encoded {
+ t.Errorf("encodePPC64RotateMask(%d,0x%x,%d) = 0x%x, expected 0x%x", v.rotate, v.mask, v.nbits, result, v.encoded)
+ }
+ rotate, mb, me, mask := DecodePPC64RotateMask(result)
+ if rotate != v.rotate || mb != v.mb || me != v.me || mask != v.mask {
+ t.Errorf("DecodePPC64Failure(Test %d) got (%d, %d, %d, %x) expected (%d, %d, %d, %x)", i, rotate, mb, me, mask, v.rotate, v.mb, v.me, v.mask)
+ }
+ }
+}
+
+func TestMergePPC64ClrlsldiSrw(t *testing.T) {
+ tests := []struct {
+ clrlsldi int32
+ srw int64
+ valid bool
+ rotate int64
+ mask uint64
+ }{
+ // ((x>>4)&0xFF)<<4
+ {newPPC64ShiftAuxInt(4, 56, 63, 64), 4, true, 0, 0xFF0},
+ // ((x>>4)&0xFFFF)<<4
+ {newPPC64ShiftAuxInt(4, 48, 63, 64), 4, true, 0, 0xFFFF0},
+ // ((x>>4)&0xFFFF)<<17
+ {newPPC64ShiftAuxInt(17, 48, 63, 64), 4, false, 0, 0},
+ // ((x>>4)&0xFFFF)<<16
+ {newPPC64ShiftAuxInt(16, 48, 63, 64), 4, true, 12, 0xFFFF0000},
+ // ((x>>32)&0xFFFF)<<17
+ {newPPC64ShiftAuxInt(17, 48, 63, 64), 32, false, 0, 0},
+ }
+ for i, v := range tests {
+ result := mergePPC64ClrlsldiSrw(int64(v.clrlsldi), v.srw)
+ if v.valid && result == 0 {
+ t.Errorf("mergePPC64ClrlsldiSrw(Test %d) did not merge", i)
+ } else if !v.valid && result != 0 {
+ t.Errorf("mergePPC64ClrlsldiSrw(Test %d) should return 0", i)
+ } else if r, _, _, m := DecodePPC64RotateMask(result); v.rotate != r || v.mask != m {
+ t.Errorf("mergePPC64ClrlsldiSrw(Test %d) got (%d,0x%x) expected (%d,0x%x)", i, r, m, v.rotate, v.mask)
+ }
+ }
+}
+
+func TestMergePPC64ClrlsldiRlwinm(t *testing.T) {
+ tests := []struct {
+ clrlsldi int32
+ rlwinm int64
+ valid bool
+ rotate int64
+ mask uint64
+ }{
+ // ((x<<4)&0xFF00)<<4
+ {newPPC64ShiftAuxInt(4, 56, 63, 64), encodePPC64RotateMask(4, 0xFF00, 32), false, 0, 0},
+ // ((x>>4)&0xFF)<<4
+ {newPPC64ShiftAuxInt(4, 56, 63, 64), encodePPC64RotateMask(28, 0x0FFFFFFF, 32), true, 0, 0xFF0},
+ // ((x>>4)&0xFFFF)<<4
+ {newPPC64ShiftAuxInt(4, 48, 63, 64), encodePPC64RotateMask(28, 0xFFFF, 32), true, 0, 0xFFFF0},
+ // ((x>>4)&0xFFFF)<<17
+ {newPPC64ShiftAuxInt(17, 48, 63, 64), encodePPC64RotateMask(28, 0xFFFF, 32), false, 0, 0},
+ // ((x>>4)&0xFFFF)<<16
+ {newPPC64ShiftAuxInt(16, 48, 63, 64), encodePPC64RotateMask(28, 0xFFFF, 32), true, 12, 0xFFFF0000},
+ // ((x>>4)&0xF000FFFF)<<16
+ {newPPC64ShiftAuxInt(16, 48, 63, 64), encodePPC64RotateMask(28, 0xF000FFFF, 32), true, 12, 0xFFFF0000},
+ }
+ for i, v := range tests {
+ result := mergePPC64ClrlsldiRlwinm(v.clrlsldi, v.rlwinm)
+ if v.valid && result == 0 {
+ t.Errorf("mergePPC64ClrlsldiRlwinm(Test %d) did not merge", i)
+ } else if !v.valid && result != 0 {
+ t.Errorf("mergePPC64ClrlsldiRlwinm(Test %d) should return 0", i)
+ } else if r, _, _, m := DecodePPC64RotateMask(result); v.rotate != r || v.mask != m {
+ t.Errorf("mergePPC64ClrlsldiRlwinm(Test %d) got (%d,0x%x) expected (%d,0x%x)", i, r, m, v.rotate, v.mask)
+ }
+ }
+}
+
+func TestMergePPC64SldiSrw(t *testing.T) {
+ tests := []struct {
+ sld int64
+ srw int64
+ valid bool
+ rotate int64
+ mask uint64
+ }{
+ {4, 4, true, 0, 0xFFFFFFF0},
+ {4, 8, true, 28, 0x0FFFFFF0},
+ {0, 0, true, 0, 0xFFFFFFFF},
+ {8, 4, false, 0, 0},
+ {0, 32, false, 0, 0},
+ {0, 31, true, 1, 0x1},
+ {31, 31, true, 0, 0x80000000},
+ {32, 32, false, 0, 0},
+ }
+ for i, v := range tests {
+ result := mergePPC64SldiSrw(v.sld, v.srw)
+ if v.valid && result == 0 {
+ t.Errorf("mergePPC64SldiSrw(Test %d) did not merge", i)
+ } else if !v.valid && result != 0 {
+ t.Errorf("mergePPC64SldiSrw(Test %d) should return 0", i)
+ } else if r, _, _, m := DecodePPC64RotateMask(result); v.rotate != r || v.mask != m {
+ t.Errorf("mergePPC64SldiSrw(Test %d) got (%d,0x%x) expected (%d,0x%x)", i, r, m, v.rotate, v.mask)
+ }
+ }
+}
+
+func TestMergePPC64AndSrwi(t *testing.T) {
+ tests := []struct {
+ and int64
+ srw int64
+ valid bool
+ rotate int64
+ mask uint64
+ }{
+ {0x000000FF, 8, true, 24, 0xFF},
+ {0xF00000FF, 8, true, 24, 0xFF},
+ {0x0F0000FF, 4, false, 0, 0},
+ {0x00000000, 4, false, 0, 0},
+ {0xF0000000, 4, false, 0, 0},
+ {0xF0000000, 32, false, 0, 0},
+ }
+ for i, v := range tests {
+ result := mergePPC64AndSrwi(v.and, v.srw)
+ if v.valid && result == 0 {
+ t.Errorf("mergePPC64AndSrwi(Test %d) did not merge", i)
+ } else if !v.valid && result != 0 {
+ t.Errorf("mergePPC64AndSrwi(Test %d) should return 0", i)
+ } else if r, _, _, m := DecodePPC64RotateMask(result); v.rotate != r || v.mask != m {
+ t.Errorf("mergePPC64AndSrwi(Test %d) got (%d,0x%x) expected (%d,0x%x)", i, r, m, v.rotate, v.mask)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/ssa/rewritedec64.go b/src/cmd/compile/internal/ssa/rewritedec64.go
index 86fbc9901a..8b9753414f 100644
--- a/src/cmd/compile/internal/ssa/rewritedec64.go
+++ b/src/cmd/compile/internal/ssa/rewritedec64.go
@@ -62,6 +62,8 @@ func rewriteValuedec64(v *Value) bool {
return rewriteValuedec64_OpNeg64(v)
case OpNeq64:
return rewriteValuedec64_OpNeq64(v)
+ case OpOr32:
+ return rewriteValuedec64_OpOr32(v)
case OpOr64:
return rewriteValuedec64_OpOr64(v)
case OpRsh16Ux64:
@@ -728,7 +730,23 @@ func rewriteValuedec64_OpLsh16x64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Lsh16x64 x y)
+ // result: (Lsh16x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpLsh16x32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpLsh32x64(v *Value) bool {
v_1 := v.Args[1]
@@ -793,83 +811,97 @@ func rewriteValuedec64_OpLsh32x64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Lsh32x64 x y)
+ // result: (Lsh32x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpLsh32x32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpLsh64x16(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Lsh64x16 (Int64Make hi lo) s)
- // result: (Int64Make (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Lsh32x16 <typ.UInt32> hi s) (Rsh32Ux16 <typ.UInt32> lo (Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) (Lsh32x16 <typ.UInt32> lo (Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))) (Lsh32x16 <typ.UInt32> lo s))
+ // match: (Lsh64x16 x s)
+ // result: (Int64Make (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Lsh32x16 <typ.UInt32> (Int64Hi x) s) (Rsh32Ux16 <typ.UInt32> (Int64Lo x) (Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) (Lsh32x16 <typ.UInt32> (Int64Lo x) (Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))) (Lsh32x16 <typ.UInt32> (Int64Lo x) s))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
v2 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
- v2.AddArg2(hi, s)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
- v4 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
- v5 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
- v5.AuxInt = int16ToAuxInt(32)
- v4.AddArg2(v5, s)
- v3.AddArg2(lo, v4)
- v1.AddArg2(v2, v3)
- v6 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
- v7 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
- v7.AddArg2(s, v5)
- v6.AddArg2(lo, v7)
- v0.AddArg2(v1, v6)
+ v3 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v3.AddArg(x)
+ v2.AddArg2(v3, s)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v6 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+ v7 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
+ v7.AuxInt = int16ToAuxInt(32)
+ v6.AddArg2(v7, s)
+ v4.AddArg2(v5, v6)
+ v1.AddArg2(v2, v4)
v8 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
- v8.AddArg2(lo, s)
- v.AddArg2(v0, v8)
+ v9 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+ v9.AddArg2(s, v7)
+ v8.AddArg2(v5, v9)
+ v0.AddArg2(v1, v8)
+ v10 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
+ v10.AddArg2(v5, s)
+ v.AddArg2(v0, v10)
return true
}
- return false
}
func rewriteValuedec64_OpLsh64x32(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Lsh64x32 (Int64Make hi lo) s)
- // result: (Int64Make (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Lsh32x32 <typ.UInt32> hi s) (Rsh32Ux32 <typ.UInt32> lo (Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) (Lsh32x32 <typ.UInt32> lo (Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))) (Lsh32x32 <typ.UInt32> lo s))
+ // match: (Lsh64x32 x s)
+ // result: (Int64Make (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Lsh32x32 <typ.UInt32> (Int64Hi x) s) (Rsh32Ux32 <typ.UInt32> (Int64Lo x) (Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) (Lsh32x32 <typ.UInt32> (Int64Lo x) (Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))) (Lsh32x32 <typ.UInt32> (Int64Lo x) s))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
v2 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
- v2.AddArg2(hi, s)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
- v4 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
- v5 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
- v5.AuxInt = int32ToAuxInt(32)
- v4.AddArg2(v5, s)
- v3.AddArg2(lo, v4)
- v1.AddArg2(v2, v3)
- v6 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
- v7 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
- v7.AddArg2(s, v5)
- v6.AddArg2(lo, v7)
- v0.AddArg2(v1, v6)
+ v3 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v3.AddArg(x)
+ v2.AddArg2(v3, s)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v6 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+ v7 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+ v7.AuxInt = int32ToAuxInt(32)
+ v6.AddArg2(v7, s)
+ v4.AddArg2(v5, v6)
+ v1.AddArg2(v2, v4)
v8 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
- v8.AddArg2(lo, s)
- v.AddArg2(v0, v8)
+ v9 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+ v9.AddArg2(s, v7)
+ v8.AddArg2(v5, v9)
+ v0.AddArg2(v1, v8)
+ v10 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
+ v10.AddArg2(v5, s)
+ v.AddArg2(v0, v10)
return true
}
- return false
}
func rewriteValuedec64_OpLsh64x64(v *Value) bool {
v_1 := v.Args[1]
@@ -934,45 +966,60 @@ func rewriteValuedec64_OpLsh64x64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Lsh64x64 x y)
+ // result: (Lsh64x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpLsh64x32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpLsh64x8(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Lsh64x8 (Int64Make hi lo) s)
- // result: (Int64Make (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Lsh32x8 <typ.UInt32> hi s) (Rsh32Ux8 <typ.UInt32> lo (Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) (Lsh32x8 <typ.UInt32> lo (Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))) (Lsh32x8 <typ.UInt32> lo s))
+ // match: (Lsh64x8 x s)
+ // result: (Int64Make (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Lsh32x8 <typ.UInt32> (Int64Hi x) s) (Rsh32Ux8 <typ.UInt32> (Int64Lo x) (Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) (Lsh32x8 <typ.UInt32> (Int64Lo x) (Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))) (Lsh32x8 <typ.UInt32> (Int64Lo x) s))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
v2 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
- v2.AddArg2(hi, s)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
- v4 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
- v5 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
- v5.AuxInt = int8ToAuxInt(32)
- v4.AddArg2(v5, s)
- v3.AddArg2(lo, v4)
- v1.AddArg2(v2, v3)
- v6 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
- v7 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
- v7.AddArg2(s, v5)
- v6.AddArg2(lo, v7)
- v0.AddArg2(v1, v6)
+ v3 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v3.AddArg(x)
+ v2.AddArg2(v3, s)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v6 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+ v7 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
+ v7.AuxInt = int8ToAuxInt(32)
+ v6.AddArg2(v7, s)
+ v4.AddArg2(v5, v6)
+ v1.AddArg2(v2, v4)
v8 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
- v8.AddArg2(lo, s)
- v.AddArg2(v0, v8)
+ v9 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+ v9.AddArg2(s, v7)
+ v8.AddArg2(v5, v9)
+ v0.AddArg2(v1, v8)
+ v10 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
+ v10.AddArg2(v5, s)
+ v.AddArg2(v0, v10)
return true
}
- return false
}
func rewriteValuedec64_OpLsh8x64(v *Value) bool {
v_1 := v.Args[1]
@@ -1037,7 +1084,23 @@ func rewriteValuedec64_OpLsh8x64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Lsh8x64 x y)
+ // result: (Lsh8x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpLsh8x32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpMul64(v *Value) bool {
v_1 := v.Args[1]
@@ -1118,6 +1181,64 @@ func rewriteValuedec64_OpNeq64(v *Value) bool {
return true
}
}
+func rewriteValuedec64_OpOr32(v *Value) bool {
+ v_1 := v.Args[1]
+ v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
+ // match: (Or32 <typ.UInt32> (Zeromask (Const32 [c])) y)
+ // cond: c == 0
+ // result: y
+ for {
+ if v.Type != typ.UInt32 {
+ break
+ }
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpZeromask {
+ continue
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpConst32 {
+ continue
+ }
+ c := auxIntToInt32(v_0_0.AuxInt)
+ y := v_1
+ if !(c == 0) {
+ continue
+ }
+ v.copyOf(y)
+ return true
+ }
+ break
+ }
+ // match: (Or32 <typ.UInt32> (Zeromask (Const32 [c])) y)
+ // cond: c != 0
+ // result: (Const32 <typ.UInt32> [-1])
+ for {
+ if v.Type != typ.UInt32 {
+ break
+ }
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ if v_0.Op != OpZeromask {
+ continue
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpConst32 {
+ continue
+ }
+ c := auxIntToInt32(v_0_0.AuxInt)
+ if !(c != 0) {
+ continue
+ }
+ v.reset(OpConst32)
+ v.Type = typ.UInt32
+ v.AuxInt = int32ToAuxInt(-1)
+ return true
+ }
+ break
+ }
+ return false
+}
func rewriteValuedec64_OpOr64(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -1208,7 +1329,23 @@ func rewriteValuedec64_OpRsh16Ux64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Rsh16Ux64 x y)
+ // result: (Rsh16Ux32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpRsh16Ux32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpRsh16x64(v *Value) bool {
v_1 := v.Args[1]
@@ -1276,7 +1413,23 @@ func rewriteValuedec64_OpRsh16x64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Rsh16x64 x y)
+ // result: (Rsh16x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpRsh16x32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpRsh32Ux64(v *Value) bool {
v_1 := v.Args[1]
@@ -1341,7 +1494,23 @@ func rewriteValuedec64_OpRsh32Ux64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Rsh32Ux64 x y)
+ // result: (Rsh32Ux32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpRsh32Ux32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpRsh32x64(v *Value) bool {
v_1 := v.Args[1]
@@ -1407,83 +1576,97 @@ func rewriteValuedec64_OpRsh32x64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Rsh32x64 x y)
+ // result: (Rsh32x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpRsh32x32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpRsh64Ux16(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Rsh64Ux16 (Int64Make hi lo) s)
- // result: (Int64Make (Rsh32Ux16 <typ.UInt32> hi s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux16 <typ.UInt32> lo s) (Lsh32x16 <typ.UInt32> hi (Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) (Rsh32Ux16 <typ.UInt32> hi (Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))))
+ // match: (Rsh64Ux16 x s)
+ // result: (Int64Make (Rsh32Ux16 <typ.UInt32> (Int64Hi x) s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux16 <typ.UInt32> (Int64Lo x) s) (Lsh32x16 <typ.UInt32> (Int64Hi x) (Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) (Rsh32Ux16 <typ.UInt32> (Int64Hi x) (Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32])))))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
- v0.AddArg2(hi, s)
- v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v1.AddArg(x)
+ v0.AddArg2(v1, s)
v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
- v3.AddArg2(lo, s)
- v4 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
- v5 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
- v6 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
- v6.AuxInt = int16ToAuxInt(32)
- v5.AddArg2(v6, s)
- v4.AddArg2(hi, v5)
- v2.AddArg2(v3, v4)
- v7 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
- v8 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
- v8.AddArg2(s, v6)
- v7.AddArg2(hi, v8)
- v1.AddArg2(v2, v7)
- v.AddArg2(v0, v1)
+ v3 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v4.AddArg2(v5, s)
+ v6 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
+ v7 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+ v8 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
+ v8.AuxInt = int16ToAuxInt(32)
+ v7.AddArg2(v8, s)
+ v6.AddArg2(v1, v7)
+ v3.AddArg2(v4, v6)
+ v9 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
+ v10 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+ v10.AddArg2(s, v8)
+ v9.AddArg2(v1, v10)
+ v2.AddArg2(v3, v9)
+ v.AddArg2(v0, v2)
return true
}
- return false
}
func rewriteValuedec64_OpRsh64Ux32(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Rsh64Ux32 (Int64Make hi lo) s)
- // result: (Int64Make (Rsh32Ux32 <typ.UInt32> hi s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux32 <typ.UInt32> lo s) (Lsh32x32 <typ.UInt32> hi (Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) (Rsh32Ux32 <typ.UInt32> hi (Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))))
+ // match: (Rsh64Ux32 x s)
+ // result: (Int64Make (Rsh32Ux32 <typ.UInt32> (Int64Hi x) s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux32 <typ.UInt32> (Int64Lo x) s) (Lsh32x32 <typ.UInt32> (Int64Hi x) (Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) (Rsh32Ux32 <typ.UInt32> (Int64Hi x) (Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32])))))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
- v0.AddArg2(hi, s)
- v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v1.AddArg(x)
+ v0.AddArg2(v1, s)
v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
- v3.AddArg2(lo, s)
- v4 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
- v5 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
- v6 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
- v6.AuxInt = int32ToAuxInt(32)
- v5.AddArg2(v6, s)
- v4.AddArg2(hi, v5)
- v2.AddArg2(v3, v4)
- v7 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
- v8 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
- v8.AddArg2(s, v6)
- v7.AddArg2(hi, v8)
- v1.AddArg2(v2, v7)
- v.AddArg2(v0, v1)
+ v3 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v4.AddArg2(v5, s)
+ v6 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
+ v7 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+ v8 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+ v8.AuxInt = int32ToAuxInt(32)
+ v7.AddArg2(v8, s)
+ v6.AddArg2(v1, v7)
+ v3.AddArg2(v4, v6)
+ v9 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
+ v10 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+ v10.AddArg2(s, v8)
+ v9.AddArg2(v1, v10)
+ v2.AddArg2(v3, v9)
+ v.AddArg2(v0, v2)
return true
}
- return false
}
func rewriteValuedec64_OpRsh64Ux64(v *Value) bool {
v_1 := v.Args[1]
@@ -1548,139 +1731,152 @@ func rewriteValuedec64_OpRsh64Ux64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Rsh64Ux64 x y)
+ // result: (Rsh64Ux32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpRsh64Ux32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpRsh64Ux8(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Rsh64Ux8 (Int64Make hi lo) s)
- // result: (Int64Make (Rsh32Ux8 <typ.UInt32> hi s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux8 <typ.UInt32> lo s) (Lsh32x8 <typ.UInt32> hi (Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) (Rsh32Ux8 <typ.UInt32> hi (Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))))
+ // match: (Rsh64Ux8 x s)
+ // result: (Int64Make (Rsh32Ux8 <typ.UInt32> (Int64Hi x) s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux8 <typ.UInt32> (Int64Lo x) s) (Lsh32x8 <typ.UInt32> (Int64Hi x) (Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) (Rsh32Ux8 <typ.UInt32> (Int64Hi x) (Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32])))))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
- v0.AddArg2(hi, s)
- v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v1.AddArg(x)
+ v0.AddArg2(v1, s)
v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
- v3.AddArg2(lo, s)
- v4 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
- v5 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
- v6 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
- v6.AuxInt = int8ToAuxInt(32)
- v5.AddArg2(v6, s)
- v4.AddArg2(hi, v5)
- v2.AddArg2(v3, v4)
- v7 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
- v8 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
- v8.AddArg2(s, v6)
- v7.AddArg2(hi, v8)
- v1.AddArg2(v2, v7)
- v.AddArg2(v0, v1)
+ v3 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v4.AddArg2(v5, s)
+ v6 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
+ v7 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+ v8 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
+ v8.AuxInt = int8ToAuxInt(32)
+ v7.AddArg2(v8, s)
+ v6.AddArg2(v1, v7)
+ v3.AddArg2(v4, v6)
+ v9 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
+ v10 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+ v10.AddArg2(s, v8)
+ v9.AddArg2(v1, v10)
+ v2.AddArg2(v3, v9)
+ v.AddArg2(v0, v2)
return true
}
- return false
}
func rewriteValuedec64_OpRsh64x16(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Rsh64x16 (Int64Make hi lo) s)
- // result: (Int64Make (Rsh32x16 <typ.UInt32> hi s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux16 <typ.UInt32> lo s) (Lsh32x16 <typ.UInt32> hi (Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) (And32 <typ.UInt32> (Rsh32x16 <typ.UInt32> hi (Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32]))) (Zeromask (ZeroExt16to32 (Rsh16Ux32 <typ.UInt16> s (Const32 <typ.UInt32> [5])))))))
+ // match: (Rsh64x16 x s)
+ // result: (Int64Make (Rsh32x16 <typ.UInt32> (Int64Hi x) s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux16 <typ.UInt32> (Int64Lo x) s) (Lsh32x16 <typ.UInt32> (Int64Hi x) (Sub16 <typ.UInt16> (Const16 <typ.UInt16> [32]) s))) (And32 <typ.UInt32> (Rsh32x16 <typ.UInt32> (Int64Hi x) (Sub16 <typ.UInt16> s (Const16 <typ.UInt16> [32]))) (Zeromask (ZeroExt16to32 (Rsh16Ux32 <typ.UInt16> s (Const32 <typ.UInt32> [5])))))))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpRsh32x16, typ.UInt32)
- v0.AddArg2(hi, s)
- v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v1.AddArg(x)
+ v0.AddArg2(v1, s)
v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
- v3.AddArg2(lo, s)
- v4 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
- v5 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
- v6 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
- v6.AuxInt = int16ToAuxInt(32)
- v5.AddArg2(v6, s)
- v4.AddArg2(hi, v5)
- v2.AddArg2(v3, v4)
- v7 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
- v8 := b.NewValue0(v.Pos, OpRsh32x16, typ.UInt32)
- v9 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
- v9.AddArg2(s, v6)
- v8.AddArg2(hi, v9)
- v10 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
- v11 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
- v12 := b.NewValue0(v.Pos, OpRsh16Ux32, typ.UInt16)
- v13 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
- v13.AuxInt = int32ToAuxInt(5)
- v12.AddArg2(s, v13)
- v11.AddArg(v12)
- v10.AddArg(v11)
- v7.AddArg2(v8, v10)
- v1.AddArg2(v2, v7)
- v.AddArg2(v0, v1)
+ v3 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux16, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v4.AddArg2(v5, s)
+ v6 := b.NewValue0(v.Pos, OpLsh32x16, typ.UInt32)
+ v7 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+ v8 := b.NewValue0(v.Pos, OpConst16, typ.UInt16)
+ v8.AuxInt = int16ToAuxInt(32)
+ v7.AddArg2(v8, s)
+ v6.AddArg2(v1, v7)
+ v3.AddArg2(v4, v6)
+ v9 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+ v10 := b.NewValue0(v.Pos, OpRsh32x16, typ.UInt32)
+ v11 := b.NewValue0(v.Pos, OpSub16, typ.UInt16)
+ v11.AddArg2(s, v8)
+ v10.AddArg2(v1, v11)
+ v12 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v13 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
+ v14 := b.NewValue0(v.Pos, OpRsh16Ux32, typ.UInt16)
+ v15 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+ v15.AuxInt = int32ToAuxInt(5)
+ v14.AddArg2(s, v15)
+ v13.AddArg(v14)
+ v12.AddArg(v13)
+ v9.AddArg2(v10, v12)
+ v2.AddArg2(v3, v9)
+ v.AddArg2(v0, v2)
return true
}
- return false
}
func rewriteValuedec64_OpRsh64x32(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Rsh64x32 (Int64Make hi lo) s)
- // result: (Int64Make (Rsh32x32 <typ.UInt32> hi s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux32 <typ.UInt32> lo s) (Lsh32x32 <typ.UInt32> hi (Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) (And32 <typ.UInt32> (Rsh32x32 <typ.UInt32> hi (Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32]))) (Zeromask (Rsh32Ux32 <typ.UInt32> s (Const32 <typ.UInt32> [5]))))))
+ // match: (Rsh64x32 x s)
+ // result: (Int64Make (Rsh32x32 <typ.UInt32> (Int64Hi x) s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux32 <typ.UInt32> (Int64Lo x) s) (Lsh32x32 <typ.UInt32> (Int64Hi x) (Sub32 <typ.UInt32> (Const32 <typ.UInt32> [32]) s))) (And32 <typ.UInt32> (Rsh32x32 <typ.UInt32> (Int64Hi x) (Sub32 <typ.UInt32> s (Const32 <typ.UInt32> [32]))) (Zeromask (Rsh32Ux32 <typ.UInt32> s (Const32 <typ.UInt32> [5]))))))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpRsh32x32, typ.UInt32)
- v0.AddArg2(hi, s)
- v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v1.AddArg(x)
+ v0.AddArg2(v1, s)
v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
- v3.AddArg2(lo, s)
- v4 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
- v5 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
- v6 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
- v6.AuxInt = int32ToAuxInt(32)
- v5.AddArg2(v6, s)
- v4.AddArg2(hi, v5)
- v2.AddArg2(v3, v4)
- v7 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
- v8 := b.NewValue0(v.Pos, OpRsh32x32, typ.UInt32)
- v9 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
- v9.AddArg2(s, v6)
- v8.AddArg2(hi, v9)
- v10 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
- v11 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
- v12 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
- v12.AuxInt = int32ToAuxInt(5)
- v11.AddArg2(s, v12)
- v10.AddArg(v11)
- v7.AddArg2(v8, v10)
- v1.AddArg2(v2, v7)
- v.AddArg2(v0, v1)
+ v3 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v4.AddArg2(v5, s)
+ v6 := b.NewValue0(v.Pos, OpLsh32x32, typ.UInt32)
+ v7 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+ v8 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+ v8.AuxInt = int32ToAuxInt(32)
+ v7.AddArg2(v8, s)
+ v6.AddArg2(v1, v7)
+ v3.AddArg2(v4, v6)
+ v9 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+ v10 := b.NewValue0(v.Pos, OpRsh32x32, typ.UInt32)
+ v11 := b.NewValue0(v.Pos, OpSub32, typ.UInt32)
+ v11.AddArg2(s, v8)
+ v10.AddArg2(v1, v11)
+ v12 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v13 := b.NewValue0(v.Pos, OpRsh32Ux32, typ.UInt32)
+ v14 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+ v14.AuxInt = int32ToAuxInt(5)
+ v13.AddArg2(s, v14)
+ v12.AddArg(v13)
+ v9.AddArg2(v10, v12)
+ v2.AddArg2(v3, v9)
+ v.AddArg2(v0, v2)
return true
}
- return false
}
func rewriteValuedec64_OpRsh64x64(v *Value) bool {
v_1 := v.Args[1]
@@ -1750,55 +1946,70 @@ func rewriteValuedec64_OpRsh64x64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Rsh64x64 x y)
+ // result: (Rsh64x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpRsh64x32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpRsh64x8(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
b := v.Block
typ := &b.Func.Config.Types
- // match: (Rsh64x8 (Int64Make hi lo) s)
- // result: (Int64Make (Rsh32x8 <typ.UInt32> hi s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux8 <typ.UInt32> lo s) (Lsh32x8 <typ.UInt32> hi (Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) (And32 <typ.UInt32> (Rsh32x8 <typ.UInt32> hi (Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32]))) (Zeromask (ZeroExt8to32 (Rsh8Ux32 <typ.UInt8> s (Const32 <typ.UInt32> [5])))))))
+ // match: (Rsh64x8 x s)
+ // result: (Int64Make (Rsh32x8 <typ.UInt32> (Int64Hi x) s) (Or32 <typ.UInt32> (Or32 <typ.UInt32> (Rsh32Ux8 <typ.UInt32> (Int64Lo x) s) (Lsh32x8 <typ.UInt32> (Int64Hi x) (Sub8 <typ.UInt8> (Const8 <typ.UInt8> [32]) s))) (And32 <typ.UInt32> (Rsh32x8 <typ.UInt32> (Int64Hi x) (Sub8 <typ.UInt8> s (Const8 <typ.UInt8> [32]))) (Zeromask (ZeroExt8to32 (Rsh8Ux32 <typ.UInt8> s (Const32 <typ.UInt32> [5])))))))
for {
- if v_0.Op != OpInt64Make {
- break
- }
- lo := v_0.Args[1]
- hi := v_0.Args[0]
+ x := v_0
s := v_1
v.reset(OpInt64Make)
v0 := b.NewValue0(v.Pos, OpRsh32x8, typ.UInt32)
- v0.AddArg2(hi, s)
- v1 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v1.AddArg(x)
+ v0.AddArg2(v1, s)
v2 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
- v3 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
- v3.AddArg2(lo, s)
- v4 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
- v5 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
- v6 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
- v6.AuxInt = int8ToAuxInt(32)
- v5.AddArg2(v6, s)
- v4.AddArg2(hi, v5)
- v2.AddArg2(v3, v4)
- v7 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
- v8 := b.NewValue0(v.Pos, OpRsh32x8, typ.UInt32)
- v9 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
- v9.AddArg2(s, v6)
- v8.AddArg2(hi, v9)
- v10 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
- v11 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
- v12 := b.NewValue0(v.Pos, OpRsh8Ux32, typ.UInt8)
- v13 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
- v13.AuxInt = int32ToAuxInt(5)
- v12.AddArg2(s, v13)
- v11.AddArg(v12)
- v10.AddArg(v11)
- v7.AddArg2(v8, v10)
- v1.AddArg2(v2, v7)
- v.AddArg2(v0, v1)
+ v3 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v4 := b.NewValue0(v.Pos, OpRsh32Ux8, typ.UInt32)
+ v5 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v5.AddArg(x)
+ v4.AddArg2(v5, s)
+ v6 := b.NewValue0(v.Pos, OpLsh32x8, typ.UInt32)
+ v7 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+ v8 := b.NewValue0(v.Pos, OpConst8, typ.UInt8)
+ v8.AuxInt = int8ToAuxInt(32)
+ v7.AddArg2(v8, s)
+ v6.AddArg2(v1, v7)
+ v3.AddArg2(v4, v6)
+ v9 := b.NewValue0(v.Pos, OpAnd32, typ.UInt32)
+ v10 := b.NewValue0(v.Pos, OpRsh32x8, typ.UInt32)
+ v11 := b.NewValue0(v.Pos, OpSub8, typ.UInt8)
+ v11.AddArg2(s, v8)
+ v10.AddArg2(v1, v11)
+ v12 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v13 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
+ v14 := b.NewValue0(v.Pos, OpRsh8Ux32, typ.UInt8)
+ v15 := b.NewValue0(v.Pos, OpConst32, typ.UInt32)
+ v15.AuxInt = int32ToAuxInt(5)
+ v14.AddArg2(s, v15)
+ v13.AddArg(v14)
+ v12.AddArg(v13)
+ v9.AddArg2(v10, v12)
+ v2.AddArg2(v3, v9)
+ v.AddArg2(v0, v2)
return true
}
- return false
}
func rewriteValuedec64_OpRsh8Ux64(v *Value) bool {
v_1 := v.Args[1]
@@ -1863,7 +2074,23 @@ func rewriteValuedec64_OpRsh8Ux64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Rsh8Ux64 x y)
+ // result: (Rsh8Ux32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpRsh8Ux32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpRsh8x64(v *Value) bool {
v_1 := v.Args[1]
@@ -1931,7 +2158,23 @@ func rewriteValuedec64_OpRsh8x64(v *Value) bool {
v.AddArg2(x, v0)
return true
}
- return false
+ // match: (Rsh8x64 x y)
+ // result: (Rsh8x32 x (Or32 <typ.UInt32> (Zeromask (Int64Hi y)) (Int64Lo y)))
+ for {
+ x := v_0
+ y := v_1
+ v.reset(OpRsh8x32)
+ v0 := b.NewValue0(v.Pos, OpOr32, typ.UInt32)
+ v1 := b.NewValue0(v.Pos, OpZeromask, typ.UInt32)
+ v2 := b.NewValue0(v.Pos, OpInt64Hi, typ.UInt32)
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v3.AddArg(y)
+ v0.AddArg2(v1, v3)
+ v.AddArg2(x, v0)
+ return true
+ }
}
func rewriteValuedec64_OpSignExt16to64(v *Value) bool {
v_0 := v.Args[0]
@@ -2071,6 +2314,8 @@ func rewriteValuedec64_OpSub64(v *Value) bool {
}
func rewriteValuedec64_OpTrunc64to16(v *Value) bool {
v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
// match: (Trunc64to16 (Int64Make _ lo))
// result: (Trunc32to16 lo)
for {
@@ -2082,7 +2327,16 @@ func rewriteValuedec64_OpTrunc64to16(v *Value) bool {
v.AddArg(lo)
return true
}
- return false
+ // match: (Trunc64to16 x)
+ // result: (Trunc32to16 (Int64Lo x))
+ for {
+ x := v_0
+ v.reset(OpTrunc32to16)
+ v0 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
}
func rewriteValuedec64_OpTrunc64to32(v *Value) bool {
v_0 := v.Args[0]
@@ -2096,10 +2350,19 @@ func rewriteValuedec64_OpTrunc64to32(v *Value) bool {
v.copyOf(lo)
return true
}
- return false
+ // match: (Trunc64to32 x)
+ // result: (Int64Lo x)
+ for {
+ x := v_0
+ v.reset(OpInt64Lo)
+ v.AddArg(x)
+ return true
+ }
}
func rewriteValuedec64_OpTrunc64to8(v *Value) bool {
v_0 := v.Args[0]
+ b := v.Block
+ typ := &b.Func.Config.Types
// match: (Trunc64to8 (Int64Make _ lo))
// result: (Trunc32to8 lo)
for {
@@ -2111,7 +2374,16 @@ func rewriteValuedec64_OpTrunc64to8(v *Value) bool {
v.AddArg(lo)
return true
}
- return false
+ // match: (Trunc64to8 x)
+ // result: (Trunc32to8 (Int64Lo x))
+ for {
+ x := v_0
+ v.reset(OpTrunc32to8)
+ v0 := b.NewValue0(v.Pos, OpInt64Lo, typ.UInt32)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
}
func rewriteValuedec64_OpXor64(v *Value) bool {
v_1 := v.Args[1]
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 925ff53fd1..11f4cc7c58 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -124,6 +124,8 @@ func rewriteValuegeneric(v *Value) bool {
return rewriteValuegeneric_OpIMake(v)
case OpInterCall:
return rewriteValuegeneric_OpInterCall(v)
+ case OpInterLECall:
+ return rewriteValuegeneric_OpInterLECall(v)
case OpIsInBounds:
return rewriteValuegeneric_OpIsInBounds(v)
case OpIsNonNil:
@@ -366,6 +368,8 @@ func rewriteValuegeneric(v *Value) bool {
return rewriteValuegeneric_OpSelect0(v)
case OpSelect1:
return rewriteValuegeneric_OpSelect1(v)
+ case OpSelectN:
+ return rewriteValuegeneric_OpSelectN(v)
case OpSignExt16to32:
return rewriteValuegeneric_OpSignExt16to32(v)
case OpSignExt16to64:
@@ -8522,6 +8526,46 @@ func rewriteValuegeneric_OpInterCall(v *Value) bool {
}
return false
}
+func rewriteValuegeneric_OpInterLECall(v *Value) bool {
+ // match: (InterLECall [argsize] {auxCall} (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) ___)
+ // cond: devirtLESym(v, auxCall, itab, off) != nil
+ // result: devirtLECall(v, devirtLESym(v, auxCall, itab, off))
+ for {
+ if len(v.Args) < 1 {
+ break
+ }
+ auxCall := auxToCall(v.Aux)
+ v_0 := v.Args[0]
+ if v_0.Op != OpLoad {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpOffPtr {
+ break
+ }
+ off := auxIntToInt64(v_0_0.AuxInt)
+ v_0_0_0 := v_0_0.Args[0]
+ if v_0_0_0.Op != OpITab {
+ break
+ }
+ v_0_0_0_0 := v_0_0_0.Args[0]
+ if v_0_0_0_0.Op != OpIMake {
+ break
+ }
+ v_0_0_0_0_0 := v_0_0_0_0.Args[0]
+ if v_0_0_0_0_0.Op != OpAddr {
+ break
+ }
+ itab := auxToSym(v_0_0_0_0_0.Aux)
+ v_0_0_0_0_0_0 := v_0_0_0_0_0.Args[0]
+ if v_0_0_0_0_0_0.Op != OpSB || !(devirtLESym(v, auxCall, itab, off) != nil) {
+ break
+ }
+ v.copyOf(devirtLECall(v, devirtLESym(v, auxCall, itab, off)))
+ return true
+ }
+ return false
+}
func rewriteValuegeneric_OpIsInBounds(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
@@ -16082,6 +16126,38 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool {
v.reset(OpInvalid)
return true
}
+ // match: (NilCheck (SelectN [0] call:(StaticLECall _ _)) (SelectN [1] call))
+ // cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")
+ // result: (Invalid)
+ for {
+ if v_0.Op != OpSelectN || auxIntToInt64(v_0.AuxInt) != 0 {
+ break
+ }
+ call := v_0.Args[0]
+ if call.Op != OpStaticLECall || len(call.Args) != 2 || v_1.Op != OpSelectN || auxIntToInt64(v_1.AuxInt) != 1 || call != v_1.Args[0] || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) {
+ break
+ }
+ v.reset(OpInvalid)
+ return true
+ }
+ // match: (NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) (SelectN [1] call))
+ // cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")
+ // result: (Invalid)
+ for {
+ if v_0.Op != OpOffPtr {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpSelectN || auxIntToInt64(v_0_0.AuxInt) != 0 {
+ break
+ }
+ call := v_0_0.Args[0]
+ if call.Op != OpStaticLECall || len(call.Args) != 2 || v_1.Op != OpSelectN || auxIntToInt64(v_1.AuxInt) != 1 || call != v_1.Args[0] || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) {
+ break
+ }
+ v.reset(OpInvalid)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpNot(v *Value) bool {
@@ -18549,6 +18625,9 @@ func rewriteValuegeneric_OpPhi(v *Value) bool {
// match: (Phi (Const8 [c]) (Const8 [c]))
// result: (Const8 [c])
for {
+ if len(v.Args) != 2 {
+ break
+ }
_ = v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpConst8 {
@@ -18556,7 +18635,7 @@ func rewriteValuegeneric_OpPhi(v *Value) bool {
}
c := auxIntToInt8(v_0.AuxInt)
v_1 := v.Args[1]
- if v_1.Op != OpConst8 || auxIntToInt8(v_1.AuxInt) != c || len(v.Args) != 2 {
+ if v_1.Op != OpConst8 || auxIntToInt8(v_1.AuxInt) != c {
break
}
v.reset(OpConst8)
@@ -18566,6 +18645,9 @@ func rewriteValuegeneric_OpPhi(v *Value) bool {
// match: (Phi (Const16 [c]) (Const16 [c]))
// result: (Const16 [c])
for {
+ if len(v.Args) != 2 {
+ break
+ }
_ = v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpConst16 {
@@ -18573,7 +18655,7 @@ func rewriteValuegeneric_OpPhi(v *Value) bool {
}
c := auxIntToInt16(v_0.AuxInt)
v_1 := v.Args[1]
- if v_1.Op != OpConst16 || auxIntToInt16(v_1.AuxInt) != c || len(v.Args) != 2 {
+ if v_1.Op != OpConst16 || auxIntToInt16(v_1.AuxInt) != c {
break
}
v.reset(OpConst16)
@@ -18583,6 +18665,9 @@ func rewriteValuegeneric_OpPhi(v *Value) bool {
// match: (Phi (Const32 [c]) (Const32 [c]))
// result: (Const32 [c])
for {
+ if len(v.Args) != 2 {
+ break
+ }
_ = v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpConst32 {
@@ -18590,7 +18675,7 @@ func rewriteValuegeneric_OpPhi(v *Value) bool {
}
c := auxIntToInt32(v_0.AuxInt)
v_1 := v.Args[1]
- if v_1.Op != OpConst32 || auxIntToInt32(v_1.AuxInt) != c || len(v.Args) != 2 {
+ if v_1.Op != OpConst32 || auxIntToInt32(v_1.AuxInt) != c {
break
}
v.reset(OpConst32)
@@ -18600,6 +18685,9 @@ func rewriteValuegeneric_OpPhi(v *Value) bool {
// match: (Phi (Const64 [c]) (Const64 [c]))
// result: (Const64 [c])
for {
+ if len(v.Args) != 2 {
+ break
+ }
_ = v.Args[1]
v_0 := v.Args[0]
if v_0.Op != OpConst64 {
@@ -18607,7 +18695,7 @@ func rewriteValuegeneric_OpPhi(v *Value) bool {
}
c := auxIntToInt64(v_0.AuxInt)
v_1 := v.Args[1]
- if v_1.Op != OpConst64 || auxIntToInt64(v_1.AuxInt) != c || len(v.Args) != 2 {
+ if v_1.Op != OpConst64 || auxIntToInt64(v_1.AuxInt) != c {
break
}
v.reset(OpConst64)
@@ -20615,6 +20703,70 @@ func rewriteValuegeneric_OpSelect1(v *Value) bool {
}
return false
}
+func rewriteValuegeneric_OpSelectN(v *Value) bool {
+ v_0 := v.Args[0]
+ b := v.Block
+ config := b.Func.Config
+ // match: (SelectN [0] call:(StaticLECall {sym} dst src (Const64 [sz]) mem))
+ // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)
+ // result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem)
+ for {
+ if auxIntToInt64(v.AuxInt) != 0 {
+ break
+ }
+ call := v_0
+ if call.Op != OpStaticLECall || len(call.Args) != 4 {
+ break
+ }
+ sym := auxToCall(call.Aux)
+ mem := call.Args[3]
+ dst := call.Args[0]
+ src := call.Args[1]
+ call_2 := call.Args[2]
+ if call_2.Op != OpConst64 {
+ break
+ }
+ sz := auxIntToInt64(call_2.AuxInt)
+ if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) {
+ break
+ }
+ v.reset(OpMove)
+ v.AuxInt = int64ToAuxInt(int64(sz))
+ v.Aux = typeToAux(dst.Type.Elem())
+ v.AddArg3(dst, src, mem)
+ return true
+ }
+ // match: (SelectN [0] call:(StaticLECall {sym} dst src (Const32 [sz]) mem))
+ // cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)
+ // result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem)
+ for {
+ if auxIntToInt64(v.AuxInt) != 0 {
+ break
+ }
+ call := v_0
+ if call.Op != OpStaticLECall || len(call.Args) != 4 {
+ break
+ }
+ sym := auxToCall(call.Aux)
+ mem := call.Args[3]
+ dst := call.Args[0]
+ src := call.Args[1]
+ call_2 := call.Args[2]
+ if call_2.Op != OpConst32 {
+ break
+ }
+ sz := auxIntToInt32(call_2.AuxInt)
+ if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) {
+ break
+ }
+ v.reset(OpMove)
+ v.AuxInt = int64ToAuxInt(int64(sz))
+ v.Aux = typeToAux(dst.Type.Elem())
+ v.AddArg3(dst, src, mem)
+ return true
+ }
+ return false
+}
func rewriteValuegeneric_OpSignExt16to32(v *Value) bool {
v_0 := v.Args[0]
// match: (SignExt16to32 (Const16 [c]))
@@ -21660,6 +21812,48 @@ func rewriteValuegeneric_OpStore(v *Value) bool {
v.copyOf(mem)
return true
}
+ // match: (Store (SelectN [0] call:(StaticLECall _ _)) x mem:(SelectN [1] call))
+ // cond: isConstZero(x) && isSameCall(call.Aux, "runtime.newobject")
+ // result: mem
+ for {
+ if v_0.Op != OpSelectN || auxIntToInt64(v_0.AuxInt) != 0 {
+ break
+ }
+ call := v_0.Args[0]
+ if call.Op != OpStaticLECall || len(call.Args) != 2 {
+ break
+ }
+ x := v_1
+ mem := v_2
+ if mem.Op != OpSelectN || auxIntToInt64(mem.AuxInt) != 1 || call != mem.Args[0] || !(isConstZero(x) && isSameCall(call.Aux, "runtime.newobject")) {
+ break
+ }
+ v.copyOf(mem)
+ return true
+ }
+ // match: (Store (OffPtr (SelectN [0] call:(StaticLECall _ _))) x mem:(SelectN [1] call))
+ // cond: isConstZero(x) && isSameCall(call.Aux, "runtime.newobject")
+ // result: mem
+ for {
+ if v_0.Op != OpOffPtr {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpSelectN || auxIntToInt64(v_0_0.AuxInt) != 0 {
+ break
+ }
+ call := v_0_0.Args[0]
+ if call.Op != OpStaticLECall || len(call.Args) != 2 {
+ break
+ }
+ x := v_1
+ mem := v_2
+ if mem.Op != OpSelectN || auxIntToInt64(mem.AuxInt) != 1 || call != mem.Args[0] || !(isConstZero(x) && isSameCall(call.Aux, "runtime.newobject")) {
+ break
+ }
+ v.copyOf(mem)
+ return true
+ }
// match: (Store {t1} op1:(OffPtr [o1] p1) d1 m2:(Store {t2} op2:(OffPtr [0] p2) d2 m3:(Move [n] p3 _ mem)))
// cond: m2.Uses == 1 && m3.Uses == 1 && o1 == t2.Size() && n == t2.Size() + t1.Size() && isSamePtr(p1, p2) && isSamePtr(p2, p3) && clobber(m2, m3)
// result: (Store {t1} op1 d1 (Store {t2} op2 d2 mem))
@@ -24357,6 +24551,24 @@ func rewriteValuegeneric_OpZero(v *Value) bool {
v.copyOf(mem)
return true
}
+ // match: (Zero (SelectN [0] call:(StaticLECall _ _)) mem:(SelectN [1] call))
+ // cond: isSameCall(call.Aux, "runtime.newobject")
+ // result: mem
+ for {
+ if v_0.Op != OpSelectN || auxIntToInt64(v_0.AuxInt) != 0 {
+ break
+ }
+ call := v_0.Args[0]
+ if call.Op != OpStaticLECall || len(call.Args) != 2 {
+ break
+ }
+ mem := v_1
+ if mem.Op != OpSelectN || auxIntToInt64(mem.AuxInt) != 1 || call != mem.Args[0] || !(isSameCall(call.Aux, "runtime.newobject")) {
+ break
+ }
+ v.copyOf(mem)
+ return true
+ }
// match: (Zero {t1} [n] p1 store:(Store {t2} (OffPtr [o2] p2) _ mem))
// cond: isSamePtr(p1, p2) && store.Uses == 1 && n >= o2 + t2.Size() && clobber(store)
// result: (Zero {t1} [n] p1 mem)
diff --git a/src/cmd/compile/internal/ssa/shortcircuit.go b/src/cmd/compile/internal/ssa/shortcircuit.go
index c5df457c4e..7b4ee2e81c 100644
--- a/src/cmd/compile/internal/ssa/shortcircuit.go
+++ b/src/cmd/compile/internal/ssa/shortcircuit.go
@@ -261,11 +261,6 @@ func shortcircuitBlock(b *Block) bool {
// and the CFG modifications must not proceed.
// The returned function assumes that shortcircuitBlock has completed its CFG modifications.
func shortcircuitPhiPlan(b *Block, ctl *Value, cidx int, ti int64) func(*Value, int) {
- const go115shortcircuitPhis = true
- if !go115shortcircuitPhis {
- return nil
- }
-
// t is the "taken" branch: the successor we always go to when coming in from p.
t := b.Succs[ti].b
// u is the "untaken" branch: the successor we never go to when coming in from p.
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
index 94b8763d5d..edc43aaae7 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -348,6 +348,9 @@ func (v *Value) reset(op Op) {
// It modifies v to be (Copy a).
//go:noinline
func (v *Value) copyOf(a *Value) {
+ if v == a {
+ return
+ }
if v.InCache {
v.Block.Func.unCache(v)
}
diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go
index df54a45b0f..849c9e8967 100644
--- a/src/cmd/compile/internal/ssa/writebarrier.go
+++ b/src/cmd/compile/internal/ssa/writebarrier.go
@@ -527,7 +527,7 @@ func IsStackAddr(v *Value) bool {
v = v.Args[0]
}
switch v.Op {
- case OpSP, OpLocalAddr:
+ case OpSP, OpLocalAddr, OpSelectNAddr:
return true
}
return false
@@ -593,7 +593,7 @@ func IsSanitizerSafeAddr(v *Value) bool {
v = v.Args[0]
}
switch v.Op {
- case OpSP, OpLocalAddr:
+ case OpSP, OpLocalAddr, OpSelectNAddr:
// Stack addresses are always safe.
return true
case OpITab, OpStringPtr, OpGetClosurePtr:
@@ -609,7 +609,7 @@ func IsSanitizerSafeAddr(v *Value) bool {
// isVolatile reports whether v is a pointer to argument region on stack which
// will be clobbered by a function call.
func isVolatile(v *Value) bool {
- for v.Op == OpOffPtr || v.Op == OpAddPtr || v.Op == OpPtrIndex || v.Op == OpCopy {
+ for v.Op == OpOffPtr || v.Op == OpAddPtr || v.Op == OpPtrIndex || v.Op == OpCopy || v.Op == OpSelectNAddr {
v = v.Args[0]
}
return v.Op == OpSP
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index 9601fab9e0..1485b70059 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -287,6 +287,7 @@ func tokstring(tok token) string {
// Convenience methods using the current token position.
func (p *parser) pos() Pos { return p.posAt(p.line, p.col) }
+func (p *parser) error(msg string) { p.errorAt(p.pos(), msg) }
func (p *parser) syntaxError(msg string) { p.syntaxErrorAt(p.pos(), msg) }
// The stopset contains keywords that start a statement.
@@ -997,17 +998,20 @@ loop:
// x[i:j...
t.Index[1] = p.expr()
}
- if p.got(_Colon) {
+ if p.tok == _Colon {
t.Full = true
// x[i:j:...]
if t.Index[1] == nil {
p.error("middle index required in 3-index slice")
+ t.Index[1] = p.badExpr()
}
+ p.next()
if p.tok != _Rbrack {
// x[i:j:k...
t.Index[2] = p.expr()
} else {
p.error("final index required in 3-index slice")
+ t.Index[2] = p.badExpr()
}
}
p.want(_Rbrack)
@@ -1836,6 +1840,7 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS
if p.tok == _Lbrace {
if keyword == _If {
p.syntaxError("missing condition in if statement")
+ cond = p.badExpr()
}
return
}
@@ -1907,6 +1912,9 @@ done:
} else {
p.syntaxErrorAt(semi.pos, "missing condition in if statement")
}
+ b := new(BadExpr)
+ b.pos = semi.pos
+ cond = b
}
case *ExprStmt:
cond = s.X
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 5d1d5d4008..023ab9af88 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -105,14 +105,14 @@ var (
Errortype *Type
// Types to represent untyped string and boolean constants.
- Idealstring *Type
- Idealbool *Type
+ UntypedString *Type
+ UntypedBool *Type
// Types to represent untyped numeric constants.
- Idealint = New(TIDEAL)
- Idealrune = New(TIDEAL)
- Idealfloat = New(TIDEAL)
- Idealcomplex = New(TIDEAL)
+ UntypedInt = New(TIDEAL)
+ UntypedRune = New(TIDEAL)
+ UntypedFloat = New(TIDEAL)
+ UntypedComplex = New(TIDEAL)
)
// A Type represents a Go type.
@@ -1436,7 +1436,7 @@ func (t *Type) IsUntyped() bool {
if t == nil {
return false
}
- if t == Idealstring || t == Idealbool {
+ if t == UntypedString || t == UntypedBool {
return true
}
switch t.Etype {
diff --git a/src/cmd/compile/internal/x86/387.go b/src/cmd/compile/internal/x86/387.go
deleted file mode 100644
index 594adb2cd5..0000000000
--- a/src/cmd/compile/internal/x86/387.go
+++ /dev/null
@@ -1,403 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package x86
-
-import (
- "cmd/compile/internal/gc"
- "cmd/compile/internal/ssa"
- "cmd/compile/internal/types"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
- "math"
-)
-
-// Generates code for v using 387 instructions.
-func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
- // The SSA compiler pretends that it has an SSE backend.
- // If we don't have one of those, we need to translate
- // all the SSE ops to equivalent 387 ops. That's what this
- // function does.
-
- switch v.Op {
- case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst:
- iv := uint64(v.AuxInt)
- if iv == 0x0000000000000000 { // +0.0
- s.Prog(x86.AFLDZ)
- } else if iv == 0x3ff0000000000000 { // +1.0
- s.Prog(x86.AFLD1)
- } else if iv == 0x8000000000000000 { // -0.0
- s.Prog(x86.AFLDZ)
- s.Prog(x86.AFCHS)
- } else if iv == 0xbff0000000000000 { // -1.0
- s.Prog(x86.AFLD1)
- s.Prog(x86.AFCHS)
- } else if iv == 0x400921fb54442d18 { // +pi
- s.Prog(x86.AFLDPI)
- } else if iv == 0xc00921fb54442d18 { // -pi
- s.Prog(x86.AFLDPI)
- s.Prog(x86.AFCHS)
- } else { // others
- p := s.Prog(loadPush(v.Type))
- p.From.Type = obj.TYPE_FCONST
- p.From.Val = math.Float64frombits(iv)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_F0
- }
- popAndSave(s, v)
-
- case ssa.Op386MOVSSconst2, ssa.Op386MOVSDconst2:
- p := s.Prog(loadPush(v.Type))
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = v.Args[0].Reg()
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_F0
- popAndSave(s, v)
-
- case ssa.Op386MOVSSload, ssa.Op386MOVSDload, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1, ssa.Op386MOVSSloadidx4, ssa.Op386MOVSDloadidx8:
- p := s.Prog(loadPush(v.Type))
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = v.Args[0].Reg()
- gc.AddAux(&p.From, v)
- switch v.Op {
- case ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1:
- p.From.Scale = 1
- p.From.Index = v.Args[1].Reg()
- if p.From.Index == x86.REG_SP {
- p.From.Reg, p.From.Index = p.From.Index, p.From.Reg
- }
- case ssa.Op386MOVSSloadidx4:
- p.From.Scale = 4
- p.From.Index = v.Args[1].Reg()
- case ssa.Op386MOVSDloadidx8:
- p.From.Scale = 8
- p.From.Index = v.Args[1].Reg()
- }
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_F0
- popAndSave(s, v)
-
- case ssa.Op386MOVSSstore, ssa.Op386MOVSDstore:
- // Push to-be-stored value on top of stack.
- push(s, v.Args[1])
-
- // Pop and store value.
- var op obj.As
- switch v.Op {
- case ssa.Op386MOVSSstore:
- op = x86.AFMOVFP
- case ssa.Op386MOVSDstore:
- op = x86.AFMOVDP
- }
- p := s.Prog(op)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = v.Args[0].Reg()
- gc.AddAux(&p.To, v)
-
- case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1, ssa.Op386MOVSSstoreidx4, ssa.Op386MOVSDstoreidx8:
- push(s, v.Args[2])
- var op obj.As
- switch v.Op {
- case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSSstoreidx4:
- op = x86.AFMOVFP
- case ssa.Op386MOVSDstoreidx1, ssa.Op386MOVSDstoreidx8:
- op = x86.AFMOVDP
- }
- p := s.Prog(op)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = v.Args[0].Reg()
- gc.AddAux(&p.To, v)
- switch v.Op {
- case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1:
- p.To.Scale = 1
- p.To.Index = v.Args[1].Reg()
- if p.To.Index == x86.REG_SP {
- p.To.Reg, p.To.Index = p.To.Index, p.To.Reg
- }
- case ssa.Op386MOVSSstoreidx4:
- p.To.Scale = 4
- p.To.Index = v.Args[1].Reg()
- case ssa.Op386MOVSDstoreidx8:
- p.To.Scale = 8
- p.To.Index = v.Args[1].Reg()
- }
-
- case ssa.Op386ADDSS, ssa.Op386ADDSD, ssa.Op386SUBSS, ssa.Op386SUBSD,
- ssa.Op386MULSS, ssa.Op386MULSD, ssa.Op386DIVSS, ssa.Op386DIVSD:
- if v.Reg() != v.Args[0].Reg() {
- v.Fatalf("input[0] and output not in same register %s", v.LongString())
- }
-
- // Push arg1 on top of stack
- push(s, v.Args[1])
-
- // Set precision if needed. 64 bits is the default.
- switch v.Op {
- case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
- // Save AX so we can use it as scratch space.
- p := s.Prog(x86.AMOVL)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_AX
- s.AddrScratch(&p.To)
- // Install a 32-bit version of the control word.
- installControlWord(s, gc.ControlWord32, x86.REG_AX)
- // Restore AX.
- p = s.Prog(x86.AMOVL)
- s.AddrScratch(&p.From)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_AX
- }
-
- var op obj.As
- switch v.Op {
- case ssa.Op386ADDSS, ssa.Op386ADDSD:
- op = x86.AFADDDP
- case ssa.Op386SUBSS, ssa.Op386SUBSD:
- op = x86.AFSUBDP
- case ssa.Op386MULSS, ssa.Op386MULSD:
- op = x86.AFMULDP
- case ssa.Op386DIVSS, ssa.Op386DIVSD:
- op = x86.AFDIVDP
- }
- p := s.Prog(op)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = s.SSEto387[v.Reg()] + 1
-
- // Restore precision if needed.
- switch v.Op {
- case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
- restoreControlWord(s)
- }
-
- case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
- push(s, v.Args[0])
-
- // Compare.
- p := s.Prog(x86.AFUCOMP)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = s.SSEto387[v.Args[1].Reg()] + 1
-
- // Save AX.
- p = s.Prog(x86.AMOVL)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_AX
- s.AddrScratch(&p.To)
-
- // Move status word into AX.
- p = s.Prog(x86.AFSTSW)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_AX
-
- // Then move the flags we need to the integer flags.
- s.Prog(x86.ASAHF)
-
- // Restore AX.
- p = s.Prog(x86.AMOVL)
- s.AddrScratch(&p.From)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_AX
-
- case ssa.Op386SQRTSD:
- push(s, v.Args[0])
- s.Prog(x86.AFSQRT)
- popAndSave(s, v)
-
- case ssa.Op386FCHS:
- push(s, v.Args[0])
- s.Prog(x86.AFCHS)
- popAndSave(s, v)
-
- case ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD:
- p := s.Prog(x86.AMOVL)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = v.Args[0].Reg()
- s.AddrScratch(&p.To)
- p = s.Prog(x86.AFMOVL)
- s.AddrScratch(&p.From)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_F0
- popAndSave(s, v)
-
- case ssa.Op386CVTTSD2SL, ssa.Op386CVTTSS2SL:
- push(s, v.Args[0])
-
- // Load control word which truncates (rounds towards zero).
- installControlWord(s, gc.ControlWord64trunc, v.Reg())
-
- // Now do the conversion.
- p := s.Prog(x86.AFMOVLP)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- s.AddrScratch(&p.To)
- p = s.Prog(x86.AMOVL)
- s.AddrScratch(&p.From)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = v.Reg()
-
- // Restore control word.
- restoreControlWord(s)
-
- case ssa.Op386CVTSS2SD:
- // float32 -> float64 is a nop
- push(s, v.Args[0])
- popAndSave(s, v)
-
- case ssa.Op386CVTSD2SS:
- // Round to nearest float32.
- push(s, v.Args[0])
- p := s.Prog(x86.AFMOVFP)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- s.AddrScratch(&p.To)
- p = s.Prog(x86.AFMOVF)
- s.AddrScratch(&p.From)
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_F0
- popAndSave(s, v)
-
- case ssa.OpLoadReg:
- if !v.Type.IsFloat() {
- ssaGenValue(s, v)
- return
- }
- // Load+push the value we need.
- p := s.Prog(loadPush(v.Type))
- gc.AddrAuto(&p.From, v.Args[0])
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_F0
- // Move the value to its assigned register.
- popAndSave(s, v)
-
- case ssa.OpStoreReg:
- if !v.Type.IsFloat() {
- ssaGenValue(s, v)
- return
- }
- push(s, v.Args[0])
- var op obj.As
- switch v.Type.Size() {
- case 4:
- op = x86.AFMOVFP
- case 8:
- op = x86.AFMOVDP
- }
- p := s.Prog(op)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- gc.AddrAuto(&p.To, v)
-
- case ssa.OpCopy:
- if !v.Type.IsFloat() {
- ssaGenValue(s, v)
- return
- }
- push(s, v.Args[0])
- popAndSave(s, v)
-
- case ssa.Op386CALLstatic, ssa.Op386CALLclosure, ssa.Op386CALLinter:
- flush387(s) // Calls must empty the FP stack.
- fallthrough // then issue the call as normal
- default:
- ssaGenValue(s, v)
- }
-}
-
-// push pushes v onto the floating-point stack. v must be in a register.
-func push(s *gc.SSAGenState, v *ssa.Value) {
- p := s.Prog(x86.AFMOVD)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = s.SSEto387[v.Reg()]
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_F0
-}
-
-// popAndSave pops a value off of the floating-point stack and stores
-// it in the register assigned to v.
-func popAndSave(s *gc.SSAGenState, v *ssa.Value) {
- r := v.Reg()
- if _, ok := s.SSEto387[r]; ok {
- // Pop value, write to correct register.
- p := s.Prog(x86.AFMOVDP)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = s.SSEto387[v.Reg()] + 1
- } else {
- // Don't actually pop value. This 387 register is now the
- // new home for the not-yet-assigned-a-home SSE register.
- // Increase the register mapping of all other registers by one.
- for rSSE, r387 := range s.SSEto387 {
- s.SSEto387[rSSE] = r387 + 1
- }
- s.SSEto387[r] = x86.REG_F0
- }
-}
-
-// loadPush returns the opcode for load+push of the given type.
-func loadPush(t *types.Type) obj.As {
- if t.Size() == 4 {
- return x86.AFMOVF
- }
- return x86.AFMOVD
-}
-
-// flush387 removes all entries from the 387 floating-point stack.
-func flush387(s *gc.SSAGenState) {
- for k := range s.SSEto387 {
- p := s.Prog(x86.AFMOVDP)
- p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_F0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_F0
- delete(s.SSEto387, k)
- }
-}
-
-func ssaGenBlock387(s *gc.SSAGenState, b, next *ssa.Block) {
- // Empty the 387's FP stack before the block ends.
- flush387(s)
-
- ssaGenBlock(s, b, next)
-}
-
-// installControlWord saves the current floating-point control
-// word and installs a new one loaded from cw.
-// scratchReg must be an unused register.
-// This call must be paired with restoreControlWord.
-// Bytes 4-5 of the scratch space (s.AddrScratch) are used between
-// this call and restoreControlWord.
-func installControlWord(s *gc.SSAGenState, cw *obj.LSym, scratchReg int16) {
- // Save current control word.
- p := s.Prog(x86.AFSTCW)
- s.AddrScratch(&p.To)
- p.To.Offset += 4
-
- // Materialize address of new control word.
- // Note: this must be a seperate instruction to handle PIE correctly.
- // See issue 41503.
- p = s.Prog(x86.ALEAL)
- p.From.Type = obj.TYPE_MEM
- p.From.Name = obj.NAME_EXTERN
- p.From.Sym = cw
- p.To.Type = obj.TYPE_REG
- p.To.Reg = scratchReg
-
- // Load replacement control word.
- p = s.Prog(x86.AFLDCW)
- p.From.Type = obj.TYPE_MEM
- p.From.Reg = scratchReg
-}
-func restoreControlWord(s *gc.SSAGenState) {
- p := s.Prog(x86.AFLDCW)
- s.AddrScratch(&p.From)
- p.From.Offset += 4
-}
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
index 56c6989d93..e137daa3fc 100644
--- a/src/cmd/compile/internal/x86/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -15,19 +15,21 @@ import (
func Init(arch *gc.Arch) {
arch.LinkArch = &x86.Link386
arch.REGSP = x86.REGSP
+ arch.SSAGenValue = ssaGenValue
+ arch.SSAGenBlock = ssaGenBlock
+ arch.MAXWIDTH = (1 << 32) - 1
switch v := objabi.GO386; v {
- case "387":
- arch.Use387 = true
- arch.SSAGenValue = ssaGenValue387
- arch.SSAGenBlock = ssaGenBlock387
case "sse2":
- arch.SSAGenValue = ssaGenValue
- arch.SSAGenBlock = ssaGenBlock
+ case "softfloat":
+ arch.SoftFloat = true
+ case "387":
+ fmt.Fprintf(os.Stderr, "unsupported setting GO386=387. Consider using GO386=softfloat instead.\n")
+ gc.Exit(1)
default:
fmt.Fprintf(os.Stderr, "unsupported setting GO386=%s\n", v)
gc.Exit(1)
+
}
- arch.MAXWIDTH = (1 << 32) - 1
arch.ZeroRange = zerorange
arch.Ginsnop = ginsnop
diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go
index c21ac32297..74a4570770 100644
--- a/src/cmd/compile/internal/x86/ssa.go
+++ b/src/cmd/compile/internal/x86/ssa.go
@@ -852,8 +852,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
if gc.Debug_checknil != 0 && v.Pos.Line() > 1 { // v.Pos.Line()==1 in generated wrappers
gc.Warnl(v.Pos, "generated nil check")
}
- case ssa.Op386FCHS:
- v.Fatalf("FCHS in non-387 mode")
case ssa.OpClobber:
p := s.Prog(x86.AMOVL)
p.From.Type = obj.TYPE_CONST
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 3ac742fa55..d822a83e44 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -144,11 +144,7 @@ func xinit() {
b = os.Getenv("GO386")
if b == "" {
- if cansse2() {
- b = "sse2"
- } else {
- b = "387"
- }
+ b = "sse2"
}
go386 = b
@@ -836,6 +832,21 @@ func runInstall(pkg string, ch chan struct{}) {
asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
}
goasmh := pathf("%s/go_asm.h", workdir)
+ if IsRuntimePackagePath(pkg) {
+ asmArgs = append(asmArgs, "-compiling-runtime")
+ if os.Getenv("GOEXPERIMENT") == "regabi" {
+ // In order to make it easier to port runtime assembly
+ // to the register ABI, we introduce a macro
+ // indicating the experiment is enabled.
+ //
+ // Note: a similar change also appears in
+ // cmd/go/internal/work/gc.go.
+ //
+ // TODO(austin): Remove this once we commit to the
+ // register ABI (#40724).
+ asmArgs = append(asmArgs, "-D=GOEXPERIMENT_REGABI=1")
+ }
+ }
// Collect symabis from assembly code.
var symabis string
@@ -1466,9 +1477,9 @@ func wrapperPathFor(goos, goarch string) string {
if gohostos != "android" {
return pathf("%s/misc/android/go_android_exec.go", goroot)
}
- case (goos == "darwin" || goos == "ios") && goarch == "arm64":
- if gohostos != "darwin" || gohostarch != "arm64" {
- return pathf("%s/misc/ios/go_darwin_arm_exec.go", goroot)
+ case goos == "ios":
+ if gohostos != "ios" {
+ return pathf("%s/misc/ios/go_ios_exec.go", goroot)
}
}
return ""
@@ -1546,6 +1557,7 @@ var cgoEnabled = map[string]bool{
"android/arm": true,
"android/arm64": true,
"ios/arm64": true,
+ "ios/amd64": true,
"js/wasm": false,
"netbsd/386": true,
"netbsd/amd64": true,
@@ -1555,6 +1567,7 @@ var cgoEnabled = map[string]bool{
"openbsd/amd64": true,
"openbsd/arm": true,
"openbsd/arm64": true,
+ "openbsd/mips64": false,
"plan9/386": false,
"plan9/amd64": false,
"plan9/arm": false,
@@ -1567,7 +1580,8 @@ var cgoEnabled = map[string]bool{
// List of platforms which are supported but not complete yet. These get
// filtered out of cgoEnabled for 'dist list'. See golang.org/issue/28944
var incomplete = map[string]bool{
- "linux/sparc64": true,
+ "linux/sparc64": true,
+ "openbsd/mips64": true,
}
func needCC() bool {
@@ -1737,3 +1751,23 @@ func cmdlist() {
fatalf("write failed: %v", err)
}
}
+
+// IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it
+// belongs to the collection of "runtime-related" packages, including
+// "runtime" itself, "reflect", "syscall", and the
+// "runtime/internal/*" packages. See also the function of the same
+// name in cmd/internal/objabi/path.go.
+func IsRuntimePackagePath(pkgpath string) bool {
+ rval := false
+ switch pkgpath {
+ case "runtime":
+ rval = true
+ case "reflect":
+ rval = true
+ case "syscall":
+ rval = true
+ default:
+ rval = strings.HasPrefix(pkgpath, "runtime/internal")
+ }
+ return rval
+}
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index 79eab24d29..37b3d45977 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -67,6 +67,7 @@ var bootstrapDirs = []string{
"cmd/internal/obj/s390x",
"cmd/internal/obj/x86",
"cmd/internal/obj/wasm",
+ "cmd/internal/pkgpath",
"cmd/internal/src",
"cmd/internal/sys",
"cmd/link",
diff --git a/src/cmd/dist/cpuid_386.s b/src/cmd/dist/cpuid_386.s
deleted file mode 100644
index 65fbb2dcb7..0000000000
--- a/src/cmd/dist/cpuid_386.s
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !gccgo
-
-TEXT ·cpuid(SB),$0-8
- MOVL ax+4(FP), AX
- CPUID
- MOVL info+0(FP), DI
- MOVL AX, 0(DI)
- MOVL BX, 4(DI)
- MOVL CX, 8(DI)
- MOVL DX, 12(DI)
- RET
-
diff --git a/src/cmd/dist/cpuid_amd64.s b/src/cmd/dist/cpuid_amd64.s
deleted file mode 100644
index ea0b9d4dc9..0000000000
--- a/src/cmd/dist/cpuid_amd64.s
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !gccgo
-
-TEXT ·cpuid(SB),$0-12
- MOVL ax+8(FP), AX
- CPUID
- MOVQ info+0(FP), DI
- MOVL AX, 0(DI)
- MOVL BX, 4(DI)
- MOVL CX, 8(DI)
- MOVL DX, 12(DI)
- RET
-
diff --git a/src/cmd/dist/cpuid_default.s b/src/cmd/dist/cpuid_default.s
deleted file mode 100644
index 6412a507a9..0000000000
--- a/src/cmd/dist/cpuid_default.s
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !386,!amd64,!gccgo
-
-#include "textflag.h"
-
-TEXT ·cpuid(SB),NOSPLIT,$0-0
- RET
diff --git a/src/cmd/dist/main.go b/src/cmd/dist/main.go
index 224b6c0c3e..37de1acc31 100644
--- a/src/cmd/dist/main.go
+++ b/src/cmd/dist/main.go
@@ -129,10 +129,14 @@ func main() {
gohostarch = "riscv64"
case strings.Contains(out, "s390x"):
gohostarch = "s390x"
- case gohostos == "darwin":
+ case gohostos == "darwin", gohostos == "ios":
if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM64_") {
gohostarch = "arm64"
}
+ case gohostos == "openbsd":
+ if strings.Contains(run("", CheckExit, "uname", "-p"), "mips64") {
+ gohostarch = "mips64"
+ }
default:
fatalf("unknown architecture: %s", out)
}
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index f953a76963..aeffc2659f 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -217,6 +217,9 @@ func (t *tester) run() {
fmt.Println("\nFAILED")
xexit(1)
} else if incomplete[goos+"/"+goarch] {
+ // The test succeeded, but consider it as failed so we don't
+ // forget to remove the port from the incomplete map once the
+ // port is complete.
fmt.Println("\nFAILED (incomplete port)")
xexit(1)
} else if t.partial {
@@ -463,13 +466,14 @@ func (t *tester) registerTests() {
})
}
- // Test the ios build tag on darwin/amd64 for the iOS simulator.
- if goos == "darwin" && goarch == "amd64" {
+ // Test ios/amd64 for the iOS simulator.
+ if goos == "darwin" && goarch == "amd64" && t.cgoEnabled {
t.tests = append(t.tests, distTest{
name: "amd64ios",
- heading: "ios tag on darwin/amd64",
+ heading: "GOOS=ios on darwin/amd64",
fn: func(dt *distTest) error {
- t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=ios", "-run=SystemRoots", "crypto/x509")
+ cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-run=SystemRoots", "crypto/x509")
+ cmd.Env = append(os.Environ(), "GOOS=ios", "CGO_ENABLED=1")
return nil
},
})
@@ -903,7 +907,7 @@ func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec.
}
func (t *tester) iOS() bool {
- return (goos == "darwin" || goos == "ios") && goarch == "arm64"
+ return goos == "ios"
}
func (t *tester) out(v string) {
@@ -921,7 +925,7 @@ func (t *tester) extLink() bool {
"darwin-amd64", "darwin-arm64",
"dragonfly-amd64",
"freebsd-386", "freebsd-amd64", "freebsd-arm",
- "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x",
+ "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-riscv64", "linux-s390x",
"netbsd-386", "netbsd-amd64",
"openbsd-386", "openbsd-amd64",
"windows-386", "windows-amd64":
@@ -946,9 +950,6 @@ func (t *tester) internalLink() bool {
if goos == "ios" {
return false
}
- if goos == "darwin" && goarch == "arm64" {
- return false
- }
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/10373
// https://golang.org/issue/14449
@@ -964,10 +965,10 @@ func (t *tester) internalLink() bool {
func (t *tester) internalLinkPIE() bool {
switch goos + "-" + goarch {
- case "linux-amd64", "linux-arm64",
- "android-arm64":
- return true
- case "windows-amd64", "windows-386", "windows-arm":
+ case "darwin-amd64", "darwin-arm64",
+ "linux-amd64", "linux-arm64",
+ "android-arm64",
+ "windows-amd64", "windows-386", "windows-arm":
return true
}
return false
@@ -982,8 +983,8 @@ func (t *tester) supportedBuildmode(mode string) bool {
}
switch pair {
case "aix-ppc64",
- "darwin-amd64", "darwin-arm64",
- "linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x",
+ "darwin-amd64", "darwin-arm64", "ios-arm64",
+ "linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x",
"freebsd-amd64",
"windows-amd64", "windows-386":
return true
@@ -991,8 +992,8 @@ func (t *tester) supportedBuildmode(mode string) bool {
return false
case "c-shared":
switch pair {
- case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
- "darwin-amd64",
+ case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
+ "darwin-amd64", "darwin-arm64",
"freebsd-amd64",
"android-arm", "android-arm64", "android-386",
"windows-amd64", "windows-386":
@@ -1001,7 +1002,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
return false
case "shared":
switch pair {
- case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
+ case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x":
return true
}
return false
@@ -1011,7 +1012,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
switch pair {
case "linux-386", "linux-amd64", "linux-arm", "linux-s390x", "linux-ppc64le":
return true
- case "darwin-amd64":
+ case "darwin-amd64", "darwin-arm64":
return true
case "freebsd-amd64":
return true
@@ -1020,10 +1021,10 @@ func (t *tester) supportedBuildmode(mode string) bool {
case "pie":
switch pair {
case "aix/ppc64",
- "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
+ "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
"android-amd64", "android-arm", "android-arm64", "android-386":
return true
- case "darwin-amd64":
+ case "darwin-amd64", "darwin-arm64":
return true
case "windows-amd64", "windows-386", "windows-arm":
return true
@@ -1081,14 +1082,19 @@ func (t *tester) cgoTest(dt *distTest) error {
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest())
cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=auto")
- if t.internalLink() {
+ // Skip internal linking cases on arm64 to support GCC-9.4 and above,
+ // only for linux, conservatively.
+ // See issue #39466.
+ skipInternalLink := goarch == "arm64" && goos == "linux"
+
+ if t.internalLink() && !skipInternalLink {
cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal")
cmd.Env = append(os.Environ(), "GOFLAGS=-ldflags=-linkmode=internal")
}
pair := gohostos + "-" + goarch
switch pair {
- case "darwin-amd64",
+ case "darwin-amd64", "darwin-arm64",
"openbsd-386", "openbsd-amd64",
"windows-386", "windows-amd64":
// test linkmode=external, but __thread not supported, so skip testtls.
@@ -1100,6 +1106,13 @@ func (t *tester) cgoTest(dt *distTest) error {
cmd = t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
+ if t.supportedBuildmode("pie") {
+ t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
+ if t.internalLink() && t.internalLinkPIE() {
+ t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie")
+ }
+ }
+
case "aix-ppc64",
"android-arm", "android-arm64",
"dragonfly-amd64",
@@ -1150,8 +1163,8 @@ func (t *tester) cgoTest(dt *distTest) error {
if t.supportedBuildmode("pie") {
t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
- if t.internalLink() && t.internalLinkPIE() {
- t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal")
+ if t.internalLink() && t.internalLinkPIE() && !skipInternalLink {
+ t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie")
}
t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie")
t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie")
diff --git a/src/cmd/dist/util_gc.go b/src/cmd/dist/util_gc.go
index 698beef704..17a0e6fbb5 100644
--- a/src/cmd/dist/util_gc.go
+++ b/src/cmd/dist/util_gc.go
@@ -6,18 +6,6 @@
package main
-func cpuid(info *[4]uint32, ax uint32)
-
-func cansse2() bool {
- if gohostarch != "386" && gohostarch != "amd64" {
- return false
- }
-
- var info [4]uint32
- cpuid(&info, 1)
- return info[3]&(1<<26) != 0 // SSE2
-}
-
// useVFPv1 tries to execute one VFPv1 instruction on ARM.
// It will crash the current process if VFPv1 is missing.
func useVFPv1()
diff --git a/src/cmd/dist/util_gccgo.go b/src/cmd/dist/util_gccgo.go
index f9f01dc048..dc897236fb 100644
--- a/src/cmd/dist/util_gccgo.go
+++ b/src/cmd/dist/util_gccgo.go
@@ -6,19 +6,6 @@
package main
-/*
-int supports_sse2() {
-#if defined(__i386__) || defined(__x86_64__)
- return __builtin_cpu_supports("sse2");
-#else
- return 0;
-#endif
-}
-*/
-import "C"
-
-func cansse2() bool { return C.supports_sse2() != 0 }
-
func useVFPv1() {}
func useVFPv3() {}
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index 47602833d3..39530e3c2d 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -36,7 +36,7 @@ func TestMain(m *testing.M) {
}
func maybeSkip(t *testing.T) {
- if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
+ if runtime.GOOS == "ios" {
t.Skip("iOS does not have a full file tree")
}
}
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index ffc302c78c..c2e06ebc8b 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -16,8 +16,8 @@ import (
"go/printer"
"go/token"
"io"
+ "io/fs"
"log"
- "os"
"path/filepath"
"strings"
"unicode"
@@ -129,11 +129,10 @@ func (pkg *Package) Fatalf(format string, args ...interface{}) {
// parsePackage turns the build package we found into a parsed package
// we can then use to generate documentation.
func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Package {
- fs := token.NewFileSet()
// include tells parser.ParseDir which files to include.
// That means the file must be in the build package's GoFiles or CgoFiles
// list only (no tag-ignored files, tests, swig or other non-Go files).
- include := func(info os.FileInfo) bool {
+ include := func(info fs.FileInfo) bool {
for _, name := range pkg.GoFiles {
if name == info.Name() {
return true
@@ -146,7 +145,8 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
}
return false
}
- pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments)
+ fset := token.NewFileSet()
+ pkgs, err := parser.ParseDir(fset, pkg.Dir, include, parser.ParseComments)
if err != nil {
log.Fatal(err)
}
@@ -203,7 +203,7 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
typedValue: typedValue,
constructor: constructor,
build: pkg,
- fs: fs,
+ fs: fset,
}
p.buf.pkg = p
return p
diff --git a/src/cmd/fix/gotypes.go b/src/cmd/fix/gotypes.go
index 8a4019cc8c..031f85c9cc 100644
--- a/src/cmd/fix/gotypes.go
+++ b/src/cmd/fix/gotypes.go
@@ -21,11 +21,11 @@ var gotypesFix = fix{
}
func gotypes(f *ast.File) bool {
- truth := fixGoTypes(f)
+ fixed := fixGoTypes(f)
if fixGoExact(f) {
- truth = true
+ fixed = true
}
- return truth
+ return fixed
}
func fixGoTypes(f *ast.File) bool {
diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go
index e72c66398f..1cea9a876a 100644
--- a/src/cmd/fix/main.go
+++ b/src/cmd/fix/main.go
@@ -13,6 +13,8 @@ import (
"go/parser"
"go/scanner"
"go/token"
+ "io"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -127,7 +129,7 @@ func processFile(filename string, useStdin bool) error {
defer f.Close()
}
- src, err := ioutil.ReadAll(f)
+ src, err := io.ReadAll(f)
if err != nil {
return err
}
@@ -137,6 +139,21 @@ func processFile(filename string, useStdin bool) error {
return err
}
+ // Make sure file is in canonical format.
+ // This "fmt" pseudo-fix cannot be disabled.
+ newSrc, err := gofmtFile(file)
+ if err != nil {
+ return err
+ }
+ if !bytes.Equal(newSrc, src) {
+ newFile, err := parser.ParseFile(fset, filename, newSrc, parserMode)
+ if err != nil {
+ return err
+ }
+ file = newFile
+ fmt.Fprintf(&fixlog, " fmt")
+ }
+
// Apply all fixes to file.
newFile := file
fixed := false
@@ -180,7 +197,7 @@ func processFile(filename string, useStdin bool) error {
// output of the printer run on a standard AST generated by the parser,
// but the source we generated inside the loop above is the
// output of the printer run on a mangled AST generated by a fixer.
- newSrc, err := gofmtFile(newFile)
+ newSrc, err = gofmtFile(newFile)
if err != nil {
return err
}
@@ -220,7 +237,7 @@ func walkDir(path string) {
filepath.Walk(path, visitFile)
}
-func visitFile(path string, f os.FileInfo, err error) error {
+func visitFile(path string, f fs.FileInfo, err error) error {
if err == nil && isGoFile(f) {
err = processFile(path, false)
}
@@ -230,7 +247,7 @@ func visitFile(path string, f os.FileInfo, err error) error {
return nil
}
-func isGoFile(f os.FileInfo) bool {
+func isGoFile(f fs.FileInfo) bool {
// ignore non-Go files
name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
diff --git a/src/cmd/fix/typecheck.go b/src/cmd/fix/typecheck.go
index 66e0cdcec0..f45155b06d 100644
--- a/src/cmd/fix/typecheck.go
+++ b/src/cmd/fix/typecheck.go
@@ -207,7 +207,7 @@ func typecheck(cfg *TypeConfig, f *ast.File) (typeof map[interface{}]string, ass
return nil
}()
if err != nil {
- fmt.Printf("warning: no cgo types: %s\n", err)
+ fmt.Fprintf(os.Stderr, "go fix: warning: no cgo types: %s\n", err)
}
}
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index 59d6152e2a..f79b238a1d 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -3,11 +3,11 @@ module cmd
go 1.16
require (
- github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
+ github.com/google/pprof v0.0.0-20201007051231-1066cbb265c7
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
- golang.org/x/arch v0.0.0-20200826200359-b19915210f00
+ golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
- golang.org/x/tools v0.0.0-20200918232735-d647fc253266
+ golang.org/x/tools v0.0.0-20201014170642-d1624618ad65
)
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index 1b6d680d62..6eff8a2c57 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -1,14 +1,14 @@
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3 h1:SRgJV+IoxM5MKyFdlSUeNy6/ycRUF2yBAKdAQswoHUk=
-github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201007051231-1066cbb265c7 h1:qYWTuM6SUNWgtvkhV8oH6GFHCpU+rKQOxPcepM3xKi0=
+github.com/google/pprof v0.0.0-20201007051231-1066cbb265c7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac=
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-golang.org/x/arch v0.0.0-20200826200359-b19915210f00 h1:cfd5G6xu8iZTFmjBYVemyBmE/sTf0A3vpE3BmoOuLCI=
-golang.org/x/arch v0.0.0-20200826200359-b19915210f00/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
+golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff h1:XmKBi9R6duxOB3lfc72wyrwiOY7X2Jl1wuI+RFOyMDE=
+golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -30,8 +30,8 @@ golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73Ih
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200918232735-d647fc253266 h1:k7tVuG0g1JwmD3Jh8oAl1vQ1C3jb4Hi/dUl1wWDBJpQ=
-golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
+golang.org/x/tools v0.0.0-20201014170642-d1624618ad65 h1:q80OtYaeeySe8Kqg0vjXehHwj5fUTqe3xOvnbi5w3Gg=
+golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 4bc87008ff..23d44ddc70 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -662,13 +662,12 @@
// this automatically as well.
//
// The -insecure flag permits fetching from repositories and resolving
-// custom domains using insecure schemes such as HTTP. Use with caution.
+// custom domains using insecure schemes such as HTTP, and also bypassess
+// module sum validation using the checksum database. Use with caution.
// This flag is deprecated and will be removed in a future version of go.
-// The GOINSECURE environment variable is usually a better alternative, since
-// it provides control over which modules may be retrieved using an insecure
-// scheme. It should be noted that the -insecure flag also turns the module
-// checksum validation off. GOINSECURE does not do that, use GONOSUMDB.
-// See 'go help environment' for details.
+// To permit the use of insecure schemes, use the GOINSECURE environment
+// variable instead. To bypass module sum validation, use GOPRIVATE or
+// GONOSUMDB. See 'go help environment' for details.
//
// The second step is to download (if needed), build, and install
// the named packages.
@@ -797,26 +796,28 @@
// BinaryOnly bool // binary-only package (no longer supported)
// ForTest string // package is only for use in named test
// Export string // file containing export data (when using -export)
+// BuildID string // build ID of the compiled package (when using -export)
// Module *Module // info about package's containing module, if any (can be nil)
// Match []string // command-line patterns matching this package
// DepOnly bool // package is only a dependency, not explicitly listed
//
// // Source files
-// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
-// CgoFiles []string // .go source files that import "C"
-// CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
-// IgnoredGoFiles []string // .go source files ignored due to build constraints
-// CFiles []string // .c source files
-// CXXFiles []string // .cc, .cxx and .cpp source files
-// MFiles []string // .m source files
-// HFiles []string // .h, .hh, .hpp and .hxx source files
-// FFiles []string // .f, .F, .for and .f90 Fortran source files
-// SFiles []string // .s source files
-// SwigFiles []string // .swig files
-// SwigCXXFiles []string // .swigcxx files
-// SysoFiles []string // .syso object files to add to archive
-// TestGoFiles []string // _test.go files in package
-// XTestGoFiles []string // _test.go files outside package
+// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+// CgoFiles []string // .go source files that import "C"
+// CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
+// IgnoredGoFiles []string // .go source files ignored due to build constraints
+// IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
+// CFiles []string // .c source files
+// CXXFiles []string // .cc, .cxx and .cpp source files
+// MFiles []string // .m source files
+// HFiles []string // .h, .hh, .hpp and .hxx source files
+// FFiles []string // .f, .F, .for and .f90 Fortran source files
+// SFiles []string // .s source files
+// SwigFiles []string // .swig files
+// SwigCXXFiles []string // .swigcxx files
+// SysoFiles []string // .syso object files to add to archive
+// TestGoFiles []string // _test.go files in package
+// XTestGoFiles []string // _test.go files outside package
//
// // Cgo directives
// CgoCFLAGS []string // cgo: flags for C compiler
@@ -1854,8 +1855,8 @@
// For GOARCH=arm, the ARM architecture for which to compile.
// Valid values are 5, 6, 7.
// GO386
-// For GOARCH=386, the floating point instruction set.
-// Valid values are 387, sse2.
+// For GOARCH=386, how to implement floating point instructions.
+// Valid values are sse2 (default), softfloat.
// GOMIPS
// For GOARCH=mips{,le}, whether to use floating point instructions.
// Valid values are hardfloat (default), softfloat.
@@ -2214,8 +2215,8 @@
// The -insecure flag permits fetching from repositories and resolving
// custom domains using insecure schemes such as HTTP. Use with caution.
// This flag is deprecated and will be removed in a future version of go.
-// The GOINSECURE environment variable is usually a better alternative, since
-// it provides control over which modules may be retrieved using an insecure
+// The GOINSECURE environment variable should be used instead, since it
+// provides control over which packages may be retrieved using an insecure
// scheme. See 'go help environment' for details.
//
// The -t flag instructs get to also download the packages required to build
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index 66a52c86ad..d1bd516a5d 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -15,6 +15,7 @@ import (
"internal/race"
"internal/testenv"
"io"
+ "io/fs"
"io/ioutil"
"log"
"os"
@@ -58,11 +59,10 @@ func init() {
switch runtime.GOOS {
case "android", "js":
canRun = false
- case "darwin", "ios":
- switch runtime.GOARCH {
- case "arm64":
- canRun = false
- }
+ case "darwin":
+ // nothing to do
+ case "ios":
+ canRun = false
case "linux":
switch runtime.GOARCH {
case "arm":
@@ -814,7 +814,7 @@ func (tg *testgoData) cleanup() {
func removeAll(dir string) error {
// module cache has 0444 directories;
// make them writable in order to remove content.
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
// chmod not only directories, but also things that we couldn't even stat
// due to permission errors: they may also be unreadable directories.
if err != nil || info.IsDir() {
@@ -861,7 +861,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
srcdir := filepath.Join(testGOROOT, copydir)
tg.tempDir(filepath.Join("goroot", copydir))
err := filepath.Walk(srcdir,
- func(path string, info os.FileInfo, err error) error {
+ func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
@@ -1237,6 +1237,18 @@ func TestGoListExport(t *testing.T) {
if _, err := os.Stat(file); err != nil {
t.Fatalf("cannot find .Export result %s: %v", file, err)
}
+
+ tg.run("list", "-export", "-f", "{{.BuildID}}", "strings")
+ buildID := strings.TrimSpace(tg.stdout.String())
+ if buildID == "" {
+ t.Fatalf(".BuildID with -export was empty")
+ }
+
+ tg.run("tool", "buildid", file)
+ toolBuildID := strings.TrimSpace(tg.stdout.String())
+ if buildID != toolBuildID {
+ t.Fatalf(".BuildID with -export %q disagrees with 'go tool buildid' %q", buildID, toolBuildID)
+ }
}
// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
@@ -2019,7 +2031,7 @@ func main() {
tg.run("build", "-o", exe, "p")
}
-func copyFile(src, dst string, perm os.FileMode) error {
+func copyFile(src, dst string, perm fs.FileMode) error {
sf, err := os.Open(src)
if err != nil {
return err
@@ -2058,7 +2070,7 @@ func TestBuildmodePIE(t *testing.T) {
platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
switch platform {
- case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
+ case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64",
"windows/386", "windows/amd64", "windows/arm":
diff --git a/src/cmd/go/go_windows_test.go b/src/cmd/go/go_windows_test.go
index 3999166ed9..02634f19f5 100644
--- a/src/cmd/go/go_windows_test.go
+++ b/src/cmd/go/go_windows_test.go
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package main
+package main_test
import (
- "internal/testenv"
"io/ioutil"
"os"
"os/exec"
@@ -17,7 +16,9 @@ import (
)
func TestAbsolutePath(t *testing.T) {
- t.Parallel()
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
tmp, err := ioutil.TempDir("", "TestAbsolutePath")
if err != nil {
@@ -38,7 +39,7 @@ func TestAbsolutePath(t *testing.T) {
noVolume := file[len(filepath.VolumeName(file)):]
wrongPath := filepath.Join(dir, noVolume)
- cmd := exec.Command(testenv.GoToolPath(t), "build", noVolume)
+ cmd := exec.Command(tg.goTool(), "build", noVolume)
cmd.Dir = dir
output, err := cmd.CombinedOutput()
if err == nil {
diff --git a/src/cmd/go/internal/base/goflags.go b/src/cmd/go/internal/base/goflags.go
index 4da27550fd..267006be7a 100644
--- a/src/cmd/go/internal/base/goflags.go
+++ b/src/cmd/go/internal/base/goflags.go
@@ -92,7 +92,11 @@ func SetFromGOFLAGS(flags *flag.FlagSet) {
}
for _, goflag := range goflags {
name, value, hasValue := goflag, "", false
- if i := strings.Index(goflag, "="); i >= 0 {
+ // Ignore invalid flags like '=' or '=value'.
+ // If it is not reported in InitGOFlags it means we don't want to report it.
+ if i := strings.Index(goflag, "="); i == 0 {
+ continue
+ } else if i > 0 {
name, value, hasValue = goflag[:i], goflag[i+1:], true
}
if strings.HasPrefix(name, "--") {
diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go
index 15545ac31f..5464fe5685 100644
--- a/src/cmd/go/internal/cache/cache.go
+++ b/src/cmd/go/internal/cache/cache.go
@@ -12,6 +12,7 @@ import (
"errors"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -54,7 +55,7 @@ func Open(dir string) (*Cache, error) {
return nil, err
}
if !info.IsDir() {
- return nil, &os.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")}
+ return nil, &fs.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")}
}
for i := 0; i < 256; i++ {
name := filepath.Join(dir, fmt.Sprintf("%02x", i))
diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index 9bf1db73ef..67d581f6e6 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -11,6 +11,7 @@ import (
"fmt"
"go/build"
"internal/cfg"
+ "io"
"io/ioutil"
"os"
"path/filepath"
@@ -18,6 +19,8 @@ import (
"strings"
"sync"
+ "cmd/go/internal/fsys"
+
"cmd/internal/objabi"
)
@@ -104,6 +107,15 @@ func defaultContext() build.Context {
// Nothing to do here.
}
+ ctxt.OpenFile = func(path string) (io.ReadCloser, error) {
+ return fsys.Open(path)
+ }
+ ctxt.ReadDir = fsys.ReadDir
+ ctxt.IsDir = func(path string) bool {
+ isDir, err := fsys.IsDir(path)
+ return err == nil && isDir
+ }
+
return ctxt
}
diff --git a/src/cmd/go/internal/clean/clean.go b/src/cmd/go/internal/clean/clean.go
index 6bfd7ae21e..87933f04f3 100644
--- a/src/cmd/go/internal/clean/clean.go
+++ b/src/cmd/go/internal/clean/clean.go
@@ -8,6 +8,7 @@ package clean
import (
"context"
"fmt"
+ "io"
"io/ioutil"
"os"
"path/filepath"
@@ -172,7 +173,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt"))
if err == nil {
now := time.Now().UnixNano()
- buf, _ := ioutil.ReadAll(f)
+ buf, _ := io.ReadAll(f)
prev, _ := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 64)
if now > prev {
if err = f.Truncate(0); err == nil {
@@ -275,6 +276,8 @@ func clean(p *load.Package) {
allRemove = append(allRemove,
elem,
elem+".exe",
+ p.DefaultExecName(),
+ p.DefaultExecName()+".exe",
)
}
@@ -282,16 +285,28 @@ func clean(p *load.Package) {
allRemove = append(allRemove,
elem+".test",
elem+".test.exe",
+ p.DefaultExecName()+".test",
+ p.DefaultExecName()+".test.exe",
)
- // Remove a potential executable for each .go file in the directory that
+ // Remove a potential executable, test executable for each .go file in the directory that
// is not part of the directory's package.
for _, dir := range dirs {
name := dir.Name()
if packageFile[name] {
continue
}
- if !dir.IsDir() && strings.HasSuffix(name, ".go") {
+
+ if dir.IsDir() {
+ continue
+ }
+
+ if strings.HasSuffix(name, "_test.go") {
+ base := name[:len(name)-len("_test.go")]
+ allRemove = append(allRemove, base+".test", base+".test.exe")
+ }
+
+ if strings.HasSuffix(name, ".go") {
// TODO(adg,rsc): check that this .go file is actually
// in "package main", and therefore capable of building
// to an executable file.
diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
index 7bd75f7305..557e418921 100644
--- a/src/cmd/go/internal/envcmd/env.go
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -21,6 +21,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/load"
"cmd/go/internal/modload"
"cmd/go/internal/work"
@@ -197,12 +198,26 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
env := cfg.CmdEnv
env = append(env, ExtraEnvVars()...)
+ if err := fsys.Init(base.Cwd); err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
// Do we need to call ExtraEnvVarsCostly, which is a bit expensive?
- // Only if we're listing all environment variables ("go env")
- // or the variables being requested are in the extra list.
- needCostly := true
- if len(args) > 0 {
+ needCostly := false
+ if *envU || *envW {
+ // We're overwriting or removing default settings,
+ // so it doesn't really matter what the existing settings are.
+ //
+ // Moreover, we haven't validated the new settings yet, so it is
+ // important that we NOT perform any actions based on them,
+ // such as initializing the builder to compute other variables.
+ } else if len(args) == 0 {
+ // We're listing all environment variables ("go env"),
+ // including the expensive ones.
+ needCostly = true
+ } else {
needCostly = false
+ checkCostly:
for _, arg := range args {
switch argKey(arg) {
case "CGO_CFLAGS",
@@ -213,6 +228,7 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
"PKG_CONFIG",
"GOGCCFLAGS":
needCostly = true
+ break checkCostly
}
}
}
@@ -264,6 +280,13 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
}
}
+ gotmp, okGOTMP := add["GOTMPDIR"]
+ if okGOTMP {
+ if !filepath.IsAbs(gotmp) && gotmp != "" {
+ base.Fatalf("go env -w: GOTMPDIR must be an absolute path")
+ }
+ }
+
updateEnvFile(add, nil)
return
}
@@ -403,6 +426,11 @@ func checkEnvWrite(key, val string) error {
if !filepath.IsAbs(val) && val != "" {
return fmt.Errorf("GOPATH entry is relative; must be absolute path: %q", val)
}
+ // Make sure CC and CXX are absolute paths
+ case "CC", "CXX":
+ if !filepath.IsAbs(val) && val != "" && val != filepath.Base(val) {
+ return fmt.Errorf("%s entry is relative; must be absolute path: %q", key, val)
+ }
}
if !utf8.ValidString(val) {
@@ -497,7 +525,10 @@ func lineToKey(line string) string {
}
// sortKeyValues sorts a sequence of lines by key.
-// It differs from sort.Strings in that GO386= sorts after GO=.
+// It differs from sort.Strings in that keys which are GOx where x is an ASCII
+// character smaller than = sort after GO=.
+// (There are no such keys currently. It used to matter for GO386 which was
+// removed in Go 1.16.)
func sortKeyValues(lines []string) {
sort.Slice(lines, func(i, j int) bool {
return lineToKey(lines[i]) < lineToKey(lines[j])
diff --git a/src/cmd/go/internal/fsys/fsys.go b/src/cmd/go/internal/fsys/fsys.go
new file mode 100644
index 0000000000..44d9b1368b
--- /dev/null
+++ b/src/cmd/go/internal/fsys/fsys.go
@@ -0,0 +1,679 @@
+// Package fsys is an abstraction for reading files that
+// allows for virtual overlays on top of the files on disk.
+package fsys
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/fs"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "sort"
+ "strings"
+ "time"
+)
+
+// OverlayFile is the path to a text file in the OverlayJSON format.
+// It is the value of the -overlay flag.
+var OverlayFile string
+
+// OverlayJSON is the format overlay files are expected to be in.
+// The Replace map maps from overlaid paths to replacement paths:
+// the Go command will forward all reads trying to open
+// each overlaid path to its replacement path, or consider the overlaid
+// path not to exist if the replacement path is empty.
+type OverlayJSON struct {
+ Replace map[string]string
+}
+
+type node struct {
+ actualFilePath string // empty if a directory
+ children map[string]*node // path element → file or directory
+}
+
+func (n *node) isDir() bool {
+ return n.actualFilePath == "" && n.children != nil
+}
+
+func (n *node) isDeleted() bool {
+ return n.actualFilePath == "" && n.children == nil
+}
+
+// TODO(matloob): encapsulate these in an io/fs-like interface
+var overlay map[string]*node // path -> file or directory node
+var cwd string // copy of base.Cwd to avoid dependency
+
+// Canonicalize a path for looking it up in the overlay.
+// Important: filepath.Join(cwd, path) doesn't always produce
+// the correct absolute path if path is relative, because on
+// Windows producing the correct absolute path requires making
+// a syscall. So this should only be used when looking up paths
+// in the overlay, or canonicalizing the paths in the overlay.
+func canonicalize(path string) string {
+ if path == "" {
+ return ""
+ }
+ if filepath.IsAbs(path) {
+ return filepath.Clean(path)
+ }
+
+ if v := filepath.VolumeName(cwd); v != "" && path[0] == filepath.Separator {
+ // On Windows filepath.Join(cwd, path) doesn't always work. In general
+ // filepath.Abs needs to make a syscall on Windows. Elsewhere in cmd/go
+ // use filepath.Join(cwd, path), but cmd/go specifically supports Windows
+ // paths that start with "\" which implies the path is relative to the
+ // volume of the working directory. See golang.org/issue/8130.
+ return filepath.Join(v, path)
+ }
+
+ // Make the path absolute.
+ return filepath.Join(cwd, path)
+}
+
+// Init initializes the overlay, if one is being used.
+func Init(wd string) error {
+ if overlay != nil {
+ // already initialized
+ return nil
+ }
+
+ cwd = wd
+
+ if OverlayFile == "" {
+ return nil
+ }
+
+ b, err := ioutil.ReadFile(OverlayFile)
+ if err != nil {
+ return fmt.Errorf("reading overlay file: %v", err)
+ }
+
+ var overlayJSON OverlayJSON
+ if err := json.Unmarshal(b, &overlayJSON); err != nil {
+ return fmt.Errorf("parsing overlay JSON: %v", err)
+ }
+
+ return initFromJSON(overlayJSON)
+}
+
+func initFromJSON(overlayJSON OverlayJSON) error {
+ // Canonicalize the paths in in the overlay map.
+ // Use reverseCanonicalized to check for collisions:
+ // no two 'from' paths should canonicalize to the same path.
+ overlay = make(map[string]*node)
+ reverseCanonicalized := make(map[string]string) // inverse of canonicalize operation, to check for duplicates
+ // Build a table of file and directory nodes from the replacement map.
+
+ // Remove any potential non-determinism from iterating over map by sorting it.
+ replaceFrom := make([]string, 0, len(overlayJSON.Replace))
+ for k := range overlayJSON.Replace {
+ replaceFrom = append(replaceFrom, k)
+ }
+ sort.Strings(replaceFrom)
+
+ for _, from := range replaceFrom {
+ to := overlayJSON.Replace[from]
+ // Canonicalize paths and check for a collision.
+ if from == "" {
+ return fmt.Errorf("empty string key in overlay file Replace map")
+ }
+ cfrom := canonicalize(from)
+ if to != "" {
+ // Don't canonicalize "", meaning to delete a file, because then it will turn into ".".
+ to = canonicalize(to)
+ }
+ if otherFrom, seen := reverseCanonicalized[cfrom]; seen {
+ return fmt.Errorf(
+ "paths %q and %q both canonicalize to %q in overlay file Replace map", otherFrom, from, cfrom)
+ }
+ reverseCanonicalized[cfrom] = from
+ from = cfrom
+
+ // Create node for overlaid file.
+ dir, base := filepath.Dir(from), filepath.Base(from)
+ if n, ok := overlay[from]; ok {
+ // All 'from' paths in the overlay are file paths. Since the from paths
+ // are in a map, they are unique, so if the node already exists we added
+ // it below when we create parent directory nodes. That is, that
+ // both a file and a path to one of its parent directories exist as keys
+ // in the Replace map.
+ //
+ // This only applies if the overlay directory has any files or directories
+ // in it: placeholder directories that only contain deleted files don't
+ // count. They are safe to be overwritten with actual files.
+ for _, f := range n.children {
+ if !f.isDeleted() {
+ return fmt.Errorf("invalid overlay: path %v is used as both file and directory", from)
+ }
+ }
+ }
+ overlay[from] = &node{actualFilePath: to}
+
+ // Add parent directory nodes to overlay structure.
+ childNode := overlay[from]
+ for {
+ dirNode := overlay[dir]
+ if dirNode == nil || dirNode.isDeleted() {
+ dirNode = &node{children: make(map[string]*node)}
+ overlay[dir] = dirNode
+ }
+ if childNode.isDeleted() {
+ // Only create one parent for a deleted file:
+ // the directory only conditionally exists if
+ // there are any non-deleted children, so
+ // we don't create their parents.
+ if dirNode.isDir() {
+ dirNode.children[base] = childNode
+ }
+ break
+ }
+ if !dirNode.isDir() {
+ // This path already exists as a file, so it can't be a parent
+ // directory. See comment at error above.
+ return fmt.Errorf("invalid overlay: path %v is used as both file and directory", dir)
+ }
+ dirNode.children[base] = childNode
+ parent := filepath.Dir(dir)
+ if parent == dir {
+ break // reached the top; there is no parent
+ }
+ dir, base = parent, filepath.Base(dir)
+ childNode = dirNode
+ }
+ }
+
+ return nil
+}
+
+// IsDir returns true if path is a directory on disk or in the
+// overlay.
+func IsDir(path string) (bool, error) {
+ path = canonicalize(path)
+
+ if _, ok := parentIsOverlayFile(path); ok {
+ return false, nil
+ }
+
+ if n, ok := overlay[path]; ok {
+ return n.isDir(), nil
+ }
+
+ fi, err := os.Stat(path)
+ if err != nil {
+ return false, err
+ }
+
+ return fi.IsDir(), nil
+}
+
+// parentIsOverlayFile returns whether name or any of
+// its parents are files in the overlay, and the first parent found,
+// including name itself, that's a file in the overlay.
+func parentIsOverlayFile(name string) (string, bool) {
+ if overlay != nil {
+ // Check if name can't possibly be a directory because
+ // it or one of its parents is overlaid with a file.
+ // TODO(matloob): Maybe save this to avoid doing it every time?
+ prefix := name
+ for {
+ node := overlay[prefix]
+ if node != nil && !node.isDir() {
+ return prefix, true
+ }
+ parent := filepath.Dir(prefix)
+ if parent == prefix {
+ break
+ }
+ prefix = parent
+ }
+ }
+
+ return "", false
+}
+
+// errNotDir is used to communicate from ReadDir to IsDirWithGoFiles
+// that the argument is not a directory, so that IsDirWithGoFiles doesn't
+// return an error.
+var errNotDir = errors.New("not a directory")
+
+// readDir reads a dir on disk, returning an error that is errNotDir if the dir is not a directory.
+// Unfortunately, the error returned by ioutil.ReadDir if dir is not a directory
+// can vary depending on the OS (Linux, Mac, Windows return ENOTDIR; BSD returns EINVAL).
+func readDir(dir string) ([]fs.FileInfo, error) {
+ fis, err := ioutil.ReadDir(dir)
+ if err == nil {
+ return fis, nil
+ }
+
+ if os.IsNotExist(err) {
+ return nil, err
+ }
+ if dirfi, staterr := os.Stat(dir); staterr == nil && !dirfi.IsDir() {
+ return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: errNotDir}
+ }
+ return nil, err
+}
+
+// ReadDir provides a slice of fs.FileInfo entries corresponding
+// to the overlaid files in the directory.
+func ReadDir(dir string) ([]fs.FileInfo, error) {
+ dir = canonicalize(dir)
+ if _, ok := parentIsOverlayFile(dir); ok {
+ return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: errNotDir}
+ }
+
+ dirNode := overlay[dir]
+ if dirNode == nil {
+ return readDir(dir)
+ }
+ if dirNode.isDeleted() {
+ return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: fs.ErrNotExist}
+ }
+ diskfis, err := readDir(dir)
+ if err != nil && !os.IsNotExist(err) && !errors.Is(err, errNotDir) {
+ return nil, err
+ }
+
+ // Stat files in overlay to make composite list of fileinfos
+ files := make(map[string]fs.FileInfo)
+ for _, f := range diskfis {
+ files[f.Name()] = f
+ }
+ for name, to := range dirNode.children {
+ switch {
+ case to.isDir():
+ files[name] = fakeDir(name)
+ case to.isDeleted():
+ delete(files, name)
+ default:
+ // This is a regular file.
+ f, err := os.Lstat(to.actualFilePath)
+ if err != nil {
+ files[name] = missingFile(name)
+ continue
+ } else if f.IsDir() {
+ return nil, fmt.Errorf("for overlay of %q to %q: overlay Replace entries can't point to dirctories",
+ filepath.Join(dir, name), to.actualFilePath)
+ }
+ // Add a fileinfo for the overlaid file, so that it has
+ // the original file's name, but the overlaid file's metadata.
+ files[name] = fakeFile{name, f}
+ }
+ }
+ sortedFiles := diskfis[:0]
+ for _, f := range files {
+ sortedFiles = append(sortedFiles, f)
+ }
+ sort.Slice(sortedFiles, func(i, j int) bool { return sortedFiles[i].Name() < sortedFiles[j].Name() })
+ return sortedFiles, nil
+}
+
+// OverlayPath returns the path to the overlaid contents of the
+// file, the empty string if the overlay deletes the file, or path
+// itself if the file is not in the overlay, the file is a directory
+// in the overlay, or there is no overlay.
+// It returns true if the path is overlaid with a regular file
+// or deleted, and false otherwise.
+func OverlayPath(path string) (string, bool) {
+ if p, ok := overlay[canonicalize(path)]; ok && !p.isDir() {
+ return p.actualFilePath, ok
+ }
+
+ return path, false
+}
+
+// Open opens the file at or overlaid on the given path.
+func Open(path string) (*os.File, error) {
+ cpath := canonicalize(path)
+ if node, ok := overlay[cpath]; ok {
+ if node.isDir() {
+ return nil, &fs.PathError{Op: "Open", Path: path, Err: errors.New("fsys.Open doesn't support opening directories yet")}
+ }
+ return os.Open(node.actualFilePath)
+ }
+ if parent, ok := parentIsOverlayFile(filepath.Dir(cpath)); ok {
+ // The file is deleted explicitly in the Replace map,
+ // or implicitly because one of its parent directories was
+ // replaced by a file.
+ return nil, &fs.PathError{
+ Op: "Open",
+ Path: path,
+ Err: fmt.Errorf("file %s does not exist: parent directory %s is replaced by a file in overlay", path, parent),
+ }
+ }
+ return os.Open(cpath)
+}
+
+// IsDirWithGoFiles reports whether dir is a directory containing Go files
+// either on disk or in the overlay.
+func IsDirWithGoFiles(dir string) (bool, error) {
+ fis, err := ReadDir(dir)
+ if os.IsNotExist(err) || errors.Is(err, errNotDir) {
+ return false, nil
+ }
+ if err != nil {
+ return false, err
+ }
+
+ var firstErr error
+ for _, fi := range fis {
+ if fi.IsDir() {
+ continue
+ }
+
+ // TODO(matloob): this enforces that the "from" in the map
+ // has a .go suffix, but the actual destination file
+ // doesn't need to have a .go suffix. Is this okay with the
+ // compiler?
+ if !strings.HasSuffix(fi.Name(), ".go") {
+ continue
+ }
+ if fi.Mode().IsRegular() {
+ return true, nil
+ }
+
+ // fi is the result of an Lstat, so it doesn't follow symlinks.
+ // But it's okay if the file is a symlink pointing to a regular
+ // file, so use os.Stat to follow symlinks and check that.
+ actualFilePath, _ := OverlayPath(filepath.Join(dir, fi.Name()))
+ fi, err := os.Stat(actualFilePath)
+ if err == nil && fi.Mode().IsRegular() {
+ return true, nil
+ }
+ if err != nil && firstErr == nil {
+ firstErr = err
+ }
+ }
+
+ // No go files found in directory.
+ return false, firstErr
+}
+
+// walk recursively descends path, calling walkFn. Copied, with some
+// modifications from path/filepath.walk.
+func walk(path string, info fs.FileInfo, walkFn filepath.WalkFunc) error {
+ if !info.IsDir() {
+ return walkFn(path, info, nil)
+ }
+
+ fis, readErr := ReadDir(path)
+ walkErr := walkFn(path, info, readErr)
+ // If readErr != nil, walk can't walk into this directory.
+ // walkErr != nil means walkFn want walk to skip this directory or stop walking.
+ // Therefore, if one of readErr and walkErr isn't nil, walk will return.
+ if readErr != nil || walkErr != nil {
+ // The caller's behavior is controlled by the return value, which is decided
+ // by walkFn. walkFn may ignore readErr and return nil.
+ // If walkFn returns SkipDir, it will be handled by the caller.
+ // So walk should return whatever walkFn returns.
+ return walkErr
+ }
+
+ for _, fi := range fis {
+ filename := filepath.Join(path, fi.Name())
+ if walkErr = walk(filename, fi, walkFn); walkErr != nil {
+ if !fi.IsDir() || walkErr != filepath.SkipDir {
+ return walkErr
+ }
+ }
+ }
+ return nil
+}
+
+// Walk walks the file tree rooted at root, calling walkFn for each file or
+// directory in the tree, including root.
+func Walk(root string, walkFn filepath.WalkFunc) error {
+ info, err := lstat(root)
+ if err != nil {
+ err = walkFn(root, nil, err)
+ } else {
+ err = walk(root, info, walkFn)
+ }
+ if err == filepath.SkipDir {
+ return nil
+ }
+ return err
+}
+
+// lstat implements a version of os.Lstat that operates on the overlay filesystem.
+func lstat(path string) (fs.FileInfo, error) {
+ return overlayStat(path, os.Lstat, "lstat")
+}
+
+// Stat implements a version of os.Stat that operates on the overlay filesystem.
+func Stat(path string) (fs.FileInfo, error) {
+ return overlayStat(path, os.Stat, "stat")
+}
+
+// overlayStat implements lstat or Stat (depending on whether os.Lstat or os.Stat is passed in).
+func overlayStat(path string, osStat func(string) (fs.FileInfo, error), opName string) (fs.FileInfo, error) {
+ cpath := canonicalize(path)
+
+ if _, ok := parentIsOverlayFile(filepath.Dir(cpath)); ok {
+ return nil, &fs.PathError{Op: opName, Path: cpath, Err: fs.ErrNotExist}
+ }
+
+ node, ok := overlay[cpath]
+ if !ok {
+ // The file or directory is not overlaid.
+ return osStat(path)
+ }
+
+ switch {
+ case node.isDeleted():
+ return nil, &fs.PathError{Op: "lstat", Path: cpath, Err: fs.ErrNotExist}
+ case node.isDir():
+ return fakeDir(filepath.Base(path)), nil
+ default:
+ fi, err := osStat(node.actualFilePath)
+ if err != nil {
+ return nil, err
+ }
+ return fakeFile{name: filepath.Base(path), real: fi}, nil
+ }
+}
+
+// fakeFile provides an fs.FileInfo implementation for an overlaid file,
+// so that the file has the name of the overlaid file, but takes all
+// other characteristics of the replacement file.
+type fakeFile struct {
+ name string
+ real fs.FileInfo
+}
+
+func (f fakeFile) Name() string { return f.name }
+func (f fakeFile) Size() int64 { return f.real.Size() }
+func (f fakeFile) Mode() fs.FileMode { return f.real.Mode() }
+func (f fakeFile) ModTime() time.Time { return f.real.ModTime() }
+func (f fakeFile) IsDir() bool { return f.real.IsDir() }
+func (f fakeFile) Sys() interface{} { return f.real.Sys() }
+
+// missingFile provides an fs.FileInfo for an overlaid file where the
+// destination file in the overlay doesn't exist. It returns zero values
+// for the fileInfo methods other than Name, set to the file's name, and Mode
+// set to ModeIrregular.
+type missingFile string
+
+func (f missingFile) Name() string { return string(f) }
+func (f missingFile) Size() int64 { return 0 }
+func (f missingFile) Mode() fs.FileMode { return fs.ModeIrregular }
+func (f missingFile) ModTime() time.Time { return time.Unix(0, 0) }
+func (f missingFile) IsDir() bool { return false }
+func (f missingFile) Sys() interface{} { return nil }
+
+// fakeDir provides an fs.FileInfo implementation for directories that are
+// implicitly created by overlaid files. Each directory in the
+// path of an overlaid file is considered to exist in the overlay filesystem.
+type fakeDir string
+
+func (f fakeDir) Name() string { return string(f) }
+func (f fakeDir) Size() int64 { return 0 }
+func (f fakeDir) Mode() fs.FileMode { return fs.ModeDir | 0500 }
+func (f fakeDir) ModTime() time.Time { return time.Unix(0, 0) }
+func (f fakeDir) IsDir() bool { return true }
+func (f fakeDir) Sys() interface{} { return nil }
+
+// Glob is like filepath.Glob but uses the overlay file system.
+func Glob(pattern string) (matches []string, err error) {
+ // Check pattern is well-formed.
+ if _, err := filepath.Match(pattern, ""); err != nil {
+ return nil, err
+ }
+ if !hasMeta(pattern) {
+ if _, err = lstat(pattern); err != nil {
+ return nil, nil
+ }
+ return []string{pattern}, nil
+ }
+
+ dir, file := filepath.Split(pattern)
+ volumeLen := 0
+ if runtime.GOOS == "windows" {
+ volumeLen, dir = cleanGlobPathWindows(dir)
+ } else {
+ dir = cleanGlobPath(dir)
+ }
+
+ if !hasMeta(dir[volumeLen:]) {
+ return glob(dir, file, nil)
+ }
+
+ // Prevent infinite recursion. See issue 15879.
+ if dir == pattern {
+ return nil, filepath.ErrBadPattern
+ }
+
+ var m []string
+ m, err = Glob(dir)
+ if err != nil {
+ return
+ }
+ for _, d := range m {
+ matches, err = glob(d, file, matches)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// cleanGlobPath prepares path for glob matching.
+func cleanGlobPath(path string) string {
+ switch path {
+ case "":
+ return "."
+ case string(filepath.Separator):
+ // do nothing to the path
+ return path
+ default:
+ return path[0 : len(path)-1] // chop off trailing separator
+ }
+}
+
+func volumeNameLen(path string) int {
+ isSlash := func(c uint8) bool {
+ return c == '\\' || c == '/'
+ }
+ if len(path) < 2 {
+ return 0
+ }
+ // with drive letter
+ c := path[0]
+ if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
+ return 2
+ }
+ // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+ if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
+ !isSlash(path[2]) && path[2] != '.' {
+ // first, leading `\\` and next shouldn't be `\`. its server name.
+ for n := 3; n < l-1; n++ {
+ // second, next '\' shouldn't be repeated.
+ if isSlash(path[n]) {
+ n++
+ // third, following something characters. its share name.
+ if !isSlash(path[n]) {
+ if path[n] == '.' {
+ break
+ }
+ for ; n < l; n++ {
+ if isSlash(path[n]) {
+ break
+ }
+ }
+ return n
+ }
+ break
+ }
+ }
+ }
+ return 0
+}
+
+// cleanGlobPathWindows is windows version of cleanGlobPath.
+func cleanGlobPathWindows(path string) (prefixLen int, cleaned string) {
+ vollen := volumeNameLen(path)
+ switch {
+ case path == "":
+ return 0, "."
+ case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/
+ // do nothing to the path
+ return vollen + 1, path
+ case vollen == len(path) && len(path) == 2: // C:
+ return vollen, path + "." // convert C: into C:.
+ default:
+ if vollen >= len(path) {
+ vollen = len(path) - 1
+ }
+ return vollen, path[0 : len(path)-1] // chop off trailing separator
+ }
+}
+
+// glob searches for files matching pattern in the directory dir
+// and appends them to matches. If the directory cannot be
+// opened, it returns the existing matches. New matches are
+// added in lexicographical order.
+func glob(dir, pattern string, matches []string) (m []string, e error) {
+ m = matches
+ fi, err := Stat(dir)
+ if err != nil {
+ return // ignore I/O error
+ }
+ if !fi.IsDir() {
+ return // ignore I/O error
+ }
+
+ list, err := ReadDir(dir)
+ if err != nil {
+ return // ignore I/O error
+ }
+
+ var names []string
+ for _, info := range list {
+ names = append(names, info.Name())
+ }
+ sort.Strings(names)
+
+ for _, n := range names {
+ matched, err := filepath.Match(pattern, n)
+ if err != nil {
+ return m, err
+ }
+ if matched {
+ m = append(m, filepath.Join(dir, n))
+ }
+ }
+ return
+}
+
+// hasMeta reports whether path contains any of the magic characters
+// recognized by filepath.Match.
+func hasMeta(path string) bool {
+ magicChars := `*?[`
+ if runtime.GOOS != "windows" {
+ magicChars = `*?[\`
+ }
+ return strings.ContainsAny(path, magicChars)
+}
diff --git a/src/cmd/go/internal/fsys/fsys_test.go b/src/cmd/go/internal/fsys/fsys_test.go
new file mode 100644
index 0000000000..22ad2fe445
--- /dev/null
+++ b/src/cmd/go/internal/fsys/fsys_test.go
@@ -0,0 +1,1095 @@
+package fsys
+
+import (
+ "cmd/go/internal/txtar"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "internal/testenv"
+ "io"
+ "io/fs"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "testing"
+)
+
+// initOverlay resets the overlay state to reflect the config.
+// config should be a text archive string. The comment is the overlay config
+// json, and the files, in the archive are laid out in a temp directory
+// that cwd is set to.
+func initOverlay(t *testing.T, config string) {
+ t.Helper()
+
+ // Create a temporary directory and chdir to it.
+ prevwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ cwd = filepath.Join(t.TempDir(), "root")
+ if err := os.Mkdir(cwd, 0777); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Chdir(cwd); err != nil {
+ t.Fatal(err)
+ }
+ t.Cleanup(func() {
+ overlay = nil
+ if err := os.Chdir(prevwd); err != nil {
+ t.Fatal(err)
+ }
+ })
+
+ a := txtar.Parse([]byte(config))
+ for _, f := range a.Files {
+ name := filepath.Join(cwd, f.Name)
+ if err := os.MkdirAll(filepath.Dir(name), 0777); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(name, f.Data, 0666); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ var overlayJSON OverlayJSON
+ if err := json.Unmarshal(a.Comment, &overlayJSON); err != nil {
+ t.Fatal(fmt.Errorf("parsing overlay JSON: %v", err))
+ }
+
+ initFromJSON(overlayJSON)
+}
+
+func TestIsDir(t *testing.T) {
+ initOverlay(t, `
+{
+ "Replace": {
+ "subdir2/file2.txt": "overlayfiles/subdir2_file2.txt",
+ "subdir4": "overlayfiles/subdir4",
+ "subdir3/file3b.txt": "overlayfiles/subdir3_file3b.txt",
+ "subdir5": "",
+ "subdir6": ""
+ }
+}
+-- subdir1/file1.txt --
+
+-- subdir3/file3a.txt --
+33
+-- subdir4/file4.txt --
+444
+-- overlayfiles/subdir2_file2.txt --
+2
+-- overlayfiles/subdir3_file3b.txt --
+66666
+-- overlayfiles/subdir4 --
+x
+-- subdir6/file6.txt --
+six
+`)
+
+ testCases := []struct {
+ path string
+ want, wantErr bool
+ }{
+ {"", true, true},
+ {".", true, false},
+ {cwd, true, false},
+ {cwd + string(filepath.Separator), true, false},
+ // subdir1 is only on disk
+ {filepath.Join(cwd, "subdir1"), true, false},
+ {"subdir1", true, false},
+ {"subdir1" + string(filepath.Separator), true, false},
+ {"subdir1/file1.txt", false, false},
+ {"subdir1/doesntexist.txt", false, true},
+ {"doesntexist", false, true},
+ // subdir2 is only in overlay
+ {filepath.Join(cwd, "subdir2"), true, false},
+ {"subdir2", true, false},
+ {"subdir2" + string(filepath.Separator), true, false},
+ {"subdir2/file2.txt", false, false},
+ {"subdir2/doesntexist.txt", false, true},
+ // subdir3 has files on disk and in overlay
+ {filepath.Join(cwd, "subdir3"), true, false},
+ {"subdir3", true, false},
+ {"subdir3" + string(filepath.Separator), true, false},
+ {"subdir3/file3a.txt", false, false},
+ {"subdir3/file3b.txt", false, false},
+ {"subdir3/doesntexist.txt", false, true},
+ // subdir4 is overlaid with a file
+ {filepath.Join(cwd, "subdir4"), false, false},
+ {"subdir4", false, false},
+ {"subdir4" + string(filepath.Separator), false, false},
+ {"subdir4/file4.txt", false, false},
+ {"subdir4/doesntexist.txt", false, false},
+ // subdir5 doesn't exist, and is overlaid with a "delete" entry
+ {filepath.Join(cwd, "subdir5"), false, false},
+ {"subdir5", false, false},
+ {"subdir5" + string(filepath.Separator), false, false},
+ {"subdir5/file5.txt", false, false},
+ {"subdir5/doesntexist.txt", false, false},
+ // subdir6 does exist, and is overlaid with a "delete" entry
+ {filepath.Join(cwd, "subdir6"), false, false},
+ {"subdir6", false, false},
+ {"subdir6" + string(filepath.Separator), false, false},
+ {"subdir6/file6.txt", false, false},
+ {"subdir6/doesntexist.txt", false, false},
+ }
+
+ for _, tc := range testCases {
+ got, err := IsDir(tc.path)
+ if err != nil {
+ if !tc.wantErr {
+ t.Errorf("IsDir(%q): got error with string %q, want no error", tc.path, err.Error())
+ }
+ continue
+ }
+ if tc.wantErr {
+ t.Errorf("IsDir(%q): got no error, want error", tc.path)
+ }
+ if tc.want != got {
+ t.Errorf("IsDir(%q) = %v, want %v", tc.path, got, tc.want)
+ }
+ }
+}
+
+const readDirOverlay = `
+{
+ "Replace": {
+ "subdir2/file2.txt": "overlayfiles/subdir2_file2.txt",
+ "subdir4": "overlayfiles/subdir4",
+ "subdir3/file3b.txt": "overlayfiles/subdir3_file3b.txt",
+ "subdir5": "",
+ "subdir6/asubsubdir/afile.txt": "overlayfiles/subdir6_asubsubdir_afile.txt",
+ "subdir6/asubsubdir/zfile.txt": "overlayfiles/subdir6_asubsubdir_zfile.txt",
+ "subdir6/zsubsubdir/file.txt": "overlayfiles/subdir6_zsubsubdir_file.txt",
+ "subdir7/asubsubdir/file.txt": "overlayfiles/subdir7_asubsubdir_file.txt",
+ "subdir7/zsubsubdir/file.txt": "overlayfiles/subdir7_zsubsubdir_file.txt",
+ "subdir8/doesntexist": "this_file_doesnt_exist_anywhere",
+ "other/pointstodir": "overlayfiles/this_is_a_directory",
+ "parentoverwritten/subdir1": "overlayfiles/parentoverwritten_subdir1",
+ "subdir9/this_file_is_overlaid.txt": "overlayfiles/subdir9_this_file_is_overlaid.txt",
+ "subdir10/only_deleted_file.txt": "",
+ "subdir11/deleted.txt": "",
+ "subdir11": "overlayfiles/subdir11",
+ "textfile.txt/file.go": "overlayfiles/textfile_txt_file.go"
+ }
+}
+-- subdir1/file1.txt --
+
+-- subdir3/file3a.txt --
+33
+-- subdir4/file4.txt --
+444
+-- subdir6/file.txt --
+-- subdir6/asubsubdir/file.txt --
+-- subdir6/anothersubsubdir/file.txt --
+-- subdir9/this_file_is_overlaid.txt --
+-- subdir10/only_deleted_file.txt --
+this will be deleted in overlay
+-- subdir11/deleted.txt --
+-- parentoverwritten/subdir1/subdir2/subdir3/file.txt --
+-- textfile.txt --
+this will be overridden by textfile.txt/file.go
+-- overlayfiles/subdir2_file2.txt --
+2
+-- overlayfiles/subdir3_file3b.txt --
+66666
+-- overlayfiles/subdir4 --
+x
+-- overlayfiles/subdir6_asubsubdir_afile.txt --
+-- overlayfiles/subdir6_asubsubdir_zfile.txt --
+-- overlayfiles/subdir6_zsubsubdir_file.txt --
+-- overlayfiles/subdir7_asubsubdir_file.txt --
+-- overlayfiles/subdir7_zsubsubdir_file.txt --
+-- overlayfiles/parentoverwritten_subdir1 --
+x
+-- overlayfiles/subdir9_this_file_is_overlaid.txt --
+99999999
+-- overlayfiles/subdir11 --
+-- overlayfiles/this_is_a_directory/file.txt --
+-- overlayfiles/textfile_txt_file.go --
+x
+`
+
+func TestReadDir(t *testing.T) {
+ initOverlay(t, readDirOverlay)
+
+ type entry struct {
+ name string
+ size int64
+ isDir bool
+ }
+
+ testCases := []struct {
+ dir string
+ want []entry
+ }{
+ {
+ ".", []entry{
+ {"other", 0, true},
+ {"overlayfiles", 0, true},
+ {"parentoverwritten", 0, true},
+ {"subdir1", 0, true},
+ {"subdir10", 0, true},
+ {"subdir11", 0, false},
+ {"subdir2", 0, true},
+ {"subdir3", 0, true},
+ {"subdir4", 2, false},
+ // no subdir5.
+ {"subdir6", 0, true},
+ {"subdir7", 0, true},
+ {"subdir8", 0, true},
+ {"subdir9", 0, true},
+ {"textfile.txt", 0, true},
+ },
+ },
+ {
+ "subdir1", []entry{
+ {"file1.txt", 1, false},
+ },
+ },
+ {
+ "subdir2", []entry{
+ {"file2.txt", 2, false},
+ },
+ },
+ {
+ "subdir3", []entry{
+ {"file3a.txt", 3, false},
+ {"file3b.txt", 6, false},
+ },
+ },
+ {
+ "subdir6", []entry{
+ {"anothersubsubdir", 0, true},
+ {"asubsubdir", 0, true},
+ {"file.txt", 0, false},
+ {"zsubsubdir", 0, true},
+ },
+ },
+ {
+ "subdir6/asubsubdir", []entry{
+ {"afile.txt", 0, false},
+ {"file.txt", 0, false},
+ {"zfile.txt", 0, false},
+ },
+ },
+ {
+ "subdir8", []entry{
+ {"doesntexist", 0, false}, // entry is returned even if destination file doesn't exist
+ },
+ },
+ {
+ // check that read dir actually redirects files that already exist
+ // the original this_file_is_overlaid.txt is empty
+ "subdir9", []entry{
+ {"this_file_is_overlaid.txt", 9, false},
+ },
+ },
+ {
+ "subdir10", []entry{},
+ },
+ {
+ "parentoverwritten", []entry{
+ {"subdir1", 2, false},
+ },
+ },
+ {
+ "textfile.txt", []entry{
+ {"file.go", 2, false},
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ dir, want := tc.dir, tc.want
+ infos, err := ReadDir(dir)
+ if err != nil {
+ t.Errorf("ReadDir(%q): %v", dir, err)
+ continue
+ }
+ // Sorted diff of want and infos.
+ for len(infos) > 0 || len(want) > 0 {
+ switch {
+ case len(want) == 0 || len(infos) > 0 && infos[0].Name() < want[0].name:
+ t.Errorf("ReadDir(%q): unexpected entry: %s IsDir=%v Size=%v", dir, infos[0].Name(), infos[0].IsDir(), infos[0].Size())
+ infos = infos[1:]
+ case len(infos) == 0 || len(want) > 0 && want[0].name < infos[0].Name():
+ t.Errorf("ReadDir(%q): missing entry: %s IsDir=%v Size=%v", dir, want[0].name, want[0].isDir, want[0].size)
+ want = want[1:]
+ default:
+ infoSize := infos[0].Size()
+ if want[0].isDir {
+ infoSize = 0
+ }
+ if infos[0].IsDir() != want[0].isDir || want[0].isDir && infoSize != want[0].size {
+ t.Errorf("ReadDir(%q): %s: IsDir=%v Size=%v, want IsDir=%v Size=%v", dir, want[0].name, infos[0].IsDir(), infoSize, want[0].isDir, want[0].size)
+ }
+ infos = infos[1:]
+ want = want[1:]
+ }
+ }
+ }
+
+ errCases := []string{
+ "subdir1/file1.txt", // regular file on disk
+ "subdir2/file2.txt", // regular file in overlay
+ "subdir4", // directory overlaid with regular file
+ "subdir5", // directory deleted in overlay
+ "parentoverwritten/subdir1/subdir2/subdir3", // parentoverwritten/subdir1 overlaid with regular file
+ "parentoverwritten/subdir1/subdir2", // parentoverwritten/subdir1 overlaid with regular file
+ "subdir11", // directory with deleted child, overlaid with regular file
+ "other/pointstodir",
+ }
+
+ for _, dir := range errCases {
+ _, err := ReadDir(dir)
+ if _, ok := err.(*fs.PathError); !ok {
+ t.Errorf("ReadDir(%q): err = %T (%v), want fs.PathError", dir, err, err)
+ }
+ }
+}
+
+func TestGlob(t *testing.T) {
+ initOverlay(t, readDirOverlay)
+
+ testCases := []struct {
+ pattern string
+ match []string
+ }{
+ {
+ "*o*",
+ []string{
+ "other",
+ "overlayfiles",
+ "parentoverwritten",
+ },
+ },
+ {
+ "subdir2/file2.txt",
+ []string{
+ "subdir2/file2.txt",
+ },
+ },
+ {
+ "*/*.txt",
+ []string{
+ "overlayfiles/subdir2_file2.txt",
+ "overlayfiles/subdir3_file3b.txt",
+ "overlayfiles/subdir6_asubsubdir_afile.txt",
+ "overlayfiles/subdir6_asubsubdir_zfile.txt",
+ "overlayfiles/subdir6_zsubsubdir_file.txt",
+ "overlayfiles/subdir7_asubsubdir_file.txt",
+ "overlayfiles/subdir7_zsubsubdir_file.txt",
+ "overlayfiles/subdir9_this_file_is_overlaid.txt",
+ "subdir1/file1.txt",
+ "subdir2/file2.txt",
+ "subdir3/file3a.txt",
+ "subdir3/file3b.txt",
+ "subdir6/file.txt",
+ "subdir9/this_file_is_overlaid.txt",
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ pattern := tc.pattern
+ match, err := Glob(pattern)
+ if err != nil {
+ t.Errorf("Glob(%q): %v", pattern, err)
+ continue
+ }
+ want := tc.match
+ for i, name := range want {
+ if name != tc.pattern {
+ want[i] = filepath.FromSlash(name)
+ }
+ }
+ for len(match) > 0 || len(want) > 0 {
+ switch {
+ case len(match) == 0 || len(want) > 0 && want[0] < match[0]:
+ t.Errorf("Glob(%q): missing match: %s", pattern, want[0])
+ want = want[1:]
+ case len(want) == 0 || len(match) > 0 && match[0] < want[0]:
+ t.Errorf("Glob(%q): extra match: %s", pattern, match[0])
+ match = match[1:]
+ default:
+ want = want[1:]
+ match = match[1:]
+ }
+ }
+ }
+}
+
+func TestOverlayPath(t *testing.T) {
+ initOverlay(t, `
+{
+ "Replace": {
+ "subdir2/file2.txt": "overlayfiles/subdir2_file2.txt",
+ "subdir3/doesntexist": "this_file_doesnt_exist_anywhere",
+ "subdir4/this_file_is_overlaid.txt": "overlayfiles/subdir4_this_file_is_overlaid.txt",
+ "subdir5/deleted.txt": "",
+ "parentoverwritten/subdir1": ""
+ }
+}
+-- subdir1/file1.txt --
+file 1
+-- subdir4/this_file_is_overlaid.txt --
+these contents are replaced by the overlay
+-- parentoverwritten/subdir1/subdir2/subdir3/file.txt --
+-- subdir5/deleted.txt --
+deleted
+-- overlayfiles/subdir2_file2.txt --
+file 2
+-- overlayfiles/subdir4_this_file_is_overlaid.txt --
+99999999
+`)
+
+ testCases := []struct {
+ path string
+ wantPath string
+ wantOK bool
+ }{
+ {"subdir1/file1.txt", "subdir1/file1.txt", false},
+ // OverlayPath returns false for directories
+ {"subdir2", "subdir2", false},
+ {"subdir2/file2.txt", filepath.Join(cwd, "overlayfiles/subdir2_file2.txt"), true},
+ // OverlayPath doesn't stat a file to see if it exists, so it happily returns
+ // the 'to' path and true even if the 'to' path doesn't exist on disk.
+ {"subdir3/doesntexist", filepath.Join(cwd, "this_file_doesnt_exist_anywhere"), true},
+ // Like the subdir2/file2.txt case above, but subdir4 exists on disk, but subdir2 does not.
+ {"subdir4/this_file_is_overlaid.txt", filepath.Join(cwd, "overlayfiles/subdir4_this_file_is_overlaid.txt"), true},
+ {"subdir5", "subdir5", false},
+ {"subdir5/deleted.txt", "", true},
+ }
+
+ for _, tc := range testCases {
+ gotPath, gotOK := OverlayPath(tc.path)
+ if gotPath != tc.wantPath || gotOK != tc.wantOK {
+ t.Errorf("OverlayPath(%q): got %v, %v; want %v, %v",
+ tc.path, gotPath, gotOK, tc.wantPath, tc.wantOK)
+ }
+ }
+}
+
+func TestOpen(t *testing.T) {
+ initOverlay(t, `
+{
+ "Replace": {
+ "subdir2/file2.txt": "overlayfiles/subdir2_file2.txt",
+ "subdir3/doesntexist": "this_file_doesnt_exist_anywhere",
+ "subdir4/this_file_is_overlaid.txt": "overlayfiles/subdir4_this_file_is_overlaid.txt",
+ "subdir5/deleted.txt": "",
+ "parentoverwritten/subdir1": "",
+ "childoverlay/subdir1.txt/child.txt": "overlayfiles/child.txt",
+ "subdir11/deleted.txt": "",
+ "subdir11": "overlayfiles/subdir11",
+ "parentdeleted": "",
+ "parentdeleted/file.txt": "overlayfiles/parentdeleted_file.txt"
+ }
+}
+-- subdir11/deleted.txt --
+-- subdir1/file1.txt --
+file 1
+-- subdir4/this_file_is_overlaid.txt --
+these contents are replaced by the overlay
+-- parentoverwritten/subdir1/subdir2/subdir3/file.txt --
+-- childoverlay/subdir1.txt --
+this file doesn't exist because the path
+childoverlay/subdir1.txt/child.txt is in the overlay
+-- subdir5/deleted.txt --
+deleted
+-- parentdeleted --
+this will be deleted so that parentdeleted/file.txt can exist
+-- overlayfiles/subdir2_file2.txt --
+file 2
+-- overlayfiles/subdir4_this_file_is_overlaid.txt --
+99999999
+-- overlayfiles/child.txt --
+-- overlayfiles/subdir11 --
+11
+-- overlayfiles/parentdeleted_file.txt --
+this can exist because the parent directory is deleted
+`)
+
+ testCases := []struct {
+ path string
+ wantContents string
+ isErr bool
+ }{
+ {"subdir1/file1.txt", "file 1\n", false},
+ {"subdir2/file2.txt", "file 2\n", false},
+ {"subdir3/doesntexist", "", true},
+ {"subdir4/this_file_is_overlaid.txt", "99999999\n", false},
+ {"subdir5/deleted.txt", "", true},
+ {"parentoverwritten/subdir1/subdir2/subdir3/file.txt", "", true},
+ {"childoverlay/subdir1.txt", "", true},
+ {"subdir11", "11\n", false},
+ {"parentdeleted/file.txt", "this can exist because the parent directory is deleted\n", false},
+ }
+
+ for _, tc := range testCases {
+ f, err := Open(tc.path)
+ if tc.isErr {
+ if err == nil {
+ f.Close()
+ t.Errorf("Open(%q): got no error, but want error", tc.path)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("Open(%q): got error %v, want nil", tc.path, err)
+ continue
+ }
+ contents, err := io.ReadAll(f)
+ if err != nil {
+ t.Errorf("unexpected error reading contents of file: %v", err)
+ }
+ if string(contents) != tc.wantContents {
+ t.Errorf("contents of file opened with Open(%q): got %q, want %q",
+ tc.path, contents, tc.wantContents)
+ }
+ f.Close()
+ }
+}
+
+func TestIsDirWithGoFiles(t *testing.T) {
+ initOverlay(t, `
+{
+ "Replace": {
+ "goinoverlay/file.go": "dummy",
+ "directory/removed/by/file": "dummy",
+ "directory_with_go_dir/dir.go/file.txt": "dummy",
+ "otherdirectory/deleted.go": "",
+ "nonexistentdirectory/deleted.go": "",
+ "textfile.txt/file.go": "dummy"
+ }
+}
+-- dummy --
+a destination file for the overlay entries to point to
+contents don't matter for this test
+-- nogo/file.txt --
+-- goondisk/file.go --
+-- goinoverlay/file.txt --
+-- directory/removed/by/file/in/overlay/file.go --
+-- otherdirectory/deleted.go --
+-- textfile.txt --
+`)
+
+ testCases := []struct {
+ dir string
+ want bool
+ wantErr bool
+ }{
+ {"nogo", false, false},
+ {"goondisk", true, false},
+ {"goinoverlay", true, false},
+ {"directory/removed/by/file/in/overlay", false, false},
+ {"directory_with_go_dir", false, false},
+ {"otherdirectory", false, false},
+ {"nonexistentdirectory", false, false},
+ {"textfile.txt", true, false},
+ }
+
+ for _, tc := range testCases {
+ got, gotErr := IsDirWithGoFiles(tc.dir)
+ if tc.wantErr {
+ if gotErr == nil {
+ t.Errorf("IsDirWithGoFiles(%q): got %v, %v; want non-nil error", tc.dir, got, gotErr)
+ }
+ continue
+ }
+ if gotErr != nil {
+ t.Errorf("IsDirWithGoFiles(%q): got %v, %v; want nil error", tc.dir, got, gotErr)
+ }
+ if got != tc.want {
+ t.Errorf("IsDirWithGoFiles(%q) = %v; want %v", tc.dir, got, tc.want)
+ }
+ }
+}
+
+func TestWalk(t *testing.T) {
+ // The root of the walk must be a name with an actual basename, not just ".".
+ // Walk uses Lstat to obtain the name of the root, and Lstat on platforms
+ // other than Plan 9 reports the name "." instead of the actual base name of
+ // the directory. (See https://golang.org/issue/42115.)
+
+ type file struct {
+ path string
+ name string
+ size int64
+ mode fs.FileMode
+ isDir bool
+ }
+ testCases := []struct {
+ name string
+ overlay string
+ root string
+ wantFiles []file
+ }{
+ {"no overlay", `
+{}
+-- dir/file.txt --
+`,
+ "dir",
+ []file{
+ {"dir", "dir", 0, fs.ModeDir | 0700, true},
+ {"dir/file.txt", "file.txt", 0, 0600, false},
+ },
+ },
+ {"overlay with different file", `
+{
+ "Replace": {
+ "dir/file.txt": "dir/other.txt"
+ }
+}
+-- dir/file.txt --
+-- dir/other.txt --
+contents of other file
+`,
+ "dir",
+ []file{
+ {"dir", "dir", 0, fs.ModeDir | 0500, true},
+ {"dir/file.txt", "file.txt", 23, 0600, false},
+ {"dir/other.txt", "other.txt", 23, 0600, false},
+ },
+ },
+ {"overlay with new file", `
+{
+ "Replace": {
+ "dir/file.txt": "dir/other.txt"
+ }
+}
+-- dir/other.txt --
+contents of other file
+`,
+ "dir",
+ []file{
+ {"dir", "dir", 0, fs.ModeDir | 0500, true},
+ {"dir/file.txt", "file.txt", 23, 0600, false},
+ {"dir/other.txt", "other.txt", 23, 0600, false},
+ },
+ },
+ {"overlay with new directory", `
+{
+ "Replace": {
+ "dir/subdir/file.txt": "dir/other.txt"
+ }
+}
+-- dir/other.txt --
+contents of other file
+`,
+ "dir",
+ []file{
+ {"dir", "dir", 0, fs.ModeDir | 0500, true},
+ {"dir/other.txt", "other.txt", 23, 0600, false},
+ {"dir/subdir", "subdir", 0, fs.ModeDir | 0500, true},
+ {"dir/subdir/file.txt", "file.txt", 23, 0600, false},
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ initOverlay(t, tc.overlay)
+
+ var got []file
+ Walk(tc.root, func(path string, info fs.FileInfo, err error) error {
+ got = append(got, file{path, info.Name(), info.Size(), info.Mode(), info.IsDir()})
+ return nil
+ })
+
+ if len(got) != len(tc.wantFiles) {
+ t.Errorf("Walk: saw %#v in walk; want %#v", got, tc.wantFiles)
+ }
+ for i := 0; i < len(got) && i < len(tc.wantFiles); i++ {
+ wantPath := filepath.FromSlash(tc.wantFiles[i].path)
+ if got[i].path != wantPath {
+ t.Errorf("path of file #%v in walk, got %q, want %q", i, got[i].path, wantPath)
+ }
+ if got[i].name != tc.wantFiles[i].name {
+ t.Errorf("name of file #%v in walk, got %q, want %q", i, got[i].name, tc.wantFiles[i].name)
+ }
+ if got[i].mode&(fs.ModeDir|0700) != tc.wantFiles[i].mode {
+ t.Errorf("mode&(fs.ModeDir|0700) for mode of file #%v in walk, got %v, want %v", i, got[i].mode&(fs.ModeDir|0700), tc.wantFiles[i].mode)
+ }
+ if got[i].isDir != tc.wantFiles[i].isDir {
+ t.Errorf("isDir for file #%v in walk, got %v, want %v", i, got[i].isDir, tc.wantFiles[i].isDir)
+ }
+ if tc.wantFiles[i].isDir {
+ continue // don't check size for directories
+ }
+ if got[i].size != tc.wantFiles[i].size {
+ t.Errorf("size of file #%v in walk, got %v, want %v", i, got[i].size, tc.wantFiles[i].size)
+ }
+ }
+ })
+ }
+}
+
+func TestWalkSkipDir(t *testing.T) {
+ initOverlay(t, `
+{
+ "Replace": {
+ "dir/skip/file.go": "dummy.txt",
+ "dir/dontskip/file.go": "dummy.txt",
+ "dir/dontskip/skip/file.go": "dummy.txt"
+ }
+}
+-- dummy.txt --
+`)
+
+ var seen []string
+ Walk("dir", func(path string, info fs.FileInfo, err error) error {
+ seen = append(seen, filepath.ToSlash(path))
+ if info.Name() == "skip" {
+ return filepath.SkipDir
+ }
+ return nil
+ })
+
+ wantSeen := []string{"dir", "dir/dontskip", "dir/dontskip/file.go", "dir/dontskip/skip", "dir/skip"}
+
+ if len(seen) != len(wantSeen) {
+ t.Errorf("paths seen in walk: got %v entries; want %v entries", len(seen), len(wantSeen))
+ }
+
+ for i := 0; i < len(seen) && i < len(wantSeen); i++ {
+ if seen[i] != wantSeen[i] {
+ t.Errorf("path #%v seen walking tree: want %q, got %q", i, seen[i], wantSeen[i])
+ }
+ }
+}
+
+func TestWalkError(t *testing.T) {
+ initOverlay(t, "{}")
+
+ alreadyCalled := false
+ err := Walk("foo", func(path string, info fs.FileInfo, err error) error {
+ if alreadyCalled {
+ t.Fatal("expected walk function to be called exactly once, but it was called more than once")
+ }
+ alreadyCalled = true
+ return errors.New("returned from function")
+ })
+ if !alreadyCalled {
+ t.Fatal("expected walk function to be called exactly once, but it was never called")
+
+ }
+ if err == nil {
+ t.Fatalf("Walk: got no error, want error")
+ }
+ if err.Error() != "returned from function" {
+ t.Fatalf("Walk: got error %v, want \"returned from function\" error", err)
+ }
+}
+
+func TestWalkSymlink(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ initOverlay(t, `{
+ "Replace": {"overlay_symlink": "symlink"}
+}
+-- dir/file --`)
+
+ // Create symlink
+ if err := os.Symlink("dir", "symlink"); err != nil {
+ t.Error(err)
+ }
+
+ testCases := []struct {
+ name string
+ dir string
+ wantFiles []string
+ }{
+ {"control", "dir", []string{"dir", "dir" + string(filepath.Separator) + "file"}},
+ // ensure Walk doesn't walk into the directory pointed to by the symlink
+ // (because it's supposed to use Lstat instead of Stat).
+ {"symlink_to_dir", "symlink", []string{"symlink"}},
+ {"overlay_to_symlink_to_dir", "overlay_symlink", []string{"overlay_symlink"}},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ var got []string
+
+ err := Walk(tc.dir, func(path string, info fs.FileInfo, err error) error {
+ got = append(got, path)
+ if err != nil {
+ t.Errorf("walkfn: got non nil err argument: %v, want nil err argument", err)
+ }
+ return nil
+ })
+ if err != nil {
+ t.Errorf("Walk: got error %q, want nil", err)
+ }
+
+ if !reflect.DeepEqual(got, tc.wantFiles) {
+ t.Errorf("files examined by walk: got %v, want %v", got, tc.wantFiles)
+ }
+ })
+ }
+
+}
+
+func TestLstat(t *testing.T) {
+ type file struct {
+ name string
+ size int64
+ mode fs.FileMode // mode & (fs.ModeDir|0x700): only check 'user' permissions
+ isDir bool
+ }
+
+ testCases := []struct {
+ name string
+ overlay string
+ path string
+
+ want file
+ wantErr bool
+ }{
+ {
+ "regular_file",
+ `{}
+-- file.txt --
+contents`,
+ "file.txt",
+ file{"file.txt", 9, 0600, false},
+ false,
+ },
+ {
+ "new_file_in_overlay",
+ `{"Replace": {"file.txt": "dummy.txt"}}
+-- dummy.txt --
+contents`,
+ "file.txt",
+ file{"file.txt", 9, 0600, false},
+ false,
+ },
+ {
+ "file_replaced_in_overlay",
+ `{"Replace": {"file.txt": "dummy.txt"}}
+-- file.txt --
+-- dummy.txt --
+contents`,
+ "file.txt",
+ file{"file.txt", 9, 0600, false},
+ false,
+ },
+ {
+ "file_cant_exist",
+ `{"Replace": {"deleted": "dummy.txt"}}
+-- deleted/file.txt --
+-- dummy.txt --
+`,
+ "deleted/file.txt",
+ file{},
+ true,
+ },
+ {
+ "deleted",
+ `{"Replace": {"deleted": ""}}
+-- deleted --
+`,
+ "deleted",
+ file{},
+ true,
+ },
+ {
+ "dir_on_disk",
+ `{}
+-- dir/foo.txt --
+`,
+ "dir",
+ file{"dir", 0, 0700 | fs.ModeDir, true},
+ false,
+ },
+ {
+ "dir_in_overlay",
+ `{"Replace": {"dir/file.txt": "dummy.txt"}}
+-- dummy.txt --
+`,
+ "dir",
+ file{"dir", 0, 0500 | fs.ModeDir, true},
+ false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ initOverlay(t, tc.overlay)
+ got, err := lstat(tc.path)
+ if tc.wantErr {
+ if err == nil {
+ t.Errorf("lstat(%q): got no error, want error", tc.path)
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("lstat(%q): got error %v, want no error", tc.path, err)
+ }
+ if got.Name() != tc.want.name {
+ t.Errorf("lstat(%q).Name(): got %q, want %q", tc.path, got.Name(), tc.want.name)
+ }
+ if got.Mode()&(fs.ModeDir|0700) != tc.want.mode {
+ t.Errorf("lstat(%q).Mode()&(fs.ModeDir|0700): got %v, want %v", tc.path, got.Mode()&(fs.ModeDir|0700), tc.want.mode)
+ }
+ if got.IsDir() != tc.want.isDir {
+ t.Errorf("lstat(%q).IsDir(): got %v, want %v", tc.path, got.IsDir(), tc.want.isDir)
+ }
+ if tc.want.isDir {
+ return // don't check size for directories
+ }
+ if got.Size() != tc.want.size {
+ t.Errorf("lstat(%q).Size(): got %v, want %v", tc.path, got.Size(), tc.want.size)
+ }
+ })
+ }
+}
+
+func TestStat(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ type file struct {
+ name string
+ size int64
+ mode os.FileMode // mode & (os.ModeDir|0x700): only check 'user' permissions
+ isDir bool
+ }
+
+ testCases := []struct {
+ name string
+ overlay string
+ path string
+
+ want file
+ wantErr bool
+ }{
+ {
+ "regular_file",
+ `{}
+-- file.txt --
+contents`,
+ "file.txt",
+ file{"file.txt", 9, 0600, false},
+ false,
+ },
+ {
+ "new_file_in_overlay",
+ `{"Replace": {"file.txt": "dummy.txt"}}
+-- dummy.txt --
+contents`,
+ "file.txt",
+ file{"file.txt", 9, 0600, false},
+ false,
+ },
+ {
+ "file_replaced_in_overlay",
+ `{"Replace": {"file.txt": "dummy.txt"}}
+-- file.txt --
+-- dummy.txt --
+contents`,
+ "file.txt",
+ file{"file.txt", 9, 0600, false},
+ false,
+ },
+ {
+ "file_cant_exist",
+ `{"Replace": {"deleted": "dummy.txt"}}
+-- deleted/file.txt --
+-- dummy.txt --
+`,
+ "deleted/file.txt",
+ file{},
+ true,
+ },
+ {
+ "deleted",
+ `{"Replace": {"deleted": ""}}
+-- deleted --
+`,
+ "deleted",
+ file{},
+ true,
+ },
+ {
+ "dir_on_disk",
+ `{}
+-- dir/foo.txt --
+`,
+ "dir",
+ file{"dir", 0, 0700 | os.ModeDir, true},
+ false,
+ },
+ {
+ "dir_in_overlay",
+ `{"Replace": {"dir/file.txt": "dummy.txt"}}
+-- dummy.txt --
+`,
+ "dir",
+ file{"dir", 0, 0500 | os.ModeDir, true},
+ false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ initOverlay(t, tc.overlay)
+ got, err := Stat(tc.path)
+ if tc.wantErr {
+ if err == nil {
+ t.Errorf("Stat(%q): got no error, want error", tc.path)
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("Stat(%q): got error %v, want no error", tc.path, err)
+ }
+ if got.Name() != tc.want.name {
+ t.Errorf("Stat(%q).Name(): got %q, want %q", tc.path, got.Name(), tc.want.name)
+ }
+ if got.Mode()&(os.ModeDir|0700) != tc.want.mode {
+ t.Errorf("Stat(%q).Mode()&(os.ModeDir|0700): got %v, want %v", tc.path, got.Mode()&(os.ModeDir|0700), tc.want.mode)
+ }
+ if got.IsDir() != tc.want.isDir {
+ t.Errorf("Stat(%q).IsDir(): got %v, want %v", tc.path, got.IsDir(), tc.want.isDir)
+ }
+ if tc.want.isDir {
+ return // don't check size for directories
+ }
+ if got.Size() != tc.want.size {
+ t.Errorf("Stat(%q).Size(): got %v, want %v", tc.path, got.Size(), tc.want.size)
+ }
+ })
+ }
+}
+
+func TestStatSymlink(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ initOverlay(t, `{
+ "Replace": {"file.go": "symlink"}
+}
+-- to.go --
+0123456789
+`)
+
+ // Create symlink
+ if err := os.Symlink("to.go", "symlink"); err != nil {
+ t.Error(err)
+ }
+
+ f := "file.go"
+ fi, err := Stat(f)
+ if err != nil {
+ t.Errorf("Stat(%q): got error %q, want nil error", f, err)
+ }
+
+ if !fi.Mode().IsRegular() {
+ t.Errorf("Stat(%q).Mode(): got %v, want regular mode", f, fi.Mode())
+ }
+
+ if fi.Size() != 11 {
+ t.Errorf("Stat(%q).Size(): got %v, want 11", f, fi.Size())
+ }
+}
diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go
index ed2786879c..268962eca8 100644
--- a/src/cmd/go/internal/get/get.go
+++ b/src/cmd/go/internal/get/get.go
@@ -46,8 +46,8 @@ before resolving dependencies or building the code.
The -insecure flag permits fetching from repositories and resolving
custom domains using insecure schemes such as HTTP. Use with caution.
This flag is deprecated and will be removed in a future version of go.
-The GOINSECURE environment variable is usually a better alternative, since
-it provides control over which modules may be retrieved using an insecure
+The GOINSECURE environment variable should be used instead, since it
+provides control over which packages may be retrieved using an insecure
scheme. See 'go help environment' for details.
The -t flag instructs get to also download the packages required to build
diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
index 0ae5fd7ca9..8dfabbaa4a 100644
--- a/src/cmd/go/internal/help/helpdoc.go
+++ b/src/cmd/go/internal/help/helpdoc.go
@@ -582,8 +582,8 @@ Architecture-specific environment variables:
For GOARCH=arm, the ARM architecture for which to compile.
Valid values are 5, 6, 7.
GO386
- For GOARCH=386, the floating point instruction set.
- Valid values are 387, sse2.
+ For GOARCH=386, how to implement floating point instructions.
+ Valid values are sse2 (default), softfloat.
GOMIPS
For GOARCH=mips{,le}, whether to use floating point instructions.
Valid values are hardfloat (default), softfloat.
diff --git a/src/cmd/go/internal/imports/read.go b/src/cmd/go/internal/imports/read.go
index 58c2abdc29..5e270781d7 100644
--- a/src/cmd/go/internal/imports/read.go
+++ b/src/cmd/go/internal/imports/read.go
@@ -198,7 +198,7 @@ func (r *importReader) readImport(imports *[]string) {
r.readString(imports)
}
-// ReadComments is like ioutil.ReadAll, except that it only reads the leading
+// ReadComments is like io.ReadAll, except that it only reads the leading
// block of comments in the file.
func ReadComments(f io.Reader) ([]byte, error) {
r := &importReader{b: bufio.NewReader(f)}
@@ -210,7 +210,7 @@ func ReadComments(f io.Reader) ([]byte, error) {
return r.buf, r.err
}
-// ReadImports is like ioutil.ReadAll, except that it expects a Go file as input
+// ReadImports is like io.ReadAll, except that it expects a Go file as input
// and stops reading the input once the imports have completed.
func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
r := &importReader{b: bufio.NewReader(f)}
diff --git a/src/cmd/go/internal/imports/scan.go b/src/cmd/go/internal/imports/scan.go
index 3d9b6132b1..ee11a8708b 100644
--- a/src/cmd/go/internal/imports/scan.go
+++ b/src/cmd/go/internal/imports/scan.go
@@ -6,16 +6,17 @@ package imports
import (
"fmt"
- "io/ioutil"
- "os"
+ "io/fs"
"path/filepath"
"sort"
"strconv"
"strings"
+
+ "cmd/go/internal/fsys"
)
func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
- infos, err := ioutil.ReadDir(dir)
+ infos, err := fsys.ReadDir(dir)
if err != nil {
return nil, nil, err
}
@@ -25,14 +26,14 @@ func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
// If the directory entry is a symlink, stat it to obtain the info for the
// link target instead of the link itself.
- if info.Mode()&os.ModeSymlink != 0 {
- info, err = os.Stat(filepath.Join(dir, name))
+ if info.Mode()&fs.ModeSymlink != 0 {
+ info, err = fsys.Stat(filepath.Join(dir, name))
if err != nil {
continue // Ignore broken symlinks.
}
}
- if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) {
+ if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) {
files = append(files, filepath.Join(dir, name))
}
}
@@ -49,7 +50,7 @@ func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]stri
numFiles := 0
Files:
for _, name := range files {
- r, err := os.Open(name)
+ r, err := fsys.Open(name)
if err != nil {
return nil, nil, err
}
diff --git a/src/cmd/go/internal/imports/tags.go b/src/cmd/go/internal/imports/tags.go
index 14b4e21a02..01b448b914 100644
--- a/src/cmd/go/internal/imports/tags.go
+++ b/src/cmd/go/internal/imports/tags.go
@@ -4,17 +4,23 @@
package imports
-import "cmd/go/internal/cfg"
+import (
+ "cmd/go/internal/cfg"
+ "sync"
+)
-var tags map[string]bool
+var (
+ tags map[string]bool
+ tagsOnce sync.Once
+)
// Tags returns a set of build tags that are true for the target platform.
// It includes GOOS, GOARCH, the compiler, possibly "cgo",
// release tags like "go1.13", and user-specified build tags.
func Tags() map[string]bool {
- if tags == nil {
+ tagsOnce.Do(func() {
tags = loadTags()
- }
+ })
return tags
}
@@ -36,14 +42,17 @@ func loadTags() map[string]bool {
return tags
}
-var anyTags map[string]bool
+var (
+ anyTags map[string]bool
+ anyTagsOnce sync.Once
+)
// AnyTags returns a special set of build tags that satisfy nearly all
// build tag expressions. Only "ignore" and malformed build tag requirements
// are considered false.
func AnyTags() map[string]bool {
- if anyTags == nil {
+ anyTagsOnce.Do(func() {
anyTags = map[string]bool{"*": true}
- }
+ })
return anyTags
}
diff --git a/src/cmd/go/internal/imports/testdata/android/.h.go b/src/cmd/go/internal/imports/testdata/android/.h.go
new file mode 100644
index 0000000000..53c529e777
--- /dev/null
+++ b/src/cmd/go/internal/imports/testdata/android/.h.go
@@ -0,0 +1,3 @@
+package android
+
+import _ "h"
diff --git a/src/cmd/go/internal/imports/testdata/illumos/.h.go b/src/cmd/go/internal/imports/testdata/illumos/.h.go
new file mode 100644
index 0000000000..53c529e777
--- /dev/null
+++ b/src/cmd/go/internal/imports/testdata/illumos/.h.go
@@ -0,0 +1,3 @@
+package android
+
+import _ "h"
diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go
index 33409eb774..89088f5def 100644
--- a/src/cmd/go/internal/list/list.go
+++ b/src/cmd/go/internal/list/list.go
@@ -66,26 +66,28 @@ to -f '{{.ImportPath}}'. The struct being passed to the template is:
BinaryOnly bool // binary-only package (no longer supported)
ForTest string // package is only for use in named test
Export string // file containing export data (when using -export)
+ BuildID string // build ID of the compiled package (when using -export)
Module *Module // info about package's containing module, if any (can be nil)
Match []string // command-line patterns matching this package
DepOnly bool // package is only a dependency, not explicitly listed
// Source files
- GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string // .go source files that import "C"
- CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
- IgnoredGoFiles []string // .go source files ignored due to build constraints
- CFiles []string // .c source files
- CXXFiles []string // .cc, .cxx and .cpp source files
- MFiles []string // .m source files
- HFiles []string // .h, .hh, .hpp and .hxx source files
- FFiles []string // .f, .F, .for and .f90 Fortran source files
- SFiles []string // .s source files
- SwigFiles []string // .swig files
- SwigCXXFiles []string // .swigcxx files
- SysoFiles []string // .syso object files to add to archive
- TestGoFiles []string // _test.go files in package
- XTestGoFiles []string // _test.go files outside package
+ GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string // .go source files that import "C"
+ CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
+ IgnoredGoFiles []string // .go source files ignored due to build constraints
+ IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
+ CFiles []string // .c source files
+ CXXFiles []string // .cc, .cxx and .cpp source files
+ MFiles []string // .m source files
+ HFiles []string // .h, .hh, .hpp and .hxx source files
+ FFiles []string // .f, .F, .for and .f90 Fortran source files
+ SFiles []string // .s source files
+ SwigFiles []string // .swig files
+ SwigCXXFiles []string // .swigcxx files
+ SysoFiles []string // .syso object files to add to archive
+ TestGoFiles []string // _test.go files in package
+ XTestGoFiles []string // _test.go files outside package
// Cgo directives
CgoCFLAGS []string // cgo: flags for C compiler
@@ -413,7 +415,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
base.Fatalf("go list -m: not using modules")
}
- modload.InitMod(ctx) // Parses go.mod and sets cfg.BuildMod.
+ modload.LoadModFile(ctx) // Parses go.mod and sets cfg.BuildMod.
if cfg.BuildMod == "vendor" {
const actionDisabledFormat = "go list -m: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index 5cc77915e7..4c541b9017 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -14,6 +14,7 @@ import (
"go/build"
"go/scanner"
"go/token"
+ "io/fs"
"io/ioutil"
"os"
pathpkg "path"
@@ -27,12 +28,14 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/modinfo"
"cmd/go/internal/modload"
"cmd/go/internal/par"
"cmd/go/internal/search"
"cmd/go/internal/str"
"cmd/go/internal/trace"
+ "cmd/internal/sys"
)
var IgnoreImports bool // control whether we ignore imports in packages
@@ -58,6 +61,7 @@ type PackagePublic struct {
ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory
ForTest string `json:",omitempty"` // package is only for use in named test
Export string `json:",omitempty"` // file containing export data (set by go list -export)
+ BuildID string `json:",omitempty"` // build ID of the compiled package (set by go list -export)
Module *modinfo.ModulePublic `json:",omitempty"` // info about package's module, if any
Match []string `json:",omitempty"` // command-line patterns matching this package
Goroot bool `json:",omitempty"` // is this package found in the Go root?
@@ -75,19 +79,20 @@ type PackagePublic struct {
// Source files
// If you add to this list you MUST add to p.AllFiles (below) too.
// Otherwise file name security lists will not apply to any new additions.
- GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
- CgoFiles []string `json:",omitempty"` // .go source files that import "C"
- CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
- IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
- CFiles []string `json:",omitempty"` // .c source files
- CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
- MFiles []string `json:",omitempty"` // .m source files
- HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
- FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
- SFiles []string `json:",omitempty"` // .s source files
- SwigFiles []string `json:",omitempty"` // .swig files
- SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
- SysoFiles []string `json:",omitempty"` // .syso system object files added to package
+ GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+ CgoFiles []string `json:",omitempty"` // .go source files that import "C"
+ CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles
+ IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints
+ IgnoredOtherFiles []string `json:",omitempty"` // non-.go source files ignored due to build constraints
+ CFiles []string `json:",omitempty"` // .c source files
+ CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files
+ MFiles []string `json:",omitempty"` // .m source files
+ HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
+ FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
+ SFiles []string `json:",omitempty"` // .s source files
+ SwigFiles []string `json:",omitempty"` // .swig files
+ SwigCXXFiles []string `json:",omitempty"` // .swigcxx files
+ SysoFiles []string `json:",omitempty"` // .syso system object files added to package
// Cgo directives
CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler
@@ -127,6 +132,7 @@ func (p *Package) AllFiles() []string {
p.CgoFiles,
// no p.CompiledGoFiles, because they are from GoFiles or generated by us
p.IgnoredGoFiles,
+ p.IgnoredOtherFiles,
p.CFiles,
p.CXXFiles,
p.MFiles,
@@ -185,7 +191,7 @@ type NoGoError struct {
}
func (e *NoGoError) Error() string {
- if len(e.Package.constraintIgnoredGoFiles()) > 0 {
+ if len(e.Package.IgnoredGoFiles) > 0 {
// Go files exist, but they were ignored due to build constraints.
return "build constraints exclude all Go files in " + e.Package.Dir
}
@@ -248,8 +254,8 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta
// package's source files themselves (scanner errors).
//
// TODO(matloob): Perhaps make each of those the errors in the first group
- // (including modload.ImportMissingError, and the corresponding
- // "cannot find package %q in any of" GOPATH-mode error
+ // (including modload.ImportMissingError, ImportMissingSumError, and the
+ // corresponding "cannot find package %q in any of" GOPATH-mode error
// produced in build.(*Context).Import; modload.AmbiguousImportError,
// and modload.PackageNotInModuleError; and the malformed module path errors
// produced in golang.org/x/mod/module.CheckMod) implement an interface
@@ -330,6 +336,7 @@ func (p *Package) copyBuild(pp *build.Package) {
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
p.IgnoredGoFiles = pp.IgnoredGoFiles
+ p.IgnoredOtherFiles = pp.IgnoredOtherFiles
p.CFiles = pp.CFiles
p.CXXFiles = pp.CXXFiles
p.MFiles = pp.MFiles
@@ -423,6 +430,7 @@ type ImportPathError interface {
var (
_ ImportPathError = (*importError)(nil)
_ ImportPathError = (*modload.ImportMissingError)(nil)
+ _ ImportPathError = (*modload.ImportMissingSumError)(nil)
)
type importError struct {
@@ -971,7 +979,7 @@ var isDirCache par.Cache
func isDir(path string) bool {
return isDirCache.Do(path, func() interface{} {
- fi, err := os.Stat(path)
+ fi, err := fsys.Stat(path)
return err == nil && fi.IsDir()
}).(bool)
}
@@ -1944,37 +1952,44 @@ func LinkerDeps(p *Package) []string {
// externalLinkingForced reports whether external linking is being
// forced even for programs that do not use cgo.
func externalLinkingForced(p *Package) bool {
+ if !cfg.BuildContext.CgoEnabled {
+ return false
+ }
+
// Some targets must use external linking even inside GOROOT.
switch cfg.BuildContext.GOOS {
case "android":
if cfg.BuildContext.GOARCH != "arm64" {
return true
}
- case "darwin", "ios":
+ case "ios":
+ return true
+ case "darwin":
if cfg.BuildContext.GOARCH == "arm64" {
return true
}
}
- if !cfg.BuildContext.CgoEnabled {
- return false
- }
// Currently build modes c-shared, pie (on systems that do not
// support PIE with internal linking mode (currently all
// systems: issue #18968)), plugin, and -linkshared force
// external linking mode, as of course does
// -ldflags=-linkmode=external. External linking mode forces
// an import of runtime/cgo.
- pieCgo := cfg.BuildBuildmode == "pie"
+ // If there are multiple -linkmode options, the last one wins.
+ pieCgo := cfg.BuildBuildmode == "pie" && !sys.InternalLinkPIESupported(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH)
linkmodeExternal := false
if p != nil {
ldflags := BuildLdflags.For(p)
- for i, a := range ldflags {
- if a == "-linkmode=external" {
- linkmodeExternal = true
- }
- if a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
+ for i := len(ldflags) - 1; i >= 0; i-- {
+ a := ldflags[i]
+ if a == "-linkmode=external" ||
+ a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
linkmodeExternal = true
+ break
+ } else if a == "-linkmode=internal" ||
+ a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "internal" {
+ break
}
}
}
@@ -2009,22 +2024,7 @@ func (p *Package) InternalXGoFiles() []string {
// using absolute paths. "Possibly relevant" means that files are not excluded
// due to build tags, but files with names beginning with . or _ are still excluded.
func (p *Package) InternalAllGoFiles() []string {
- return p.mkAbs(str.StringList(p.constraintIgnoredGoFiles(), p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
-}
-
-// constraintIgnoredGoFiles returns the list of Go files ignored for reasons
-// other than having a name beginning with '.' or '_'.
-func (p *Package) constraintIgnoredGoFiles() []string {
- if len(p.IgnoredGoFiles) == 0 {
- return nil
- }
- files := make([]string, 0, len(p.IgnoredGoFiles))
- for _, f := range p.IgnoredGoFiles {
- if f != "" && f[0] != '.' && f[0] != '_' {
- files = append(files, f)
- }
- }
- return files
+ return p.mkAbs(str.StringList(p.IgnoredGoFiles, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
}
// usesSwig reports whether the package needs to run SWIG.
@@ -2153,7 +2153,7 @@ func PackagesAndErrors(ctx context.Context, patterns []string) []*Package {
if strings.HasSuffix(p, ".go") {
// We need to test whether the path is an actual Go file and not a
// package path or pattern ending in '.go' (see golang.org/issue/34653).
- if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
+ if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() {
return []*Package{GoFilesPackage(ctx, patterns)}
}
}
@@ -2310,10 +2310,10 @@ func GoFilesPackage(ctx context.Context, gofiles []string) *Package {
// to make it look like this is a standard package or
// command directory. So that local imports resolve
// consistently, the files must all be in the same directory.
- var dirent []os.FileInfo
+ var dirent []fs.FileInfo
var dir string
for _, file := range gofiles {
- fi, err := os.Stat(file)
+ fi, err := fsys.Stat(file)
if err != nil {
base.Fatalf("%s", err)
}
@@ -2331,7 +2331,7 @@ func GoFilesPackage(ctx context.Context, gofiles []string) *Package {
}
dirent = append(dirent, fi)
}
- ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+ ctxt.ReadDir = func(string) ([]fs.FileInfo, error) { return dirent, nil }
if cfg.ModulesEnabled {
modload.ImportFromFiles(ctx, gofiles)
diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go
index aba3eed776..05f27c321a 100644
--- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go
+++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go
@@ -9,6 +9,7 @@ package filelock
import (
"errors"
+ "io/fs"
"os"
)
@@ -24,7 +25,7 @@ type File interface {
Fd() uintptr
// Stat returns the FileInfo structure describing file.
- Stat() (os.FileInfo, error)
+ Stat() (fs.FileInfo, error)
}
// Lock places an advisory write lock on the file, blocking until it can be
@@ -87,7 +88,7 @@ var ErrNotSupported = errors.New("operation not supported")
// underlyingError returns the underlying error for known os error types.
func underlyingError(err error) error {
switch err := err.(type) {
- case *os.PathError:
+ case *fs.PathError:
return err.Err
case *os.LinkError:
return err.Err
diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go
index 8776c5741c..1fa4327a89 100644
--- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go
+++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go
@@ -18,8 +18,8 @@ package filelock
import (
"errors"
"io"
+ "io/fs"
"math/rand"
- "os"
"sync"
"syscall"
"time"
@@ -61,7 +61,7 @@ func lock(f File, lt lockType) (err error) {
mu.Lock()
if i, dup := inodes[f]; dup && i != ino {
mu.Unlock()
- return &os.PathError{
+ return &fs.PathError{
Op: lt.String(),
Path: f.Name(),
Err: errors.New("inode for file changed since last Lock or RLock"),
@@ -152,7 +152,7 @@ func lock(f File, lt lockType) (err error) {
if err != nil {
unlock(f)
- return &os.PathError{
+ return &fs.PathError{
Op: lt.String(),
Path: f.Name(),
Err: err,
diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go
index 107611e1ce..bc480343fc 100644
--- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go
+++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go
@@ -6,7 +6,7 @@
package filelock
-import "os"
+import "io/fs"
type lockType int8
@@ -16,7 +16,7 @@ const (
)
func lock(f File, lt lockType) error {
- return &os.PathError{
+ return &fs.PathError{
Op: lt.String(),
Path: f.Name(),
Err: ErrNotSupported,
@@ -24,7 +24,7 @@ func lock(f File, lt lockType) error {
}
func unlock(f File) error {
- return &os.PathError{
+ return &fs.PathError{
Op: "Unlock",
Path: f.Name(),
Err: ErrNotSupported,
diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go
index afdffe323f..0798ee469a 100644
--- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go
+++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go
@@ -6,9 +6,7 @@
package filelock
-import (
- "os"
-)
+import "io/fs"
type lockType int8
@@ -18,7 +16,7 @@ const (
)
func lock(f File, lt lockType) error {
- return &os.PathError{
+ return &fs.PathError{
Op: lt.String(),
Path: f.Name(),
Err: ErrNotSupported,
@@ -26,7 +24,7 @@ func lock(f File, lt lockType) error {
}
func unlock(f File) error {
- return &os.PathError{
+ return &fs.PathError{
Op: "Unlock",
Path: f.Name(),
Err: ErrNotSupported,
diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go
index 78f2c51129..ed07bac608 100644
--- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go
+++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go
@@ -7,7 +7,7 @@
package filelock
import (
- "os"
+ "io/fs"
"syscall"
)
@@ -26,7 +26,7 @@ func lock(f File, lt lockType) (err error) {
}
}
if err != nil {
- return &os.PathError{
+ return &fs.PathError{
Op: lt.String(),
Path: f.Name(),
Err: err,
diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go
index 43e85e450e..19de27eb9b 100644
--- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go
+++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go
@@ -8,7 +8,7 @@ package filelock
import (
"internal/syscall/windows"
- "os"
+ "io/fs"
"syscall"
)
@@ -34,7 +34,7 @@ func lock(f File, lt lockType) error {
err := windows.LockFileEx(syscall.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol)
if err != nil {
- return &os.PathError{
+ return &fs.PathError{
Op: lt.String(),
Path: f.Name(),
Err: err,
@@ -47,7 +47,7 @@ func unlock(f File) error {
ol := new(syscall.Overlapped)
err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol)
if err != nil {
- return &os.PathError{
+ return &fs.PathError{
Op: "Unlock",
Path: f.Name(),
Err: err,
diff --git a/src/cmd/go/internal/lockedfile/lockedfile.go b/src/cmd/go/internal/lockedfile/lockedfile.go
index 59b2dba44c..82e1a89675 100644
--- a/src/cmd/go/internal/lockedfile/lockedfile.go
+++ b/src/cmd/go/internal/lockedfile/lockedfile.go
@@ -9,7 +9,7 @@ package lockedfile
import (
"fmt"
"io"
- "io/ioutil"
+ "io/fs"
"os"
"runtime"
)
@@ -35,7 +35,7 @@ type osFile struct {
// OpenFile is like os.OpenFile, but returns a locked file.
// If flag includes os.O_WRONLY or os.O_RDWR, the file is write-locked;
// otherwise, it is read-locked.
-func OpenFile(name string, flag int, perm os.FileMode) (*File, error) {
+func OpenFile(name string, flag int, perm fs.FileMode) (*File, error) {
var (
f = new(File)
err error
@@ -82,10 +82,10 @@ func Edit(name string) (*File, error) {
// non-nil error.
func (f *File) Close() error {
if f.closed {
- return &os.PathError{
+ return &fs.PathError{
Op: "close",
Path: f.Name(),
- Err: os.ErrClosed,
+ Err: fs.ErrClosed,
}
}
f.closed = true
@@ -103,12 +103,12 @@ func Read(name string) ([]byte, error) {
}
defer f.Close()
- return ioutil.ReadAll(f)
+ return io.ReadAll(f)
}
// Write opens the named file (creating it with the given permissions if needed),
// then write-locks it and overwrites it with the given content.
-func Write(name string, content io.Reader, perm os.FileMode) (err error) {
+func Write(name string, content io.Reader, perm fs.FileMode) (err error) {
f, err := OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
@@ -135,7 +135,7 @@ func Transform(name string, t func([]byte) ([]byte, error)) (err error) {
}
defer f.Close()
- old, err := ioutil.ReadAll(f)
+ old, err := io.ReadAll(f)
if err != nil {
return err
}
diff --git a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go
index f63dd8664b..10e1240efd 100644
--- a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go
+++ b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go
@@ -7,12 +7,13 @@
package lockedfile
import (
+ "io/fs"
"os"
"cmd/go/internal/lockedfile/internal/filelock"
)
-func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
+func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
// On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile
// call instead of locking separately, but we have to support separate locking
// calls for Linux and Windows anyway, so it's simpler to use that approach
diff --git a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go
index 4a52c94976..51681381d7 100644
--- a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go
+++ b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go
@@ -7,6 +7,7 @@
package lockedfile
import (
+ "io/fs"
"math/rand"
"os"
"strings"
@@ -41,7 +42,7 @@ func isLocked(err error) bool {
return false
}
-func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
+func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
// Plan 9 uses a mode bit instead of explicit lock/unlock syscalls.
//
// Per http://man.cat-v.org/plan_9/5/stat: “Exclusive use files may be open
@@ -56,8 +57,8 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
// have the ModeExclusive bit set. Set it before we call OpenFile, so that we
// can be confident that a successful OpenFile implies exclusive use.
if fi, err := os.Stat(name); err == nil {
- if fi.Mode()&os.ModeExclusive == 0 {
- if err := os.Chmod(name, fi.Mode()|os.ModeExclusive); err != nil {
+ if fi.Mode()&fs.ModeExclusive == 0 {
+ if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil {
return nil, err
}
}
@@ -68,7 +69,7 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
nextSleep := 1 * time.Millisecond
const maxSleep = 500 * time.Millisecond
for {
- f, err := os.OpenFile(name, flag, perm|os.ModeExclusive)
+ f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive)
if err == nil {
return f, nil
}
diff --git a/src/cmd/go/internal/modcmd/download.go b/src/cmd/go/internal/modcmd/download.go
index 050a2e0e12..e2e8ba6825 100644
--- a/src/cmd/go/internal/modcmd/download.go
+++ b/src/cmd/go/internal/modcmd/download.go
@@ -87,7 +87,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
if len(args) == 0 {
args = []string{"all"}
} else if modload.HasModRoot() {
- modload.InitMod(ctx) // to fill Target
+ modload.LoadModFile(ctx) // to fill Target
targetAtLatest := modload.Target.Path + "@latest"
targetAtUpgrade := modload.Target.Path + "@upgrade"
targetAtPatch := modload.Target.Path + "@patch"
diff --git a/src/cmd/go/internal/modcmd/init.go b/src/cmd/go/internal/modcmd/init.go
index 7cfc0e6f5b..7384f3f293 100644
--- a/src/cmd/go/internal/modcmd/init.go
+++ b/src/cmd/go/internal/modcmd/init.go
@@ -10,8 +10,6 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/modload"
"context"
- "os"
- "strings"
)
var cmdInit = &base.Command{
@@ -33,21 +31,14 @@ func init() {
}
func runInit(ctx context.Context, cmd *base.Command, args []string) {
- modload.CmdModInit = true
if len(args) > 1 {
base.Fatalf("go mod init: too many arguments")
}
+ var modPath string
if len(args) == 1 {
- modload.CmdModModule = args[0]
+ modPath = args[0]
}
+
modload.ForceUseModules = true
- modFilePath := modload.ModFilePath()
- if _, err := os.Stat(modFilePath); err == nil {
- base.Fatalf("go mod init: go.mod already exists")
- }
- if strings.Contains(modload.CmdModModule, "@") {
- base.Fatalf("go mod init: module path must not contain '@'")
- }
- modload.InitMod(ctx) // does all the hard work
- modload.WriteGoMod()
+ modload.CreateModFile(ctx, modPath) // does all the hard work
}
diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go
index 1bc4ab3def..1b9ce60529 100644
--- a/src/cmd/go/internal/modcmd/vendor.go
+++ b/src/cmd/go/internal/modcmd/vendor.go
@@ -9,6 +9,7 @@ import (
"context"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -232,7 +233,7 @@ var metaPrefixes = []string{
}
// matchMetadata reports whether info is a metadata file.
-func matchMetadata(dir string, info os.FileInfo) bool {
+func matchMetadata(dir string, info fs.FileInfo) bool {
name := info.Name()
for _, p := range metaPrefixes {
if strings.HasPrefix(name, p) {
@@ -243,7 +244,7 @@ func matchMetadata(dir string, info os.FileInfo) bool {
}
// matchPotentialSourceFile reports whether info may be relevant to a build operation.
-func matchPotentialSourceFile(dir string, info os.FileInfo) bool {
+func matchPotentialSourceFile(dir string, info fs.FileInfo) bool {
if strings.HasSuffix(info.Name(), "_test.go") {
return false
}
@@ -269,7 +270,7 @@ func matchPotentialSourceFile(dir string, info os.FileInfo) bool {
}
// copyDir copies all regular files satisfying match(info) from src to dst.
-func copyDir(dst, src string, match func(dir string, info os.FileInfo) bool) {
+func copyDir(dst, src string, match func(dir string, info fs.FileInfo) bool) {
files, err := ioutil.ReadDir(src)
if err != nil {
base.Fatalf("go mod vendor: %v", err)
diff --git a/src/cmd/go/internal/modcmd/verify.go b/src/cmd/go/internal/modcmd/verify.go
index bd591d3f32..ce24793929 100644
--- a/src/cmd/go/internal/modcmd/verify.go
+++ b/src/cmd/go/internal/modcmd/verify.go
@@ -9,6 +9,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"io/ioutil"
"os"
"runtime"
@@ -88,8 +89,8 @@ func verifyMod(mod module.Version) []error {
dir, dirErr := modfetch.DownloadDir(mod)
data, err := ioutil.ReadFile(zip + "hash")
if err != nil {
- if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) &&
- dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
+ if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) &&
+ dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) {
// Nothing downloaded yet. Nothing to verify.
return nil
}
@@ -98,7 +99,7 @@ func verifyMod(mod module.Version) []error {
}
h := string(bytes.TrimSpace(data))
- if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) {
+ if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) {
// ok
} else {
hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
@@ -109,7 +110,7 @@ func verifyMod(mod module.Version) []error {
errs = append(errs, fmt.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip))
}
}
- if dirErr != nil && errors.Is(dirErr, os.ErrNotExist) {
+ if dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) {
// ok
} else {
hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go
index e3074b775e..b7aa670250 100644
--- a/src/cmd/go/internal/modfetch/cache.go
+++ b/src/cmd/go/internal/modfetch/cache.go
@@ -10,10 +10,12 @@ import (
"errors"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
"strings"
+ "sync"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
@@ -59,7 +61,7 @@ func CachePath(m module.Version, suffix string) (string, error) {
// DownloadDir returns the directory to which m should have been downloaded.
// An error will be returned if the module path or version cannot be escaped.
-// An error satisfying errors.Is(err, os.ErrNotExist) will be returned
+// An error satisfying errors.Is(err, fs.ErrNotExist) will be returned
// along with the directory if the directory does not exist or if the directory
// is not completely populated.
func DownloadDir(m module.Version) (string, error) {
@@ -106,14 +108,14 @@ func DownloadDir(m module.Version) (string, error) {
// DownloadDirPartialError is returned by DownloadDir if a module directory
// exists but was not completely populated.
//
-// DownloadDirPartialError is equivalent to os.ErrNotExist.
+// DownloadDirPartialError is equivalent to fs.ErrNotExist.
type DownloadDirPartialError struct {
Dir string
Err error
}
func (e *DownloadDirPartialError) Error() string { return fmt.Sprintf("%s: %v", e.Dir, e.Err) }
-func (e *DownloadDirPartialError) Is(err error) bool { return err == os.ErrNotExist }
+func (e *DownloadDirPartialError) Is(err error) bool { return err == fs.ErrNotExist }
// lockVersion locks a file within the module cache that guards the downloading
// and extraction of the zipfile for the given module version.
@@ -155,16 +157,30 @@ func SideLock() (unlock func(), err error) {
type cachingRepo struct {
path string
cache par.Cache // cache for all operations
- r Repo
+
+ once sync.Once
+ initRepo func() (Repo, error)
+ r Repo
}
-func newCachingRepo(r Repo) *cachingRepo {
+func newCachingRepo(path string, initRepo func() (Repo, error)) *cachingRepo {
return &cachingRepo{
- r: r,
- path: r.ModulePath(),
+ path: path,
+ initRepo: initRepo,
}
}
+func (r *cachingRepo) repo() Repo {
+ r.once.Do(func() {
+ var err error
+ r.r, err = r.initRepo()
+ if err != nil {
+ r.r = errRepo{r.path, err}
+ }
+ })
+ return r.r
+}
+
func (r *cachingRepo) ModulePath() string {
return r.path
}
@@ -175,7 +191,7 @@ func (r *cachingRepo) Versions(prefix string) ([]string, error) {
err error
}
c := r.cache.Do("versions:"+prefix, func() interface{} {
- list, err := r.r.Versions(prefix)
+ list, err := r.repo().Versions(prefix)
return cached{list, err}
}).(cached)
@@ -197,7 +213,7 @@ func (r *cachingRepo) Stat(rev string) (*RevInfo, error) {
return cachedInfo{info, nil}
}
- info, err = r.r.Stat(rev)
+ info, err = r.repo().Stat(rev)
if err == nil {
// If we resolved, say, 1234abcde to v0.0.0-20180604122334-1234abcdef78,
// then save the information under the proper version, for future use.
@@ -224,7 +240,7 @@ func (r *cachingRepo) Stat(rev string) (*RevInfo, error) {
func (r *cachingRepo) Latest() (*RevInfo, error) {
c := r.cache.Do("latest:", func() interface{} {
- info, err := r.r.Latest()
+ info, err := r.repo().Latest()
// Save info for likely future Stat call.
if err == nil {
@@ -258,7 +274,7 @@ func (r *cachingRepo) GoMod(version string) ([]byte, error) {
return cached{text, nil}
}
- text, err = r.r.GoMod(version)
+ text, err = r.repo().GoMod(version)
if err == nil {
if err := checkGoMod(r.path, version, text); err != nil {
return cached{text, err}
@@ -277,26 +293,11 @@ func (r *cachingRepo) GoMod(version string) ([]byte, error) {
}
func (r *cachingRepo) Zip(dst io.Writer, version string) error {
- return r.r.Zip(dst, version)
-}
-
-// Stat is like Lookup(path).Stat(rev) but avoids the
-// repository path resolution in Lookup if the result is
-// already cached on local disk.
-func Stat(proxy, path, rev string) (*RevInfo, error) {
- _, info, err := readDiskStat(path, rev)
- if err == nil {
- return info, nil
- }
- repo, err := Lookup(proxy, path)
- if err != nil {
- return nil, err
- }
- return repo.Stat(rev)
+ return r.repo().Zip(dst, version)
}
-// InfoFile is like Stat but returns the name of the file containing
-// the cached information.
+// InfoFile is like Lookup(path).Stat(version) but returns the name of the file
+// containing the cached information.
func InfoFile(path, version string) (string, error) {
if !semver.IsValid(version) {
return "", fmt.Errorf("invalid version %q", version)
@@ -307,10 +308,7 @@ func InfoFile(path, version string) (string, error) {
}
err := TryProxies(func(proxy string) error {
- repo, err := Lookup(proxy, path)
- if err == nil {
- _, err = repo.Stat(version)
- }
+ _, err := Lookup(proxy, path).Stat(version)
return err
})
if err != nil {
@@ -336,11 +334,7 @@ func GoMod(path, rev string) ([]byte, error) {
rev = info.Version
} else {
err := TryProxies(func(proxy string) error {
- repo, err := Lookup(proxy, path)
- if err != nil {
- return err
- }
- info, err := repo.Stat(rev)
+ info, err := Lookup(proxy, path).Stat(rev)
if err == nil {
rev = info.Version
}
@@ -357,11 +351,8 @@ func GoMod(path, rev string) ([]byte, error) {
return data, nil
}
- err = TryProxies(func(proxy string) error {
- repo, err := Lookup(proxy, path)
- if err == nil {
- data, err = repo.GoMod(rev)
- }
+ err = TryProxies(func(proxy string) (err error) {
+ data, err = Lookup(proxy, path).GoMod(rev)
return err
})
return data, err
diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go
index d85eddf767..c5fbb31b2b 100644
--- a/src/cmd/go/internal/modfetch/codehost/codehost.go
+++ b/src/cmd/go/internal/modfetch/codehost/codehost.go
@@ -11,6 +11,7 @@ import (
"crypto/sha256"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"os"
"os/exec"
@@ -79,9 +80,8 @@ type Repo interface {
ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, err error)
// RecentTag returns the most recent tag on rev or one of its predecessors
- // with the given prefix and major version.
- // An empty major string matches any major version.
- RecentTag(rev, prefix, major string) (tag string, err error)
+ // with the given prefix. allowed may be used to filter out unwanted versions.
+ RecentTag(rev, prefix string, allowed func(string) bool) (tag string, err error)
// DescendsFrom reports whether rev or any of its ancestors has the given tag.
//
@@ -106,7 +106,7 @@ type FileRev struct {
Err error // error if any; os.IsNotExist(Err)==true if rev exists but file does not exist in that rev
}
-// UnknownRevisionError is an error equivalent to os.ErrNotExist, but for a
+// UnknownRevisionError is an error equivalent to fs.ErrNotExist, but for a
// revision rather than a file.
type UnknownRevisionError struct {
Rev string
@@ -116,10 +116,10 @@ func (e *UnknownRevisionError) Error() string {
return "unknown revision " + e.Rev
}
func (UnknownRevisionError) Is(err error) bool {
- return err == os.ErrNotExist
+ return err == fs.ErrNotExist
}
-// ErrNoCommits is an error equivalent to os.ErrNotExist indicating that a given
+// ErrNoCommits is an error equivalent to fs.ErrNotExist indicating that a given
// repository or module contains no commits.
var ErrNoCommits error = noCommitsError{}
@@ -129,7 +129,7 @@ func (noCommitsError) Error() string {
return "no commits"
}
func (noCommitsError) Is(err error) bool {
- return err == os.ErrNotExist
+ return err == fs.ErrNotExist
}
// AllHex reports whether the revision rev is entirely lower-case hexadecimal digits.
diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go
index 31921324a7..8abc039e7f 100644
--- a/src/cmd/go/internal/modfetch/codehost/git.go
+++ b/src/cmd/go/internal/modfetch/codehost/git.go
@@ -9,7 +9,7 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
+ "io/fs"
"net/url"
"os"
"os/exec"
@@ -34,13 +34,13 @@ func LocalGitRepo(remote string) (Repo, error) {
}
// A notExistError wraps another error to retain its original text
-// but makes it opaquely equivalent to os.ErrNotExist.
+// but makes it opaquely equivalent to fs.ErrNotExist.
type notExistError struct {
err error
}
func (e notExistError) Error() string { return e.err.Error() }
-func (notExistError) Is(err error) bool { return err == os.ErrNotExist }
+func (notExistError) Is(err error) bool { return err == fs.ErrNotExist }
const gitWorkDirType = "git3"
@@ -188,7 +188,7 @@ func (r *gitRepo) loadRefs() {
// For HTTP and HTTPS, that's easy to detect: we'll try to fetch the URL
// ourselves and see what code it serves.
if u, err := url.Parse(r.remoteURL); err == nil && (u.Scheme == "http" || u.Scheme == "https") {
- if _, err := web.GetBytes(u); errors.Is(err, os.ErrNotExist) {
+ if _, err := web.GetBytes(u); errors.Is(err, fs.ErrNotExist) {
gitErr = notExistError{gitErr}
}
}
@@ -505,7 +505,7 @@ func (r *gitRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
}
out, err := Run(r.dir, "git", "cat-file", "blob", info.Name+":"+file)
if err != nil {
- return nil, os.ErrNotExist
+ return nil, fs.ErrNotExist
}
return out, nil
}
@@ -629,9 +629,9 @@ func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*F
case "tag", "commit":
switch fileType {
default:
- f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)}
+ f.Err = &fs.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)}
case "missing":
- f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: os.ErrNotExist}
+ f.Err = &fs.PathError{Path: tag + ":" + file, Op: "read", Err: fs.ErrNotExist}
case "blob":
f.Data = fileData
}
@@ -644,7 +644,7 @@ func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*F
return missing, nil
}
-func (r *gitRepo) RecentTag(rev, prefix, major string) (tag string, err error) {
+func (r *gitRepo) RecentTag(rev, prefix string, allowed func(string) bool) (tag string, err error) {
info, err := r.Stat(rev)
if err != nil {
return "", err
@@ -680,7 +680,10 @@ func (r *gitRepo) RecentTag(rev, prefix, major string) (tag string, err error) {
// NOTE: Do not replace the call to semver.Compare with semver.Max.
// We want to return the actual tag, not a canonicalized version of it,
// and semver.Max currently canonicalizes (see golang.org/issue/32700).
- if c := semver.Canonical(semtag); c != "" && strings.HasPrefix(semtag, c) && (major == "" || semver.Major(c) == major) && semver.Compare(semtag, highest) > 0 {
+ if c := semver.Canonical(semtag); c == "" || !strings.HasPrefix(semtag, c) || !allowed(semtag) {
+ continue
+ }
+ if semver.Compare(semtag, highest) > 0 {
highest = semtag
}
}
@@ -823,12 +826,12 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser,
archive, err := Run(r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", info.Name, args)
if err != nil {
if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) {
- return nil, os.ErrNotExist
+ return nil, fs.ErrNotExist
}
return nil, err
}
- return ioutil.NopCloser(bytes.NewReader(archive)), nil
+ return io.NopCloser(bytes.NewReader(archive)), nil
}
// ensureGitAttributes makes sure export-subst and export-ignore features are
@@ -859,7 +862,7 @@ func ensureGitAttributes(repoDir string) (err error) {
}
}()
- b, err := ioutil.ReadAll(f)
+ b, err := io.ReadAll(f)
if err != nil {
return err
}
diff --git a/src/cmd/go/internal/modfetch/codehost/git_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go
index ba27c70f5a..981e3fe91f 100644
--- a/src/cmd/go/internal/modfetch/codehost/git_test.go
+++ b/src/cmd/go/internal/modfetch/codehost/git_test.go
@@ -10,6 +10,8 @@ import (
"flag"
"fmt"
"internal/testenv"
+ "io"
+ "io/fs"
"io/ioutil"
"log"
"os"
@@ -210,7 +212,7 @@ var readFileTests = []struct {
repo: gitrepo1,
rev: "v2.3.4",
file: "another.txt",
- err: os.ErrNotExist.Error(),
+ err: fs.ErrNotExist.Error(),
},
}
@@ -432,7 +434,7 @@ func TestReadZip(t *testing.T) {
if tt.err != "" {
t.Fatalf("ReadZip: no error, wanted %v", tt.err)
}
- zipdata, err := ioutil.ReadAll(rc)
+ zipdata, err := io.ReadAll(rc)
if err != nil {
t.Fatal(err)
}
diff --git a/src/cmd/go/internal/modfetch/codehost/shell.go b/src/cmd/go/internal/modfetch/codehost/shell.go
index 2762c55720..b9525adf5e 100644
--- a/src/cmd/go/internal/modfetch/codehost/shell.go
+++ b/src/cmd/go/internal/modfetch/codehost/shell.go
@@ -14,6 +14,7 @@ import (
"bytes"
"flag"
"fmt"
+ "io"
"io/ioutil"
"log"
"os"
@@ -115,7 +116,7 @@ func main() {
fmt.Fprintf(os.Stderr, "?%s\n", err)
continue
}
- data, err := ioutil.ReadAll(rc)
+ data, err := io.ReadAll(rc)
rc.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "?%s\n", err)
diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go
index 7284557f4b..ec97fc7e1b 100644
--- a/src/cmd/go/internal/modfetch/codehost/vcs.go
+++ b/src/cmd/go/internal/modfetch/codehost/vcs.go
@@ -9,6 +9,7 @@ import (
"fmt"
"internal/lazyregexp"
"io"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -377,7 +378,7 @@ func (r *vcsRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
out, err := Run(r.dir, r.cmd.readFile(rev, file, r.remote))
if err != nil {
- return nil, os.ErrNotExist
+ return nil, fs.ErrNotExist
}
return out, nil
}
@@ -395,7 +396,7 @@ func (r *vcsRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[s
return nil, vcsErrorf("ReadFileRevs not implemented")
}
-func (r *vcsRepo) RecentTag(rev, prefix, major string) (tag string, err error) {
+func (r *vcsRepo) RecentTag(rev, prefix string, allowed func(string) bool) (tag string, err error) {
// We don't technically need to lock here since we're returning an error
// uncondititonally, but doing so anyway will help to avoid baking in
// lock-inversion bugs.
diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go
index d043903336..b6bcf83f1a 100644
--- a/src/cmd/go/internal/modfetch/coderepo.go
+++ b/src/cmd/go/internal/modfetch/coderepo.go
@@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"os"
"path"
@@ -419,9 +420,14 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
tagPrefix = r.codeDir + "/"
}
+ isRetracted, err := r.retractedVersions()
+ if err != nil {
+ isRetracted = func(string) bool { return false }
+ }
+
// tagToVersion returns the version obtained by trimming tagPrefix from tag.
- // If the tag is invalid or a pseudo-version, tagToVersion returns an empty
- // version.
+ // If the tag is invalid, retracted, or a pseudo-version, tagToVersion returns
+ // an empty version.
tagToVersion := func(tag string) (v string, tagIsCanonical bool) {
if !strings.HasPrefix(tag, tagPrefix) {
return "", false
@@ -436,6 +442,9 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
if v == "" || !strings.HasPrefix(trimmed, v) {
return "", false // Invalid or incomplete version (just vX or vX.Y).
}
+ if isRetracted(v) {
+ return "", false
+ }
if v == trimmed {
tagIsCanonical = true
}
@@ -500,15 +509,24 @@ func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, e
return checkGoMod()
}
+ // Find the highest tagged version in the revision's history, subject to
+ // major version and +incompatible constraints. Use that version as the
+ // pseudo-version base so that the pseudo-version sorts higher. Ignore
+ // retracted versions.
+ allowedMajor := func(major string) func(v string) bool {
+ return func(v string) bool {
+ return (major == "" || semver.Major(v) == major) && !isRetracted(v)
+ }
+ }
if pseudoBase == "" {
var tag string
if r.pseudoMajor != "" || canUseIncompatible() {
- tag, _ = r.code.RecentTag(info.Name, tagPrefix, r.pseudoMajor)
+ tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor(r.pseudoMajor))
} else {
// Allow either v1 or v0, but not incompatible higher versions.
- tag, _ = r.code.RecentTag(info.Name, tagPrefix, "v1")
+ tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v1"))
if tag == "" {
- tag, _ = r.code.RecentTag(info.Name, tagPrefix, "v0")
+ tag, _ = r.code.RecentTag(info.Name, tagPrefix, allowedMajor("v0"))
}
}
pseudoBase, _ = tagToVersion(tag) // empty if the tag is invalid
@@ -869,6 +887,57 @@ func (r *codeRepo) modPrefix(rev string) string {
return r.modPath + "@" + rev
}
+func (r *codeRepo) retractedVersions() (func(string) bool, error) {
+ versions, err := r.Versions("")
+ if err != nil {
+ return nil, err
+ }
+
+ for i, v := range versions {
+ if strings.HasSuffix(v, "+incompatible") {
+ versions = versions[:i]
+ break
+ }
+ }
+ if len(versions) == 0 {
+ return func(string) bool { return false }, nil
+ }
+
+ var highest string
+ for i := len(versions) - 1; i >= 0; i-- {
+ v := versions[i]
+ if semver.Prerelease(v) == "" {
+ highest = v
+ break
+ }
+ }
+ if highest == "" {
+ highest = versions[len(versions)-1]
+ }
+
+ data, err := r.GoMod(highest)
+ if err != nil {
+ return nil, err
+ }
+ f, err := modfile.ParseLax("go.mod", data, nil)
+ if err != nil {
+ return nil, err
+ }
+ retractions := make([]modfile.VersionInterval, len(f.Retract))
+ for _, r := range f.Retract {
+ retractions = append(retractions, r.VersionInterval)
+ }
+
+ return func(v string) bool {
+ for _, r := range retractions {
+ if semver.Compare(r.Low, v) <= 0 && semver.Compare(v, r.High) <= 0 {
+ return true
+ }
+ }
+ return false
+ }, nil
+}
+
func (r *codeRepo) Zip(dst io.Writer, version string) error {
if version != module.CanonicalVersion(version) {
return fmt.Errorf("version %s is not canonical", version)
@@ -972,7 +1041,7 @@ type zipFile struct {
}
func (f zipFile) Path() string { return f.name }
-func (f zipFile) Lstat() (os.FileInfo, error) { return f.f.FileInfo(), nil }
+func (f zipFile) Lstat() (fs.FileInfo, error) { return f.f.FileInfo(), nil }
func (f zipFile) Open() (io.ReadCloser, error) { return f.f.Open() }
type dataFile struct {
@@ -981,9 +1050,9 @@ type dataFile struct {
}
func (f dataFile) Path() string { return f.name }
-func (f dataFile) Lstat() (os.FileInfo, error) { return dataFileInfo{f}, nil }
+func (f dataFile) Lstat() (fs.FileInfo, error) { return dataFileInfo{f}, nil }
func (f dataFile) Open() (io.ReadCloser, error) {
- return ioutil.NopCloser(bytes.NewReader(f.data)), nil
+ return io.NopCloser(bytes.NewReader(f.data)), nil
}
type dataFileInfo struct {
@@ -992,7 +1061,7 @@ type dataFileInfo struct {
func (fi dataFileInfo) Name() string { return path.Base(fi.f.name) }
func (fi dataFileInfo) Size() int64 { return int64(len(fi.f.data)) }
-func (fi dataFileInfo) Mode() os.FileMode { return 0644 }
+func (fi dataFileInfo) Mode() fs.FileMode { return 0644 }
func (fi dataFileInfo) ModTime() time.Time { return time.Time{} }
func (fi dataFileInfo) IsDir() bool { return false }
func (fi dataFileInfo) Sys() interface{} { return nil }
diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go
index f69c193b86..4364fef6d1 100644
--- a/src/cmd/go/internal/modfetch/coderepo_test.go
+++ b/src/cmd/go/internal/modfetch/coderepo_test.go
@@ -60,7 +60,6 @@ var altVgotests = map[string]string{
type codeRepoTest struct {
vcs string
path string
- lookErr string
mpath string
rev string
err string
@@ -332,9 +331,9 @@ var codeRepoTests = []codeRepoTest{
// package in subdirectory - custom domain
// In general we can't reject these definitively in Lookup,
// but gopkg.in is special.
- vcs: "git",
- path: "gopkg.in/yaml.v2/abc",
- lookErr: "invalid module path \"gopkg.in/yaml.v2/abc\"",
+ vcs: "git",
+ path: "gopkg.in/yaml.v2/abc",
+ err: "invalid module path \"gopkg.in/yaml.v2/abc\"",
},
{
// package in subdirectory - github
@@ -440,16 +439,7 @@ func TestCodeRepo(t *testing.T) {
testenv.MustHaveExecPath(t, tt.vcs)
}
- repo, err := Lookup("direct", tt.path)
- if tt.lookErr != "" {
- if err != nil && err.Error() == tt.lookErr {
- return
- }
- t.Errorf("Lookup(%q): %v, want error %q", tt.path, err, tt.lookErr)
- }
- if err != nil {
- t.Fatalf("Lookup(%q): %v", tt.path, err)
- }
+ repo := Lookup("direct", tt.path)
if tt.mpath == "" {
tt.mpath = tt.path
@@ -658,7 +648,7 @@ var codeRepoVersionsTests = []struct {
{
vcs: "git",
path: "gopkg.in/russross/blackfriday.v2",
- versions: []string{"v2.0.0", "v2.0.1"},
+ versions: []string{"v2.0.0", "v2.0.1", "v2.1.0-pre.1"},
},
{
vcs: "git",
@@ -685,10 +675,7 @@ func TestCodeRepoVersions(t *testing.T) {
testenv.MustHaveExecPath(t, tt.vcs)
}
- repo, err := Lookup("direct", tt.path)
- if err != nil {
- t.Fatalf("Lookup(%q): %v", tt.path, err)
- }
+ repo := Lookup("direct", tt.path)
list, err := repo.Versions(tt.prefix)
if err != nil {
t.Fatalf("Versions(%q): %v", tt.prefix, err)
@@ -763,10 +750,7 @@ func TestLatest(t *testing.T) {
testenv.MustHaveExecPath(t, tt.vcs)
}
- repo, err := Lookup("direct", tt.path)
- if err != nil {
- t.Fatalf("Lookup(%q): %v", tt.path, err)
- }
+ repo := Lookup("direct", tt.path)
info, err := repo.Latest()
if err != nil {
if tt.err != "" {
diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go
index 01d8f007ac..25e9fb62c1 100644
--- a/src/cmd/go/internal/modfetch/fetch.go
+++ b/src/cmd/go/internal/modfetch/fetch.go
@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -63,14 +64,11 @@ func download(ctx context.Context, mod module.Version) (dir string, err error) {
ctx, span := trace.StartSpan(ctx, "modfetch.download "+mod.String())
defer span.Done()
- // If the directory exists, and no .partial file exists, the module has
- // already been completely extracted. .partial files may be created when a
- // module zip directory is extracted in place instead of being extracted to a
- // temporary directory and renamed.
dir, err = DownloadDir(mod)
if err == nil {
+ // The directory has already been completely extracted (no .partial file exists).
return dir, nil
- } else if dir == "" || !errors.Is(err, os.ErrNotExist) {
+ } else if dir == "" || !errors.Is(err, fs.ErrNotExist) {
return "", err
}
@@ -88,6 +86,9 @@ func download(ctx context.Context, mod module.Version) (dir string, err error) {
}
defer unlock()
+ ctx, span = trace.StartSpan(ctx, "unzip "+zipfile)
+ defer span.Done()
+
// Check whether the directory was populated while we were waiting on the lock.
_, dirErr := DownloadDir(mod)
if dirErr == nil {
@@ -95,10 +96,11 @@ func download(ctx context.Context, mod module.Version) (dir string, err error) {
}
_, dirExists := dirErr.(*DownloadDirPartialError)
- // Clean up any remaining temporary directories from previous runs, as well
- // as partially extracted diectories created by future versions of cmd/go.
- // This is only safe to do because the lock file ensures that their writers
- // are no longer active.
+ // Clean up any remaining temporary directories created by old versions
+ // (before 1.16), as well as partially extracted directories (indicated by
+ // DownloadDirPartialError, usually because of a .partial file). This is only
+ // safe to do because the lock file ensures that their writers are no longer
+ // active.
parentDir := filepath.Dir(dir)
tmpPrefix := filepath.Base(dir) + ".tmp-"
if old, err := filepath.Glob(filepath.Join(parentDir, tmpPrefix+"*")); err == nil {
@@ -116,88 +118,44 @@ func download(ctx context.Context, mod module.Version) (dir string, err error) {
if err != nil {
return "", err
}
- if err := os.Remove(partialPath); err != nil && !os.IsNotExist(err) {
- return "", err
- }
- // Extract the module zip directory.
+ // Extract the module zip directory at its final location.
//
- // By default, we extract to a temporary directory, then atomically rename to
- // its final location. We use the existence of the source directory to signal
- // that it has been extracted successfully (see DownloadDir). If someone
- // deletes the entire directory (e.g., as an attempt to prune out file
- // corruption), the module cache will still be left in a recoverable
- // state.
+ // To prevent other processes from reading the directory if we crash,
+ // create a .partial file before extracting the directory, and delete
+ // the .partial file afterward (all while holding the lock).
//
- // Unfortunately, os.Rename may fail with ERROR_ACCESS_DENIED on Windows if
- // another process opens files in the temporary directory. This is partially
- // mitigated by using robustio.Rename, which retries os.Rename for a short
- // time.
+ // Before Go 1.16, we extracted to a temporary directory with a random name
+ // then renamed it into place with os.Rename. On Windows, this failed with
+ // ERROR_ACCESS_DENIED when another process (usually an anti-virus scanner)
+ // opened files in the temporary directory.
//
- // To avoid this error completely, if unzipInPlace is set, we instead create a
- // .partial file (indicating the directory isn't fully extracted), then we
- // extract the directory at its final location, then we delete the .partial
- // file. This is not the default behavior because older versions of Go may
- // simply stat the directory to check whether it exists without looking for a
- // .partial file. If multiple versions run concurrently, the older version may
- // assume a partially extracted directory is complete.
- // TODO(golang.org/issue/36568): when these older versions are no longer
- // supported, remove the old default behavior and the unzipInPlace flag.
+ // Go 1.14.2 and higher respect .partial files. Older versions may use
+ // partially extracted directories. 'go mod verify' can detect this,
+ // and 'go clean -modcache' can fix it.
if err := os.MkdirAll(parentDir, 0777); err != nil {
return "", err
}
-
- ctx, span = trace.StartSpan(ctx, "unzip "+zipfile)
- if unzipInPlace {
- if err := ioutil.WriteFile(partialPath, nil, 0666); err != nil {
- return "", err
- }
- if err := modzip.Unzip(dir, mod, zipfile); err != nil {
- fmt.Fprintf(os.Stderr, "-> %s\n", err)
- if rmErr := RemoveAll(dir); rmErr == nil {
- os.Remove(partialPath)
- }
- return "", err
- }
- if err := os.Remove(partialPath); err != nil {
- return "", err
- }
- } else {
- tmpDir, err := ioutil.TempDir(parentDir, tmpPrefix)
- if err != nil {
- return "", err
- }
- if err := modzip.Unzip(tmpDir, mod, zipfile); err != nil {
- fmt.Fprintf(os.Stderr, "-> %s\n", err)
- RemoveAll(tmpDir)
- return "", err
- }
- if err := robustio.Rename(tmpDir, dir); err != nil {
- RemoveAll(tmpDir)
- return "", err
+ if err := ioutil.WriteFile(partialPath, nil, 0666); err != nil {
+ return "", err
+ }
+ if err := modzip.Unzip(dir, mod, zipfile); err != nil {
+ fmt.Fprintf(os.Stderr, "-> %s\n", err)
+ if rmErr := RemoveAll(dir); rmErr == nil {
+ os.Remove(partialPath)
}
+ return "", err
+ }
+ if err := os.Remove(partialPath); err != nil {
+ return "", err
}
- defer span.Done()
if !cfg.ModCacheRW {
- // Make dir read-only only *after* renaming it.
- // os.Rename was observed to fail for read-only directories on macOS.
makeDirsReadOnly(dir)
}
return dir, nil
}
-var unzipInPlace bool
-
-func init() {
- for _, f := range strings.Split(os.Getenv("GODEBUG"), ",") {
- if f == "modcacheunzipinplace=1" {
- unzipInPlace = true
- break
- }
- }
-}
-
var downloadZipCache par.Cache
// DownloadZip downloads the specific module version to the
@@ -276,12 +234,28 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
}
}()
+ var unrecoverableErr error
err = TryProxies(func(proxy string) error {
- repo, err := Lookup(proxy, mod.Path)
+ if unrecoverableErr != nil {
+ return unrecoverableErr
+ }
+ repo := Lookup(proxy, mod.Path)
+ err := repo.Zip(f, mod.Version)
if err != nil {
- return err
+ // Zip may have partially written to f before failing.
+ // (Perhaps the server crashed while sending the file?)
+ // Since we allow fallback on error in some cases, we need to fix up the
+ // file to be empty again for the next attempt.
+ if _, err := f.Seek(0, io.SeekStart); err != nil {
+ unrecoverableErr = err
+ return err
+ }
+ if err := f.Truncate(0); err != nil {
+ unrecoverableErr = err
+ return err
+ }
}
- return repo.Zip(f, mod.Version)
+ return err
})
if err != nil {
return err
@@ -341,10 +315,10 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
func makeDirsReadOnly(dir string) {
type pathMode struct {
path string
- mode os.FileMode
+ mode fs.FileMode
}
var dirs []pathMode // in lexical order
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
if err == nil && info.Mode()&0222 != 0 {
if info.IsDir() {
dirs = append(dirs, pathMode{path, info.Mode()})
@@ -363,7 +337,7 @@ func makeDirsReadOnly(dir string) {
// any permission changes needed to do so.
func RemoveAll(dir string) error {
// Module cache has 0555 directories; make them writable in order to remove content.
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return nil // ignore errors walking in file system
}
@@ -454,6 +428,28 @@ func readGoSum(dst map[module.Version][]string, file string, data []byte) error
return nil
}
+// HaveSum returns true if the go.sum file contains an entry for mod.
+// The entry's hash must be generated with a known hash algorithm.
+// mod.Version may have a "/go.mod" suffix to distinguish sums for
+// .mod and .zip files.
+func HaveSum(mod module.Version) bool {
+ goSum.mu.Lock()
+ defer goSum.mu.Unlock()
+ inited, err := initGoSum()
+ if err != nil || !inited {
+ return false
+ }
+ for _, h := range goSum.m[mod] {
+ if !strings.HasPrefix(h, "h1:") {
+ continue
+ }
+ if !goSum.status[modSum{mod, h}].dirty {
+ return true
+ }
+ }
+ return false
+}
+
// checkMod checks the given module's checksum.
func checkMod(mod module.Version) {
if cfg.GOMODCACHE == "" {
@@ -468,7 +464,7 @@ func checkMod(mod module.Version) {
}
data, err := renameio.ReadFile(ziphash)
if err != nil {
- if errors.Is(err, os.ErrNotExist) {
+ if errors.Is(err, fs.ErrNotExist) {
// This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes.
return
}
@@ -487,7 +483,7 @@ func checkMod(mod module.Version) {
// goModSum returns the checksum for the go.mod contents.
func goModSum(data []byte) (string, error) {
return dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) {
- return ioutil.NopCloser(bytes.NewReader(data)), nil
+ return io.NopCloser(bytes.NewReader(data)), nil
})
}
diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go
index 4ac26650a9..d75b4da521 100644
--- a/src/cmd/go/internal/modfetch/proxy.go
+++ b/src/cmd/go/internal/modfetch/proxy.go
@@ -9,9 +9,8 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
+ "io/fs"
"net/url"
- "os"
"path"
pathpkg "path"
"path/filepath"
@@ -186,7 +185,7 @@ func proxyList() ([]proxySpec, error) {
// TryProxies iterates f over each configured proxy (including "noproxy" and
// "direct" if applicable) until f returns no error or until f returns an
-// error that is not equivalent to os.ErrNotExist on a proxy configured
+// error that is not equivalent to fs.ErrNotExist on a proxy configured
// not to fall back on errors.
//
// TryProxies then returns that final error.
@@ -222,7 +221,7 @@ func TryProxies(f func(proxy string) error) error {
if err == nil {
return nil
}
- isNotExistErr := errors.Is(err, os.ErrNotExist)
+ isNotExistErr := errors.Is(err, fs.ErrNotExist)
if proxy.url == "direct" || (proxy.url == "noproxy" && err != errUseProxy) {
bestErr = err
@@ -305,7 +304,7 @@ func (p *proxyRepo) getBytes(path string) ([]byte, error) {
return nil, err
}
defer body.Close()
- return ioutil.ReadAll(body)
+ return io.ReadAll(body)
}
func (p *proxyRepo) getBody(path string) (io.ReadCloser, error) {
@@ -428,7 +427,7 @@ func (p *proxyRepo) Stat(rev string) (*RevInfo, error) {
func (p *proxyRepo) Latest() (*RevInfo, error) {
data, err := p.getBytes("@latest")
if err != nil {
- if !errors.Is(err, os.ErrNotExist) {
+ if !errors.Is(err, fs.ErrNotExist) {
return nil, p.versionError("", err)
}
return p.latest()
diff --git a/src/cmd/go/internal/modfetch/pseudo.go b/src/cmd/go/internal/modfetch/pseudo.go
index 20c0b060ab..93eb0fad96 100644
--- a/src/cmd/go/internal/modfetch/pseudo.go
+++ b/src/cmd/go/internal/modfetch/pseudo.go
@@ -76,6 +76,12 @@ func PseudoVersion(major, older string, t time.Time, rev string) string {
return v + incDecimal(patch) + "-0." + segment + build
}
+// ZeroPseudoVersion returns a pseudo-version with a zero timestamp and
+// revision, which may be used as a placeholder.
+func ZeroPseudoVersion(major string) string {
+ return PseudoVersion(major, "", time.Time{}, "000000000000")
+}
+
// incDecimal returns the decimal string incremented by 1.
func incDecimal(decimal string) string {
// Scan right to left turning 9s to 0s until you find a digit to increment.
@@ -120,6 +126,12 @@ func IsPseudoVersion(v string) bool {
return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v)
}
+// IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base,
+// timestamp, and revision, as returned by ZeroPseudoVersion.
+func IsZeroPseudoVersion(v string) bool {
+ return v == ZeroPseudoVersion(semver.Major(v))
+}
+
// PseudoVersionTime returns the time stamp of the pseudo-version v.
// It returns an error if v is not a pseudo-version or if the time stamp
// embedded in the pseudo-version is not a valid time.
diff --git a/src/cmd/go/internal/modfetch/repo.go b/src/cmd/go/internal/modfetch/repo.go
index eed4dd4258..af9e24cefd 100644
--- a/src/cmd/go/internal/modfetch/repo.go
+++ b/src/cmd/go/internal/modfetch/repo.go
@@ -7,6 +7,7 @@ package modfetch
import (
"fmt"
"io"
+ "io/fs"
"os"
"sort"
"strconv"
@@ -32,8 +33,17 @@ type Repo interface {
// Versions lists all known versions with the given prefix.
// Pseudo-versions are not included.
+ //
// Versions should be returned sorted in semver order
// (implementations can use SortVersions).
+ //
+ // Versions returns a non-nil error only if there was a problem
+ // fetching the list of versions: it may return an empty list
+ // along with a nil error if the list of matching versions
+ // is known to be empty.
+ //
+ // If the underlying repository does not exist,
+ // Versions returns an error matching errors.Is(_, os.NotExist).
Versions(prefix string) ([]string, error)
// Stat returns information about the revision rev.
@@ -188,27 +198,26 @@ type lookupCacheKey struct {
//
// A successful return does not guarantee that the module
// has any defined versions.
-func Lookup(proxy, path string) (Repo, error) {
+func Lookup(proxy, path string) Repo {
if traceRepo {
defer logCall("Lookup(%q, %q)", proxy, path)()
}
type cached struct {
- r Repo
- err error
+ r Repo
}
c := lookupCache.Do(lookupCacheKey{proxy, path}, func() interface{} {
- r, err := lookup(proxy, path)
- if err == nil {
- if traceRepo {
+ r := newCachingRepo(path, func() (Repo, error) {
+ r, err := lookup(proxy, path)
+ if err == nil && traceRepo {
r = newLoggingRepo(r)
}
- r = newCachingRepo(r)
- }
- return cached{r, err}
+ return r, err
+ })
+ return cached{r}
}).(cached)
- return c.r, c.err
+ return c.r
}
// lookup returns the module with the given module path.
@@ -228,7 +237,7 @@ func lookup(proxy, path string) (r Repo, err error) {
switch proxy {
case "off":
- return nil, errProxyOff
+ return errRepo{path, errProxyOff}, nil
case "direct":
return lookupDirect(path)
case "noproxy":
@@ -407,7 +416,24 @@ func (l *loggingRepo) Zip(dst io.Writer, version string) error {
return l.r.Zip(dst, version)
}
-// A notExistError is like os.ErrNotExist, but with a custom message
+// errRepo is a Repo that returns the same error for all operations.
+//
+// It is useful in conjunction with caching, since cache hits will not attempt
+// the prohibited operations.
+type errRepo struct {
+ modulePath string
+ err error
+}
+
+func (r errRepo) ModulePath() string { return r.modulePath }
+
+func (r errRepo) Versions(prefix string) (tags []string, err error) { return nil, r.err }
+func (r errRepo) Stat(rev string) (*RevInfo, error) { return nil, r.err }
+func (r errRepo) Latest() (*RevInfo, error) { return nil, r.err }
+func (r errRepo) GoMod(version string) ([]byte, error) { return nil, r.err }
+func (r errRepo) Zip(dst io.Writer, version string) error { return r.err }
+
+// A notExistError is like fs.ErrNotExist, but with a custom message
type notExistError struct {
err error
}
@@ -421,7 +447,7 @@ func (e notExistError) Error() string {
}
func (notExistError) Is(target error) bool {
- return target == os.ErrNotExist
+ return target == fs.ErrNotExist
}
func (e notExistError) Unwrap() error {
diff --git a/src/cmd/go/internal/modfetch/sumdb.go b/src/cmd/go/internal/modfetch/sumdb.go
index 47a2571531..4fbc54d15c 100644
--- a/src/cmd/go/internal/modfetch/sumdb.go
+++ b/src/cmd/go/internal/modfetch/sumdb.go
@@ -12,7 +12,8 @@ import (
"bytes"
"errors"
"fmt"
- "io/ioutil"
+ "io"
+ "io/fs"
"net/url"
"os"
"path/filepath"
@@ -182,7 +183,7 @@ func (c *dbClient) initBase() {
return nil
}
})
- if errors.Is(err, os.ErrNotExist) {
+ if errors.Is(err, fs.ErrNotExist) {
// No proxies, or all proxies failed (with 404, 410, or were were allowed
// to fall back), or we reached an explicit "direct" or "off".
c.base = c.direct
@@ -203,7 +204,7 @@ func (c *dbClient) ReadConfig(file string) (data []byte, err error) {
}
targ := filepath.Join(cfg.SumdbDir, file)
data, err = lockedfile.Read(targ)
- if errors.Is(err, os.ErrNotExist) {
+ if errors.Is(err, fs.ErrNotExist) {
// Treat non-existent as empty, to bootstrap the "latest" file
// the first time we connect to a given database.
return []byte{}, nil
@@ -227,7 +228,7 @@ func (*dbClient) WriteConfig(file string, old, new []byte) error {
return err
}
defer f.Close()
- data, err := ioutil.ReadAll(f)
+ data, err := io.ReadAll(f)
if err != nil {
return err
}
@@ -257,7 +258,7 @@ func (*dbClient) ReadCache(file string) ([]byte, error) {
// during which the empty file can be locked for reading.
// Treat observing an empty file as file not found.
if err == nil && len(data) == 0 {
- err = &os.PathError{Op: "read", Path: targ, Err: os.ErrNotExist}
+ err = &fs.PathError{Op: "read", Path: targ, Err: fs.ErrNotExist}
}
return data, err
}
diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
index f1cf8b17a8..171c070ab3 100644
--- a/src/cmd/go/internal/modget/get.go
+++ b/src/cmd/go/internal/modget/get.go
@@ -115,13 +115,12 @@ require downgrading other dependencies, and 'go get' does
this automatically as well.
The -insecure flag permits fetching from repositories and resolving
-custom domains using insecure schemes such as HTTP. Use with caution.
+custom domains using insecure schemes such as HTTP, and also bypassess
+module sum validation using the checksum database. Use with caution.
This flag is deprecated and will be removed in a future version of go.
-The GOINSECURE environment variable is usually a better alternative, since
-it provides control over which modules may be retrieved using an insecure
-scheme. It should be noted that the -insecure flag also turns the module
-checksum validation off. GOINSECURE does not do that, use GONOSUMDB.
-See 'go help environment' for details.
+To permit the use of insecure schemes, use the GOINSECURE environment
+variable instead. To bypass module sum validation, use GOPRIVATE or
+GONOSUMDB. See 'go help environment' for details.
The second step is to download (if needed), build, and install
the named packages.
@@ -875,6 +874,8 @@ func getQuery(ctx context.Context, path, vers string, prevM module.Version, forc
allowed := modload.CheckAllowed
if modload.IsRevisionQuery(vers) {
allowed = modload.CheckExclusions
+ } else if vers == "upgrade" || vers == "patch" {
+ allowed = checkAllowedOrCurrent(prevM.Version)
}
// If the query must be a module path, try only that module path.
@@ -911,7 +912,7 @@ func getQuery(ctx context.Context, path, vers string, prevM module.Version, forc
// If it turns out to only exist as a module, we can detect the resulting
// PackageNotInModuleError and avoid a second round-trip through (potentially)
// all of the configured proxies.
- results, err := modload.QueryPattern(ctx, path, vers, allowed)
+ results, err := modload.QueryPattern(ctx, path, vers, modload.Selected, allowed)
if err != nil {
// If the path doesn't contain a wildcard, check whether it was actually a
// module path instead. If so, return that.
@@ -982,3 +983,18 @@ func logOncef(format string, args ...interface{}) {
fmt.Fprintln(os.Stderr, msg)
}
}
+
+// checkAllowedOrCurrent is like modload.CheckAllowed, but always allows the
+// current version (even if it is retracted or otherwise excluded).
+func checkAllowedOrCurrent(current string) modload.AllowedFunc {
+ if current == "" {
+ return modload.CheckAllowed
+ }
+
+ return func(ctx context.Context, m module.Version) error {
+ if m.Version == current {
+ return nil
+ }
+ return modload.CheckAllowed(ctx, m)
+ }
+}
diff --git a/src/cmd/go/internal/modget/mvs.go b/src/cmd/go/internal/modget/mvs.go
index 19fffd2947..e7e0ec80d0 100644
--- a/src/cmd/go/internal/modget/mvs.go
+++ b/src/cmd/go/internal/modget/mvs.go
@@ -145,7 +145,7 @@ func (u *upgrader) Upgrade(m module.Version) (module.Version, error) {
// If we're querying "upgrade" or "patch", Query will compare the current
// version against the chosen version and will return the current version
// if it is newer.
- info, err := modload.Query(context.TODO(), m.Path, string(getU), m.Version, modload.CheckAllowed)
+ info, err := modload.Query(context.TODO(), m.Path, string(getU), m.Version, checkAllowedOrCurrent(m.Version))
if err != nil {
// Report error but return m, to let version selection continue.
// (Reporting the error will fail the command at the next base.ExitIfErrors.)
diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go
index f49b52df56..b9abb0b93c 100644
--- a/src/cmd/go/internal/modload/build.go
+++ b/src/cmd/go/internal/modload/build.go
@@ -13,7 +13,6 @@ import (
"internal/goroot"
"os"
"path/filepath"
- "runtime/debug"
"strings"
"cmd/go/internal/base"
@@ -312,9 +311,6 @@ func mustFindModule(target, path string) module.Version {
return Target
}
- if printStackInDie {
- debug.PrintStack()
- }
base.Fatalf("build %v: cannot find module for path %v", target, path)
panic("unreachable")
}
diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go
index 059b020420..4a183d6881 100644
--- a/src/cmd/go/internal/modload/buildlist.go
+++ b/src/cmd/go/internal/modload/buildlist.go
@@ -37,7 +37,7 @@ var buildList []module.Version
//
// The caller must not modify the returned list.
func LoadAllModules(ctx context.Context) []module.Version {
- InitMod(ctx)
+ LoadModFile(ctx)
ReloadBuildList()
WriteGoMod()
return buildList
@@ -52,6 +52,21 @@ func LoadedModules() []module.Version {
return buildList
}
+// Selected returns the selected version of the module with the given path, or
+// the empty string if the given module has no selected version
+// (either because it is not required or because it is the Target module).
+func Selected(path string) (version string) {
+ if path == Target.Path {
+ return ""
+ }
+ for _, m := range buildList {
+ if m.Path == path {
+ return m.Version
+ }
+ }
+ return ""
+}
+
// SetBuildList sets the module build list.
// The caller is responsible for ensuring that the list is valid.
// SetBuildList does not retain a reference to the original list.
@@ -63,7 +78,9 @@ func SetBuildList(list []module.Version) {
// the build list set in SetBuildList.
func ReloadBuildList() []module.Version {
loaded = loadFromRoots(loaderParams{
- tags: imports.Tags(),
+ PackageOpts: PackageOpts{
+ Tags: imports.Tags(),
+ },
listRoots: func() []string { return nil },
allClosesOverTests: index.allPatternClosesOverTests(), // but doesn't matter because the root list is empty.
})
diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go
index c36c8bd29b..e959347020 100644
--- a/src/cmd/go/internal/modload/import.go
+++ b/src/cmd/go/internal/modload/import.go
@@ -10,13 +10,14 @@ import (
"fmt"
"go/build"
"internal/goroot"
+ "io/fs"
"os"
"path/filepath"
"sort"
"strings"
- "time"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/modfetch"
"cmd/go/internal/par"
"cmd/go/internal/search"
@@ -25,13 +26,25 @@ import (
"golang.org/x/mod/semver"
)
-var errImportMissing = errors.New("import missing")
-
type ImportMissingError struct {
Path string
Module module.Version
QueryErr error
+ // inAll indicates whether Path is in the "all" package pattern,
+ // and thus would be added by 'go mod tidy'.
+ inAll bool
+
+ // isStd indicates whether we would expect to find the package in the standard
+ // library. This is normally true for all dotless import paths, but replace
+ // directives can cause us to treat the replaced paths as also being in
+ // modules.
+ isStd bool
+
+ // replaced the highest replaced version of the module where the replacement
+ // contains the package. replaced is only set if the replacement is unused.
+ replaced module.Version
+
// newMissingVersion is set to a newer version of Module if one is present
// in the build list. When set, we can't automatically upgrade.
newMissingVersion string
@@ -39,13 +52,33 @@ type ImportMissingError struct {
func (e *ImportMissingError) Error() string {
if e.Module.Path == "" {
- if search.IsStandardImportPath(e.Path) {
+ if e.isStd {
return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path))
}
if e.QueryErr != nil {
return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr)
}
- return "cannot find module providing package " + e.Path
+ if cfg.BuildMod == "mod" {
+ return "cannot find module providing package " + e.Path
+ }
+
+ if e.replaced.Path != "" {
+ suggestArg := e.replaced.Path
+ if !modfetch.IsZeroPseudoVersion(e.replaced.Version) {
+ suggestArg = e.replaced.String()
+ }
+ return fmt.Sprintf("module %s provides package %s and is replaced but not required; try 'go get -d %s' to add it", e.replaced.Path, e.Path, suggestArg)
+ }
+
+ suggestion := ""
+ if !HasModRoot() {
+ suggestion = ": working directory is not part of a module"
+ } else if e.inAll {
+ suggestion = "; try 'go mod tidy' to add it"
+ } else {
+ suggestion = fmt.Sprintf("; try 'go get -d %s' to add it", e.Path)
+ }
+ return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion)
}
if e.newMissingVersion != "" {
@@ -102,6 +135,31 @@ func (e *AmbiguousImportError) Error() string {
return buf.String()
}
+// ImportMissingSumError is reported in readonly mode when we need to check
+// if a module in the build list contains a package, but we don't have a sum
+// for its .zip file.
+type ImportMissingSumError struct {
+ importPath string
+ found, inAll bool
+}
+
+func (e *ImportMissingSumError) Error() string {
+ var message string
+ if e.found {
+ message = fmt.Sprintf("missing go.sum entry needed to verify package %s is provided by exactly one module", e.importPath)
+ } else {
+ message = fmt.Sprintf("missing go.sum entry for module providing package %s", e.importPath)
+ }
+ if e.inAll {
+ return message + "; try 'go mod tidy' to add it"
+ }
+ return message
+}
+
+func (e *ImportMissingSumError) ImportPath() string {
+ return e.importPath
+}
+
type invalidImportError struct {
importPath string
err error
@@ -131,7 +189,7 @@ func (e *invalidImportError) Unwrap() error {
// like "C" and "unsafe".
//
// If the package cannot be found in the current build list,
-// importFromBuildList returns errImportMissing as the error.
+// importFromBuildList returns an *ImportMissingError.
func importFromBuildList(ctx context.Context, path string) (m module.Version, dir string, err error) {
if strings.Contains(path, "@") {
return module.Version{}, "", fmt.Errorf("import path should not have @version")
@@ -143,6 +201,10 @@ func importFromBuildList(ctx context.Context, path string) (m module.Version, di
// There's no directory for import "C" or import "unsafe".
return module.Version{}, "", nil
}
+ // Before any further lookup, check that the path is valid.
+ if err := module.CheckImportPath(path); err != nil {
+ return module.Version{}, "", &invalidImportError{importPath: path, err: err}
+ }
// Is the package in the standard library?
pathIsStd := search.IsStandardImportPath(path)
@@ -182,13 +244,23 @@ func importFromBuildList(ctx context.Context, path string) (m module.Version, di
// Check each module on the build list.
var dirs []string
var mods []module.Version
+ haveSumErr := false
for _, m := range buildList {
if !maybeInModule(path, m.Path) {
// Avoid possibly downloading irrelevant modules.
continue
}
- root, isLocal, err := fetch(ctx, m)
+ needSum := true
+ root, isLocal, err := fetch(ctx, m, needSum)
if err != nil {
+ if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) {
+ // We are missing a sum needed to fetch a module in the build list.
+ // We can't verify that the package is unique, and we may not find
+ // the package at all. Keep checking other modules to decide which
+ // error to report.
+ haveSumErr = true
+ continue
+ }
// Report fetch error.
// Note that we don't know for sure this module is necessary,
// but it certainly _could_ provide the package, and even if we
@@ -204,60 +276,46 @@ func importFromBuildList(ctx context.Context, path string) (m module.Version, di
dirs = append(dirs, dir)
}
}
+ if len(mods) > 1 {
+ return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
+ }
+ if haveSumErr {
+ return module.Version{}, "", &ImportMissingSumError{importPath: path, found: len(mods) > 0}
+ }
if len(mods) == 1 {
return mods[0], dirs[0], nil
}
- if len(mods) > 0 {
- return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: dirs, Modules: mods}
- }
- return module.Version{}, "", errImportMissing
+ return module.Version{}, "", &ImportMissingError{Path: path, isStd: pathIsStd}
}
// queryImport attempts to locate a module that can be added to the current
// build list to provide the package with the given import path.
+//
+// Unlike QueryPattern, queryImport prefers to add a replaced version of a
+// module *before* checking the proxies for a version to add.
func queryImport(ctx context.Context, path string) (module.Version, error) {
- pathIsStd := search.IsStandardImportPath(path)
-
- if modRoot == "" && !allowMissingModuleImports {
- return module.Version{}, &ImportMissingError{
- Path: path,
- QueryErr: errors.New("working directory is not part of a module"),
- }
- }
-
- // Not on build list.
- // To avoid spurious remote fetches, next try the latest replacement for each
- // module (golang.org/issue/26241). This should give a useful message
- // in -mod=readonly, and it will allow us to add a requirement with -mod=mod.
- if modFile != nil {
- latest := map[string]string{} // path -> version
- for _, r := range modFile.Replace {
- if maybeInModule(path, r.Old.Path) {
- // Don't use semver.Max here; need to preserve +incompatible suffix.
- v := latest[r.Old.Path]
- if semver.Compare(r.Old.Version, v) > 0 {
- v = r.Old.Version
- }
- latest[r.Old.Path] = v
+ // To avoid spurious remote fetches, try the latest replacement for each
+ // module (golang.org/issue/26241).
+ if index != nil {
+ var mods []module.Version
+ for mp, mv := range index.highestReplaced {
+ if !maybeInModule(path, mp) {
+ continue
}
- }
-
- mods := make([]module.Version, 0, len(latest))
- for p, v := range latest {
- // If the replacement didn't specify a version, synthesize a
- // pseudo-version with an appropriate major version and a timestamp below
- // any real timestamp. That way, if the main module is used from within
- // some other module, the user will be able to upgrade the requirement to
- // any real version they choose.
- if v == "" {
- if _, pathMajor, ok := module.SplitPathVersion(p); ok && len(pathMajor) > 0 {
- v = modfetch.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000")
+ if mv == "" {
+ // The only replacement is a wildcard that doesn't specify a version, so
+ // synthesize a pseudo-version with an appropriate major version and a
+ // timestamp below any real timestamp. That way, if the main module is
+ // used from within some other module, the user will be able to upgrade
+ // the requirement to any real version they choose.
+ if _, pathMajor, ok := module.SplitPathVersion(mp); ok && len(pathMajor) > 0 {
+ mv = modfetch.ZeroPseudoVersion(pathMajor[1:])
} else {
- v = modfetch.PseudoVersion("v0", "", time.Time{}, "000000000000")
+ mv = modfetch.ZeroPseudoVersion("v0")
}
}
- mods = append(mods, module.Version{Path: p, Version: v})
+ mods = append(mods, module.Version{Path: mp, Version: mv})
}
// Every module path in mods is a prefix of the import path.
@@ -266,20 +324,26 @@ func queryImport(ctx context.Context, path string) (module.Version, error) {
return len(mods[i].Path) > len(mods[j].Path)
})
for _, m := range mods {
- root, isLocal, err := fetch(ctx, m)
+ needSum := true
+ root, isLocal, err := fetch(ctx, m, needSum)
if err != nil {
- // Report fetch error as above.
+ if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) {
+ return module.Version{}, &ImportMissingSumError{importPath: path}
+ }
return module.Version{}, err
}
if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
return m, err
} else if ok {
+ if cfg.BuildMod == "readonly" {
+ return module.Version{}, &ImportMissingError{Path: path, replaced: m}
+ }
return m, nil
}
}
if len(mods) > 0 && module.CheckPath(path) != nil {
// The package path is not valid to fetch remotely,
- // so it can only exist if in a replaced module,
+ // so it can only exist in a replaced module,
// and we know from the above loop that it is not.
return module.Version{}, &PackageNotInModuleError{
Mod: mods[0],
@@ -290,12 +354,7 @@ func queryImport(ctx context.Context, path string) (module.Version, error) {
}
}
- // Before any further lookup, check that the path is valid.
- if err := module.CheckImportPath(path); err != nil {
- return module.Version{}, &invalidImportError{importPath: path, err: err}
- }
-
- if pathIsStd {
+ if search.IsStandardImportPath(path) {
// This package isn't in the standard library, isn't in any module already
// in the build list, and isn't in any other module that the user has
// shimmed in via a "replace" directive.
@@ -303,10 +362,13 @@ func queryImport(ctx context.Context, path string) (module.Version, error) {
// QueryPattern cannot possibly find a module containing this package.
//
// Instead of trying QueryPattern, report an ImportMissingError immediately.
- return module.Version{}, &ImportMissingError{Path: path}
+ return module.Version{}, &ImportMissingError{Path: path, isStd: true}
}
if cfg.BuildMod == "readonly" {
+ // In readonly mode, we can't write go.mod, so we shouldn't try to look up
+ // the module. If readonly mode was enabled explicitly, include that in
+ // the error message.
var queryErr error
if cfg.BuildModExplicit {
queryErr = fmt.Errorf("import lookup disabled by -mod=%s", cfg.BuildMod)
@@ -321,9 +383,9 @@ func queryImport(ctx context.Context, path string) (module.Version, error) {
// and return m, dir, ImpportMissingError.
fmt.Fprintf(os.Stderr, "go: finding module for package %s\n", path)
- candidates, err := QueryPattern(ctx, path, "latest", CheckAllowed)
+ candidates, err := QueryPattern(ctx, path, "latest", Selected, CheckAllowed)
if err != nil {
- if errors.Is(err, os.ErrNotExist) {
+ if errors.Is(err, fs.ErrNotExist) {
// Return "cannot find module providing package […]" instead of whatever
// low-level error QueryPattern produced.
return module.Version{}, &ImportMissingError{Path: path, QueryErr: err}
@@ -438,57 +500,65 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
// We don't care about build tags, not even "+build ignore".
// We're just looking for a plausible directory.
res := haveGoFilesCache.Do(dir, func() interface{} {
- ok, err := isDirWithGoFiles(dir)
+ ok, err := fsys.IsDirWithGoFiles(dir)
return goFilesEntry{haveGoFiles: ok, err: err}
}).(goFilesEntry)
return dir, res.haveGoFiles, res.err
}
-func isDirWithGoFiles(dir string) (bool, error) {
- f, err := os.Open(dir)
- if err != nil {
- if os.IsNotExist(err) {
- return false, nil
- }
- return false, err
- }
- defer f.Close()
-
- names, firstErr := f.Readdirnames(-1)
- if firstErr != nil {
- if fi, err := f.Stat(); err == nil && !fi.IsDir() {
- return false, nil
- }
-
- // Rewrite the error from ReadDirNames to include the path if not present.
- // See https://golang.org/issue/38923.
- var pe *os.PathError
- if !errors.As(firstErr, &pe) {
- firstErr = &os.PathError{Op: "readdir", Path: dir, Err: firstErr}
- }
+// fetch downloads the given module (or its replacement)
+// and returns its location.
+//
+// needSum indicates whether the module may be downloaded in readonly mode
+// without a go.sum entry. It should only be false for modules fetched
+// speculatively (for example, for incompatible version filtering). The sum
+// will still be verified normally.
+//
+// The isLocal return value reports whether the replacement,
+// if any, is local to the filesystem.
+func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, isLocal bool, err error) {
+ if mod == Target {
+ return ModRoot(), true, nil
}
-
- for _, name := range names {
- if strings.HasSuffix(name, ".go") {
- info, err := os.Stat(filepath.Join(dir, name))
- if err == nil && info.Mode().IsRegular() {
- // If any .go source file exists, the package exists regardless of
- // errors for other source files. Leave further error reporting for
- // later.
- return true, nil
+ if r := Replacement(mod); r.Path != "" {
+ if r.Version == "" {
+ dir = r.Path
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(ModRoot(), dir)
}
- if firstErr == nil {
+ // Ensure that the replacement directory actually exists:
+ // dirInModule does not report errors for missing modules,
+ // so if we don't report the error now, later failures will be
+ // very mysterious.
+ if _, err := os.Stat(dir); err != nil {
if os.IsNotExist(err) {
- // If the file was concurrently deleted, or was a broken symlink,
- // convert the error to an opaque error instead of one matching
- // os.IsNotExist.
- err = errors.New(err.Error())
+ // Semantically the module version itself “exists” — we just don't
+ // have its source code. Remove the equivalence to os.ErrNotExist,
+ // and make the message more concise while we're at it.
+ err = fmt.Errorf("replacement directory %s does not exist", r.Path)
+ } else {
+ err = fmt.Errorf("replacement directory %s: %w", r.Path, err)
}
- firstErr = err
+ return dir, true, module.VersionError(mod, err)
}
+ return dir, true, nil
}
+ mod = r
+ }
+
+ if cfg.BuildMod == "readonly" && needSum && !modfetch.HaveSum(mod) {
+ return "", false, module.VersionError(mod, &sumMissingError{})
}
- return false, firstErr
+ dir, err = modfetch.Download(ctx, mod)
+ return dir, false, err
+}
+
+type sumMissingError struct {
+ suggestion string
+}
+
+func (e *sumMissingError) Error() string {
+ return "missing go.sum entry" + e.suggestion
}
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index 3344242489..8fe71a2448 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -16,12 +16,13 @@ import (
"os"
"path"
"path/filepath"
- "runtime/debug"
"strconv"
"strings"
+ "sync"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/lockedfile"
"cmd/go/internal/modconv"
"cmd/go/internal/modfetch"
@@ -50,9 +51,6 @@ var (
gopath string
- CmdModInit bool // running 'go mod init'
- CmdModModule string // module argument for 'go mod init'
-
// RootMode determines whether a module root is needed.
RootMode Root
@@ -132,6 +130,10 @@ func Init() {
return
}
+ if err := fsys.Init(base.Cwd); err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
// Disable any prompting for passwords by Git.
// Only has an effect for 2.3.0 or later, but avoiding
// the prompt in earlier versions is just too hard.
@@ -159,9 +161,9 @@ func Init() {
os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
}
- if CmdModInit {
- // Running 'go mod init': go.mod will be created in current directory.
- modRoot = base.Cwd
+ if modRoot != "" {
+ // modRoot set before Init was called ("go mod init" does this).
+ // No need to search for go.mod.
} else if RootMode == NoRoot {
if cfg.ModFile != "" && !base.InGOFLAGS("-modfile") {
base.Fatalf("go: -modfile cannot be used with commands that ignore the current module")
@@ -198,8 +200,7 @@ func Init() {
base.Fatalf("go: -modfile=%s: file does not have .mod extension", cfg.ModFile)
}
- // We're in module mode. Install the hooks to make it work.
-
+ // We're in module mode. Set any global variables that need to be set.
list := filepath.SplitList(cfg.BuildContext.GOPATH)
if len(list) == 0 || list[0] == "" {
base.Fatalf("missing $GOPATH")
@@ -266,10 +267,6 @@ func WillBeEnabled() bool {
return false
}
- if CmdModInit {
- // Running 'go mod init': go.mod will be created in current directory.
- return true
- }
if modRoot := findModuleRoot(base.Cwd); modRoot == "" {
// GO111MODULE is 'auto', and we can't find a module root.
// Stay in GOPATH mode.
@@ -325,16 +322,7 @@ func ModFilePath() string {
return filepath.Join(modRoot, "go.mod")
}
-// printStackInDie causes die to print a stack trace.
-//
-// It is enabled by the testgo tag, and helps to diagnose paths that
-// unexpectedly require a main module.
-var printStackInDie = false
-
func die() {
- if printStackInDie {
- debug.PrintStack()
- }
if cfg.Getenv("GO111MODULE") == "off" {
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
}
@@ -352,16 +340,16 @@ func die() {
base.Fatalf("go: cannot find main module; see 'go help modules'")
}
-// InitMod sets Target and, if there is a main module, parses the initial build
-// list from its go.mod file. If InitMod is called by 'go mod init', InitMod
-// will populate go.mod in memory, possibly importing dependencies from a
-// legacy configuration file. For other commands, InitMod may make other
-// adjustments in memory, like adding a go directive. WriteGoMod should be
-// called later to write changes out to disk.
+// LoadModFile sets Target and, if there is a main module, parses the initial
+// build list from its go.mod file.
//
-// As a side-effect, InitMod sets a default for cfg.BuildMod if it does not
+// LoadModFile may make changes in memory, like adding a go directive and
+// ensuring requirements are consistent. WriteGoMod should be called later to
+// write changes out to disk or report errors in readonly mode.
+//
+// As a side-effect, LoadModFile sets a default for cfg.BuildMod if it does not
// already have an explicit value.
-func InitMod(ctx context.Context) {
+func LoadModFile(ctx context.Context) {
if len(buildList) > 0 {
return
}
@@ -374,13 +362,6 @@ func InitMod(ctx context.Context) {
return
}
- if CmdModInit {
- // Running go mod init: do legacy module conversion
- legacyModInit()
- modFileToBuildList()
- return
- }
-
gomod := ModFilePath()
data, err := lockedfile.Read(gomod)
if err != nil {
@@ -401,12 +382,6 @@ func InitMod(ctx context.Context) {
base.Fatalf("go: no module declaration in go.mod.\n\tRun 'go mod edit -module=example.com/mod' to specify the module path.")
}
- if len(f.Syntax.Stmt) == 1 && f.Module != nil {
- // Entire file is just a module statement.
- // Populate require if possible.
- legacyModInit()
- }
-
if err := checkModulePathLax(f.Module.Mod.Path); err != nil {
base.Fatalf("go: %v", err)
}
@@ -419,6 +394,73 @@ func InitMod(ctx context.Context) {
}
}
+// CreateModFile initializes a new module by creating a go.mod file.
+//
+// If modPath is empty, CreateModFile will attempt to infer the path from the
+// directory location within GOPATH.
+//
+// If a vendoring configuration file is present, CreateModFile will attempt to
+// translate it to go.mod directives. The resulting build list may not be
+// exactly the same as in the legacy configuration (for example, we can't get
+// packages at multiple versions from the same module).
+func CreateModFile(ctx context.Context, modPath string) {
+ modRoot = base.Cwd
+ Init()
+ modFilePath := ModFilePath()
+ if _, err := os.Stat(modFilePath); err == nil {
+ base.Fatalf("go: %s already exists", modFilePath)
+ }
+
+ if modPath == "" {
+ var err error
+ modPath, err = findModulePath(modRoot)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ } else if err := checkModulePathLax(modPath); err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
+ fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath)
+ modFile = new(modfile.File)
+ modFile.AddModuleStmt(modPath)
+ addGoStmt() // Add the go directive before converted module requirements.
+
+ convertedFrom, err := convertLegacyConfig(modPath)
+ if convertedFrom != "" {
+ fmt.Fprintf(os.Stderr, "go: copying requirements from %s\n", base.ShortPath(convertedFrom))
+ }
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
+ modFileToBuildList()
+ WriteGoMod()
+
+ // Suggest running 'go mod tidy' unless the project is empty. Even if we
+ // imported all the correct requirements above, we're probably missing
+ // some sums, so the next build command in -mod=readonly will likely fail.
+ //
+ // We look for non-hidden .go files or subdirectories to determine whether
+ // this is an existing project. Walking the tree for packages would be more
+ // accurate, but could take much longer.
+ empty := true
+ fis, _ := ioutil.ReadDir(modRoot)
+ for _, fi := range fis {
+ name := fi.Name()
+ if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") {
+ continue
+ }
+ if strings.HasSuffix(name, ".go") || fi.IsDir() {
+ empty = false
+ break
+ }
+ }
+ if !empty {
+ fmt.Fprintf(os.Stderr, "go: run 'go mod tidy' to add module requirements and sums\n")
+ }
+}
+
// checkModulePathLax checks that the path meets some minimum requirements
// to avoid confusing users or the module cache. The requirements are weaker
// than those of module.CheckPath to allow room for weakening module path
@@ -585,38 +627,23 @@ func setDefaultBuildMod() {
cfg.BuildMod = "readonly"
}
-func legacyModInit() {
- if modFile == nil {
- path, err := findModulePath(modRoot)
- if err != nil {
- base.Fatalf("go: %v", err)
- }
- fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", path)
- modFile = new(modfile.File)
- modFile.AddModuleStmt(path)
- addGoStmt() // Add the go directive before converted module requirements.
- }
-
+// convertLegacyConfig imports module requirements from a legacy vendoring
+// configuration file, if one is present.
+func convertLegacyConfig(modPath string) (from string, err error) {
for _, name := range altConfigs {
cfg := filepath.Join(modRoot, name)
data, err := ioutil.ReadFile(cfg)
if err == nil {
convert := modconv.Converters[name]
if convert == nil {
- return
+ return "", nil
}
- fmt.Fprintf(os.Stderr, "go: copying requirements from %s\n", base.ShortPath(cfg))
cfg = filepath.ToSlash(cfg)
- if err := modconv.ConvertLegacyConfig(modFile, cfg, data); err != nil {
- base.Fatalf("go: %v", err)
- }
- if len(modFile.Syntax.Stmt) == 1 {
- // Add comment to avoid re-converting every time it runs.
- modFile.AddComment("// go: no requirements found in " + name)
- }
- return
+ err := modconv.ConvertLegacyConfig(modFile, cfg, data)
+ return name, err
}
}
+ return "", nil
}
// addGoStmt adds a go directive to the go.mod file if it does not already include one.
@@ -696,14 +723,6 @@ func findAltConfig(dir string) (root, name string) {
}
func findModulePath(dir string) (string, error) {
- if CmdModModule != "" {
- // Running go mod init x/y/z; return x/y/z.
- if err := module.CheckImportPath(CmdModModule); err != nil {
- return "", err
- }
- return CmdModModule, nil
- }
-
// TODO(bcmills): once we have located a plausible module path, we should
// query version control (if available) to verify that it matches the major
// version of the most recent tag.
@@ -893,7 +912,10 @@ func WriteGoMod() {
// The go.mod file has the same semantic content that it had before
// (but not necessarily the same exact bytes).
// Don't write go.mod, but write go.sum in case we added or trimmed sums.
- modfetch.WriteGoSum(keepSums(true))
+ // 'go mod init' shouldn't write go.sum, since it will be incomplete.
+ if cfg.CmdName != "mod init" {
+ modfetch.WriteGoSum(keepSums(true))
+ }
return
}
@@ -906,7 +928,10 @@ func WriteGoMod() {
index = indexModFile(new, modFile, false)
// Update go.sum after releasing the side lock and refreshing the index.
- modfetch.WriteGoSum(keepSums(true))
+ // 'go mod init' shouldn't write go.sum, since it will be incomplete.
+ if cfg.CmdName != "mod init" {
+ modfetch.WriteGoSum(keepSums(true))
+ }
}()
// Make a best-effort attempt to acquire the side lock, only to exclude
@@ -951,41 +976,55 @@ func WriteGoMod() {
// If addDirect is true, the set also includes sums for modules directly
// required by go.mod, as represented by the index, with replacements applied.
func keepSums(addDirect bool) map[module.Version]bool {
- // Walk the module graph and keep sums needed by MVS.
+ // Re-derive the build list using the current list of direct requirements.
+ // Keep the sum for the go.mod of each visited module version (or its
+ // replacement).
modkey := func(m module.Version) module.Version {
return module.Version{Path: m.Path, Version: m.Version + "/go.mod"}
}
keep := make(map[module.Version]bool)
- replaced := make(map[module.Version]bool)
- reqs := Reqs()
- var walk func(module.Version)
- walk = func(m module.Version) {
- // If we build using a replacement module, keep the sum for the replacement,
- // since that's the code we'll actually use during a build.
- r := Replacement(m)
- if r.Path == "" {
- keep[modkey(m)] = true
- } else {
- replaced[m] = true
- keep[modkey(r)] = true
- }
- list, _ := reqs.Required(m)
- for _, r := range list {
- if !keep[modkey(r)] && !replaced[r] {
- walk(r)
+ var mu sync.Mutex
+ reqs := &keepSumReqs{
+ Reqs: Reqs(),
+ visit: func(m module.Version) {
+ // If we build using a replacement module, keep the sum for the replacement,
+ // since that's the code we'll actually use during a build.
+ mu.Lock()
+ r := Replacement(m)
+ if r.Path == "" {
+ keep[modkey(m)] = true
+ } else {
+ keep[modkey(r)] = true
}
- }
+ mu.Unlock()
+ },
+ }
+ buildList, err := mvs.BuildList(Target, reqs)
+ if err != nil {
+ panic(fmt.Sprintf("unexpected error reloading build list: %v", err))
}
- walk(Target)
- // Add entries for modules from which packages were loaded.
+ // Add entries for modules in the build list with paths that are prefixes of
+ // paths of loaded packages. We need to retain sums for modules needed to
+ // report ambiguous import errors. We use our re-derived build list,
+ // since the global build list may have been tidied.
if loaded != nil {
- for _, pkg := range loaded.pkgs {
- m := pkg.mod
+ actualMods := make(map[string]module.Version)
+ for _, m := range buildList[1:] {
if r := Replacement(m); r.Path != "" {
- keep[r] = true
+ actualMods[m.Path] = r
} else {
- keep[m] = true
+ actualMods[m.Path] = m
+ }
+ }
+ for _, pkg := range loaded.pkgs {
+ if pkg.testOf != nil || pkg.inStd {
+ continue
+ }
+ for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) {
+ if m, ok := actualMods[prefix]; ok {
+ keep[m] = true
+ }
}
}
}
@@ -1007,6 +1046,18 @@ func keepSums(addDirect bool) map[module.Version]bool {
return keep
}
+// keepSumReqs embeds another Reqs implementation. The Required method
+// calls visit for each version in the module graph.
+type keepSumReqs struct {
+ mvs.Reqs
+ visit func(module.Version)
+}
+
+func (r *keepSumReqs) Required(m module.Version) ([]module.Version, error) {
+ r.visit(m)
+ return r.Reqs.Required(m)
+}
+
func TrimGoSum() {
// Don't retain sums for direct requirements in go.mod. When TrimGoSum is
// called, go.mod has not been updated, and it may contain requirements on
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index 9194f9cc7c..f9c468c8b2 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -98,6 +98,7 @@ import (
"errors"
"fmt"
"go/build"
+ "io/fs"
"os"
"path"
pathpkg "path"
@@ -111,6 +112,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch"
"cmd/go/internal/mvs"
@@ -167,7 +169,7 @@ type PackageOpts struct {
// LoadPackages identifies the set of packages matching the given patterns and
// loads the packages in the import graph rooted at that set.
func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (matches []*search.Match, loadedPackages []string) {
- InitMod(ctx)
+ LoadModFile(ctx)
if opts.Tags == nil {
opts.Tags = imports.Tags()
}
@@ -248,9 +250,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
}
loaded = loadFromRoots(loaderParams{
- tags: opts.Tags,
- loadTests: opts.LoadTests,
- resolveMissing: opts.ResolveMissingImports,
+ PackageOpts: opts,
allClosesOverTests: index.allPatternClosesOverTests() && !opts.UseVendorAll,
allPatternIsRoot: allPatternIsRoot,
@@ -270,11 +270,21 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// Report errors, if any.
checkMultiplePaths()
for _, pkg := range loaded.pkgs {
- if pkg.err != nil && !opts.SilenceErrors {
- if opts.AllowErrors {
- fmt.Fprintf(os.Stderr, "%s: %v\n", pkg.stackText(), pkg.err)
- } else {
- base.Errorf("%s: %v", pkg.stackText(), pkg.err)
+ if pkg.err != nil {
+ if pkg.flags.has(pkgInAll) {
+ if imErr := (*ImportMissingError)(nil); errors.As(pkg.err, &imErr) {
+ imErr.inAll = true
+ } else if sumErr := (*ImportMissingSumError)(nil); errors.As(pkg.err, &sumErr) {
+ sumErr.inAll = true
+ }
+ }
+
+ if !opts.SilenceErrors {
+ if opts.AllowErrors {
+ fmt.Fprintf(os.Stderr, "%s: %v\n", pkg.stackText(), pkg.err)
+ } else {
+ base.Errorf("%s: %v", pkg.stackText(), pkg.err)
+ }
}
}
if !pkg.isTest() {
@@ -352,11 +362,11 @@ func resolveLocalPackage(dir string) (string, error) {
// If the named directory does not exist or contains no Go files,
// the package does not exist.
// Other errors may affect package loading, but not resolution.
- if _, err := os.Stat(absDir); err != nil {
+ if _, err := fsys.Stat(absDir); err != nil {
if os.IsNotExist(err) {
// Canonicalize OS-specific errors to errDirectoryNotFound so that error
// messages will be easier for users to search for.
- return "", &os.PathError{Op: "stat", Path: absDir, Err: errDirectoryNotFound}
+ return "", &fs.PathError{Op: "stat", Path: absDir, Err: errDirectoryNotFound}
}
return "", err
}
@@ -484,7 +494,7 @@ func pathInModuleCache(dir string) string {
// ImportFromFiles adds modules to the build list as needed
// to satisfy the imports in the named Go source files.
func ImportFromFiles(ctx context.Context, gofiles []string) {
- InitMod(ctx)
+ LoadModFile(ctx)
tags := imports.Tags()
imports, testImports, err := imports.ScanFiles(gofiles, tags)
@@ -493,8 +503,10 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
}
loaded = loadFromRoots(loaderParams{
- tags: tags,
- resolveMissing: true,
+ PackageOpts: PackageOpts{
+ Tags: tags,
+ ResolveMissingImports: true,
+ },
allClosesOverTests: index.allPatternClosesOverTests(),
listRoots: func() (roots []string) {
roots = append(roots, imports...)
@@ -647,10 +659,10 @@ type loader struct {
direct map[string]bool // imported directly by main module
}
+// loaderParams configure the packages loaded by, and the properties reported
+// by, a loader instance.
type loaderParams struct {
- tags map[string]bool // tags for scanDir
- loadTests bool
- resolveMissing bool
+ PackageOpts
allClosesOverTests bool // Does the "all" pattern include the transitive closure of tests of packages in "all"?
allPatternIsRoot bool // Is the "all" pattern an additional root?
@@ -809,7 +821,7 @@ func loadFromRoots(params loaderParams) *loader {
ld.buildStacks()
- if !ld.resolveMissing {
+ if !ld.ResolveMissingImports || (!HasModRoot() && !allowMissingModuleImports) {
// We've loaded as much as we can without resolving missing imports.
break
}
@@ -852,7 +864,7 @@ func loadFromRoots(params loaderParams) *loader {
// contributes “direct” imports — so we can't safely mark existing
// dependencies as indirect-only.
// Conservatively mark those dependencies as direct.
- if modFile != nil && (!ld.allPatternIsRoot || !reflect.DeepEqual(ld.tags, imports.AnyTags())) {
+ if modFile != nil && (!ld.allPatternIsRoot || !reflect.DeepEqual(ld.Tags, imports.AnyTags())) {
for _, r := range modFile.Require {
if !r.Indirect {
ld.direct[r.Mod.Path] = true
@@ -872,12 +884,15 @@ func loadFromRoots(params loaderParams) *loader {
func (ld *loader) resolveMissingImports(addedModuleFor map[string]bool) (modAddedBy map[module.Version]*loadPkg) {
var needPkgs []*loadPkg
for _, pkg := range ld.pkgs {
+ if pkg.err == nil {
+ continue
+ }
if pkg.isTest() {
// If we are missing a test, we are also missing its non-test version, and
// we should only add the missing import once.
continue
}
- if pkg.err != errImportMissing {
+ if !errors.As(pkg.err, new(*ImportMissingError)) {
// Leave other errors for Import or load.Packages to report.
continue
}
@@ -980,7 +995,7 @@ func (ld *loader) applyPkgFlags(pkg *loadPkg, flags loadPkgFlags) {
// also in "all" (as above).
wantTest = true
- case ld.loadTests && new.has(pkgIsRoot):
+ case ld.LoadTests && new.has(pkgIsRoot):
// LoadTest explicitly requests tests of “the root packages”.
wantTest = true
}
@@ -1043,7 +1058,7 @@ func (ld *loader) load(pkg *loadPkg) {
ld.applyPkgFlags(pkg, pkgInAll)
}
- imports, testImports, err := scanDir(pkg.dir, ld.tags)
+ imports, testImports, err := scanDir(pkg.dir, ld.Tags)
if err != nil {
pkg.err = err
return
diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go
index 6457a7d968..7a8963246b 100644
--- a/src/cmd/go/internal/modload/modfile.go
+++ b/src/cmd/go/internal/modload/modfile.go
@@ -35,13 +35,14 @@ var modFile *modfile.File
// A modFileIndex is an index of data corresponding to a modFile
// at a specific point in time.
type modFileIndex struct {
- data []byte
- dataNeedsFix bool // true if fixVersion applied a change while parsing data
- module module.Version
- goVersionV string // GoVersion with "v" prefix
- require map[module.Version]requireMeta
- replace map[module.Version]module.Version
- exclude map[module.Version]bool
+ data []byte
+ dataNeedsFix bool // true if fixVersion applied a change while parsing data
+ module module.Version
+ goVersionV string // GoVersion with "v" prefix
+ require map[module.Version]requireMeta
+ replace map[module.Version]module.Version
+ highestReplaced map[string]string // highest replaced version of each module path; empty string for wildcard-only replacements
+ exclude map[module.Version]bool
}
// index is the index of the go.mod file as of when it was last read or written.
@@ -115,9 +116,9 @@ func checkRetractions(ctx context.Context, m module.Version) error {
// Ignore exclusions from the main module's go.mod.
// We may need to account for the current version: for example,
// v2.0.0+incompatible is not "latest" if v1.0.0 is current.
- rev, err := Query(ctx, path, "latest", findCurrentVersion(path), nil)
+ rev, err := Query(ctx, path, "latest", Selected(path), nil)
if err != nil {
- return &entry{err: err}
+ return &entry{nil, err}
}
// Load go.mod for that version.
@@ -138,13 +139,19 @@ func checkRetractions(ctx context.Context, m module.Version) error {
}
summary, err := rawGoModSummary(rm)
if err != nil {
- return &entry{err: err}
+ return &entry{nil, err}
}
- return &entry{retract: summary.retract}
+ return &entry{summary.retract, nil}
}).(*entry)
- if e.err != nil {
- return fmt.Errorf("loading module retractions: %v", e.err)
+ if err := e.err; err != nil {
+ // Attribute the error to the version being checked, not the version from
+ // which the retractions were to be loaded.
+ var mErr *module.ModuleError
+ if errors.As(err, &mErr) {
+ err = mErr.Err
+ }
+ return &retractionLoadingError{m: m, err: err}
}
var rationale []string
@@ -158,7 +165,7 @@ func checkRetractions(ctx context.Context, m module.Version) error {
}
}
if isRetracted {
- return &retractedError{rationale: rationale}
+ return module.VersionError(m, &retractedError{rationale: rationale})
}
return nil
}
@@ -183,6 +190,19 @@ func (e *retractedError) Is(err error) bool {
return err == ErrDisallowed
}
+type retractionLoadingError struct {
+ m module.Version
+ err error
+}
+
+func (e *retractionLoadingError) Error() string {
+ return fmt.Sprintf("loading module retractions for %v: %v", e.m, e.err)
+}
+
+func (e *retractionLoadingError) Unwrap() error {
+ return e.err
+}
+
// ShortRetractionRationale returns a retraction rationale string that is safe
// to print in a terminal. It returns hard-coded strings if the rationale
// is empty, too long, or contains non-printable characters.
@@ -255,6 +275,14 @@ func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileInd
i.replace[r.Old] = r.New
}
+ i.highestReplaced = make(map[string]string)
+ for _, r := range modFile.Replace {
+ v, ok := i.highestReplaced[r.Old.Path]
+ if !ok || semver.Compare(r.Old.Version, v) > 0 {
+ i.highestReplaced[r.Old.Path] = r.Old.Version
+ }
+ }
+
i.exclude = make(map[module.Version]bool, len(modFile.Exclude))
for _, x := range modFile.Exclude {
i.exclude[x.Mod] = true
@@ -378,8 +406,11 @@ type retraction struct {
// taking into account any replacements for m, exclusions of its dependencies,
// and/or vendoring.
//
-// goModSummary cannot be used on the Target module, as its requirements
-// may change.
+// m must be a version in the module graph, reachable from the Target module.
+// In readonly mode, the go.sum file must contain an entry for m's go.mod file
+// (or its replacement). goModSummary must not be called for the Target module
+// itself, as its requirements may change. Use rawGoModSummary for other
+// module versions.
//
// The caller must not modify the returned summary.
func goModSummary(m module.Version) (*modFileSummary, error) {
@@ -414,6 +445,13 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
if actual.Path == "" {
actual = m
}
+ if cfg.BuildMod == "readonly" && actual.Version != "" {
+ key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
+ if !modfetch.HaveSum(key) {
+ suggestion := fmt.Sprintf("; try 'go mod download %s' to add it", m.Path)
+ return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
+ }
+ }
summary, err := rawGoModSummary(actual)
if err != nil {
return nil, err
diff --git a/src/cmd/go/internal/modload/mvs.go b/src/cmd/go/internal/modload/mvs.go
index 24856260d4..76a1d8a12a 100644
--- a/src/cmd/go/internal/modload/mvs.go
+++ b/src/cmd/go/internal/modload/mvs.go
@@ -7,9 +7,6 @@ package modload
import (
"context"
"errors"
- "fmt"
- "os"
- "path/filepath"
"sort"
"cmd/go/internal/modfetch"
@@ -77,11 +74,7 @@ func versions(ctx context.Context, path string, allowed AllowedFunc) ([]string,
// so there's no need for us to add extra caching here.
var versions []string
err := modfetch.TryProxies(func(proxy string) error {
- repo, err := modfetch.Lookup(proxy, path)
- if err != nil {
- return err
- }
- allVersions, err := repo.Versions("")
+ allVersions, err := modfetch.Lookup(proxy, path).Versions("")
if err != nil {
return err
}
@@ -129,42 +122,3 @@ func (*mvsReqs) next(m module.Version) (module.Version, error) {
}
return module.Version{Path: m.Path, Version: "none"}, nil
}
-
-// fetch downloads the given module (or its replacement)
-// and returns its location.
-//
-// The isLocal return value reports whether the replacement,
-// if any, is local to the filesystem.
-func fetch(ctx context.Context, mod module.Version) (dir string, isLocal bool, err error) {
- if mod == Target {
- return ModRoot(), true, nil
- }
- if r := Replacement(mod); r.Path != "" {
- if r.Version == "" {
- dir = r.Path
- if !filepath.IsAbs(dir) {
- dir = filepath.Join(ModRoot(), dir)
- }
- // Ensure that the replacement directory actually exists:
- // dirInModule does not report errors for missing modules,
- // so if we don't report the error now, later failures will be
- // very mysterious.
- if _, err := os.Stat(dir); err != nil {
- if os.IsNotExist(err) {
- // Semantically the module version itself “exists” — we just don't
- // have its source code. Remove the equivalence to os.ErrNotExist,
- // and make the message more concise while we're at it.
- err = fmt.Errorf("replacement directory %s does not exist", r.Path)
- } else {
- err = fmt.Errorf("replacement directory %s: %w", r.Path, err)
- }
- return dir, true, module.VersionError(mod, err)
- }
- return dir, true, nil
- }
- mod = r
- }
-
- dir, err = modfetch.Download(ctx, mod)
- return dir, false, err
-}
diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go
index e75d901ec6..3927051015 100644
--- a/src/cmd/go/internal/modload/query.go
+++ b/src/cmd/go/internal/modload/query.go
@@ -8,17 +8,19 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
pathpkg "path"
"path/filepath"
+ "sort"
"strings"
"sync"
+ "time"
"cmd/go/internal/cfg"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch"
"cmd/go/internal/search"
- "cmd/go/internal/str"
"cmd/go/internal/trace"
"golang.org/x/mod/module"
@@ -106,138 +108,45 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
allowed = func(context.Context, module.Version) error { return nil }
}
- // Parse query to detect parse errors (and possibly handle query)
- // before any network I/O.
- badVersion := func(v string) (*modfetch.RevInfo, error) {
- return nil, fmt.Errorf("invalid semantic version %q in range %q", v, query)
- }
- matchesMajor := func(v string) bool {
- _, pathMajor, ok := module.SplitPathVersion(path)
- if !ok {
- return false
- }
- return module.CheckPathMajor(v, pathMajor) == nil
- }
- var (
- match = func(m module.Version) bool { return true }
-
- prefix string
- preferOlder bool
- mayUseLatest bool
- preferIncompatible bool = strings.HasSuffix(current, "+incompatible")
- )
- switch {
- case query == "latest":
- mayUseLatest = true
-
- case query == "upgrade":
- mayUseLatest = true
-
- case query == "patch":
- if current == "" {
- mayUseLatest = true
- } else {
- prefix = semver.MajorMinor(current)
- match = func(m module.Version) bool {
- return matchSemverPrefix(prefix, m.Version)
- }
- }
-
- case strings.HasPrefix(query, "<="):
- v := query[len("<="):]
- if !semver.IsValid(v) {
- return badVersion(v)
- }
- if isSemverPrefix(v) {
- // Refuse to say whether <=v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
- return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
- }
- match = func(m module.Version) bool {
- return semver.Compare(m.Version, v) <= 0
- }
- if !matchesMajor(v) {
- preferIncompatible = true
- }
-
- case strings.HasPrefix(query, "<"):
- v := query[len("<"):]
- if !semver.IsValid(v) {
- return badVersion(v)
- }
- match = func(m module.Version) bool {
- return semver.Compare(m.Version, v) < 0
- }
- if !matchesMajor(v) {
- preferIncompatible = true
- }
-
- case strings.HasPrefix(query, ">="):
- v := query[len(">="):]
- if !semver.IsValid(v) {
- return badVersion(v)
- }
- match = func(m module.Version) bool {
- return semver.Compare(m.Version, v) >= 0
+ if path == Target.Path {
+ if query != "latest" {
+ return nil, fmt.Errorf("can't query specific version (%q) for the main module (%s)", query, path)
}
- preferOlder = true
- if !matchesMajor(v) {
- preferIncompatible = true
+ if err := allowed(ctx, Target); err != nil {
+ return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
}
+ return &modfetch.RevInfo{Version: Target.Version}, nil
+ }
- case strings.HasPrefix(query, ">"):
- v := query[len(">"):]
- if !semver.IsValid(v) {
- return badVersion(v)
- }
- if isSemverPrefix(v) {
- // Refuse to say whether >v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
- return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
- }
- match = func(m module.Version) bool {
- return semver.Compare(m.Version, v) > 0
- }
- preferOlder = true
- if !matchesMajor(v) {
- preferIncompatible = true
- }
+ if path == "std" || path == "cmd" {
+ return nil, fmt.Errorf("can't query specific version (%q) of standard-library module %q", query, path)
+ }
- case semver.IsValid(query) && isSemverPrefix(query):
- match = func(m module.Version) bool {
- return matchSemverPrefix(query, m.Version)
- }
- prefix = query + "."
- if !matchesMajor(query) {
- preferIncompatible = true
- }
+ repo, err := lookupRepo(proxy, path)
+ if err != nil {
+ return nil, err
+ }
- default:
- // Direct lookup of semantic version or commit identifier.
-
- // If the query is a valid semantic version and that version is replaced,
- // use the replacement module without searching the proxy.
- canonicalQuery := module.CanonicalVersion(query)
- if canonicalQuery != "" {
- m := module.Version{Path: path, Version: query}
- if r := Replacement(m); r.Path != "" {
- if err := allowed(ctx, m); errors.Is(err, ErrDisallowed) {
- return nil, err
- }
- return &modfetch.RevInfo{Version: query}, nil
- }
- }
+ // Parse query to detect parse errors (and possibly handle query)
+ // before any network I/O.
+ qm, err := newQueryMatcher(path, query, current, allowed)
+ if (err == nil && qm.canStat) || err == errRevQuery {
+ // Direct lookup of a commit identifier or complete (non-prefix) semantic
+ // version.
// If the identifier is not a canonical semver tag — including if it's a
// semver tag with a +metadata suffix — then modfetch.Stat will populate
// info.Version with a suitable pseudo-version.
- info, err := modfetch.Stat(proxy, path, query)
+ info, err := repo.Stat(query)
if err != nil {
queryErr := err
// The full query doesn't correspond to a tag. If it is a semantic version
// with a +metadata suffix, see if there is a tag without that suffix:
// semantic versioning defines them to be equivalent.
+ canonicalQuery := module.CanonicalVersion(query)
if canonicalQuery != "" && query != canonicalQuery {
- info, err = modfetch.Stat(proxy, path, canonicalQuery)
- if err != nil && !errors.Is(err, os.ErrNotExist) {
+ info, err = repo.Stat(canonicalQuery)
+ if err != nil && !errors.Is(err, fs.ErrNotExist) {
return info, err
}
}
@@ -249,38 +158,16 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
return nil, err
}
return info, nil
- }
-
- if path == Target.Path {
- if query != "latest" {
- return nil, fmt.Errorf("can't query specific version (%q) for the main module (%s)", query, path)
- }
- if err := allowed(ctx, Target); err != nil {
- return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
- }
- return &modfetch.RevInfo{Version: Target.Version}, nil
- }
-
- if str.HasPathPrefix(path, "std") || str.HasPathPrefix(path, "cmd") {
- return nil, fmt.Errorf("explicit requirement on standard-library module %s not allowed", path)
+ } else if err != nil {
+ return nil, err
}
// Load versions and execute query.
- repo, err := modfetch.Lookup(proxy, path)
- if err != nil {
- return nil, err
- }
- versions, err := repo.Versions(prefix)
+ versions, err := repo.Versions(qm.prefix)
if err != nil {
return nil, err
}
- matchAndAllowed := func(ctx context.Context, m module.Version) error {
- if !match(m) {
- return ErrDisallowed
- }
- return allowed(ctx, m)
- }
- releases, prereleases, err := filterVersions(ctx, path, versions, matchAndAllowed, preferIncompatible)
+ releases, prereleases, err := qm.filterVersions(ctx, versions)
if err != nil {
return nil, err
}
@@ -291,11 +178,30 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
return nil, err
}
- // For "upgrade" and "patch", make sure we don't accidentally downgrade
- // from a newer prerelease or from a chronologically newer pseudoversion.
- if current != "" && (query == "upgrade" || query == "patch") {
+ if (query == "upgrade" || query == "patch") && modfetch.IsPseudoVersion(current) && !rev.Time.IsZero() {
+ // Don't allow "upgrade" or "patch" to move from a pseudo-version
+ // to a chronologically older version or pseudo-version.
+ //
+ // If the current version is a pseudo-version from an untagged branch, it
+ // may be semantically lower than the "latest" release or the latest
+ // pseudo-version on the main branch. A user on such a version is unlikely
+ // to intend to “upgrade” to a version that already existed at that point
+ // in time.
+ //
+ // We do this only if the current version is a pseudo-version: if the
+ // version is tagged, the author of the dependency module has given us
+ // explicit information about their intended precedence of this version
+ // relative to other versions, and we shouldn't contradict that
+ // information. (For example, v1.0.1 might be a backport of a fix already
+ // incorporated into v1.1.0, in which case v1.0.1 would be chronologically
+ // newer but v1.1.0 is still an “upgrade”; or v1.0.2 might be a revert of
+ // an unsuccessful fix in v1.0.1, in which case the v1.0.2 commit may be
+ // older than the v1.0.1 commit despite the tag itself being newer.)
currentTime, err := modfetch.PseudoVersionTime(current)
- if semver.Compare(rev.Version, current) < 0 || (err == nil && rev.Time.Before(currentTime)) {
+ if err == nil && rev.Time.Before(currentTime) {
+ if err := allowed(ctx, module.Version{Path: path, Version: current}); errors.Is(err, ErrDisallowed) {
+ return nil, err
+ }
return repo.Stat(current)
}
}
@@ -303,7 +209,7 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
return rev, nil
}
- if preferOlder {
+ if qm.preferLower {
if len(releases) > 0 {
return lookup(releases[0])
}
@@ -319,20 +225,25 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
}
}
- if mayUseLatest {
- // Special case for "latest": if no tags match, use latest commit in repo
- // if it is allowed.
+ if qm.mayUseLatest {
latest, err := repo.Latest()
if err == nil {
- m := module.Version{Path: path, Version: latest.Version}
- if err := allowed(ctx, m); !errors.Is(err, ErrDisallowed) {
+ if qm.allowsVersion(ctx, latest.Version) {
return lookup(latest.Version)
}
- } else if !errors.Is(err, os.ErrNotExist) {
+ } else if !errors.Is(err, fs.ErrNotExist) {
return nil, err
}
}
+ if (query == "upgrade" || query == "patch") && current != "" {
+ // "upgrade" and "patch" may stay on the current version if allowed.
+ if err := allowed(ctx, module.Version{Path: path, Version: current}); errors.Is(err, ErrDisallowed) {
+ return nil, err
+ }
+ return lookup(current)
+ }
+
return nil, &NoMatchingVersionError{query: query, current: current}
}
@@ -370,10 +281,151 @@ func isSemverPrefix(v string) bool {
return true
}
-// matchSemverPrefix reports whether the shortened semantic version p
-// matches the full-width (non-shortened) semantic version v.
-func matchSemverPrefix(p, v string) bool {
- return len(v) > len(p) && v[len(p)] == '.' && v[:len(p)] == p && semver.Prerelease(v) == ""
+type queryMatcher struct {
+ path string
+ prefix string
+ filter func(version string) bool
+ allowed AllowedFunc
+ canStat bool // if true, the query can be resolved by repo.Stat
+ preferLower bool // if true, choose the lowest matching version
+ mayUseLatest bool
+ preferIncompatible bool
+}
+
+var errRevQuery = errors.New("query refers to a non-semver revision")
+
+// newQueryMatcher returns a new queryMatcher that matches the versions
+// specified by the given query on the module with the given path.
+//
+// If the query can only be resolved by statting a non-SemVer revision,
+// newQueryMatcher returns errRevQuery.
+func newQueryMatcher(path string, query, current string, allowed AllowedFunc) (*queryMatcher, error) {
+ badVersion := func(v string) (*queryMatcher, error) {
+ return nil, fmt.Errorf("invalid semantic version %q in range %q", v, query)
+ }
+
+ matchesMajor := func(v string) bool {
+ _, pathMajor, ok := module.SplitPathVersion(path)
+ if !ok {
+ return false
+ }
+ return module.CheckPathMajor(v, pathMajor) == nil
+ }
+
+ qm := &queryMatcher{
+ path: path,
+ allowed: allowed,
+ preferIncompatible: strings.HasSuffix(current, "+incompatible"),
+ }
+
+ switch {
+ case query == "latest":
+ qm.mayUseLatest = true
+
+ case query == "upgrade":
+ if current == "" {
+ qm.mayUseLatest = true
+ } else {
+ qm.mayUseLatest = modfetch.IsPseudoVersion(current)
+ qm.filter = func(mv string) bool { return semver.Compare(mv, current) >= 0 }
+ }
+
+ case query == "patch":
+ if current == "" {
+ qm.mayUseLatest = true
+ } else {
+ qm.mayUseLatest = modfetch.IsPseudoVersion(current)
+ qm.prefix = semver.MajorMinor(current) + "."
+ qm.filter = func(mv string) bool { return semver.Compare(mv, current) >= 0 }
+ }
+
+ case strings.HasPrefix(query, "<="):
+ v := query[len("<="):]
+ if !semver.IsValid(v) {
+ return badVersion(v)
+ }
+ if isSemverPrefix(v) {
+ // Refuse to say whether <=v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
+ return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
+ }
+ qm.filter = func(mv string) bool { return semver.Compare(mv, v) <= 0 }
+ if !matchesMajor(v) {
+ qm.preferIncompatible = true
+ }
+
+ case strings.HasPrefix(query, "<"):
+ v := query[len("<"):]
+ if !semver.IsValid(v) {
+ return badVersion(v)
+ }
+ qm.filter = func(mv string) bool { return semver.Compare(mv, v) < 0 }
+ if !matchesMajor(v) {
+ qm.preferIncompatible = true
+ }
+
+ case strings.HasPrefix(query, ">="):
+ v := query[len(">="):]
+ if !semver.IsValid(v) {
+ return badVersion(v)
+ }
+ qm.filter = func(mv string) bool { return semver.Compare(mv, v) >= 0 }
+ qm.preferLower = true
+ if !matchesMajor(v) {
+ qm.preferIncompatible = true
+ }
+
+ case strings.HasPrefix(query, ">"):
+ v := query[len(">"):]
+ if !semver.IsValid(v) {
+ return badVersion(v)
+ }
+ if isSemverPrefix(v) {
+ // Refuse to say whether >v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3).
+ return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query)
+ }
+ qm.filter = func(mv string) bool { return semver.Compare(mv, v) > 0 }
+ qm.preferLower = true
+ if !matchesMajor(v) {
+ qm.preferIncompatible = true
+ }
+
+ case semver.IsValid(query):
+ if isSemverPrefix(query) {
+ qm.prefix = query + "."
+ // Do not allow the query "v1.2" to match versions lower than "v1.2.0",
+ // such as prereleases for that version. (https://golang.org/issue/31972)
+ qm.filter = func(mv string) bool { return semver.Compare(mv, query) >= 0 }
+ } else {
+ qm.canStat = true
+ qm.filter = func(mv string) bool { return semver.Compare(mv, query) == 0 }
+ qm.prefix = semver.Canonical(query)
+ }
+ if !matchesMajor(query) {
+ qm.preferIncompatible = true
+ }
+
+ default:
+ return nil, errRevQuery
+ }
+
+ return qm, nil
+}
+
+// allowsVersion reports whether version v is allowed by the prefix, filter, and
+// AllowedFunc of qm.
+func (qm *queryMatcher) allowsVersion(ctx context.Context, v string) bool {
+ if qm.prefix != "" && !strings.HasPrefix(v, qm.prefix) {
+ return false
+ }
+ if qm.filter != nil && !qm.filter(v) {
+ return false
+ }
+ if qm.allowed != nil {
+ if err := qm.allowed(ctx, module.Version{Path: qm.path, Version: v}); errors.Is(err, ErrDisallowed) {
+ return false
+ }
+ }
+ return true
}
// filterVersions classifies versions into releases and pre-releases, filtering
@@ -384,14 +436,32 @@ func matchSemverPrefix(p, v string) bool {
//
// If the allowed predicate returns an error not equivalent to ErrDisallowed,
// filterVersions returns that error.
-func filterVersions(ctx context.Context, path string, versions []string, allowed AllowedFunc, preferIncompatible bool) (releases, prereleases []string, err error) {
+func (qm *queryMatcher) filterVersions(ctx context.Context, versions []string) (releases, prereleases []string, err error) {
+ needIncompatible := qm.preferIncompatible
+
var lastCompatible string
for _, v := range versions {
- if err := allowed(ctx, module.Version{Path: path, Version: v}); errors.Is(err, ErrDisallowed) {
+ if !qm.allowsVersion(ctx, v) {
continue
}
- if !preferIncompatible {
+ if !needIncompatible {
+ // We're not yet sure whether we need to include +incomptaible versions.
+ // Keep track of the last compatible version we've seen, and use the
+ // presence (or absence) of a go.mod file in that version to decide: a
+ // go.mod file implies that the module author is supporting modules at a
+ // compatible version (and we should ignore +incompatible versions unless
+ // requested explicitly), while a lack of go.mod file implies the
+ // potential for legacy (pre-modules) versioning without semantic import
+ // paths (and thus *with* +incompatible versions).
+ //
+ // This isn't strictly accurate if the latest compatible version has been
+ // replaced by a local file path, because we do not allow file-path
+ // replacements without a go.mod file: the user would have needed to add
+ // one. However, replacing the last compatible version while
+ // simultaneously expecting to upgrade implicitly to a +incompatible
+ // version seems like an extreme enough corner case to ignore for now.
+
if !strings.HasSuffix(v, "+incompatible") {
lastCompatible = v
} else if lastCompatible != "" {
@@ -399,19 +469,22 @@ func filterVersions(ctx context.Context, path string, versions []string, allowed
// ignore any version with a higher (+incompatible) major version. (See
// https://golang.org/issue/34165.) Note that we even prefer a
// compatible pre-release over an incompatible release.
-
- ok, err := versionHasGoMod(ctx, module.Version{Path: path, Version: lastCompatible})
+ ok, err := versionHasGoMod(ctx, module.Version{Path: qm.path, Version: lastCompatible})
if err != nil {
return nil, nil, err
}
if ok {
+ // The last compatible version has a go.mod file, so that's the
+ // highest version we're willing to consider. Don't bother even
+ // looking at higher versions, because they're all +incompatible from
+ // here onward.
break
}
// No acceptable compatible release has a go.mod file, so the versioning
// for the module might not be module-aware, and we should respect
// legacy major-version tags.
- preferIncompatible = true
+ needIncompatible = true
}
}
@@ -444,7 +517,7 @@ type QueryResult struct {
// If any matching package is in the main module, QueryPattern considers only
// the main module and only the version "latest", without checking for other
// possible modules.
-func QueryPattern(ctx context.Context, pattern, query string, allowed AllowedFunc) ([]QueryResult, error) {
+func QueryPattern(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) ([]QueryResult, error) {
ctx, span := trace.StartSpan(ctx, "modload.QueryPattern "+pattern+" "+query)
defer span.Done()
@@ -519,14 +592,15 @@ func QueryPattern(ctx context.Context, pattern, query string, allowed AllowedFun
ctx, span := trace.StartSpan(ctx, "modload.QueryPattern.queryModule ["+proxy+"] "+path)
defer span.Done()
- current := findCurrentVersion(path)
+ pathCurrent := current(path)
r.Mod.Path = path
- r.Rev, err = queryProxy(ctx, proxy, path, query, current, allowed)
+ r.Rev, err = queryProxy(ctx, proxy, path, query, pathCurrent, allowed)
if err != nil {
return r, err
}
r.Mod.Version = r.Rev.Version
- root, isLocal, err := fetch(ctx, r.Mod)
+ needSum := true
+ root, isLocal, err := fetch(ctx, r.Mod, needSum)
if err != nil {
return r, err
}
@@ -577,15 +651,6 @@ func modulePrefixesExcludingTarget(path string) []string {
return prefixes
}
-func findCurrentVersion(path string) string {
- for _, m := range buildList {
- if m.Path == path {
- return m.Version
- }
- }
- return ""
-}
-
type prefixResult struct {
QueryResult
err error
@@ -638,7 +703,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod
noVersion = rErr
}
default:
- if errors.Is(rErr, os.ErrNotExist) {
+ if errors.Is(rErr, fs.ErrNotExist) {
if notExistErr == nil {
notExistErr = rErr
}
@@ -681,7 +746,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod
// A NoMatchingVersionError indicates that Query found a module at the requested
// path, but not at any versions satisfying the query string and allow-function.
//
-// NOTE: NoMatchingVersionError MUST NOT implement Is(os.ErrNotExist).
+// NOTE: NoMatchingVersionError MUST NOT implement Is(fs.ErrNotExist).
//
// If the module came from a proxy, that proxy had to return a successful status
// code for the versions it knows about, and thus did not have the opportunity
@@ -702,7 +767,7 @@ func (e *NoMatchingVersionError) Error() string {
// module at the requested version, but that module did not contain any packages
// matching the requested pattern.
//
-// NOTE: PackageNotInModuleError MUST NOT implement Is(os.ErrNotExist).
+// NOTE: PackageNotInModuleError MUST NOT implement Is(fs.ErrNotExist).
//
// If the module came from a proxy, that proxy had to return a successful status
// code for the versions it knows about, and thus did not have the opportunity
@@ -752,7 +817,8 @@ func (e *PackageNotInModuleError) ImportPath() string {
// ModuleHasRootPackage returns whether module m contains a package m.Path.
func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
- root, isLocal, err := fetch(ctx, m)
+ needSum := false
+ root, isLocal, err := fetch(ctx, m, needSum)
if err != nil {
return false, err
}
@@ -761,10 +827,165 @@ func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
}
func versionHasGoMod(ctx context.Context, m module.Version) (bool, error) {
- root, _, err := fetch(ctx, m)
+ needSum := false
+ root, _, err := fetch(ctx, m, needSum)
if err != nil {
return false, err
}
fi, err := os.Stat(filepath.Join(root, "go.mod"))
return err == nil && !fi.IsDir(), nil
}
+
+// A versionRepo is a subset of modfetch.Repo that can report information about
+// available versions, but cannot fetch specific source files.
+type versionRepo interface {
+ ModulePath() string
+ Versions(prefix string) ([]string, error)
+ Stat(rev string) (*modfetch.RevInfo, error)
+ Latest() (*modfetch.RevInfo, error)
+}
+
+var _ versionRepo = modfetch.Repo(nil)
+
+func lookupRepo(proxy, path string) (repo versionRepo, err error) {
+ err = module.CheckPath(path)
+ if err == nil {
+ repo = modfetch.Lookup(proxy, path)
+ } else {
+ repo = emptyRepo{path: path, err: err}
+ }
+
+ if index == nil {
+ return repo, err
+ }
+ if _, ok := index.highestReplaced[path]; !ok {
+ return repo, err
+ }
+
+ return &replacementRepo{repo: repo}, nil
+}
+
+// An emptyRepo is a versionRepo that contains no versions.
+type emptyRepo struct {
+ path string
+ err error
+}
+
+var _ versionRepo = emptyRepo{}
+
+func (er emptyRepo) ModulePath() string { return er.path }
+func (er emptyRepo) Versions(prefix string) ([]string, error) { return nil, nil }
+func (er emptyRepo) Stat(rev string) (*modfetch.RevInfo, error) { return nil, er.err }
+func (er emptyRepo) Latest() (*modfetch.RevInfo, error) { return nil, er.err }
+
+// A replacementRepo augments a versionRepo to include the replacement versions
+// (if any) found in the main module's go.mod file.
+//
+// A replacementRepo suppresses "not found" errors for otherwise-nonexistent
+// modules, so a replacementRepo should only be constructed for a module that
+// actually has one or more valid replacements.
+type replacementRepo struct {
+ repo versionRepo
+}
+
+var _ versionRepo = (*replacementRepo)(nil)
+
+func (rr *replacementRepo) ModulePath() string { return rr.repo.ModulePath() }
+
+// Versions returns the versions from rr.repo augmented with any matching
+// replacement versions.
+func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
+ repoVersions, err := rr.repo.Versions(prefix)
+ if err != nil && !errors.Is(err, os.ErrNotExist) {
+ return nil, err
+ }
+
+ versions := repoVersions
+ if index != nil && len(index.replace) > 0 {
+ path := rr.ModulePath()
+ for m, _ := range index.replace {
+ if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !modfetch.IsPseudoVersion(m.Version) {
+ versions = append(versions, m.Version)
+ }
+ }
+ }
+
+ if len(versions) == len(repoVersions) { // No replacement versions added.
+ return versions, nil
+ }
+
+ sort.Slice(versions, func(i, j int) bool {
+ return semver.Compare(versions[i], versions[j]) < 0
+ })
+ uniq := versions[:1]
+ for _, v := range versions {
+ if v != uniq[len(uniq)-1] {
+ uniq = append(uniq, v)
+ }
+ }
+ return uniq, nil
+}
+
+func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
+ info, err := rr.repo.Stat(rev)
+ if err == nil || index == nil || len(index.replace) == 0 {
+ return info, err
+ }
+
+ v := module.CanonicalVersion(rev)
+ if v != rev {
+ // The replacements in the go.mod file list only canonical semantic versions,
+ // so a non-canonical version can't possibly have a replacement.
+ return info, err
+ }
+
+ path := rr.ModulePath()
+ _, pathMajor, ok := module.SplitPathVersion(path)
+ if ok && pathMajor == "" {
+ if err := module.CheckPathMajor(v, pathMajor); err != nil && semver.Build(v) == "" {
+ v += "+incompatible"
+ }
+ }
+
+ if r := Replacement(module.Version{Path: path, Version: v}); r.Path == "" {
+ return info, err
+ }
+ return rr.replacementStat(v)
+}
+
+func (rr *replacementRepo) Latest() (*modfetch.RevInfo, error) {
+ info, err := rr.repo.Latest()
+
+ if index != nil {
+ path := rr.ModulePath()
+ if v, ok := index.highestReplaced[path]; ok {
+ if v == "" {
+ // The only replacement is a wildcard that doesn't specify a version, so
+ // synthesize a pseudo-version with an appropriate major version and a
+ // timestamp below any real timestamp. That way, if the main module is
+ // used from within some other module, the user will be able to upgrade
+ // the requirement to any real version they choose.
+ if _, pathMajor, ok := module.SplitPathVersion(path); ok && len(pathMajor) > 0 {
+ v = modfetch.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000")
+ } else {
+ v = modfetch.PseudoVersion("v0", "", time.Time{}, "000000000000")
+ }
+ }
+
+ if err != nil || semver.Compare(v, info.Version) > 0 {
+ return rr.replacementStat(v)
+ }
+ }
+ }
+
+ return info, err
+}
+
+func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error) {
+ rev := &modfetch.RevInfo{Version: v}
+ if modfetch.IsPseudoVersion(v) {
+ rev.Time, _ = modfetch.PseudoVersionTime(v)
+ rev.Short, _ = modfetch.PseudoVersionRev(v)
+ }
+ return rev, nil
+}
diff --git a/src/cmd/go/internal/modload/query_test.go b/src/cmd/go/internal/modload/query_test.go
index 351826f2ab..777a56b977 100644
--- a/src/cmd/go/internal/modload/query_test.go
+++ b/src/cmd/go/internal/modload/query_test.go
@@ -45,7 +45,7 @@ var (
queryRepoV3 = queryRepo + "/v3"
// Empty version list (no semver tags), not actually empty.
- emptyRepo = "vcs-test.golang.org/git/emptytest.git"
+ emptyRepoPath = "vcs-test.golang.org/git/emptytest.git"
)
var queryTests = []struct {
@@ -121,14 +121,14 @@ var queryTests = []struct {
{path: queryRepo, query: "upgrade", current: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
{path: queryRepo, query: "upgrade", current: "v0.0.0-20190513201126-42abcb6df8ee", vers: "v0.0.0-20190513201126-42abcb6df8ee"},
{path: queryRepo, query: "upgrade", allow: "NOMATCH", err: `no matching versions for query "upgrade"`},
- {path: queryRepo, query: "upgrade", current: "v1.9.9", allow: "NOMATCH", err: `no matching versions for query "upgrade" (current version is v1.9.9)`},
+ {path: queryRepo, query: "upgrade", current: "v1.9.9", allow: "NOMATCH", err: `vcs-test.golang.org/git/querytest.git@v1.9.9: disallowed module version`},
{path: queryRepo, query: "upgrade", current: "v1.99.99", err: `vcs-test.golang.org/git/querytest.git@v1.99.99: invalid version: unknown revision v1.99.99`},
{path: queryRepo, query: "patch", current: "", vers: "v1.9.9"},
{path: queryRepo, query: "patch", current: "v0.1.0", vers: "v0.1.2"},
{path: queryRepo, query: "patch", current: "v1.9.0", vers: "v1.9.9"},
{path: queryRepo, query: "patch", current: "v1.9.10-pre1", vers: "v1.9.10-pre1"},
{path: queryRepo, query: "patch", current: "v1.9.10-pre2+metadata", vers: "v1.9.10-pre2.0.20190513201126-42abcb6df8ee"},
- {path: queryRepo, query: "patch", current: "v1.99.99", err: `no matching versions for query "patch" (current version is v1.99.99)`},
+ {path: queryRepo, query: "patch", current: "v1.99.99", err: `vcs-test.golang.org/git/querytest.git@v1.99.99: invalid version: unknown revision v1.99.99`},
{path: queryRepo, query: ">v1.9.9", vers: "v1.9.10-pre1"},
{path: queryRepo, query: ">v1.10.0", err: `no matching versions for query ">v1.10.0"`},
{path: queryRepo, query: ">=v1.10.0", err: `no matching versions for query ">=v1.10.0"`},
@@ -171,9 +171,9 @@ var queryTests = []struct {
// That should prevent us from resolving any version for the /v3 path.
{path: queryRepoV3, query: "latest", err: `no matching versions for query "latest"`},
- {path: emptyRepo, query: "latest", vers: "v0.0.0-20180704023549-7bb914627242"},
- {path: emptyRepo, query: ">v0.0.0", err: `no matching versions for query ">v0.0.0"`},
- {path: emptyRepo, query: "<v10.0.0", err: `no matching versions for query "<v10.0.0"`},
+ {path: emptyRepoPath, query: "latest", vers: "v0.0.0-20180704023549-7bb914627242"},
+ {path: emptyRepoPath, query: ">v0.0.0", err: `no matching versions for query ">v0.0.0"`},
+ {path: emptyRepoPath, query: "<v10.0.0", err: `no matching versions for query "<v10.0.0"`},
}
func TestQuery(t *testing.T) {
@@ -189,7 +189,7 @@ func TestQuery(t *testing.T) {
}
allowed := func(ctx context.Context, m module.Version) error {
if ok, _ := path.Match(allow, m.Version); !ok {
- return ErrDisallowed
+ return module.VersionError(m, ErrDisallowed)
}
return nil
}
@@ -200,17 +200,17 @@ func TestQuery(t *testing.T) {
info, err := Query(ctx, tt.path, tt.query, tt.current, allowed)
if tt.err != "" {
if err == nil {
- t.Errorf("Query(%q, %q, %v) = %v, want error %q", tt.path, tt.query, allow, info.Version, tt.err)
+ t.Errorf("Query(_, %q, %q, %q, %v) = %v, want error %q", tt.path, tt.query, tt.current, allow, info.Version, tt.err)
} else if err.Error() != tt.err {
- t.Errorf("Query(%q, %q, %v): %v, want error %q", tt.path, tt.query, allow, err, tt.err)
+ t.Errorf("Query(_, %q, %q, %q, %v): %v\nwant error %q", tt.path, tt.query, tt.current, allow, err, tt.err)
}
return
}
if err != nil {
- t.Fatalf("Query(%q, %q, %v): %v", tt.path, tt.query, allow, err)
+ t.Fatalf("Query(_, %q, %q, %q, %v): %v\nwant %v", tt.path, tt.query, tt.current, allow, err, tt.vers)
}
if info.Version != tt.vers {
- t.Errorf("Query(%q, %q, %v) = %v, want %v", tt.path, tt.query, allow, info.Version, tt.vers)
+ t.Errorf("Query(_, %q, %q, %q, %v) = %v, want %v", tt.path, tt.query, tt.current, allow, info.Version, tt.vers)
}
})
}
diff --git a/src/cmd/go/internal/modload/search.go b/src/cmd/go/internal/modload/search.go
index a9bee0af4e..f6d6f5f764 100644
--- a/src/cmd/go/internal/modload/search.go
+++ b/src/cmd/go/internal/modload/search.go
@@ -7,11 +7,13 @@ package modload
import (
"context"
"fmt"
+ "io/fs"
"os"
"path/filepath"
"strings"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/imports"
"cmd/go/internal/search"
@@ -53,7 +55,7 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
walkPkgs := func(root, importPathRoot string, prune pruning) {
root = filepath.Clean(root)
- err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ err := fsys.Walk(root, func(path string, fi fs.FileInfo, err error) error {
if err != nil {
m.AddError(err)
return nil
@@ -84,8 +86,8 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
}
if !fi.IsDir() {
- if fi.Mode()&os.ModeSymlink != 0 && want {
- if target, err := os.Stat(path); err == nil && target.IsDir() {
+ if fi.Mode()&fs.ModeSymlink != 0 && want {
+ if target, err := fsys.Stat(path); err == nil && target.IsDir() {
fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
}
}
@@ -154,7 +156,8 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
isLocal = true
} else {
var err error
- root, isLocal, err = fetch(ctx, mod)
+ needSum := true
+ root, isLocal, err = fetch(ctx, mod, needSum)
if err != nil {
m.AddError(err)
continue
diff --git a/src/cmd/go/internal/modload/stat_openfile.go b/src/cmd/go/internal/modload/stat_openfile.go
index 931aaf1577..5842b858f0 100644
--- a/src/cmd/go/internal/modload/stat_openfile.go
+++ b/src/cmd/go/internal/modload/stat_openfile.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build aix js,wasm plan9
+// +build js,wasm plan9
// On plan9, per http://9p.io/magic/man2html/2/access: “Since file permissions
// are checked by the server and group information is not known to the client,
@@ -13,12 +13,13 @@
package modload
import (
+ "io/fs"
"os"
)
// hasWritePerm reports whether the current user has permission to write to the
// file with the given info.
-func hasWritePerm(path string, _ os.FileInfo) bool {
+func hasWritePerm(path string, _ fs.FileInfo) bool {
if f, err := os.OpenFile(path, os.O_WRONLY, 0); err == nil {
f.Close()
return true
diff --git a/src/cmd/go/internal/modload/stat_unix.go b/src/cmd/go/internal/modload/stat_unix.go
index ea3b801f2c..f49278ec3a 100644
--- a/src/cmd/go/internal/modload/stat_unix.go
+++ b/src/cmd/go/internal/modload/stat_unix.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package modload
import (
+ "io/fs"
"os"
"syscall"
)
@@ -17,7 +18,7 @@ import (
// Although the root user on most Unix systems can write to files even without
// permission, hasWritePerm reports false if no appropriate permission bit is
// set even if the current user is root.
-func hasWritePerm(path string, fi os.FileInfo) bool {
+func hasWritePerm(path string, fi fs.FileInfo) bool {
if os.Getuid() == 0 {
// The root user can access any file, but we still want to default to
// read-only mode if the go.mod file is marked as globally non-writable.
diff --git a/src/cmd/go/internal/modload/stat_windows.go b/src/cmd/go/internal/modload/stat_windows.go
index d7826cfc6b..0ac2391347 100644
--- a/src/cmd/go/internal/modload/stat_windows.go
+++ b/src/cmd/go/internal/modload/stat_windows.go
@@ -6,13 +6,11 @@
package modload
-import (
- "os"
-)
+import "io/fs"
// hasWritePerm reports whether the current user has permission to write to the
// file with the given info.
-func hasWritePerm(_ string, fi os.FileInfo) bool {
+func hasWritePerm(_ string, fi fs.FileInfo) bool {
// Windows has a read-only attribute independent of ACLs, so use that to
// determine whether the file is intended to be overwritten.
//
diff --git a/src/cmd/go/internal/modload/testgo.go b/src/cmd/go/internal/modload/testgo.go
deleted file mode 100644
index 6b34f5be39..0000000000
--- a/src/cmd/go/internal/modload/testgo.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build testgo
-
-package modload
-
-func init() {
- printStackInDie = true
-}
diff --git a/src/cmd/go/internal/modload/vendor.go b/src/cmd/go/internal/modload/vendor.go
index 9f34b829fc..ab29d4d014 100644
--- a/src/cmd/go/internal/modload/vendor.go
+++ b/src/cmd/go/internal/modload/vendor.go
@@ -7,8 +7,8 @@ package modload
import (
"errors"
"fmt"
+ "io/fs"
"io/ioutil"
- "os"
"path/filepath"
"strings"
"sync"
@@ -42,7 +42,7 @@ func readVendorList() {
vendorMeta = make(map[module.Version]vendorMetadata)
data, err := ioutil.ReadFile(filepath.Join(ModRoot(), "vendor/modules.txt"))
if err != nil {
- if !errors.Is(err, os.ErrNotExist) {
+ if !errors.Is(err, fs.ErrNotExist) {
base.Fatalf("go: %s", err)
}
return
diff --git a/src/cmd/go/internal/renameio/renameio.go b/src/cmd/go/internal/renameio/renameio.go
index d573cc690d..60a7138a76 100644
--- a/src/cmd/go/internal/renameio/renameio.go
+++ b/src/cmd/go/internal/renameio/renameio.go
@@ -8,6 +8,7 @@ package renameio
import (
"bytes"
"io"
+ "io/fs"
"math/rand"
"os"
"path/filepath"
@@ -29,13 +30,13 @@ func Pattern(filename string) string {
// final name.
//
// That ensures that the final location, if it exists, is always a complete file.
-func WriteFile(filename string, data []byte, perm os.FileMode) (err error) {
+func WriteFile(filename string, data []byte, perm fs.FileMode) (err error) {
return WriteToFile(filename, bytes.NewReader(data), perm)
}
// WriteToFile is a variant of WriteFile that accepts the data as an io.Reader
// instead of a slice.
-func WriteToFile(filename string, data io.Reader, perm os.FileMode) (err error) {
+func WriteToFile(filename string, data io.Reader, perm fs.FileMode) (err error) {
f, err := tempFile(filepath.Dir(filename), filepath.Base(filename), perm)
if err != nil {
return err
@@ -80,7 +81,7 @@ func ReadFile(filename string) ([]byte, error) {
}
// tempFile creates a new temporary file with given permission bits.
-func tempFile(dir, prefix string, perm os.FileMode) (f *os.File, err error) {
+func tempFile(dir, prefix string, perm fs.FileMode) (f *os.File, err error) {
for i := 0; i < 10000; i++ {
name := filepath.Join(dir, prefix+strconv.Itoa(rand.Intn(1000000000))+patternSuffix)
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, perm)
diff --git a/src/cmd/go/internal/renameio/renameio_test.go b/src/cmd/go/internal/renameio/renameio_test.go
index df8ddabdb8..e6d2025a0e 100644
--- a/src/cmd/go/internal/renameio/renameio_test.go
+++ b/src/cmd/go/internal/renameio/renameio_test.go
@@ -144,10 +144,12 @@ func TestConcurrentReadsAndWrites(t *testing.T) {
// As long as those are the only errors and *some* of the reads succeed, we're happy.
minReadSuccesses = attempts / 4
- case "darwin":
- // The filesystem on macOS 10.14 occasionally fails with "no such file or
- // directory" errors. See https://golang.org/issue/33041. The flake rate is
- // fairly low, so ensure that at least 75% of attempts succeed.
+ case "darwin", "ios":
+ // The filesystem on certain versions of macOS (10.14) and iOS (affected
+ // versions TBD) occasionally fail with "no such file or directory" errors.
+ // See https://golang.org/issue/33041 and https://golang.org/issue/42066.
+ // The flake rate is fairly low, so ensure that at least 75% of attempts
+ // succeed.
minReadSuccesses = attempts - (attempts / 4)
}
diff --git a/src/cmd/go/internal/renameio/umask_test.go b/src/cmd/go/internal/renameio/umask_test.go
index d75d67c9a9..19e217c548 100644
--- a/src/cmd/go/internal/renameio/umask_test.go
+++ b/src/cmd/go/internal/renameio/umask_test.go
@@ -7,6 +7,7 @@
package renameio
import (
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -36,7 +37,7 @@ func TestWriteFileModeAppliesUmask(t *testing.T) {
t.Fatalf("Stat %q (looking for mode %#o): %s", file, mode, err)
}
- if fi.Mode()&os.ModePerm != 0640 {
- t.Errorf("Stat %q: mode %#o want %#o", file, fi.Mode()&os.ModePerm, 0640)
+ if fi.Mode()&fs.ModePerm != 0640 {
+ t.Errorf("Stat %q: mode %#o want %#o", file, fi.Mode()&fs.ModePerm, 0640)
}
}
diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go
index 4efef24152..57cbb282a8 100644
--- a/src/cmd/go/internal/search/search.go
+++ b/src/cmd/go/internal/search/search.go
@@ -7,8 +7,10 @@ package search
import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"fmt"
"go/build"
+ "io/fs"
"os"
"path"
"path/filepath"
@@ -127,7 +129,7 @@ func (m *Match) MatchPackages() {
if m.pattern == "cmd" {
root += "cmd" + string(filepath.Separator)
}
- err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ err := fsys.Walk(root, func(path string, fi fs.FileInfo, err error) error {
if err != nil {
return err // Likely a permission error, which could interfere with matching.
}
@@ -153,8 +155,8 @@ func (m *Match) MatchPackages() {
}
if !fi.IsDir() {
- if fi.Mode()&os.ModeSymlink != 0 && want {
- if target, err := os.Stat(path); err == nil && target.IsDir() {
+ if fi.Mode()&fs.ModeSymlink != 0 && want {
+ if target, err := fsys.Stat(path); err == nil && target.IsDir() {
fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
}
}
@@ -263,7 +265,7 @@ func (m *Match) MatchDirs() {
}
}
- err := filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
+ err := fsys.Walk(dir, func(path string, fi fs.FileInfo, err error) error {
if err != nil {
return err // Likely a permission error, which could interfere with matching.
}
@@ -272,7 +274,7 @@ func (m *Match) MatchDirs() {
}
top := false
if path == dir {
- // filepath.Walk starts at dir and recurses. For the recursive case,
+ // Walk starts at dir and recurses. For the recursive case,
// the path is the result of filepath.Join, which calls filepath.Clean.
// The initial case is not Cleaned, though, so we do this explicitly.
//
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 51d333d866..00da9770df 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -12,6 +12,7 @@ import (
"fmt"
"go/build"
"io"
+ "io/fs"
"io/ioutil"
"os"
"os/exec"
@@ -1598,7 +1599,7 @@ func hashStat(name string) cache.ActionID {
return h.Sum()
}
-func hashWriteStat(h io.Writer, info os.FileInfo) {
+func hashWriteStat(h io.Writer, info fs.FileInfo) {
fmt.Fprintf(h, "stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir())
}
diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go
index 90bf10244d..7812afd488 100644
--- a/src/cmd/go/internal/vcs/vcs.go
+++ b/src/cmd/go/internal/vcs/vcs.go
@@ -10,6 +10,7 @@ import (
"fmt"
"internal/lazyregexp"
"internal/singleflight"
+ "io/fs"
"log"
urlpkg "net/url"
"os"
@@ -404,9 +405,9 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([
if len(args) >= 2 && args[0] == "-go-internal-mkdir" {
var err error
if filepath.IsAbs(args[1]) {
- err = os.Mkdir(args[1], os.ModePerm)
+ err = os.Mkdir(args[1], fs.ModePerm)
} else {
- err = os.Mkdir(filepath.Join(dir, args[1]), os.ModePerm)
+ err = os.Mkdir(filepath.Join(dir, args[1]), fs.ModePerm)
}
if err != nil {
return nil, err
diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go
index 5aa0f8e7ed..44ac24c62d 100644
--- a/src/cmd/go/internal/version/version.go
+++ b/src/cmd/go/internal/version/version.go
@@ -10,6 +10,7 @@ import (
"context"
"encoding/binary"
"fmt"
+ "io/fs"
"os"
"path/filepath"
"runtime"
@@ -87,8 +88,8 @@ func runVersion(ctx context.Context, cmd *base.Command, args []string) {
// scanDir scans a directory for executables to run scanFile on.
func scanDir(dir string) {
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
+ filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
+ if info.Mode().IsRegular() || info.Mode()&fs.ModeSymlink != 0 {
scanFile(path, info, *versionV)
}
return nil
@@ -96,7 +97,7 @@ func scanDir(dir string) {
}
// isExe reports whether the file should be considered executable.
-func isExe(file string, info os.FileInfo) bool {
+func isExe(file string, info fs.FileInfo) bool {
if runtime.GOOS == "windows" {
return strings.HasSuffix(strings.ToLower(file), ".exe")
}
@@ -107,8 +108,8 @@ func isExe(file string, info os.FileInfo) bool {
// If mustPrint is true, scanFile will report any error reading file.
// Otherwise (mustPrint is false, because scanFile is being called
// by scanDir) scanFile prints nothing for non-Go executables.
-func scanFile(file string, info os.FileInfo, mustPrint bool) {
- if info.Mode()&os.ModeSymlink != 0 {
+func scanFile(file string, info fs.FileInfo, mustPrint bool) {
+ if info.Mode()&fs.ModeSymlink != 0 {
// Accept file symlinks only.
i, err := os.Stat(file)
if err != nil || !i.Mode().IsRegular() {
diff --git a/src/cmd/go/internal/web/api.go b/src/cmd/go/internal/web/api.go
index 570818843b..9053b16b62 100644
--- a/src/cmd/go/internal/web/api.go
+++ b/src/cmd/go/internal/web/api.go
@@ -13,9 +13,8 @@ import (
"bytes"
"fmt"
"io"
- "io/ioutil"
+ "io/fs"
"net/url"
- "os"
"strings"
"unicode"
"unicode/utf8"
@@ -56,7 +55,7 @@ func (e *HTTPError) Error() string {
}
if err := e.Err; err != nil {
- if pErr, ok := e.Err.(*os.PathError); ok && strings.HasSuffix(e.URL, pErr.Path) {
+ if pErr, ok := e.Err.(*fs.PathError); ok && strings.HasSuffix(e.URL, pErr.Path) {
// Remove the redundant copy of the path.
err = pErr.Err
}
@@ -67,7 +66,7 @@ func (e *HTTPError) Error() string {
}
func (e *HTTPError) Is(target error) bool {
- return target == os.ErrNotExist && (e.StatusCode == 404 || e.StatusCode == 410)
+ return target == fs.ErrNotExist && (e.StatusCode == 404 || e.StatusCode == 410)
}
func (e *HTTPError) Unwrap() error {
@@ -87,7 +86,7 @@ func GetBytes(u *url.URL) ([]byte, error) {
if err := resp.Err(); err != nil {
return nil, err
}
- b, err := ioutil.ReadAll(resp.Body)
+ b, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading %s: %v", u.Redacted(), err)
}
@@ -130,7 +129,7 @@ func (r *Response) formatErrorDetail() string {
}
// Ensure that r.errorDetail has been populated.
- _, _ = io.Copy(ioutil.Discard, r.Body)
+ _, _ = io.Copy(io.Discard, r.Body)
s := r.errorDetail.buf.String()
if !utf8.ValidString(s) {
diff --git a/src/cmd/go/internal/web/file_test.go b/src/cmd/go/internal/web/file_test.go
index 6339469045..a1bb080e07 100644
--- a/src/cmd/go/internal/web/file_test.go
+++ b/src/cmd/go/internal/web/file_test.go
@@ -6,6 +6,7 @@ package web
import (
"errors"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -54,7 +55,7 @@ func TestGetNonexistentFile(t *testing.T) {
}
b, err := GetBytes(u)
- if !errors.Is(err, os.ErrNotExist) {
- t.Fatalf("GetBytes(%v) = %q, %v; want _, os.ErrNotExist", u, b, err)
+ if !errors.Is(err, fs.ErrNotExist) {
+ t.Fatalf("GetBytes(%v) = %q, %v; want _, fs.ErrNotExist", u, b, err)
}
}
diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
index 86423f118c..3531612dc6 100644
--- a/src/cmd/go/internal/work/build.go
+++ b/src/cmd/go/internal/work/build.go
@@ -19,6 +19,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/load"
"cmd/go/internal/modfetch"
"cmd/go/internal/modload"
@@ -277,6 +278,8 @@ func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
cmd.Flag.BoolVar(&cfg.BuildTrimpath, "trimpath", false, "")
cmd.Flag.BoolVar(&cfg.BuildWork, "work", false, "")
+ cmd.Flag.StringVar(&fsys.OverlayFile, "overlay", "", "")
+
// Undocumented, unstable debugging flags.
cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "")
cmd.Flag.StringVar(&cfg.DebugTrace, "debug-trace", "", "")
@@ -738,7 +741,7 @@ func installOutsideModule(ctx context.Context, args []string) {
// Don't check for retractions if a specific revision is requested.
allowed = nil
}
- qrs, err := modload.QueryPattern(ctx, patterns[0], version, allowed)
+ qrs, err := modload.QueryPattern(ctx, patterns[0], version, modload.Selected, allowed)
if err != nil {
base.Fatalf("go install %s: %v", args[0], err)
}
diff --git a/src/cmd/go/internal/work/build_test.go b/src/cmd/go/internal/work/build_test.go
index afed0fba72..e941729734 100644
--- a/src/cmd/go/internal/work/build_test.go
+++ b/src/cmd/go/internal/work/build_test.go
@@ -7,6 +7,7 @@ package work
import (
"bytes"
"fmt"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -221,10 +222,8 @@ func pkgImportPath(pkgpath string) *load.Package {
// See https://golang.org/issue/18878.
func TestRespectSetgidDir(t *testing.T) {
switch runtime.GOOS {
- case "darwin", "ios":
- if runtime.GOARCH == "arm64" {
- t.Skip("can't set SetGID bit with chmod on iOS")
- }
+ case "ios":
+ t.Skip("can't set SetGID bit with chmod on iOS")
case "windows", "plan9":
t.Skip("chown/chmod setgid are not supported on Windows or Plan 9")
}
@@ -255,7 +254,7 @@ func TestRespectSetgidDir(t *testing.T) {
}
// Change setgiddir's permissions to include the SetGID bit.
- if err := os.Chmod(setgiddir, 0755|os.ModeSetgid); err != nil {
+ if err := os.Chmod(setgiddir, 0755|fs.ModeSetgid); err != nil {
t.Fatal(err)
}
diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go
index a3c9b1a2c1..5cd3124e54 100644
--- a/src/cmd/go/internal/work/buildid.go
+++ b/src/cmd/go/internal/work/buildid.go
@@ -713,6 +713,7 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error {
return err
}
a.Package.Export = c.OutputFile(outputID)
+ a.Package.BuildID = a.buildID
}
}
}
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 51fc2b588d..24e309c657 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -14,6 +14,7 @@ import (
"fmt"
"internal/lazyregexp"
"io"
+ "io/fs"
"io/ioutil"
"log"
"math/rand"
@@ -271,7 +272,7 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags)
}
- // GO386, GOARM, GOMIPS, etc.
+ // GOARM, GOMIPS, etc.
key, val := cfg.GetArchEnv()
fmt.Fprintf(h, "%s=%s\n", key, val)
@@ -432,6 +433,7 @@ func (b *Builder) build(ctx context.Context, a *Action) (err error) {
need &^= needBuild
if b.NeedExport {
p.Export = a.built
+ p.BuildID = a.buildID
}
if need&needCompiledGoFiles != 0 {
if err := b.loadCachedSrcFiles(a); err == nil {
@@ -922,12 +924,13 @@ func (b *Builder) loadCachedSrcFiles(a *Action) error {
// vetConfig is the configuration passed to vet describing a single package.
type vetConfig struct {
- ID string // package ID (example: "fmt [fmt.test]")
- Compiler string // compiler name (gc, gccgo)
- Dir string // directory containing package
- ImportPath string // canonical import path ("package path")
- GoFiles []string // absolute paths to package source files
- NonGoFiles []string // absolute paths to package non-Go files
+ ID string // package ID (example: "fmt [fmt.test]")
+ Compiler string // compiler name (gc, gccgo)
+ Dir string // directory containing package
+ ImportPath string // canonical import path ("package path")
+ GoFiles []string // absolute paths to package source files
+ NonGoFiles []string // absolute paths to package non-Go files
+ IgnoredFiles []string // absolute paths to ignored source files
ImportMap map[string]string // map import path in source code to package path
PackageFile map[string]string // map package path to .a file with export data
@@ -951,20 +954,23 @@ func buildVetConfig(a *Action, srcfiles []string) {
}
}
+ ignored := str.StringList(a.Package.IgnoredGoFiles, a.Package.IgnoredOtherFiles)
+
// Pass list of absolute paths to vet,
// so that vet's error messages will use absolute paths,
// so that we can reformat them relative to the directory
// in which the go command is invoked.
vcfg := &vetConfig{
- ID: a.Package.ImportPath,
- Compiler: cfg.BuildToolchainName,
- Dir: a.Package.Dir,
- GoFiles: mkAbsFiles(a.Package.Dir, gofiles),
- NonGoFiles: mkAbsFiles(a.Package.Dir, nongofiles),
- ImportPath: a.Package.ImportPath,
- ImportMap: make(map[string]string),
- PackageFile: make(map[string]string),
- Standard: make(map[string]bool),
+ ID: a.Package.ImportPath,
+ Compiler: cfg.BuildToolchainName,
+ Dir: a.Package.Dir,
+ GoFiles: mkAbsFiles(a.Package.Dir, gofiles),
+ NonGoFiles: mkAbsFiles(a.Package.Dir, nongofiles),
+ IgnoredFiles: mkAbsFiles(a.Package.Dir, ignored),
+ ImportPath: a.Package.ImportPath,
+ ImportMap: make(map[string]string),
+ PackageFile: make(map[string]string),
+ Standard: make(map[string]bool),
}
a.vetCfg = vcfg
for i, raw := range a.Package.Internal.RawImports {
@@ -1052,17 +1058,28 @@ func (b *Builder) vet(ctx context.Context, a *Action) error {
// This is OK as long as the packages that are farther down the
// dependency tree turn on *more* analysis, as here.
// (The unsafeptr check does not write any facts for use by
- // later vet runs.)
+ // later vet runs, nor does unreachable.)
if a.Package.Goroot && !VetExplicit && VetTool == "" {
+ // Turn off -unsafeptr checks.
+ // There's too much unsafe.Pointer code
+ // that vet doesn't like in low-level packages
+ // like runtime, sync, and reflect.
// Note that $GOROOT/src/buildall.bash
// does the same for the misc-compile trybots
// and should be updated if these flags are
// changed here.
- //
- // There's too much unsafe.Pointer code
- // that vet doesn't like in low-level packages
- // like runtime, sync, and reflect.
vetFlags = []string{"-unsafeptr=false"}
+
+ // Also turn off -unreachable checks during go test.
+ // During testing it is very common to make changes
+ // like hard-coded forced returns or panics that make
+ // code unreachable. It's unreasonable to insist on files
+ // not having any unreachable code during "go test".
+ // (buildall.bash still runs with -unreachable enabled
+ // for the overall whole-tree scan.)
+ if cfg.CmdName == "test" {
+ vetFlags = append(vetFlags, "-unreachable=false")
+ }
}
// Note: We could decide that vet should compute export data for
@@ -1175,7 +1192,7 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) {
fmt.Fprintf(h, "linkflags %q\n", p.Internal.Ldflags)
}
- // GO386, GOARM, GOMIPS, etc.
+ // GOARM, GOMIPS, etc.
key, val := cfg.GetArchEnv()
fmt.Fprintf(h, "%s=%s\n", key, val)
@@ -1545,7 +1562,7 @@ func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) {
return err
}
- perm := os.FileMode(0666)
+ perm := fs.FileMode(0666)
if a1.Mode == "link" {
switch cfg.BuildBuildmode {
case "c-archive", "c-shared", "plugin":
@@ -1594,7 +1611,7 @@ func (b *Builder) cleanup(a *Action) {
}
// moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
-func (b *Builder) moveOrCopyFile(dst, src string, perm os.FileMode, force bool) error {
+func (b *Builder) moveOrCopyFile(dst, src string, perm fs.FileMode, force bool) error {
if cfg.BuildN {
b.Showcmd("", "mv %s %s", src, dst)
return nil
@@ -1620,7 +1637,7 @@ func (b *Builder) moveOrCopyFile(dst, src string, perm os.FileMode, force bool)
// we have to copy the file to retain the correct permissions.
// https://golang.org/issue/18878
if fi, err := os.Stat(filepath.Dir(dst)); err == nil {
- if fi.IsDir() && (fi.Mode()&os.ModeSetgid) != 0 {
+ if fi.IsDir() && (fi.Mode()&fs.ModeSetgid) != 0 {
return b.copyFile(dst, src, perm, force)
}
}
@@ -1655,7 +1672,7 @@ func (b *Builder) moveOrCopyFile(dst, src string, perm os.FileMode, force bool)
}
// copyFile is like 'cp src dst'.
-func (b *Builder) copyFile(dst, src string, perm os.FileMode, force bool) error {
+func (b *Builder) copyFile(dst, src string, perm fs.FileMode, force bool) error {
if cfg.BuildN || cfg.BuildX {
b.Showcmd("", "cp %s %s", src, dst)
if cfg.BuildN {
@@ -1984,6 +2001,13 @@ func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...interfa
defer cleanup()
cmd.Dir = dir
cmd.Env = base.AppendPWD(os.Environ(), cmd.Dir)
+
+ // Add the TOOLEXEC_IMPORTPATH environment variable for -toolexec tools.
+ // It doesn't really matter if -toolexec isn't being used.
+ if a != nil && a.Package != nil {
+ cmd.Env = append(cmd.Env, "TOOLEXEC_IMPORTPATH="+a.Package.ImportPath)
+ }
+
cmd.Env = append(cmd.Env, env...)
start := time.Now()
err := cmd.Run()
@@ -2199,6 +2223,8 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
// when -trimpath is enabled.
if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
if cfg.BuildTrimpath {
+ // TODO(#39958): handle overlays
+
// Keep in sync with Action.trimpath.
// The trimmed paths are a little different, but we need to trim in the
// same situations.
diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go
index d76574932e..0c4a7fa6e3 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -18,6 +18,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/load"
"cmd/go/internal/str"
"cmd/internal/objabi"
@@ -88,7 +89,11 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, s
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
- case "bytes", "internal/poll", "net", "os", "runtime/pprof", "runtime/trace", "sync", "syscall", "time":
+ case "bytes", "internal/poll", "net", "os":
+ fallthrough
+ case "runtime/metrics", "runtime/pprof", "runtime/trace":
+ fallthrough
+ case "sync", "syscall", "time":
extFiles++
}
}
@@ -145,10 +150,26 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, s
}
for _, f := range gofiles {
- args = append(args, mkAbs(p.Dir, f))
- }
-
- output, err = b.runOut(a, p.Dir, nil, args...)
+ f := mkAbs(p.Dir, f)
+
+ // Handle overlays. Convert path names using OverlayPath
+ // so these paths can be handed directly to tools.
+ // Deleted files won't show up in when scanning directories earlier,
+ // so OverlayPath will never return "" (meaning a deleted file) here.
+ // TODO(#39958): Handle cases where the package directory
+ // doesn't exist on disk (this can happen when all the package's
+ // files are in an overlay): the code expects the package directory
+ // to exist and runs some tools in that directory.
+ // TODO(#39958): Process the overlays when the
+ // gofiles, cgofiles, cfiles, sfiles, and cxxfiles variables are
+ // created in (*Builder).build. Doing that requires rewriting the
+ // code that uses those values to expect absolute paths.
+ f, _ = fsys.OverlayPath(f)
+
+ args = append(args, f)
+ }
+
+ output, err = b.runOut(a, base.Cwd, nil, args...)
return ofile, output, err
}
@@ -237,13 +258,26 @@ func (a *Action) trimpath() string {
}
rewrite := objdir + "=>"
- // For "go build -trimpath", rewrite package source directory
- // to a file system-independent path (just the import path).
+ rewriteDir := a.Package.Dir
if cfg.BuildTrimpath {
if m := a.Package.Module; m != nil && m.Version != "" {
- rewrite += ";" + a.Package.Dir + "=>" + m.Path + "@" + m.Version + strings.TrimPrefix(a.Package.ImportPath, m.Path)
+ rewriteDir = m.Path + "@" + m.Version + strings.TrimPrefix(a.Package.ImportPath, m.Path)
} else {
- rewrite += ";" + a.Package.Dir + "=>" + a.Package.ImportPath
+ rewriteDir = a.Package.ImportPath
+ }
+ rewrite += ";" + a.Package.Dir + "=>" + rewriteDir
+ }
+
+ // Add rewrites for overlays. The 'from' and 'to' paths in overlays don't need to have
+ // same basename, so go from the overlay contents file path (passed to the compiler)
+ // to the path the disk path would be rewritten to.
+ if fsys.OverlayFile != "" {
+ for _, filename := range a.Package.AllFiles() {
+ overlayPath, ok := fsys.OverlayPath(filepath.Join(a.Package.Dir, filename))
+ if !ok {
+ continue
+ }
+ rewrite += ";" + overlayPath + "=>" + filepath.Join(rewriteDir, filename)
}
}
@@ -262,14 +296,20 @@ func asmArgs(a *Action, p *load.Package) []interface{} {
}
}
}
- if p.ImportPath == "runtime" && objabi.Regabi_enabled != 0 {
- // In order to make it easier to port runtime assembly
- // to the register ABI, we introduce a macro
- // indicating the experiment is enabled.
- //
- // TODO(austin): Remove this once we commit to the
- // register ABI (#40724).
- args = append(args, "-D=GOEXPERIMENT_REGABI=1")
+ if objabi.IsRuntimePackagePath(pkgpath) {
+ args = append(args, "-compiling-runtime")
+ if objabi.Regabi_enabled != 0 {
+ // In order to make it easier to port runtime assembly
+ // to the register ABI, we introduce a macro
+ // indicating the experiment is enabled.
+ //
+ // Note: a similar change also appears in
+ // cmd/dist/build.go.
+ //
+ // TODO(austin): Remove this once we commit to the
+ // register ABI (#40724).
+ args = append(args, "-D=GOEXPERIMENT_REGABI=1")
+ }
}
if cfg.Goarch == "mips" || cfg.Goarch == "mipsle" {
diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go
index 4c1f36dbd6..ade8964b7c 100644
--- a/src/cmd/go/internal/work/gccgo.go
+++ b/src/cmd/go/internal/work/gccgo.go
@@ -11,11 +11,14 @@ import (
"os/exec"
"path/filepath"
"strings"
+ "sync"
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/load"
"cmd/go/internal/str"
+ "cmd/internal/pkgpath"
)
// The Gccgo toolchain.
@@ -91,13 +94,37 @@ func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg
args = append(args, "-I", root)
}
}
- if cfg.BuildTrimpath && b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") {
- args = append(args, "-ffile-prefix-map="+base.Cwd+"=.")
- args = append(args, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build")
+
+ if b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") {
+ if cfg.BuildTrimpath {
+ args = append(args, "-ffile-prefix-map="+base.Cwd+"=.")
+ args = append(args, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build")
+ }
+ if fsys.OverlayFile != "" {
+ for _, name := range gofiles {
+ absPath := mkAbs(p.Dir, name)
+ overlayPath, ok := fsys.OverlayPath(absPath)
+ if !ok {
+ continue
+ }
+ toPath := absPath
+ // gccgo only applies the last matching rule, so also handle the case where
+ // BuildTrimpath is true and the path is relative to base.Cwd.
+ if cfg.BuildTrimpath && str.HasFilePathPrefix(toPath, base.Cwd) {
+ toPath = "." + toPath[len(base.Cwd):]
+ }
+ args = append(args, "-ffile-prefix-map="+overlayPath+"="+toPath)
+ }
+ }
}
+
args = append(args, a.Package.Internal.Gccgoflags...)
for _, f := range gofiles {
- args = append(args, mkAbs(p.Dir, f))
+ f := mkAbs(p.Dir, f)
+ // Overlay files if necessary.
+ // See comment on gctoolchain.gc about overlay TODOs
+ f, _ = fsys.OverlayPath(f)
+ args = append(args, f)
}
output, err = b.runOut(a, p.Dir, nil, args)
@@ -174,7 +201,7 @@ func (tools gccgoToolchain) asm(b *Builder, a *Action, sfiles []string) ([]strin
ofiles = append(ofiles, ofile)
sfile = mkAbs(p.Dir, sfile)
defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch}
- if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
+ if pkgpath := tools.gccgoCleanPkgpath(b, p); pkgpath != "" {
defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
}
defs = tools.maybePIC(defs)
@@ -531,7 +558,7 @@ func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error
cfile = mkAbs(p.Dir, cfile)
defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch}
defs = append(defs, b.gccArchArgs()...)
- if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
+ if pkgpath := tools.gccgoCleanPkgpath(b, p); pkgpath != "" {
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
}
compiler := envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
@@ -568,14 +595,19 @@ func gccgoPkgpath(p *load.Package) string {
return p.ImportPath
}
-func gccgoCleanPkgpath(p *load.Package) string {
- clean := func(r rune) rune {
- switch {
- case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
- '0' <= r && r <= '9':
- return r
+var gccgoToSymbolFuncOnce sync.Once
+var gccgoToSymbolFunc func(string) string
+
+func (tools gccgoToolchain) gccgoCleanPkgpath(b *Builder, p *load.Package) string {
+ gccgoToSymbolFuncOnce.Do(func() {
+ fn, err := pkgpath.ToSymbolFunc(tools.compiler(), b.WorkDir)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "cmd/go: %v\n", err)
+ base.SetExitStatus(2)
+ base.Exit()
}
- return '_'
- }
- return strings.Map(clean, gccgoPkgpath(p))
+ gccgoToSymbolFunc = fn
+ })
+
+ return gccgoToSymbolFunc(gccgoPkgpath(p))
}
diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go
index b0d6133768..d65c076c6a 100644
--- a/src/cmd/go/internal/work/init.go
+++ b/src/cmd/go/internal/work/init.go
@@ -9,6 +9,7 @@ package work
import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/fsys"
"cmd/go/internal/modload"
"cmd/internal/objabi"
"cmd/internal/sys"
@@ -24,6 +25,9 @@ func BuildInit() {
modload.Init()
instrumentInit()
buildModeInit()
+ if err := fsys.Init(base.Cwd); err != nil {
+ base.Fatalf("go: %v", err)
+ }
// Make sure -pkgdir is absolute, because we run commands
// in different directories.
@@ -37,6 +41,13 @@ func BuildInit() {
cfg.BuildPkgdir = p
}
+ // Make sure CC and CXX are absolute paths
+ for _, key := range []string{"CC", "CXX"} {
+ if path := cfg.Getenv(key); !filepath.IsAbs(path) && path != "" && path != filepath.Base(path) {
+ base.Fatalf("go %s: %s environment variable is relative; must be absolute path: %s\n", flag.Args()[0], key, path)
+ }
+ }
+
// For each experiment that has been enabled in the toolchain, define a
// build tag with the same name but prefixed by "goexperiment." which can be
// used for compiling alternative files for the experiment. This allows
@@ -157,7 +168,10 @@ func buildModeInit() {
ldBuildmode = "pie"
case "windows":
ldBuildmode = "pie"
- case "darwin", "ios":
+ case "ios":
+ codegenArg = "-shared"
+ ldBuildmode = "pie"
+ case "darwin":
switch cfg.Goarch {
case "arm64":
codegenArg = "-shared"
diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
index d2a2697f0f..bcc29c8cbe 100644
--- a/src/cmd/go/internal/work/security.go
+++ b/src/cmd/go/internal/work/security.go
@@ -132,6 +132,7 @@ var validCompilerFlagsWithNextArg = []string{
"-U",
"-I",
"-framework",
+ "-include",
"-isysroot",
"-isystem",
"--sysroot",
diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go
index 11e74f29c6..43a0ab1e47 100644
--- a/src/cmd/go/internal/work/security_test.go
+++ b/src/cmd/go/internal/work/security_test.go
@@ -62,6 +62,8 @@ var goodCompilerFlags = [][]string{
{"-I", "=/usr/include/libxml2"},
{"-I", "dir"},
{"-I", "$SYSROOT/dir"},
+ {"-isystem", "/usr/include/mozjs-68"},
+ {"-include", "/usr/include/mozjs-68/RequiredDefines.h"},
{"-framework", "Chocolate"},
{"-x", "c"},
{"-v"},
@@ -91,6 +93,7 @@ var badCompilerFlags = [][]string{
{"-I", "@foo"},
{"-I", "-foo"},
{"-I", "=@obj"},
+ {"-include", "@foo"},
{"-framework", "-Caffeine"},
{"-framework", "@Home"},
{"-x", "--c"},
diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go
index 42972f5b2a..3ed42face2 100644
--- a/src/cmd/go/proxy_test.go
+++ b/src/cmd/go/proxy_test.go
@@ -12,6 +12,7 @@ import (
"flag"
"fmt"
"io"
+ "io/fs"
"io/ioutil"
"log"
"net"
@@ -335,7 +336,7 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
if testing.Verbose() {
fmt.Fprintf(os.Stderr, "go proxy: no archive %s %s: %v\n", path, vers, err)
}
- if errors.Is(err, os.ErrNotExist) {
+ if errors.Is(err, fs.ErrNotExist) {
http.NotFound(w, r)
} else {
http.Error(w, "cannot load archive", 500)
@@ -443,7 +444,7 @@ func readArchive(path, vers string) (*txtar.Archive, error) {
return a
}).(*txtar.Archive)
if a == nil {
- return nil, os.ErrNotExist
+ return nil, fs.ErrNotExist
}
return a, nil
}
@@ -470,13 +471,13 @@ func proxyGoSum(path, vers string) ([]byte, error) {
}
h1, err := dirhash.Hash1(names, func(name string) (io.ReadCloser, error) {
data := files[name]
- return ioutil.NopCloser(bytes.NewReader(data)), nil
+ return io.NopCloser(bytes.NewReader(data)), nil
})
if err != nil {
return nil, err
}
h1mod, err := dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) {
- return ioutil.NopCloser(bytes.NewReader(gomod)), nil
+ return io.NopCloser(bytes.NewReader(gomod)), nil
})
if err != nil {
return nil, err
diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go
index 986646252a..a31561cd86 100644
--- a/src/cmd/go/script_test.go
+++ b/src/cmd/go/script_test.go
@@ -14,6 +14,7 @@ import (
"fmt"
"go/build"
"internal/testenv"
+ "io/fs"
"io/ioutil"
"os"
"os/exec"
@@ -500,7 +501,7 @@ func (ts *testScript) cmdChmod(want simpleStatus, args []string) {
ts.fatalf("usage: chmod perm paths...")
}
perm, err := strconv.ParseUint(args[0], 0, 32)
- if err != nil || perm&uint64(os.ModePerm) != perm {
+ if err != nil || perm&uint64(fs.ModePerm) != perm {
ts.fatalf("invalid mode: %s", args[0])
}
for _, arg := range args[1:] {
@@ -508,7 +509,7 @@ func (ts *testScript) cmdChmod(want simpleStatus, args []string) {
if !filepath.IsAbs(path) {
path = filepath.Join(ts.cd, arg)
}
- err := os.Chmod(path, os.FileMode(perm))
+ err := os.Chmod(path, fs.FileMode(perm))
ts.check(err)
}
}
@@ -595,7 +596,7 @@ func (ts *testScript) cmdCp(want simpleStatus, args []string) {
var (
src string
data []byte
- mode os.FileMode
+ mode fs.FileMode
)
switch arg {
case "stdout":
diff --git a/src/cmd/go/testdata/addmod.go b/src/cmd/go/testdata/addmod.go
index d9c3aab9c4..d1b6467c5d 100644
--- a/src/cmd/go/testdata/addmod.go
+++ b/src/cmd/go/testdata/addmod.go
@@ -22,6 +22,7 @@ import (
"bytes"
"flag"
"fmt"
+ "io/fs"
"io/ioutil"
"log"
"os"
@@ -121,7 +122,7 @@ func main() {
{Name: ".info", Data: info},
}
dir = filepath.Clean(dir)
- err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ err = filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
if !info.Mode().IsRegular() {
return nil
}
diff --git a/src/cmd/go/testdata/mod/example.com_ambiguous_a_b_v0.0.0-empty.txt b/src/cmd/go/testdata/mod/example.com_ambiguous_a_b_v0.0.0-empty.txt
new file mode 100644
index 0000000000..a86951981e
--- /dev/null
+++ b/src/cmd/go/testdata/mod/example.com_ambiguous_a_b_v0.0.0-empty.txt
@@ -0,0 +1,12 @@
+Module example.com/ambiguous/a/b is a suffix of example.com/a.
+This version contains no package.
+-- .mod --
+module example.com/ambiguous/a/b
+
+go 1.16
+-- .info --
+{"Version":"v0.0.0-empty"}
+-- go.mod --
+module example.com/ambiguous/a/b
+
+go 1.16
diff --git a/src/cmd/go/testdata/mod/example.com_ambiguous_a_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_ambiguous_a_v1.0.0.txt
new file mode 100644
index 0000000000..bb438262e1
--- /dev/null
+++ b/src/cmd/go/testdata/mod/example.com_ambiguous_a_v1.0.0.txt
@@ -0,0 +1,18 @@
+Module example.com/ambiguous/a is a prefix of example.com/a/b.
+It contains package example.com/a/b.
+-- .mod --
+module example.com/ambiguous/a
+
+go 1.16
+
+require example.com/ambiguous/a/b v0.0.0-empty
+-- .info --
+{"Version":"v1.0.0"}
+-- go.mod --
+module example.com/ambiguous/a
+
+go 1.16
+
+require example.com/ambiguous/a/b v0.0.0-empty
+-- b/b.go --
+package b
diff --git a/src/cmd/go/testdata/savedir.go b/src/cmd/go/testdata/savedir.go
index 48a6318860..04902df61e 100644
--- a/src/cmd/go/testdata/savedir.go
+++ b/src/cmd/go/testdata/savedir.go
@@ -17,6 +17,7 @@ package main
import (
"flag"
"fmt"
+ "io/fs"
"io/ioutil"
"log"
"os"
@@ -48,7 +49,7 @@ func main() {
a := new(txtar.Archive)
dir = filepath.Clean(dir)
- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+ filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
if path == dir {
return nil
}
diff --git a/src/cmd/go/testdata/script/build_cache_arch_mode.txt b/src/cmd/go/testdata/script/build_cache_arch_mode.txt
index 68e662555f..931827fbde 100644
--- a/src/cmd/go/testdata/script/build_cache_arch_mode.txt
+++ b/src/cmd/go/testdata/script/build_cache_arch_mode.txt
@@ -1,15 +1,7 @@
-# Issue 9737: verify that GOARM and GO386 affect the computed build ID
+# Issue 9737: verify that GOARM affects the computed build ID
[short] skip
-# 386
-env GOOS=linux
-env GOARCH=386
-env GO386=387
-go install mycmd
-env GO386=sse2
-stale mycmd
-
# arm
env GOOS=linux
env GOARCH=arm
diff --git a/src/cmd/go/testdata/script/build_overlay.txt b/src/cmd/go/testdata/script/build_overlay.txt
new file mode 100644
index 0000000000..0602e706e9
--- /dev/null
+++ b/src/cmd/go/testdata/script/build_overlay.txt
@@ -0,0 +1,130 @@
+[short] skip
+
+# Test building in overlays.
+# TODO(matloob): add a test case where the destination file in the replace map
+# isn't a go file. Either completely exclude that case in fs.IsDirWithGoFiles
+# if the compiler doesn't allow it, or test that it works all the way.
+
+# The main package (m) is contained in an overlay. It imports m/dir2 which has one
+# file in an overlay and one file outside the overlay, which in turn imports m/dir,
+# which only has source files in the overlay.
+
+cd m
+
+! go build .
+go build -overlay overlay.json -o main$GOEXE .
+exec ./main$goexe
+stdout '^hello$'
+
+go build -overlay overlay.json -o print_abspath$GOEXE ./printpath
+exec ./print_abspath$GOEXE
+stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go
+
+go build -overlay overlay.json -o print_trimpath$GOEXE -trimpath ./printpath
+exec ./print_trimpath$GOEXE
+stdout ^m[/\\]printpath[/\\]main.go
+
+go build -overlay overlay.json -o print_trimpath_two_files$GOEXE printpath/main.go printpath/other.go
+exec ./print_trimpath_two_files$GOEXE
+stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go
+stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]other.go
+
+# Run same tests but with gccgo.
+env GO111MODULE=off
+[!exec:gccgo] stop
+
+! go build -compiler=gccgo .
+go build -compiler=gccgo -overlay overlay.json -o main_gccgo$GOEXE .
+exec ./main_gccgo$goexe
+stdout '^hello$'
+
+go build -compiler=gccgo -overlay overlay.json -o print_abspath_gccgo$GOEXE ./printpath
+exec ./print_abspath_gccgo$GOEXE
+stdout $WORK[/\\]gopath[/\\]src[/\\]m[/\\]printpath[/\\]main.go
+
+go build -compiler=gccgo -overlay overlay.json -o print_trimpath_gccgo$GOEXE -trimpath ./printpath
+exec ./print_trimpath_gccgo$GOEXE
+stdout ^\.[/\\]printpath[/\\]main.go
+
+-- m/go.mod --
+// TODO(matloob): how do overlays work with go.mod (especially if mod=readonly)
+module m
+
+go 1.16
+
+-- m/dir2/h.go --
+package dir2
+
+func PrintMessage() {
+ printMessage()
+}
+-- m/dir/foo.txt --
+The build action code currently expects the package directory
+to exist, so it can run the compiler in that directory.
+TODO(matloob): Remove this requirement.
+-- m/printpath/about.txt --
+the actual code is in the overlay
+-- m/overlay.json --
+{
+ "Replace": {
+ "f.go": "overlay/f.go",
+ "dir/g.go": "overlay/dir_g.go",
+ "dir2/i.go": "overlay/dir2_i.go",
+ "printpath/main.go": "overlay/printpath.go",
+ "printpath/other.go": "overlay2/printpath2.go"
+ }
+}
+-- m/overlay/f.go --
+package main
+
+import "m/dir2"
+
+func main() {
+ dir2.PrintMessage()
+}
+-- m/overlay/dir_g.go --
+package dir
+
+import "fmt"
+
+func PrintMessage() {
+ fmt.Println("hello")
+}
+-- m/overlay/printpath.go --
+package main
+
+import (
+ "fmt"
+ "path/filepath"
+ "runtime"
+)
+
+func main() {
+ _, file, _, _ := runtime.Caller(0)
+
+ // Since https://golang.org/cl/214286, the runtime's debug paths are
+ // slash-separated regardless of platform, so normalize them to system file
+ // paths.
+ fmt.Println(filepath.FromSlash(file))
+}
+-- m/overlay2/printpath2.go --
+package main
+
+import (
+ "fmt"
+ "path/filepath"
+ "runtime"
+)
+
+func init() {
+ _, file, _, _ := runtime.Caller(0)
+ fmt.Println(filepath.FromSlash(file))
+}
+-- m/overlay/dir2_i.go --
+package dir2
+
+import "m/dir"
+
+func printMessage() {
+ dir.PrintMessage()
+}
diff --git a/src/cmd/go/testdata/script/build_trimpath.txt b/src/cmd/go/testdata/script/build_trimpath.txt
index ad78bcf2b2..2c3bee8fdc 100644
--- a/src/cmd/go/testdata/script/build_trimpath.txt
+++ b/src/cmd/go/testdata/script/build_trimpath.txt
@@ -9,6 +9,8 @@ env GO111MODULE=on
mkdir $WORK/a/src/paths $WORK/b/src/paths
cp paths.go $WORK/a/src/paths
cp paths.go $WORK/b/src/paths
+cp overlay.json $WORK/a/src/paths
+cp overlay.json $WORK/b/src/paths
cp go.mod $WORK/a/src/paths/
cp go.mod $WORK/b/src/paths/
@@ -43,6 +45,29 @@ go build -trimpath -o $WORK/paths-b.exe
cmp -q $WORK/paths-a.exe $WORK/paths-b.exe
+# Same sequence of tests but with overlays.
+# A binary built without -trimpath should contain the module root dir
+# and GOROOT for debugging and stack traces.
+cd $WORK/a/src/paths
+go build -overlay overlay.json -o $WORK/paths-dbg.exe ./overlaydir
+exec $WORK/paths-dbg.exe $WORK/paths-dbg.exe
+stdout 'binary contains module root: true'
+stdout 'binary contains GOROOT: true'
+
+# A binary built with -trimpath should not contain the current workspace
+# or GOROOT.
+go build -overlay overlay.json -trimpath -o $WORK/paths-a.exe ./overlaydir
+exec $WORK/paths-a.exe $WORK/paths-a.exe
+stdout 'binary contains module root: false'
+stdout 'binary contains GOROOT: false'
+
+# Two binaries built from identical packages in different directories
+# should be identical.
+cd $WORK/b/src/paths
+go build -overlay overlay.json -trimpath -o $WORK/paths-b.exe ./overlaydir
+cmp -q $WORK/paths-a.exe $WORK/paths-b.exe
+
+
# Same sequence of tests but in GOPATH mode.
# A binary built without -trimpath should contain GOPATH and GOROOT.
env GO111MODULE=off
@@ -129,7 +154,8 @@ func check(data []byte, desc, dir string) {
containsSlashDir := bytes.Contains(data, []byte(filepath.ToSlash(dir)))
fmt.Printf("binary contains %s: %v\n", desc, containsDir || containsSlashDir)
}
-
+-- overlay.json --
+{ "Replace": { "overlaydir/paths.go": "paths.go" } }
-- go.mod --
module paths
diff --git a/src/cmd/go/testdata/script/clean_binary.txt b/src/cmd/go/testdata/script/clean_binary.txt
new file mode 100644
index 0000000000..7335f8a4c7
--- /dev/null
+++ b/src/cmd/go/testdata/script/clean_binary.txt
@@ -0,0 +1,78 @@
+# Build something to create the executable, including several cases
+[short] skip
+
+# --------------------- clean executables -------------------------
+
+# case1: test file-named executable 'main'
+env GO111MODULE=on
+
+! exists main$GOEXE
+go build main.go
+exists -exec main$GOEXE
+go clean
+! exists main$GOEXE
+
+# case2: test module-named executable 'a.b.c'
+! exists a.b.c$GOEXE
+go build
+exists -exec a.b.c$GOEXE
+go clean
+! exists a.b.c$GOEXE
+
+# case3: directory-named executable 'src'
+env GO111MODULE=off
+
+! exists src$GOEXE
+go build
+exists -exec src$GOEXE
+go clean
+! exists src$GOEXE
+
+# --------------------- clean test files -------------------------
+
+# case1: test file-named test file
+env GO111MODULE=on
+
+! exists main.test$GOEXE
+go test -c main_test.go
+exists -exec main.test$GOEXE
+go clean
+! exists main.test$GOEXE
+
+# case2: test module-named test file
+! exists a.b.c.test$GOEXE
+go test -c
+exists -exec a.b.c.test$GOEXE
+go clean
+! exists a.b.c.test$GOEXE
+
+# case3: test directory-based test file
+env GO111MODULE=off
+
+! exists src.test$GOEXE
+go test -c
+exists -exec src.test$GOEXE
+go clean
+! exists src.test$GOEXE
+
+-- main.go --
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("hello!")
+}
+
+-- main_test.go --
+package main
+
+import "testing"
+
+func TestSomething(t *testing.T) {
+}
+
+-- go.mod --
+module example.com/a.b.c/v2
+
+go 1.12 \ No newline at end of file
diff --git a/src/cmd/go/testdata/script/env_write.txt b/src/cmd/go/testdata/script/env_write.txt
index 2366c3f580..0af22ed421 100644
--- a/src/cmd/go/testdata/script/env_write.txt
+++ b/src/cmd/go/testdata/script/env_write.txt
@@ -24,6 +24,16 @@ stdout GOARCH=
stdout GOOS=
stdout GOROOT=
+# go env ignores invalid flag in GOFLAGS environment variable
+env GOFLAGS='=true'
+go env
+
+# checking errors
+! go env -w
+stderr 'go env -w: no KEY=VALUE arguments given'
+! go env -u
+stderr 'go env -u: no arguments given'
+
# go env -w changes default setting
env root=
[windows] env root=c:
@@ -97,6 +107,50 @@ stderr 'GOPATH entry cannot start with shell metacharacter'
! go env -w GOPATH=./go
stderr 'GOPATH entry is relative; must be absolute path'
+# go env -w rejects invalid GOTMPDIR values
+! go env -w GOTMPDIR=x
+stderr 'go env -w: GOTMPDIR must be an absolute path'
+
+# go env -w should accept absolute GOTMPDIR value
+# and should not create it
+[windows] go env -w GOTMPDIR=$WORK\x\y\z
+[!windows] go env -w GOTMPDIR=$WORK/x/y/z
+! exists $WORK/x/y/z
+# we should be able to clear an env
+go env -u GOTMPDIR
+go env GOTMPDIR
+stdout ^$
+
+[windows] go env -w GOTMPDIR=$WORK\x\y\z
+[!windows] go env -w GOTMPDIR=$WORK/x/y/z
+go env -w GOTMPDIR=
+go env GOTMPDIR
+stdout ^$
+
+# go env -w rejects relative CC values
+[!windows] go env -w CC=/usr/bin/clang
+go env -w CC=clang
+[!windows] ! go env -w CC=./clang
+[!windows] ! go env -w CC=bin/clang
+[!windows] stderr 'go env -w: CC entry is relative; must be absolute path'
+
+[windows] go env -w CC=$WORK\bin\clang
+[windows] ! go env -w CC=.\clang
+[windows] ! go env -w CC=bin\clang
+[windows] stderr 'go env -w: CC entry is relative; must be absolute path'
+
+# go env -w rejects relative CXX values
+[!windows] go env -w CC=/usr/bin/cpp
+go env -w CXX=cpp
+[!windows] ! go env -w CXX=./cpp
+[!windows] ! go env -w CXX=bin/cpp
+[!windows] stderr 'go env -w: CXX entry is relative; must be absolute path'
+
+[windows] go env -w CXX=$WORK\bin\cpp
+[windows] ! go env -w CXX=.\cpp
+[windows] ! go env -w CXX=bin\cpp
+[windows] stderr 'go env -w: CXX entry is relative; must be absolute path'
+
# go env -w/-u checks validity of GOOS/ARCH combinations
env GOOS=
env GOARCH=
diff --git a/src/cmd/go/testdata/script/gcflags_patterns.txt b/src/cmd/go/testdata/script/gcflags_patterns.txt
index 5374493a43..f23cecefd3 100644
--- a/src/cmd/go/testdata/script/gcflags_patterns.txt
+++ b/src/cmd/go/testdata/script/gcflags_patterns.txt
@@ -63,6 +63,10 @@ stderr 'link.* -X=math.pi=3'
go build -n -ldflags=-X=math.pi=3
stderr 'link.* -X=math.pi=3'
+# cgo.a should not be a dependency of internally-linked go package
+go build -ldflags='-linkmode=external -linkmode=internal' -n prog.go
+! stderr 'packagefile .*runtime/cgo.a'
+
-- z1/z.go --
package z1
import _ "y"
diff --git a/src/cmd/go/testdata/script/import_ignore.txt b/src/cmd/go/testdata/script/import_ignore.txt
new file mode 100644
index 0000000000..83a39a0be3
--- /dev/null
+++ b/src/cmd/go/testdata/script/import_ignore.txt
@@ -0,0 +1,11 @@
+cp go.mod go.mod.orig
+go mod tidy
+cmp go.mod go.mod.orig
+
+-- go.mod --
+module m.test
+
+go 1.16
+-- .ignore.go --
+package p
+import _ "golang.org/x/mod/modfile" \ No newline at end of file
diff --git a/src/cmd/go/testdata/script/link_syso_issue33139.txt b/src/cmd/go/testdata/script/link_syso_issue33139.txt
index d4f0b87537..26034c9626 100644
--- a/src/cmd/go/testdata/script/link_syso_issue33139.txt
+++ b/src/cmd/go/testdata/script/link_syso_issue33139.txt
@@ -8,10 +8,6 @@
# See: https://github.com/golang/go/issues/8912
[linux] [ppc64] skip
-# External linking is not supported on linux/riscv64.
-# See: https://github.com/golang/go/issues/36739
-[linux] [riscv64] skip
-
cc -c -o syso/objTestImpl.syso syso/src/objTestImpl.c
go build -ldflags='-linkmode=external' ./cmd/main.go
diff --git a/src/cmd/go/testdata/script/list_overlay.txt b/src/cmd/go/testdata/script/list_overlay.txt
new file mode 100644
index 0000000000..1153975345
--- /dev/null
+++ b/src/cmd/go/testdata/script/list_overlay.txt
@@ -0,0 +1,63 @@
+# Test listing with overlays
+
+# Overlay in an existing directory
+go list -overlay overlay.json -f '{{.GoFiles}}' .
+stdout '^\[f.go\]$'
+
+# Overlays in a non-existing directory
+go list -overlay overlay.json -f '{{.GoFiles}}' ./dir
+stdout '^\[g.go\]$'
+
+# Overlays in an existing directory with already existing files
+go list -overlay overlay.json -f '{{.GoFiles}}' ./dir2
+stdout '^\[h.go i.go\]$'
+
+# Overlay that removes a file from a directory
+! go list ./dir3 # contains a file without a package statement
+go list -overlay overlay.json -f '{{.GoFiles}}' ./dir3 # overlay removes that file
+
+# Walking through an overlay
+go list -overlay overlay.json ./...
+cmp stdout want-list.txt
+
+# TODO(#39958): assembly files, C files, files that require cgo preprocessing
+
+-- want-list.txt --
+m
+m/dir
+m/dir2
+m/dir3
+-- go.mod --
+// TODO(#39958): Support and test overlays including go.mod itself (especially if mod=readonly)
+module m
+
+go 1.16
+
+-- dir2/h.go --
+package dir2
+
+-- dir3/good.go --
+package dir3
+-- dir3/bad.go --
+// no package statement
+-- overlay.json --
+{
+ "Replace": {
+ "f.go": "overlay/f_go",
+ "dir/g.go": "overlay/dir_g_go",
+ "dir2/i.go": "overlay/dir2_i_go",
+ "dir3/bad.go": ""
+ }
+}
+-- overlay/f_go --
+package m
+
+func f() {
+}
+-- overlay/dir_g_go --
+package m
+
+func g() {
+}
+-- overlay/dir2_i_go --
+package dir2
diff --git a/src/cmd/go/testdata/script/mod_bad_domain.txt b/src/cmd/go/testdata/script/mod_bad_domain.txt
index ec0d474382..868a8d43d6 100644
--- a/src/cmd/go/testdata/script/mod_bad_domain.txt
+++ b/src/cmd/go/testdata/script/mod_bad_domain.txt
@@ -6,18 +6,30 @@ stderr '^go get appengine: package appengine is not in GOROOT \(.*\)$'
! go get x/y.z
stderr 'malformed module path "x/y.z": missing dot in first path element'
+
# 'go list -m' should report errors about module names, never GOROOT.
! go list -m -versions appengine
stderr 'malformed module path "appengine": missing dot in first path element'
! go list -m -versions x/y.z
stderr 'malformed module path "x/y.z": missing dot in first path element'
+
# build should report all unsatisfied imports,
# but should be more definitive about non-module import paths
! go build ./useappengine
-stderr 'cannot find package'
+stderr '^useappengine[/\\]x.go:2:8: cannot find package$'
! go build ./usenonexistent
-stderr 'cannot find module providing package nonexistent.rsc.io'
+stderr '^usenonexistent[/\\]x.go:2:8: no required module provides package nonexistent.rsc.io; try ''go mod tidy'' to add it$'
+
+
+# 'get -d' should be similarly definitive
+
+go get -d ./useappengine # TODO(#41315): This should fail.
+ # stderr '^useappengine[/\\]x.go:2:8: cannot find package$'
+
+! go get -d ./usenonexistent
+stderr '^x/usenonexistent imports\n\tnonexistent.rsc.io: cannot find module providing package nonexistent.rsc.io$'
+
# go mod vendor and go mod tidy should ignore appengine imports.
rm usenonexistent/x.go
diff --git a/src/cmd/go/testdata/script/mod_build_info_err.txt b/src/cmd/go/testdata/script/mod_build_info_err.txt
index 4a6ee9e8bb..cee055eabe 100644
--- a/src/cmd/go/testdata/script/mod_build_info_err.txt
+++ b/src/cmd/go/testdata/script/mod_build_info_err.txt
@@ -10,9 +10,9 @@ stdout '^bad[/\\]bad.go:3:8: malformed import path "🐧.example.com/string": in
stderr '^bad[/\\]bad.go:3:8: malformed import path "🐧.example.com/string": invalid char ''🐧''$'
# TODO(#41688): This should include a file and line, and report the reason for the error..
-# (Today it includes only an import stack, and does not indicate the actual problem.)
+# (Today it includes only an import stack.)
! go get -d ./main
-stderr '^m/main imports\n\tm/bad imports\n\t🐧.example.com/string: import missing$'
+stderr '^m/main imports\n\tm/bad imports\n\t🐧.example.com/string: malformed import path "🐧.example.com/string": invalid char ''🐧''$'
-- go.mod --
diff --git a/src/cmd/go/testdata/script/mod_concurrent_unzipinplace.txt b/src/cmd/go/testdata/script/mod_concurrent_unzipinplace.txt
deleted file mode 100644
index 473be71c9c..0000000000
--- a/src/cmd/go/testdata/script/mod_concurrent_unzipinplace.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-# This tests checks the GODEBUG=modcacheunzipinplace=1 flag, used as part of
-# a migration in golang.org/issue/36568.
-#
-# Concurrent downloads with and without GODEBUG=modcacheunzipinplace=1 should
-# not conflict. This is meant to simulate an old version and a new version
-# of Go accessing the cache concurrently.
-go mod download &
-env GODEBUG=modcacheunzipinplace=1
-go mod download
-wait
-
--- go.mod --
-module golang.org/issue/36568
-
-go 1.14
-
-require rsc.io/quote v1.5.2
diff --git a/src/cmd/go/testdata/script/mod_download_concurrent_read.txt b/src/cmd/go/testdata/script/mod_download_concurrent_read.txt
index bb9c588896..caf105c6e5 100644
--- a/src/cmd/go/testdata/script/mod_download_concurrent_read.txt
+++ b/src/cmd/go/testdata/script/mod_download_concurrent_read.txt
@@ -1,27 +1,18 @@
# This test simulates a process watching for changes and reading files in
# module cache as a module is extracted.
#
-# By default, we unzip a downloaded module into a temporary directory with a
-# random name, then rename the directory into place. On Windows, this fails
-# with ERROR_ACCESS_DENIED if another process (e.g., antivirus) opens files
-# in the directory.
+# Before Go 1.16, we extracted each module zip to a temporary directory with
+# a random name, then renamed that into place with os.Rename. On Windows,
+# this failed with ERROR_ACCESS_DENIED when another process (usually an
+# anti-virus scanner) opened files in the temporary directory. This test
+# simulates that behavior, verifying golang.org/issue/36568.
#
-# Setting GODEBUG=modcacheunzipinplace=1 opts into new behavior: a downloaded
-# module is unzipped in place. A .partial file is created elsewhere to indicate
-# that the extraction is incomplete.
-#
-# Verifies golang.org/issue/36568.
+# Since 1.16, we extract to the final directory, but we create a .partial file
+# so that if we crash, other processes know the directory is incomplete.
[!windows] skip
[short] skip
-# Control case: check that the default behavior fails.
-# This is commented out to avoid flakiness. We can't reproduce the failure
-# 100% of the time.
-# ! go run downloader.go
-
-# Experiment: check that the new behavior does not fail.
-env GODEBUG=modcacheunzipinplace=1
go run downloader.go
-- go.mod --
diff --git a/src/cmd/go/testdata/script/mod_download_partial.txt b/src/cmd/go/testdata/script/mod_download_partial.txt
index 8d31970160..0aab60ddaf 100644
--- a/src/cmd/go/testdata/script/mod_download_partial.txt
+++ b/src/cmd/go/testdata/script/mod_download_partial.txt
@@ -46,7 +46,6 @@ rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
# 'go mod download' should not leave behind a directory or a .partial file
# if there is an error extracting the zip file.
-env GODEBUG=modcacheunzipinplace=1
rm $GOPATH/pkg/mod/rsc.io/quote@v1.5.2
cp empty $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
! go mod download
diff --git a/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt b/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt
index 53b789ecc5..49e17e6507 100644
--- a/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt
+++ b/src/cmd/go/testdata/script/mod_get_downgrade_missing.txt
@@ -14,7 +14,7 @@ cmp go.mod.orig go.mod
! go get example.net/pkgadded@v1.0.0 .
stderr -count=1 '^go: found example.net/pkgadded/subpkg in example.net/pkgadded v1\.2\.0$' # TODO: We shouldn't even try v1.2.0.
-stderr '^example.com/m imports\n\texample.net/pkgadded/subpkg: import missing' # TODO: better error message
+stderr '^example.com/m imports\n\texample.net/pkgadded/subpkg: cannot find module providing package example.net/pkgadded/subpkg$'
cmp go.mod.orig go.mod
go get example.net/pkgadded@v1.0.0
diff --git a/src/cmd/go/testdata/script/mod_get_errors.txt b/src/cmd/go/testdata/script/mod_get_errors.txt
index 7ce045ff82..5c37058d1c 100644
--- a/src/cmd/go/testdata/script/mod_get_errors.txt
+++ b/src/cmd/go/testdata/script/mod_get_errors.txt
@@ -6,11 +6,11 @@ cp go.mod go.mod.orig
# the package in the current directory) cannot be resolved.
! go get
-stderr '^example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: import missing$' # TODO: better error message
+stderr '^example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: cannot find module providing package example.net/oops$'
cmp go.mod.orig go.mod
! go get -d
-stderr '^example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: import missing$' # TODO: better error message
+stderr '^example.com/m imports\n\texample.com/badimport imports\n\texample.net/oops: cannot find module providing package example.net/oops$'
cmp go.mod.orig go.mod
cd importsyntax
diff --git a/src/cmd/go/testdata/script/mod_get_replaced.txt b/src/cmd/go/testdata/script/mod_get_replaced.txt
new file mode 100644
index 0000000000..ea4c603795
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_get_replaced.txt
@@ -0,0 +1,111 @@
+cp go.mod go.mod.orig
+
+env oldGOPROXY=$GOPROXY
+
+# If a wildcard replacement exists for an otherwise-nonexistent module,
+# 'go get' should resolve it to the minimum valid pseudo-version.
+
+go mod edit -replace=example.com/x=./x
+go get -d example.com/x
+
+go list -m example.com/x
+stdout '^example.com/x v0.0.0-00010101000000-000000000000 '
+
+# If specific-version replacements exist, the highest matching version should be used.
+go mod edit -replace=example.com/x@v0.1.0=./x
+go mod edit -replace=example.com/x@v0.2.0=./x
+
+go get -d example.com/x
+go list -m example.com/x
+stdout '^example.com/x v0.2.0 '
+
+go get -d example.com/x@<v0.2.0
+go list -m example.com/x
+stdout '^example.com/x v0.1.0 '
+
+
+# The same should work with GOPROXY=off.
+
+env GOPROXY=off
+cp go.mod.orig go.mod
+
+go mod edit -replace=example.com/x=./x
+go get -d example.com/x
+
+go list -m example.com/x
+stdout '^example.com/x v0.0.0-00010101000000-000000000000 '
+
+# If specific-version replacements exist, the highest matching version should be used.
+go mod edit -replace=example.com/x@v0.1.0=./x
+go mod edit -replace=example.com/x@v0.2.0=./x
+
+go get -d example.com/x
+go list -m example.com/x
+stdout '^example.com/x v0.2.0 '
+
+go get -d example.com/x@<v0.2.0
+go list -m example.com/x
+stdout '^example.com/x v0.1.0 '
+
+
+# Replacements should not be listed as known versions, but 'go get' should sort
+# them in with ordinary versions.
+
+env GOPROXY=$oldGOPROXY
+
+cp go.mod.orig go.mod
+go list -versions -m rsc.io/quote
+stdout 'v1.3.0 v1.4.0'
+
+go get -d rsc.io/quote@v1.3
+go list -m rsc.io/quote
+stdout '^rsc.io/quote v1.3.0'
+
+go mod edit -replace rsc.io/quote@v1.3.1=rsc.io/quote@v1.4.0
+
+go list -versions -m rsc.io/quote
+stdout 'v1.3.0 v1.4.0'
+
+go get -d rsc.io/quote@v1.3
+go list -m rsc.io/quote
+stdout '^rsc.io/quote v1.3.1 '
+
+go get -d rsc.io/quote@>v1.3.1
+go list -m rsc.io/quote
+stdout '^rsc.io/quote v1.4.0'
+
+
+# Replacements should allow 'go get' to work even with dotless module paths.
+
+cp go.mod.orig go.mod
+
+! go list example
+stderr '^package example is not in GOROOT \(.*\)$'
+! go get -d example
+stderr '^go get example: package example is not in GOROOT \(.*\)$'
+
+go mod edit -replace example@v0.1.0=./example
+
+! go list example
+stderr '^module example provides package example and is replaced but not required; try ''go get -d example@v0.1.0'' to add it$'
+
+go get -d example
+go list -m example
+stdout '^example v0.1.0 '
+
+
+-- go.mod --
+module example.com
+
+go 1.16
+-- x/go.mod --
+module example.com/x
+
+go 1.16
+-- x/x.go --
+package x
+-- example/go.mod --
+module example
+go 1.16
+-- example/example.go --
+package example
diff --git a/src/cmd/go/testdata/script/mod_gobuild_import.txt b/src/cmd/go/testdata/script/mod_gobuild_import.txt
index 948496241e..3a133663ec 100644
--- a/src/cmd/go/testdata/script/mod_gobuild_import.txt
+++ b/src/cmd/go/testdata/script/mod_gobuild_import.txt
@@ -19,7 +19,7 @@ exec $WORK/testimport$GOEXE other/x/y/z/w .
stdout w2.go
! exec $WORK/testimport$GOEXE gobuild.example.com/x/y/z/w .
-stderr 'cannot find module providing package gobuild.example.com/x/y/z/w'
+stderr 'no required module provides package gobuild.example.com/x/y/z/w; try ''go get -d gobuild.example.com/x/y/z/w'' to add it'
cd z
exec $WORK/testimport$GOEXE other/x/y/z/w .
diff --git a/src/cmd/go/testdata/script/mod_indirect.txt b/src/cmd/go/testdata/script/mod_indirect.txt
index 87a3f0b10f..6ea1cae98b 100644
--- a/src/cmd/go/testdata/script/mod_indirect.txt
+++ b/src/cmd/go/testdata/script/mod_indirect.txt
@@ -1,6 +1,6 @@
env GO111MODULE=on
-# golang.org/issue/31248: module requirements imposed by dependency versions
+# golang.org/issue/31248: required modules imposed by dependency versions
# older than the selected version must still be taken into account.
env GOFLAGS=-mod=readonly
diff --git a/src/cmd/go/testdata/script/mod_init_path.txt b/src/cmd/go/testdata/script/mod_init_path.txt
index 637c29f4bc..ccdfc92317 100644
--- a/src/cmd/go/testdata/script/mod_init_path.txt
+++ b/src/cmd/go/testdata/script/mod_init_path.txt
@@ -1,7 +1,7 @@
env GO111MODULE=on
! go mod init .
-stderr 'malformed import path'
+stderr '^go: invalid module path "\.": is a local import path$'
cd x
go mod init example.com/x
diff --git a/src/cmd/go/testdata/script/mod_init_tidy.txt b/src/cmd/go/testdata/script/mod_init_tidy.txt
new file mode 100644
index 0000000000..6a37edd960
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_init_tidy.txt
@@ -0,0 +1,30 @@
+# 'go mod init' should not recommend 'go mod tidy' in an empty directory
+# (one that contains no non-hidden .go files or subdirectories).
+cd empty
+go mod init m
+! stderr tidy
+cd ..
+
+# 'go mod init' should recommend 'go mod tidy' if the directory has a .go file.
+cd pkginroot
+go mod init m
+stderr '^go: run ''go mod tidy'' to add module requirements and sums$'
+cd ..
+
+# 'go mod init' should recommend 'go mod tidy' if the directory has a
+# subdirectory. We don't walk the tree to see if it has .go files.
+cd subdir
+go mod init m
+stderr '^go: run ''go mod tidy'' to add module requirements and sums$'
+cd ..
+
+-- empty/empty.txt --
+Not a .go file. Still counts as an empty project.
+-- empty/.hidden/empty.go --
+File in hidden directory. Still as an empty project.
+-- empty/_hidden/empty.go --
+File in hidden directory. Still as an empty project.
+-- pkginroot/hello.go --
+package vendorimport
+-- subdir/sub/empty.txt --
+Subdirectory doesn't need to contain a package.
diff --git a/src/cmd/go/testdata/script/mod_install_pkg_version.txt b/src/cmd/go/testdata/script/mod_install_pkg_version.txt
index dc4a329688..93318b6659 100644
--- a/src/cmd/go/testdata/script/mod_install_pkg_version.txt
+++ b/src/cmd/go/testdata/script/mod_install_pkg_version.txt
@@ -16,7 +16,7 @@ env GO111MODULE=auto
cd m
cp go.mod go.mod.orig
! go list -m all
-stderr 'example.com/cmd@v1.1.0-doesnotexist:.*404 Not Found'
+stderr '^go: example.com/cmd@v1.1.0-doesnotexist: missing go.sum entry; try ''go mod download example.com/cmd'' to add it$'
go install example.com/cmd/a@latest
cmp go.mod go.mod.orig
exists $GOPATH/bin/a$GOEXE
@@ -67,9 +67,9 @@ cd tmp
go mod init tmp
go mod edit -require=rsc.io/fortune@v1.0.0
! go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0
-stderr '^go: updates to go.sum needed, disabled by -mod=readonly$'
+stderr '^go: rsc.io/fortune@v1.0.0: missing go.sum entry; try ''go mod download rsc.io/fortune'' to add it$'
! go install -mod=readonly ../../pkg/mod/rsc.io/fortune@v1.0.0
-stderr '^go: updates to go.sum needed, disabled by -mod=readonly$'
+stderr '^go: rsc.io/fortune@v1.0.0: missing go.sum entry; try ''go mod download rsc.io/fortune'' to add it$'
go get -d rsc.io/fortune@v1.0.0
go install -mod=readonly $GOPATH/pkg/mod/rsc.io/fortune@v1.0.0
exists $GOPATH/bin/fortune$GOEXE
diff --git a/src/cmd/go/testdata/script/mod_list_bad_import.txt b/src/cmd/go/testdata/script/mod_list_bad_import.txt
index b3e2fff67d..3cd50b0de2 100644
--- a/src/cmd/go/testdata/script/mod_list_bad_import.txt
+++ b/src/cmd/go/testdata/script/mod_list_bad_import.txt
@@ -39,7 +39,7 @@ stdout example.com/notfound
# Listing the missing dependency directly should fail outright...
! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound
-stderr 'cannot find module providing package example.com/notfound'
+stderr 'no required module provides package example.com/notfound; try ''go get -d example.com/notfound'' to add it'
! stdout error
! stdout incomplete
diff --git a/src/cmd/go/testdata/script/mod_list_retract.txt b/src/cmd/go/testdata/script/mod_list_retract.txt
index 4e177b3f54..3ba53bc596 100644
--- a/src/cmd/go/testdata/script/mod_list_retract.txt
+++ b/src/cmd/go/testdata/script/mod_list_retract.txt
@@ -32,9 +32,9 @@ go list -m -f '{{with .Retracted}}retracted{{end}}' example.com/retract@v1.0.0-u
# 'go list -m -retracted mod@version' shows an error if the go.mod that should
# contain the retractions is not available.
! go list -m -retracted example.com/retract/missingmod@v1.0.0
-stderr '^go list -m: loading module retractions: example.com/retract/missingmod@v1.9.0:.*404 Not Found$'
+stderr '^go list -m: loading module retractions for example.com/retract/missingmod@v1.0.0: .*404 Not Found$'
go list -e -m -retracted -f '{{.Error.Err}}' example.com/retract/missingmod@v1.0.0
-stdout '^loading module retractions: example.com/retract/missingmod@v1.9.0:.*404 Not Found$'
+stdout '^loading module retractions for example.com/retract/missingmod@v1.0.0: .*404 Not Found$'
# 'go list -m -retracted mod@version' shows retractions.
go list -m -retracted example.com/retract@v1.0.0-unused
diff --git a/src/cmd/go/testdata/script/mod_load_badchain.txt b/src/cmd/go/testdata/script/mod_load_badchain.txt
index e943179c54..a71c4a849e 100644
--- a/src/cmd/go/testdata/script/mod_load_badchain.txt
+++ b/src/cmd/go/testdata/script/mod_load_badchain.txt
@@ -40,6 +40,19 @@ module m
go 1.13
require example.com/badchain/a v1.0.0
+-- go.sum --
+example.com/badchain/a v1.0.0 h1:iJDLiHLmpQgr9Zrv+44UqywAE2IG6WkHnH4uG08vf+s=
+example.com/badchain/a v1.0.0/go.mod h1:6/gnCYHdVrs6mUgatUYUSbuHxEY+/yWedmTggLz23EI=
+example.com/badchain/a v1.1.0 h1:cPxQpsOjaIrn05yDfl4dFFgGSbjYmytLqtIIBfTsEqA=
+example.com/badchain/a v1.1.0/go.mod h1:T15b2BEK+RY7h7Lr2dgS38p1pgH5/t7Kf5nQXBlcW/A=
+example.com/badchain/b v1.0.0 h1:kjDVlBxpjQavYxHE7ECCyyXhfwsfhWIqvghfRgPktSA=
+example.com/badchain/b v1.0.0/go.mod h1:sYsH934pMc3/A2vQZh019qrWmp4+k87l3O0VFUYqL+I=
+example.com/badchain/b v1.1.0 h1:iEALV+DRN62FArnYylBR4YwCALn/hCdITvhdagHa0L4=
+example.com/badchain/b v1.1.0/go.mod h1:mlCgKO7lRZ+ijwMFIBFRPCGt5r5oqCcHdhSSE0VL4uY=
+example.com/badchain/c v1.0.0 h1:lOeUHQKR7SboSH7Bj6eIDWoNHaDQXI0T2GfaH2x9fNA=
+example.com/badchain/c v1.0.0/go.mod h1:4U3gzno17SaQ2koSVNxITu9r60CeLSgye9y4/5LnfOE=
+example.com/badchain/c v1.1.0 h1:VtTg1g7fOutWKHQf+ag04KLRpdMGSfQ9s9tagVtGW14=
+example.com/badchain/c v1.1.0/go.mod h1:tyoJj5qh+qtb48sflwdVvk4R+OjPQEY2UJOoibsVLPk=
-- use/use.go --
package use
diff --git a/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt b/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt
index 067e209b01..2ca8b3cace 100644
--- a/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt
+++ b/src/cmd/go/testdata/script/mod_load_replace_mismatch.txt
@@ -2,7 +2,7 @@
# the original module and its location, report an error with all three paths.
# In particular, the "required as" path should be the original.
# Verifies golang.org/issue/38220.
-! go list .
+! go mod download
cmp stderr want
-- go.mod --
diff --git a/src/cmd/go/testdata/script/mod_outside.txt b/src/cmd/go/testdata/script/mod_outside.txt
index e398f7bc40..d969fce145 100644
--- a/src/cmd/go/testdata/script/mod_outside.txt
+++ b/src/cmd/go/testdata/script/mod_outside.txt
@@ -39,6 +39,11 @@ stdout '^fmt$'
go list ./needmod/needmod.go
stdout 'command-line-arguments'
+# 'go list' on a package from a module should fail.
+! go list example.com/printversion
+stderr '^no required module provides package example.com/printversion: working directory is not part of a module$'
+
+
# 'go list -m' with an explicit version should resolve that version.
go list -m example.com/version@latest
stdout 'example.com/version v1.1.0'
@@ -151,7 +156,7 @@ stderr 'cannot find main module'
# 'go build' of source files should fail if they import anything outside std.
! go build -n ./needmod/needmod.go
-stderr 'needmod[/\\]needmod.go:10:2: cannot find module providing package example.com/version: working directory is not part of a module'
+stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$'
# 'go build' of source files should succeed if they do not import anything outside std.
go build -n -o ignore ./stdonly/stdonly.go
@@ -174,7 +179,7 @@ go doc fmt
# 'go doc' should fail for a package path outside a module.
! go doc example.com/version
-stderr 'doc: cannot find module providing package example.com/version: working directory is not part of a module'
+stderr 'doc: no required module provides package example.com/version: working directory is not part of a module'
# 'go install' with a version should succeed if all constraints are met.
# See mod_install_pkg_version.
@@ -184,12 +189,12 @@ exists $GOPATH/bin/printversion$GOEXE
# 'go install' should fail if a package argument must be resolved to a module.
! go install example.com/printversion
-stderr 'cannot find module providing package example.com/printversion: working directory is not part of a module'
+stderr 'no required module provides package example.com/printversion: working directory is not part of a module'
# 'go install' should fail if a source file imports a package that must be
# resolved to a module.
! go install ./needmod/needmod.go
-stderr 'needmod[/\\]needmod.go:10:2: cannot find module providing package example.com/version: working directory is not part of a module'
+stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module'
# 'go run' with a verison should fail due to syntax.
@@ -198,12 +203,12 @@ stderr 'can only use path@version syntax with'
# 'go run' should fail if a package argument must be resolved to a module.
! go run example.com/printversion
-stderr 'cannot find module providing package example.com/printversion: working directory is not part of a module'
+stderr '^no required module provides package example.com/printversion: working directory is not part of a module$'
# 'go run' should fail if a source file imports a package that must be
# resolved to a module.
! go run ./needmod/needmod.go
-stderr 'needmod[/\\]needmod.go:10:2: cannot find module providing package example.com/version: working directory is not part of a module'
+stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$'
# 'go fmt' should be able to format files outside of a module.
@@ -221,7 +226,7 @@ stdout 'main is example.com/printversion v0.1.0'
stdout 'using example.com/version v1.1.0'
# 'go get' of a versioned binary should build and install the latest version
-# using its minimal module requirements, ignoring replacements and exclusions.
+# using its minimal required modules, ignoring replacements and exclusions.
go get example.com/printversion
exec ../bin/printversion
stdout 'path is example.com/printversion'
diff --git a/src/cmd/go/testdata/script/mod_proxy_invalid.txt b/src/cmd/go/testdata/script/mod_proxy_invalid.txt
index 6427cc1527..b9418b4df1 100644
--- a/src/cmd/go/testdata/script/mod_proxy_invalid.txt
+++ b/src/cmd/go/testdata/script/mod_proxy_invalid.txt
@@ -2,7 +2,7 @@ env GO111MODULE=on
env GOPROXY=$GOPROXY/invalid
! go list -m rsc.io/quote@latest
-stderr '^go list -m: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
+stderr '^go list -m: module rsc.io/quote: invalid response from proxy "'$GOPROXY'": json: invalid character ''i'' looking for beginning of value$'
! go list -m rsc.io/quote@1.5.2
-stderr '^go list -m: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": invalid character ''i'' looking for beginning of value$'
+stderr '^go list -m: rsc.io/quote@1.5.2: invalid version: invalid response from proxy "'$GOPROXY'": json: invalid character ''i'' looking for beginning of value$'
diff --git a/src/cmd/go/testdata/script/mod_query_empty.txt b/src/cmd/go/testdata/script/mod_query_empty.txt
index b3ea3e3de0..a07a07c4bc 100644
--- a/src/cmd/go/testdata/script/mod_query_empty.txt
+++ b/src/cmd/go/testdata/script/mod_query_empty.txt
@@ -40,7 +40,7 @@ env GOPROXY=file:///$WORK/gatekeeper
chmod 0000 $WORK/gatekeeper/example.com/join/subpkg/@latest
cp go.mod.orig go.mod
! go get -d example.com/join/subpkg
-stderr 'go get example.com/join/subpkg: module example.com/join/subpkg: (invalid response from proxy ".+": invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)'
+stderr 'go get example.com/join/subpkg: module example.com/join/subpkg: (invalid response from proxy ".+": json: invalid character .+|reading file://.*/gatekeeper/example.com/join/subpkg/@latest: .+)'
-- go.mod.orig --
module example.com/othermodule
diff --git a/src/cmd/go/testdata/script/mod_readonly.txt b/src/cmd/go/testdata/script/mod_readonly.txt
index a8458fdea3..f2c77de806 100644
--- a/src/cmd/go/testdata/script/mod_readonly.txt
+++ b/src/cmd/go/testdata/script/mod_readonly.txt
@@ -13,7 +13,7 @@ cmp go.mod go.mod.empty
# -mod=readonly should be set by default.
env GOFLAGS=
! go list all
-stderr '^x.go:2:8: cannot find module providing package rsc\.io/quote$'
+stderr '^x.go:2:8: no required module provides package rsc\.io/quote; try ''go mod tidy'' to add it$'
cmp go.mod go.mod.empty
env GOFLAGS=-mod=readonly
@@ -41,7 +41,8 @@ go list -m all
# -mod=readonly should reject inconsistent go.mod files
# (ones that would be rewritten).
-go mod edit -require rsc.io/sampler@v1.2.0
+go get -d rsc.io/sampler@v1.2.0
+go mod edit -require rsc.io/quote@v1.5.2
cp go.mod go.mod.inconsistent
! go list
stderr 'go: updates to go.mod needed, disabled by -mod=readonly'
@@ -68,6 +69,23 @@ cp go.mod.indirect go.mod
go list all
cmp go.mod go.mod.indirect
+
+# If we identify a missing package as a dependency of some other package in the
+# main module, we should suggest 'go mod tidy' instead of resolving it.
+
+cp go.mod.untidy go.mod
+! go list all
+stderr '^x.go:2:8: no required module provides package rsc.io/quote; try ''go mod tidy'' to add it$'
+
+! go list -deps .
+stderr '^x.go:2:8: no required module provides package rsc.io/quote; try ''go mod tidy'' to add it$'
+
+# However, if we didn't see an import from the main module, we should suggest
+# 'go get -d' instead, because we don't know whether 'go mod tidy' would add it.
+! go list rsc.io/quote
+stderr '^no required module provides package rsc.io/quote; try ''go get -d rsc.io/quote'' to add it$'
+
+
-- go.mod --
module m
@@ -103,3 +121,11 @@ require (
rsc.io/sampler v1.3.0 // indirect
rsc.io/testonly v1.0.0 // indirect
)
+-- go.mod.untidy --
+module m
+
+go 1.20
+
+require (
+ rsc.io/sampler v1.3.0 // indirect
+)
diff --git a/src/cmd/go/testdata/script/mod_replace_import.txt b/src/cmd/go/testdata/script/mod_replace_import.txt
index 407a6cef7d..2add31f71c 100644
--- a/src/cmd/go/testdata/script/mod_replace_import.txt
+++ b/src/cmd/go/testdata/script/mod_replace_import.txt
@@ -25,10 +25,11 @@ stdout 'example.com/v v1.12.0 => ./v12'
# The go command should print an informative error when the matched
# module does not contain a package.
+# TODO(#26909): Ideally these errors should include line numbers for the imports within the main module.
cd fail
-! go list all
-stderr '^m.go:4:2: module w@latest found \(v0.0.0-00010101000000-000000000000, replaced by ../w\), but does not contain package w$'
-stderr '^m.go:5:2: nonexist@v0.1.0: replacement directory ../nonexist does not exist$'
+! go mod tidy
+stderr '^localhost.fail imports\n\tw: module w@latest found \(v0.0.0-00010101000000-000000000000, replaced by ../w\), but does not contain package w$'
+stderr '^localhost.fail imports\n\tnonexist: nonexist@v0.1.0: replacement directory ../nonexist does not exist$'
-- go.mod --
module example.com/m
diff --git a/src/cmd/go/testdata/script/mod_replace_readonly.txt b/src/cmd/go/testdata/script/mod_replace_readonly.txt
new file mode 100644
index 0000000000..882c755337
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_replace_readonly.txt
@@ -0,0 +1,62 @@
+# Check that with -mod=readonly, when we load a package in a module that is
+# replaced but not required, we emit an error with the command to add the
+# requirement.
+# Verifies golang.org/issue/41416, golang.org/issue/41577.
+cp go.mod go.mod.orig
+
+# Replace all versions of a module without requiring it.
+# With -mod=mod, we'd add a requirement for a "zero" pseudo-version, but we
+# can't in readonly mode, since its go.mod may alter the build list.
+go mod edit -replace rsc.io/quote=./quote
+! go list rsc.io/quote
+stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; try ''go get -d rsc.io/quote'' to add it$'
+go get -d rsc.io/quote
+cmp go.mod go.mod.latest
+go list rsc.io/quote
+cp go.mod.orig go.mod
+
+# Same test with a specific version.
+go mod edit -replace rsc.io/quote@v1.0.0-doesnotexist=./quote
+! go list rsc.io/quote
+stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; try ''go get -d rsc.io/quote@v1.0.0-doesnotexist'' to add it$'
+go get -d rsc.io/quote@v1.0.0-doesnotexist
+cmp go.mod go.mod.specific
+go list rsc.io/quote
+cp go.mod.orig go.mod
+
+# If there are multiple versions, the highest is suggested.
+go mod edit -replace rsc.io/quote@v1.0.0-doesnotexist=./quote
+go mod edit -replace rsc.io/quote@v1.1.0-doesnotexist=./quote
+! go list rsc.io/quote
+stderr '^module rsc.io/quote provides package rsc.io/quote and is replaced but not required; try ''go get -d rsc.io/quote@v1.1.0-doesnotexist'' to add it$'
+
+-- go.mod --
+module m
+
+go 1.16
+-- go.mod.latest --
+module m
+
+go 1.16
+
+replace rsc.io/quote => ./quote
+
+require rsc.io/quote v1.5.2 // indirect
+-- go.mod.specific --
+module m
+
+go 1.16
+
+replace rsc.io/quote v1.0.0-doesnotexist => ./quote
+
+require rsc.io/quote v1.0.0-doesnotexist // indirect
+-- use.go --
+package use
+
+import _ "rsc.io/quote"
+-- quote/go.mod --
+module rsc.io/quote
+
+go 1.16
+-- quote/quote.go --
+package quote
diff --git a/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt b/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt
new file mode 100644
index 0000000000..93609f36c9
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_retract_pseudo_base.txt
@@ -0,0 +1,62 @@
+# When converting a commit to a pseudo-version, don't use a retracted version
+# as the base.
+# Verifies golang.org/issue/41700.
+
+[!net] skip
+[!exec:git] skip
+env GOPROXY=direct
+env GOSUMDB=off
+go mod init m
+
+# Control: check that v1.0.0 is the only version and is retracted.
+go list -m -versions vcs-test.golang.org/git/retract-pseudo.git
+stdout '^vcs-test.golang.org/git/retract-pseudo.git$'
+go list -m -versions -retracted vcs-test.golang.org/git/retract-pseudo.git
+stdout '^vcs-test.golang.org/git/retract-pseudo.git v1.0.0$'
+
+# 713affd19d7b is a commit after v1.0.0. Don't use v1.0.0 as the base.
+go list -m vcs-test.golang.org/git/retract-pseudo.git@713affd19d7b
+stdout '^vcs-test.golang.org/git/retract-pseudo.git v0.0.0-20201009173747-713affd19d7b$'
+
+# 64c061ed4371 is the commit v1.0.0 refers to. Don't convert to v1.0.0.
+go list -m vcs-test.golang.org/git/retract-pseudo.git@64c061ed4371
+stdout '^vcs-test.golang.org/git/retract-pseudo.git v0.0.0-20201009173747-64c061ed4371'
+
+# A retracted version is a valid base. Retraction should not validate existing
+# pseudo-versions, nor should it turn invalid pseudo-versions valid.
+go get -d vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-713affd19d7b
+go list -m vcs-test.golang.org/git/retract-pseudo.git
+stdout '^vcs-test.golang.org/git/retract-pseudo.git v1.0.1-0.20201009173747-713affd19d7b$'
+
+! go get -d vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371
+stderr '^go get vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371: vcs-test.golang.org/git/retract-pseudo.git@v1.0.1-0.20201009173747-64c061ed4371: invalid pseudo-version: tag \(v1.0.0\) found on revision 64c061ed4371 is already canonical, so should not be replaced with a pseudo-version derived from that tag$'
+
+-- retract-pseudo.sh --
+#!/bin/bash
+
+# This is not part of the test.
+# Run this to generate and update the repository on vcs-test.golang.org.
+
+set -euo pipefail
+
+rm -rf retract-pseudo
+mkdir retract-pseudo
+cd retract-pseudo
+git init
+
+# Create the module.
+# Retract v1.0.0 and tag v1.0.0 at the same commit.
+# The module has no unretracted release versions.
+go mod init vcs-test.golang.org/git/retract-pseudo.git
+go mod edit -retract v1.0.0
+echo 'package p' >p.go
+git add -A
+git commit -m 'create module retract-pseudo'
+git tag v1.0.0
+
+# Commit a trivial change so the default branch does not point to v1.0.0.
+git mv p.go q.go
+git commit -m 'trivial change'
+
+zip -r ../retract-pseudo.zip .
+gsutil cp ../retract-pseudo.zip gs://vcs-test/git/retract-pseudo.zip
diff --git a/src/cmd/go/testdata/script/mod_retract_replace.txt b/src/cmd/go/testdata/script/mod_retract_replace.txt
index 7aec438dda..770aea41a5 100644
--- a/src/cmd/go/testdata/script/mod_retract_replace.txt
+++ b/src/cmd/go/testdata/script/mod_retract_replace.txt
@@ -6,7 +6,7 @@ go get -d
# The latest version, v1.9.0, is not available on the proxy.
! go list -m -retracted example.com/retract/missingmod
-stderr '^go list -m: loading module retractions: example.com/retract/missingmod@v1.9.0:.*404 Not Found$'
+stderr '^go list -m: loading module retractions for example.com/retract/missingmod@v1.0.0: .*404 Not Found$'
# If we replace that version, we should see retractions.
go mod edit -replace=example.com/retract/missingmod@v1.9.0=./missingmod-v1.9.0
diff --git a/src/cmd/go/testdata/script/mod_sum_ambiguous.txt b/src/cmd/go/testdata/script/mod_sum_ambiguous.txt
new file mode 100644
index 0000000000..999257c419
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_sum_ambiguous.txt
@@ -0,0 +1,48 @@
+# Confirm our build list.
+cp go.sum.buildlist-only go.sum
+go list -m all
+stdout '^example.com/ambiguous/a v1.0.0$'
+stdout '^example.com/ambiguous/a/b v0.0.0-empty$'
+
+# If two modules could provide a package, but only one does,
+# 'go mod tidy' should retain sums for both zips.
+go mod tidy
+grep '^example.com/ambiguous/a v1.0.0 h1:' go.sum
+grep '^example.com/ambiguous/a/b v0.0.0-empty h1:' go.sum
+
+# If two modules could provide a package, and we're missing a sum for one,
+# we should see a missing sum error, even if we have a sum for a module that
+# provides the package.
+cp go.sum.a-only go.sum
+! go list example.com/ambiguous/a/b
+stderr '^missing go.sum entry needed to verify package example.com/ambiguous/a/b is provided by exactly one module$'
+! go list -deps .
+stderr '^use.go:3:8: missing go.sum entry needed to verify package example.com/ambiguous/a/b is provided by exactly one module; try ''go mod tidy'' to add it$'
+
+cp go.sum.b-only go.sum
+! go list example.com/ambiguous/a/b
+stderr '^missing go.sum entry for module providing package example.com/ambiguous/a/b$'
+! go list -deps .
+stderr '^use.go:3:8: missing go.sum entry for module providing package example.com/ambiguous/a/b; try ''go mod tidy'' to add it$'
+
+-- go.mod --
+module m
+
+go 1.15
+
+require example.com/ambiguous/a v1.0.0
+-- go.sum.buildlist-only --
+example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0=
+example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ=
+-- go.sum.a-only --
+example.com/ambiguous/a v1.0.0 h1:pGZhTXy6+titE2rNfwHwJykSjXDR4plO52PfZrBM0T8=
+example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0=
+example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ=
+-- go.sum.b-only --
+example.com/ambiguous/a v1.0.0/go.mod h1:TrBl/3xTPFJ2gmMIYz53h2gkNtg0dokszEMuyS1QEb0=
+example.com/ambiguous/a/b v0.0.0-empty h1:xS29ReXXuhjT7jc79mo91h/PevaZ2oS9PciF1DucXtg=
+example.com/ambiguous/a/b v0.0.0-empty/go.mod h1:MajJq5jPEBnnXP+NTWIeXX7kwaPS1sbVEJdooTmsePQ=
+-- use.go --
+package use
+
+import _ "example.com/ambiguous/a/b"
diff --git a/src/cmd/go/testdata/script/mod_sum_readonly.txt b/src/cmd/go/testdata/script/mod_sum_readonly.txt
new file mode 100644
index 0000000000..4d6e8aae6a
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_sum_readonly.txt
@@ -0,0 +1,87 @@
+# Test that go.sum does not get updated when -mod=readonly flag is set
+env GO111MODULE=on
+
+# When a sum is needed to load the build list, we get an error for the
+# specific module. The .mod file is not downloaded, and go.sum is not written.
+! go list -m all
+stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; try ''go mod download rsc.io/quote'' to add it$'
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
+! exists go.sum
+
+# If go.sum exists but contains hashes from an algorithm we don't know about,
+# we should see the same error.
+cp go.sum.h2only go.sum
+! go list -m all
+stderr '^go: rsc.io/quote@v1.5.2: missing go.sum entry; try ''go mod download rsc.io/quote'' to add it$'
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
+cmp go.sum go.sum.h2only
+rm go.sum
+
+# If we replace a module, we should see a missing sum error for the replacement.
+cp go.mod go.mod.orig
+go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1
+! go list -m all
+stderr '^go: rsc.io/quote@v1.5.2 \(replaced by rsc.io/quote@v1.5.1\): missing go.sum entry; try ''go mod download rsc.io/quote'' to add it$'
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.mod
+! exists go.sum
+cp go.mod.orig go.mod
+
+# Control: when sums are present, loading the build list downloads .mod files.
+cp go.sum.buildlistonly go.sum
+go list -m all
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod
+
+
+# When a sum is needed to load a .mod file for a package outside the build list,
+# we get a generic missing import error.
+! go list example.com/doesnotexist
+stderr '^no required module provides package example.com/doesnotexist; try ''go get -d example.com/doesnotexist'' to add it$'
+
+# When a sum is needed to load a .zip file, we get a more specific error.
+# The .zip file is not downloaded.
+! go list rsc.io/quote
+stderr '^missing go.sum entry for module providing package rsc.io/quote$'
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+
+# The error is attached to the package from the missing module. We can load
+# a package that imports it without that error.
+go list -e -deps -f '{{.ImportPath}}{{with .Error}} {{.Err}}{{end}}' .
+stdout '^m$'
+stdout '^rsc.io/quote missing go.sum entry for module providing package rsc.io/quote; try ''go mod tidy'' to add it$'
+! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+
+# go.sum should not have been written.
+cmp go.sum go.sum.buildlistonly
+
+# Control: when sums are present, 'go list' downloads .zip files.
+cp go.sum.tidy go.sum
+go list .
+exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+
+-- go.mod --
+module m
+
+go 1.15
+
+require rsc.io/quote v1.5.2
+-- use.go --
+package use
+
+import _ "rsc.io/quote"
+-- go.sum.h2only --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h2:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.5.2/go.mod h2:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0/go.mod h2:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+-- go.sum.buildlistonly --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+-- go.sum.tidy --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+rsc.io/testonly v1.0.0 h1:K/VWHdO+Jv7woUXG0GzVNx1czBXUt3Ib1deaMn+xk64=
+rsc.io/testonly v1.0.0/go.mod h1:OqmGbIFOcF+XrFReLOGZ6BhMM7uMBiQwZsyNmh74SzY=
diff --git a/src/cmd/go/testdata/script/mod_sumdb.txt b/src/cmd/go/testdata/script/mod_sumdb.txt
index 68bbd9c274..fb320a557a 100644
--- a/src/cmd/go/testdata/script/mod_sumdb.txt
+++ b/src/cmd/go/testdata/script/mod_sumdb.txt
@@ -17,7 +17,7 @@ stderr 'SECURITY ERROR\nThis download does NOT match the one reported by the che
! go get -d golang.org/x/text
go mod edit -require rsc.io/quote@v1.5.2
-! go list all
+! go mod tidy
stderr 'go: rsc.io/quote@v1.5.2: verifying go.mod: checksum mismatch'
stderr 'SECURITY ERROR\n'
diff --git a/src/cmd/go/testdata/script/mod_vendor_auto.txt b/src/cmd/go/testdata/script/mod_vendor_auto.txt
index 53120dcfa1..e71db96643 100644
--- a/src/cmd/go/testdata/script/mod_vendor_auto.txt
+++ b/src/cmd/go/testdata/script/mod_vendor_auto.txt
@@ -177,7 +177,7 @@ stdout '^'$WORK'[/\\]auto[/\\]vendor[/\\]example.com[/\\]version$'
# 'go get' should update from the network or module cache,
# even if a vendor directory is present.
-go get -u example.com/printversion
+go get example.com/version@v1.1.0
! go list -f {{.Dir}} -tags tools all
stderr '^go: inconsistent vendoring'
diff --git a/src/cmd/go/testdata/script/sum_readonly.txt b/src/cmd/go/testdata/script/sum_readonly.txt
deleted file mode 100644
index 8aa61166ac..0000000000
--- a/src/cmd/go/testdata/script/sum_readonly.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-# Test that go.sum does not get updated when -mod=readonly flag is set
-env GO111MODULE=on
-
-go get -d rsc.io/quote
-go mod tidy
-
-# go.sum != dirty; -mod=readonly
-go list -mod=readonly
-
-# dirty up go.sum by removing it.
-rm go.sum
-
-# go.sum == dirty; -mod=readonly
-! go list -mod=readonly
-
-stderr 'go: updates to go.sum needed, disabled by -mod=readonly'
-
--- go.mod --
-module m
-
--- main.go --
-
-package main
-
-import "rsc.io/quote"
-
-func main() {
- println(quote.Hello())
-} \ No newline at end of file
diff --git a/src/cmd/go/testdata/script/test_cache_inputs.txt b/src/cmd/go/testdata/script/test_cache_inputs.txt
index 57602e91dc..50486e1909 100644
--- a/src/cmd/go/testdata/script/test_cache_inputs.txt
+++ b/src/cmd/go/testdata/script/test_cache_inputs.txt
@@ -137,7 +137,7 @@ exit 0
package testcache
import (
- "io/ioutil"
+ "io"
"os"
"testing"
)
@@ -159,7 +159,7 @@ func TestOddFileContent(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- data, err := ioutil.ReadAll(f)
+ data, err := io.ReadAll(f)
f.Close()
if err != nil {
t.Fatal(err)
diff --git a/src/cmd/go/testdata/script/toolexec.txt b/src/cmd/go/testdata/script/toolexec.txt
new file mode 100644
index 0000000000..526234196b
--- /dev/null
+++ b/src/cmd/go/testdata/script/toolexec.txt
@@ -0,0 +1,85 @@
+[short] skip
+
+# Build our simple toolexec program.
+go build ./cmd/mytool
+
+# Build the main package with our toolexec program. For each action, it will
+# print the tool's name and the TOOLEXEC_IMPORTPATH value. We expect to compile
+# each package once, and link the main package once.
+# Don't check the entire output at once, because the order in which the tools
+# are run is irrelevant here.
+# Finally, note that asm and cgo are run twice.
+
+go build -toolexec=$PWD/mytool
+[amd64] stderr -count=2 '^asm'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main/withasm$'
+stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main/withasm$'
+[cgo] stderr -count=2 '^cgo'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main/withcgo$'
+[cgo] stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main/withcgo$'
+stderr -count=1 '^compile'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main$'
+stderr -count=1 '^link'${GOEXE}' TOOLEXEC_IMPORTPATH=test/main$'
+
+-- go.mod --
+module test/main
+-- foo.go --
+// Simple package so we can test a program build with -toolexec.
+// With a dummy import, to test different TOOLEXEC_IMPORTPATH values.
+// Includes dummy uses of cgo and asm, to cover those tools as well.
+package main
+
+import (
+ _ "test/main/withasm"
+ _ "test/main/withcgo"
+)
+
+func main() {}
+-- withcgo/withcgo.go --
+package withcgo
+
+// int fortytwo()
+// {
+// return 42;
+// }
+import "C"
+-- withcgo/stub.go --
+package withcgo
+
+// Stub file to ensure we build without cgo too.
+-- withasm/withasm.go --
+package withasm
+
+// Note that we don't need to declare the Add func at all.
+-- withasm/withasm_amd64.s --
+TEXT ·Add(SB),$0-24
+ MOVQ a+0(FP), AX
+ ADDQ b+8(FP), AX
+ MOVQ AX, ret+16(FP)
+ RET
+-- cmd/mytool/main.go --
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+)
+
+func main() {
+ tool, args := os.Args[1], os.Args[2:]
+ toolName := filepath.Base(tool)
+ if len(args) > 0 && args[0] == "-V=full" {
+ // We can't alter the version output.
+ } else {
+ // Print which tool we're running, and on what package.
+ fmt.Fprintf(os.Stdout, "%s TOOLEXEC_IMPORTPATH=%s\n", toolName, os.Getenv("TOOLEXEC_IMPORTPATH"))
+ }
+
+ // Simply run the tool.
+ cmd := exec.Command(tool, args...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(1)
+ }
+}
diff --git a/src/cmd/go/testdata/script/vet_flags.txt b/src/cmd/go/testdata/script/vet_flags.txt
index b85b133c19..e2e3f5bc55 100644
--- a/src/cmd/go/testdata/script/vet_flags.txt
+++ b/src/cmd/go/testdata/script/vet_flags.txt
@@ -2,21 +2,25 @@ env GO111MODULE=on
# Issue 35837: "go vet -<analyzer> <std package>" should use the requested
# analyzers, not the default analyzers for 'go test'.
-go vet -n -unreachable=false encoding/binary
-stderr '-unreachable=false'
+go vet -n -buildtags=false runtime
+stderr '-buildtags=false'
! stderr '-unsafeptr=false'
# Issue 37030: "go vet <std package>" without other flags should disable the
# unsafeptr check by default.
-go vet -n encoding/binary
+go vet -n runtime
stderr '-unsafeptr=false'
! stderr '-unreachable=false'
# However, it should be enabled if requested explicitly.
-go vet -n -unsafeptr encoding/binary
+go vet -n -unsafeptr runtime
stderr '-unsafeptr'
! stderr '-unsafeptr=false'
+# -unreachable is disabled during test but on during plain vet.
+go test -n runtime
+stderr '-unreachable=false'
+
# A flag terminator should be allowed before the package list.
go vet -n -- .
@@ -60,10 +64,10 @@ stderr '[/\\]vet'$GOEXE'["]? .* -errorsas .* ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
# "go test" on a standard package should by default disable an explicit list.
go test -x -run=none encoding/binary
-stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
+stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
go test -x -vet= -run=none encoding/binary
-stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
+stderr '[/\\]vet'$GOEXE'["]? -unsafeptr=false -unreachable=false ["]?\$WORK[/\\][^ ]*[/\\]vet\.cfg'
# Both should allow users to override via the -vet flag.
go test -x -vet=unreachable -run=none .
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 8c56af7559..dba2411eed 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -14,6 +14,7 @@ import (
"go/scanner"
"go/token"
"io"
+ "io/fs"
"io/ioutil"
"os"
"path/filepath"
@@ -73,7 +74,7 @@ func initParserMode() {
}
}
-func isGoFile(f os.FileInfo) bool {
+func isGoFile(f fs.FileInfo) bool {
// ignore non-Go files
name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
@@ -81,7 +82,7 @@ func isGoFile(f os.FileInfo) bool {
// If in == nil, the source is the contents of the file with the given filename.
func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
- var perm os.FileMode = 0644
+ var perm fs.FileMode = 0644
if in == nil {
f, err := os.Open(filename)
if err != nil {
@@ -96,7 +97,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
perm = fi.Mode().Perm()
}
- src, err := ioutil.ReadAll(in)
+ src, err := io.ReadAll(in)
if err != nil {
return err
}
@@ -163,7 +164,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
return err
}
-func visitFile(path string, f os.FileInfo, err error) error {
+func visitFile(path string, f fs.FileInfo, err error) error {
if err == nil && isGoFile(f) {
err = processFile(path, nil, os.Stdout, false)
}
@@ -275,7 +276,7 @@ const chmodSupported = runtime.GOOS != "windows"
// backupFile writes data to a new file named filename<number> with permissions perm,
// with <number randomly chosen such that the file name is unique. backupFile returns
// the chosen file name.
-func backupFile(filename string, data []byte, perm os.FileMode) (string, error) {
+func backupFile(filename string, data []byte, perm fs.FileMode) (string, error) {
// create backup file
f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename))
if err != nil {
diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go
index e2a6208f87..28306ce83e 100644
--- a/src/cmd/gofmt/long_test.go
+++ b/src/cmd/gofmt/long_test.go
@@ -16,6 +16,7 @@ import (
"go/printer"
"go/token"
"io"
+ "io/fs"
"os"
"path/filepath"
"runtime"
@@ -107,7 +108,7 @@ func testFiles(t *testing.T, filenames <-chan string, done chan<- int) {
func genFilenames(t *testing.T, filenames chan<- string) {
defer close(filenames)
- handleFile := func(filename string, fi os.FileInfo, err error) error {
+ handleFile := func(filename string, fi fs.FileInfo, err error) error {
if err != nil {
t.Error(err)
return nil
diff --git a/src/cmd/internal/buildid/buildid.go b/src/cmd/internal/buildid/buildid.go
index ac238d70ea..1d6563cafc 100644
--- a/src/cmd/internal/buildid/buildid.go
+++ b/src/cmd/internal/buildid/buildid.go
@@ -10,6 +10,7 @@ import (
"fmt"
"internal/xcoff"
"io"
+ "io/fs"
"os"
"strconv"
"strings"
@@ -109,7 +110,7 @@ func ReadFile(name string) (id string, err error) {
// in cmd/go/internal/work/exec.go.
func readGccgoArchive(name string, f *os.File) (string, error) {
bad := func() (string, error) {
- return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+ return "", &fs.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
}
off := int64(8)
@@ -167,7 +168,7 @@ func readGccgoArchive(name string, f *os.File) (string, error) {
// in cmd/go/internal/work/exec.go.
func readGccgoBigArchive(name string, f *os.File) (string, error) {
bad := func() (string, error) {
- return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+ return "", &fs.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
}
// Read fixed-length header.
@@ -309,13 +310,13 @@ func readRaw(name string, data []byte) (id string, err error) {
j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd)
if j < 0 {
- return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+ return "", &fs.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
}
quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1]
id, err = strconv.Unquote(string(quoted))
if err != nil {
- return "", &os.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
+ return "", &fs.PathError{Op: "parse", Path: name, Err: errBuildIDMalformed}
}
return id, nil
}
diff --git a/src/cmd/internal/buildid/note.go b/src/cmd/internal/buildid/note.go
index 2d26ea9961..f5b6fc565f 100644
--- a/src/cmd/internal/buildid/note.go
+++ b/src/cmd/internal/buildid/note.go
@@ -11,6 +11,7 @@ import (
"encoding/binary"
"fmt"
"io"
+ "io/fs"
"os"
)
@@ -96,7 +97,7 @@ func readELF(name string, f *os.File, data []byte) (buildid string, err error) {
ef, err := elf.NewFile(bytes.NewReader(data))
if err != nil {
- return "", &os.PathError{Path: name, Op: "parse", Err: err}
+ return "", &fs.PathError{Path: name, Op: "parse", Err: err}
}
var gnu string
for _, p := range ef.Progs {
@@ -181,13 +182,13 @@ func readMacho(name string, f *os.File, data []byte) (buildid string, err error)
mf, err := macho.NewFile(f)
if err != nil {
- return "", &os.PathError{Path: name, Op: "parse", Err: err}
+ return "", &fs.PathError{Path: name, Op: "parse", Err: err}
}
sect := mf.Section("__text")
if sect == nil {
// Every binary has a __text section. Something is wrong.
- return "", &os.PathError{Path: name, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
+ return "", &fs.PathError{Path: name, Op: "parse", Err: fmt.Errorf("cannot find __text section")}
}
// It should be in the first few bytes, but read a lot just in case,
diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go
index 2e6167322e..7362e7868b 100644
--- a/src/cmd/internal/moddeps/moddeps_test.go
+++ b/src/cmd/internal/moddeps/moddeps_test.go
@@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"internal/testenv"
+ "io/fs"
"io/ioutil"
"os"
"os/exec"
@@ -32,7 +33,7 @@ func findGorootModules(t *testing.T) []gorootModule {
goBin := testenv.GoToolPath(t)
goroot.once.Do(func() {
- goroot.err = filepath.Walk(runtime.GOROOT(), func(path string, info os.FileInfo, err error) error {
+ goroot.err = filepath.Walk(runtime.GOROOT(), func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index 269a4223d5..ebb98b4859 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -390,7 +390,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
var p *obj.Prog
var op *obj.Prog
- p = cursym.Func.Text
+ p = cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -482,8 +482,8 @@ func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
bflag = 0
pc = 0
times++
- c.cursym.Func.Text.Pc = 0 // force re-layout the code.
- for p = c.cursym.Func.Text; p != nil; p = p.Link {
+ c.cursym.Func().Text.Pc = 0 // force re-layout the code.
+ for p = c.cursym.Func().Text; p != nil; p = p.Link {
o = c.oplook(p)
if int64(pc) > p.Pc {
p.Pc = int64(pc)
@@ -558,7 +558,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
* perhaps we'd be able to parallelize the span loop above.
*/
- p = c.cursym.Func.Text
+ p = c.cursym.Func().Text
c.autosize = p.To.Offset + 4
c.cursym.Grow(c.cursym.Size)
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 4d9187b530..29d3a5867d 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -249,13 +249,13 @@ const (
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize := int32(0)
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
autoffset := int32(p.To.Offset)
if autoffset == -4 {
// Historical way to mark NOFRAME.
@@ -271,30 +271,30 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- cursym.Func.Locals = autoffset
- cursym.Func.Args = p.To.Val.(int32)
+ cursym.Func().Locals = autoffset
+ cursym.Func().Args = p.To.Val.(int32)
/*
* find leaf subroutines
*/
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
p.Mark |= LEAF
case ADIV, ADIVU, AMOD, AMODU:
- cursym.Func.Text.Mark &^= LEAF
+ cursym.Func().Text.Mark &^= LEAF
case ABL,
ABX,
obj.ADUFFZERO,
obj.ADUFFCOPY:
- cursym.Func.Text.Mark &^= LEAF
+ cursym.Func().Text.Mark &^= LEAF
}
}
var q2 *obj.Prog
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
@@ -311,20 +311,20 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize += 4
}
- if autosize == 0 && cursym.Func.Text.Mark&LEAF == 0 {
+ if autosize == 0 && cursym.Func().Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// are not identified as leaves but still have no frame.
if ctxt.Debugvlog {
ctxt.Logf("save suppressed in: %s\n", cursym.Name)
}
- cursym.Func.Text.Mark |= LEAF
+ cursym.Func().Text.Mark |= LEAF
}
// FP offsets need an updated p.To.Offset.
p.To.Offset = int64(autosize) - 4
- if cursym.Func.Text.Mark&LEAF != 0 {
+ if cursym.Func().Text.Mark&LEAF != 0 {
cursym.Set(obj.AttrLeaf, true)
if p.From.Sym.NoFrame() {
break
@@ -347,7 +347,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Reg = REGSP
p.Spadj = autosize
- if cursym.Func.Text.From.Sym.Wrapper() {
+ if cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVW g_panic(g), R1
@@ -460,7 +460,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case obj.ARET:
nocache(p)
- if cursym.Func.Text.Mark&LEAF != 0 {
+ if cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = AB
p.From = obj.Addr{}
@@ -487,6 +487,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// If there are instructions following
// this ARET, they come from a branch
// with the same stackframe, so no spadj.
+
if p.To.Sym != nil { // retjmp
p.To.Reg = REGLINK
q2 = obj.Appendp(p, newprog)
@@ -494,6 +495,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q2.To.Type = obj.TYPE_BRANCH
q2.To.Sym = p.To.Sym
p.To.Sym = nil
+ p.To.Name = obj.NAME_NONE
p = q2
}
@@ -508,7 +510,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
case ADIV, ADIVU, AMOD, AMODU:
- if cursym.Func.Text.From.Sym.NoSplit() {
+ if cursym.Func().Text.From.Sym.NoSplit() {
ctxt.Diag("cannot divide in NOSPLIT function")
}
const debugdivmod = false
@@ -720,7 +722,7 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
var last *obj.Prog
- for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
+ for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
}
// Now we are at the end of the function, but logically
@@ -751,7 +753,7 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
switch {
case c.cursym.CFunc():
morestack = "runtime.morestackc"
- case !c.cursym.Func.Text.From.Sym.NeedCtxt():
+ case !c.cursym.Func().Text.From.Sym.NeedCtxt():
morestack = "runtime.morestack_noctxt"
}
call.To.Sym = c.ctxt.Lookup(morestack)
@@ -762,7 +764,7 @@ func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
b := obj.Appendp(pcdata, c.newprog)
b.As = obj.AJMP
b.To.Type = obj.TYPE_BRANCH
- b.To.SetTarget(c.cursym.Func.Text.Link)
+ b.To.SetTarget(c.cursym.Func().Text.Link)
b.Spadj = +framesize
return end
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
index 1ca41c15ba..33319e48df 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -958,9 +958,11 @@ const (
AVADDP
AVAND
AVBIF
+ AVBCAX
AVCMEQ
AVCNT
AVEOR
+ AVEOR3
AVMOV
AVLD1
AVLD2
@@ -989,6 +991,7 @@ const (
AVPMULL2
AVEXT
AVRBIT
+ AVRAX1
AVUSHR
AVUSHLL
AVUSHLL2
@@ -1001,6 +1004,7 @@ const (
AVBSL
AVBIT
AVTBL
+ AVXAR
AVZIP1
AVZIP2
AVCMTST
diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go
index 900cdba817..e5534e26b9 100644
--- a/src/cmd/internal/obj/arm64/anames.go
+++ b/src/cmd/internal/obj/arm64/anames.go
@@ -464,9 +464,11 @@ var Anames = []string{
"VADDP",
"VAND",
"VBIF",
+ "VBCAX",
"VCMEQ",
"VCNT",
"VEOR",
+ "VEOR3",
"VMOV",
"VLD1",
"VLD2",
@@ -495,6 +497,7 @@ var Anames = []string{
"VPMULL2",
"VEXT",
"VRBIT",
+ "VRAX1",
"VUSHR",
"VUSHLL",
"VUSHLL2",
@@ -507,6 +510,7 @@ var Anames = []string{
"VBSL",
"VBIT",
"VTBL",
+ "VXAR",
"VZIP1",
"VZIP2",
"VCMTST",
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index ee4a33eef4..6b9fe27c05 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -843,6 +843,8 @@ var optab = []Optab{
{ASHA256H, C_ARNG, C_VREG, C_NONE, C_VREG, 1, 4, 0, 0, 0},
{AVREV32, C_ARNG, C_NONE, C_NONE, C_ARNG, 83, 4, 0, 0, 0},
{AVPMULL, C_ARNG, C_ARNG, C_NONE, C_ARNG, 93, 4, 0, 0, 0},
+ {AVEOR3, C_ARNG, C_ARNG, C_ARNG, C_ARNG, 103, 4, 0, 0, 0},
+ {AVXAR, C_VCON, C_ARNG, C_ARNG, C_ARNG, 104, 4, 0, 0, 0},
{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0},
{obj.APCDATA, C_VCON, C_NONE, C_NONE, C_VCON, 0, 0, 0, 0, 0},
@@ -911,7 +913,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Retpoline = false // don't keep printing
}
- p := cursym.Func.Text
+ p := cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -941,8 +943,8 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
alignedValue := p.From.Offset
m = pcAlignPadLength(pc, alignedValue, ctxt)
// Update the current text symbol alignment value.
- if int32(alignedValue) > cursym.Func.Align {
- cursym.Func.Align = int32(alignedValue)
+ if int32(alignedValue) > cursym.Func().Align {
+ cursym.Func().Align = int32(alignedValue)
}
break
case obj.ANOP, obj.AFUNCDATA, obj.APCDATA:
@@ -981,7 +983,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
for bflag != 0 {
bflag = 0
pc = 0
- for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p = c.cursym.Func().Text.Link; p != nil; p = p.Link {
if p.As == ADWORD && (pc&7) != 0 {
pc += 4
}
@@ -1045,7 +1047,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
psz := int32(0)
var i int
var out [6]uint32
- for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text.Link; p != nil; p = p.Link {
c.pc = p.Pc
o = c.oplook(p)
@@ -1086,7 +1088,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// We use REGTMP as a scratch register during call injection,
// so instruction sequences that use REGTMP are unsafe to
// preempt asynchronously.
- obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, c.isRestartable)
+ obj.MarkUnsafePoints(c.ctxt, c.cursym.Func().Text, c.newprog, c.isUnsafePoint, c.isRestartable)
}
// isUnsafePoint returns whether p is an unsafe point.
@@ -2769,6 +2771,7 @@ func buildop(ctxt *obj.Link) {
case AVADD:
oprangeset(AVSUB, t)
+ oprangeset(AVRAX1, t)
case AAESD:
oprangeset(AAESE, t)
@@ -2827,6 +2830,9 @@ func buildop(ctxt *obj.Link) {
oprangeset(AVLD4, t)
oprangeset(AVLD4R, t)
+ case AVEOR3:
+ oprangeset(AVBCAX, t)
+
case ASHA1H,
AVCNT,
AVMOV,
@@ -2839,7 +2845,8 @@ func buildop(ctxt *obj.Link) {
AVDUP,
AVMOVI,
APRFM,
- AVEXT:
+ AVEXT,
+ AVXAR:
break
case obj.ANOP,
@@ -3120,12 +3127,13 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
case 6: /* b ,O(R); bl ,O(R) */
o1 = c.opbrr(p, p.As)
-
o1 |= uint32(p.To.Reg&31) << 5
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 0
- rel.Type = objabi.R_CALLIND
+ if p.As == obj.ACALL {
+ rel := obj.Addrel(c.cursym)
+ rel.Off = int32(c.pc)
+ rel.Siz = 0
+ rel.Type = objabi.R_CALLIND
+ }
case 7: /* beq s */
o1 = c.opbra(p, p.As)
@@ -4204,7 +4212,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
rel.Add = 0
rel.Type = objabi.R_ARM64_GOTPCREL
- case 72: /* vaddp/vand/vcmeq/vorr/vadd/veor/vfmla/vfmls/vbit/vbsl/vcmtst/vsub/vbif/vuzip1/vuzip2 Vm.<T>, Vn.<T>, Vd.<T> */
+ case 72: /* vaddp/vand/vcmeq/vorr/vadd/veor/vfmla/vfmls/vbit/vbsl/vcmtst/vsub/vbif/vuzip1/vuzip2/vrax1 Vm.<T>, Vn.<T>, Vd.<T> */
af := int((p.From.Reg >> 5) & 15)
af3 := int((p.Reg >> 5) & 15)
at := int((p.To.Reg >> 5) & 15)
@@ -4268,6 +4276,12 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
} else {
size = 0
}
+ case AVRAX1:
+ if af != ARNG_2D {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ }
+ size = 0
+ Q = 0
}
o1 |= (uint32(Q&1) << 30) | (uint32(size&3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
@@ -5185,6 +5199,51 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
c.ctxt.Diag("shift amount out of range: %v\n", p)
}
o1 |= uint32(immh)<<19 | uint32(shift)<<16 | uint32(rf&31)<<5 | uint32(p.To.Reg&31)
+ case 103: /* VEOR3/VBCAX Va.B16, Vm.B16, Vn.B16, Vd.B16 */
+ ta := (p.From.Reg >> 5) & 15
+ tm := (p.Reg >> 5) & 15
+ td := (p.To.Reg >> 5) & 15
+ tn := ((p.GetFrom3().Reg) >> 5) & 15
+
+ if ta != tm || ta != tn || ta != td || ta != ARNG_16B {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ break
+ }
+
+ o1 = c.oprrr(p, p.As)
+ ra := int(p.From.Reg)
+ rm := int(p.Reg)
+ rn := int(p.GetFrom3().Reg)
+ rd := int(p.To.Reg)
+ o1 |= uint32(rm&31)<<16 | uint32(ra&31)<<10 | uint32(rn&31)<<5 | uint32(rd)&31
+
+ case 104: /* vxar $imm4, Vm.<T>, Vn.<T>, Vd.<T> */
+ af := ((p.GetFrom3().Reg) >> 5) & 15
+ at := (p.To.Reg >> 5) & 15
+ a := (p.Reg >> 5) & 15
+ index := int(p.From.Offset)
+
+ if af != a || af != at {
+ c.ctxt.Diag("invalid arrangement: %v", p)
+ break
+ }
+
+ if af != ARNG_2D {
+ c.ctxt.Diag("invalid arrangement, should be D2: %v", p)
+ break
+ }
+
+ if index < 0 || index > 63 {
+ c.ctxt.Diag("illegal offset: %v", p)
+ }
+
+ o1 = c.opirr(p, p.As)
+ rf := (p.GetFrom3().Reg) & 31
+ rt := (p.To.Reg) & 31
+ r := (p.Reg) & 31
+
+ o1 |= (uint32(r&31) << 16) | (uint32(index&63) << 10) | (uint32(rf&31) << 5) | uint32(rt&31)
+
}
out[0] = o1
out[1] = o2
@@ -5760,6 +5819,9 @@ func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 {
case AVAND:
return 7<<25 | 1<<21 | 7<<10
+ case AVBCAX:
+ return 0xCE<<24 | 1<<21
+
case AVCMEQ:
return 1<<29 | 0x71<<21 | 0x23<<10
@@ -5775,12 +5837,18 @@ func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 {
case AVEOR:
return 1<<29 | 0x71<<21 | 7<<10
+ case AVEOR3:
+ return 0xCE << 24
+
case AVORR:
return 7<<25 | 5<<21 | 7<<10
case AVREV16:
return 3<<26 | 2<<24 | 1<<21 | 3<<11
+ case AVRAX1:
+ return 0xCE<<24 | 3<<21 | 1<<15 | 3<<10
+
case AVREV32:
return 11<<26 | 2<<24 | 1<<21 | 1<<11
@@ -6038,6 +6106,8 @@ func (c *ctxt7) opirr(p *obj.Prog, a obj.As) uint32 {
case AVUSHLL2, AVUXTL2:
return 3<<29 | 15<<24 | 0x29<<10
+ case AVXAR:
+ return 0xCE<<24 | 1<<23
}
c.ctxt.Diag("%v: bad irr %v", p, a)
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 56da854f16..0baf51973a 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -166,7 +166,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
var last *obj.Prog
- for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
+ for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
}
// Now we are at the end of the function, but logically
@@ -209,7 +209,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
switch {
case c.cursym.CFunc():
morestack = "runtime.morestackc"
- case !c.cursym.Func.Text.From.Sym.NeedCtxt():
+ case !c.cursym.Func().Text.From.Sym.NeedCtxt():
morestack = "runtime.morestack_noctxt"
}
call.To.Sym = c.ctxt.Lookup(morestack)
@@ -220,7 +220,7 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
jmp := obj.Appendp(pcdata, c.newprog)
jmp.As = AB
jmp.To.Type = obj.TYPE_BRANCH
- jmp.To.SetTarget(c.cursym.Func.Text.Link)
+ jmp.To.SetTarget(c.cursym.Func().Text.Link)
jmp.Spadj = +framesize
return end
@@ -441,13 +441,13 @@ func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
}
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
textstksiz := p.To.Offset
if textstksiz == -8 {
// Historical way to mark NOFRAME.
@@ -463,13 +463,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
+ c.cursym.Func().Args = p.To.Val.(int32)
+ c.cursym.Func().Locals = int32(textstksiz)
/*
* find leaf subroutines
*/
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
p.Mark |= LEAF
@@ -477,18 +477,18 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case ABL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
- c.cursym.Func.Text.Mark &^= LEAF
+ c.cursym.Func().Text.Mark &^= LEAF
}
}
var q *obj.Prog
var q1 *obj.Prog
var retjmp *obj.LSym
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
- c.cursym.Func.Text = p
+ c.cursym.Func().Text = p
c.autosize = int32(textstksiz)
if p.Mark&LEAF != 0 && c.autosize == 0 {
@@ -514,7 +514,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
c.ctxt.Diag("%v: unaligned frame size %d - must be 16 aligned", p, c.autosize-8)
}
c.autosize += extrasize
- c.cursym.Func.Locals += extrasize
+ c.cursym.Func().Locals += extrasize
// low 32 bits for autosize
// high 32 bits for extrasize
@@ -524,14 +524,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Offset = 0
}
- if c.autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
+ if c.autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
if c.ctxt.Debugvlog {
- c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func.Text.From.Sym.Name)
+ c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func().Text.From.Sym.Name)
}
- c.cursym.Func.Text.Mark |= LEAF
+ c.cursym.Func().Text.Mark |= LEAF
}
- if cursym.Func.Text.Mark&LEAF != 0 {
+ if cursym.Func().Text.Mark&LEAF != 0 {
cursym.Set(obj.AttrLeaf, true)
if p.From.Sym.NoFrame() {
break
@@ -589,7 +589,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.To.Reg = REGSP
q1.Spadj = c.autosize
- if c.ctxt.Headtype == objabi.Hdarwin {
+ if objabi.GOOS == "ios" {
// iOS does not support SA_ONSTACK. We will run the signal handler
// on the G stack. If we write below SP, it may be clobbered by
// the signal handler. So we save LR after decrementing SP.
@@ -641,7 +641,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.To.Reg = REGFP
}
- if c.cursym.Func.Text.From.Sym.Wrapper() {
+ if c.cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), R1
@@ -755,7 +755,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
retjmp = p.To.Sym
p.To = obj.Addr{}
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
if c.autosize != 0 {
p.As = AADD
p.From.Type = obj.TYPE_CONST
diff --git a/src/cmd/internal/obj/dwarf.go b/src/cmd/internal/obj/dwarf.go
index 9abb31b558..328fb03b24 100644
--- a/src/cmd/internal/obj/dwarf.go
+++ b/src/cmd/internal/obj/dwarf.go
@@ -46,12 +46,12 @@ func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
// we expect at the start of a new sequence.
stmt := true
line := int64(1)
- pc := s.Func.Text.Pc
+ pc := s.Func().Text.Pc
var lastpc int64 // last PC written to line table, not last PC in func
name := ""
prologue, wrotePrologue := false, false
// Walk the progs, generating the DWARF table.
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
prologue = prologue || (p.Pos.Xlogue() == src.PosPrologueEnd)
// If we're not at a real instruction, keep looping!
if p.Pos.Line() == 0 || (p.Link != nil && p.Link.Pc == p.Pc) {
@@ -103,7 +103,7 @@ func (ctxt *Link) generateDebugLinesSymbol(s, lines *LSym) {
// text address before the end sequence op. If this isn't done,
// GDB will assign a line number of zero the last row in the line
// table, which we don't want.
- lastlen := uint64(s.Size - (lastpc - s.Func.Text.Pc))
+ lastlen := uint64(s.Size - (lastpc - s.Func().Text.Pc))
putpclcdelta(ctxt, dctxt, lines, lastlen, 0)
dctxt.AddUint8(lines, 0) // start extended opcode
dwarf.Uleb128put(dctxt, lines, 1)
@@ -301,26 +301,27 @@ func (ctxt *Link) dwarfSym(s *LSym) (dwarfInfoSym, dwarfLocSym, dwarfRangesSym,
if s.Type != objabi.STEXT {
ctxt.Diag("dwarfSym of non-TEXT %v", s)
}
- if s.Func.dwarfInfoSym == nil {
- s.Func.dwarfInfoSym = &LSym{
+ fn := s.Func()
+ if fn.dwarfInfoSym == nil {
+ fn.dwarfInfoSym = &LSym{
Type: objabi.SDWARFFCN,
}
if ctxt.Flag_locationlists {
- s.Func.dwarfLocSym = &LSym{
+ fn.dwarfLocSym = &LSym{
Type: objabi.SDWARFLOC,
}
}
- s.Func.dwarfRangesSym = &LSym{
+ fn.dwarfRangesSym = &LSym{
Type: objabi.SDWARFRANGE,
}
- s.Func.dwarfDebugLinesSym = &LSym{
+ fn.dwarfDebugLinesSym = &LSym{
Type: objabi.SDWARFLINES,
}
if s.WasInlined() {
- s.Func.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
+ fn.dwarfAbsFnSym = ctxt.DwFixups.AbsFuncDwarfSym(s)
}
}
- return s.Func.dwarfInfoSym, s.Func.dwarfLocSym, s.Func.dwarfRangesSym, s.Func.dwarfAbsFnSym, s.Func.dwarfDebugLinesSym
+ return fn.dwarfInfoSym, fn.dwarfLocSym, fn.dwarfRangesSym, fn.dwarfAbsFnSym, fn.dwarfDebugLinesSym
}
func (s *LSym) Length(dwarfContext interface{}) int64 {
@@ -331,7 +332,7 @@ func (s *LSym) Length(dwarfContext interface{}) int64 {
// first instruction (prog) of the specified function. This will
// presumably be the file in which the function is defined.
func (ctxt *Link) fileSymbol(fn *LSym) *LSym {
- p := fn.Func.Text
+ p := fn.Func().Text
if p != nil {
f, _ := linkgetlineFromPos(ctxt, p.Pos)
fsym := ctxt.Lookup(f)
@@ -405,8 +406,8 @@ func (ctxt *Link) DwarfAbstractFunc(curfn interface{}, s *LSym, myimportpath str
if absfn.Size != 0 {
ctxt.Diag("internal error: DwarfAbstractFunc double process %v", s)
}
- if s.Func == nil {
- s.Func = new(FuncInfo)
+ if s.Func() == nil {
+ s.NewFuncInfo()
}
scopes, _ := ctxt.DebugInfo(s, absfn, curfn)
dwctxt := dwCtxt{ctxt}
@@ -527,8 +528,8 @@ func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
// wrapper generation as opposed to the main inlining phase) it's
// possible that we didn't cache the abstract function sym for the
// text symbol -- do so now if needed. See issue 38068.
- if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
- s.Func.dwarfAbsFnSym = absfn
+ if fn := s.Func(); fn != nil && fn.dwarfAbsFnSym == nil {
+ fn.dwarfAbsFnSym = absfn
}
ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
diff --git a/src/cmd/internal/obj/ld.go b/src/cmd/internal/obj/ld.go
index 4ba52c7785..5d6c000dc6 100644
--- a/src/cmd/internal/obj/ld.go
+++ b/src/cmd/internal/obj/ld.go
@@ -59,7 +59,7 @@ func mkfwd(sym *LSym) {
}
i := 0
- for p := sym.Func.Text; p != nil && p.Link != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil && p.Link != nil; p = p.Link {
i--
if i < 0 {
i = LOG - 1
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 014c78dbfc..2037beca72 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -38,6 +38,7 @@ import (
"cmd/internal/src"
"cmd/internal/sys"
"fmt"
+ "log"
"sync"
)
@@ -395,17 +396,16 @@ type LSym struct {
Type objabi.SymKind
Attribute
- RefIdx int // Index of this symbol in the symbol reference list.
Size int64
Gotype *LSym
P []byte
R []Reloc
- Func *FuncInfo
+ Extra *interface{} // *FuncInfo or *FileInfo, if present
Pkg string
PkgIdx int32
- SymIdx int32 // TODO: replace RefIdx
+ SymIdx int32
}
// A FuncInfo contains extra fields for STEXT symbols.
@@ -434,6 +434,53 @@ type FuncInfo struct {
FuncInfoSym *LSym
}
+// NewFuncInfo allocates and returns a FuncInfo for LSym.
+func (s *LSym) NewFuncInfo() *FuncInfo {
+ if s.Extra != nil {
+ log.Fatalf("invalid use of LSym - NewFuncInfo with Extra of type %T", *s.Extra)
+ }
+ f := new(FuncInfo)
+ s.Extra = new(interface{})
+ *s.Extra = f
+ return f
+}
+
+// Func returns the *FuncInfo associated with s, or else nil.
+func (s *LSym) Func() *FuncInfo {
+ if s.Extra == nil {
+ return nil
+ }
+ f, _ := (*s.Extra).(*FuncInfo)
+ return f
+}
+
+// A FileInfo contains extra fields for SDATA symbols backed by files.
+// (If LSym.Extra is a *FileInfo, LSym.P == nil.)
+type FileInfo struct {
+ Name string // name of file to read into object file
+ Size int64 // length of file
+}
+
+// NewFileInfo allocates and returns a FileInfo for LSym.
+func (s *LSym) NewFileInfo() *FileInfo {
+ if s.Extra != nil {
+ log.Fatalf("invalid use of LSym - NewFileInfo with Extra of type %T", *s.Extra)
+ }
+ f := new(FileInfo)
+ s.Extra = new(interface{})
+ *s.Extra = f
+ return f
+}
+
+// File returns the *FileInfo associated with s, or else nil.
+func (s *LSym) File() *FileInfo {
+ if s.Extra == nil {
+ return nil
+ }
+ f, _ := (*s.Extra).(*FileInfo)
+ return f
+}
+
type InlMark struct {
// When unwinding from an instruction in an inlined body, mark
// where we should unwind to.
@@ -482,6 +529,20 @@ const (
ABICount
)
+// ParseABI converts from a string representation in 'abistr' to the
+// corresponding ABI value. Second return value is TRUE if the
+// abi string is recognized, FALSE otherwise.
+func ParseABI(abistr string) (ABI, bool) {
+ switch abistr {
+ default:
+ return ABI0, false
+ case "ABI0":
+ return ABI0, true
+ case "ABIInternal":
+ return ABIInternal, true
+ }
+}
+
// Attribute is a set of symbol attributes.
type Attribute uint32
diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go
index 6107974745..fd29f9fa21 100644
--- a/src/cmd/internal/obj/mips/asm0.go
+++ b/src/cmd/internal/obj/mips/asm0.go
@@ -410,7 +410,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Retpoline = false // don't keep printing
}
- p := cursym.Func.Text
+ p := cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -455,7 +455,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
for bflag != 0 {
bflag = 0
pc = 0
- for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p = c.cursym.Func().Text.Link; p != nil; p = p.Link {
p.Pc = pc
o = c.oplook(p)
@@ -512,7 +512,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
bp := c.cursym.P
var i int32
var out [4]uint32
- for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text.Link; p != nil; p = p.Link {
c.pc = p.Pc
o = c.oplook(p)
if int(o.size) > 4*len(out) {
@@ -529,7 +529,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// We use REGTMP as a scratch register during call injection,
// so instruction sequences that use REGTMP are unsafe to
// preempt asynchronously.
- obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, c.isRestartable)
+ obj.MarkUnsafePoints(c.ctxt, c.cursym.Func().Text, c.newprog, c.isUnsafePoint, c.isRestartable)
}
// isUnsafePoint returns whether p is an unsafe point.
@@ -1302,7 +1302,7 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
}
o1 = OP_JMP(c.opirr(p.As), uint32(v))
if p.To.Sym == nil {
- p.To.Sym = c.cursym.Func.Text.From.Sym
+ p.To.Sym = c.cursym.Func().Text.From.Sym
p.To.Offset = p.To.Target().Pc
}
rel := obj.Addrel(c.cursym)
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index f19facc00c..135a8df3aa 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -133,11 +133,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// a switch for enabling/disabling instruction scheduling
nosched := true
- if c.cursym.Func.Text == nil || c.cursym.Func.Text.Link == nil {
+ if c.cursym.Func().Text == nil || c.cursym.Func().Text.Link == nil {
return
}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
textstksiz := p.To.Offset
if textstksiz == -ctxt.FixedFrameSize() {
// Historical way to mark NOFRAME.
@@ -153,8 +153,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
+ c.cursym.Func().Args = p.To.Val.(int32)
+ c.cursym.Func().Locals = int32(textstksiz)
/*
* find leaf subroutines
@@ -162,7 +162,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
* expand BECOME pseudo
*/
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
/* too hard, just leave alone */
case obj.ATEXT:
@@ -203,7 +203,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
AJAL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
- c.cursym.Func.Text.Mark &^= LEAF
+ c.cursym.Func().Text.Mark &^= LEAF
fallthrough
case AJMP,
@@ -267,7 +267,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize := int32(0)
var p1 *obj.Prog
var p2 *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
@@ -288,19 +288,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize += 4
}
- if autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
- if c.cursym.Func.Text.From.Sym.NoSplit() {
+ if autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
+ if c.cursym.Func().Text.From.Sym.NoSplit() {
if ctxt.Debugvlog {
ctxt.Logf("save suppressed in: %s\n", c.cursym.Name)
}
- c.cursym.Func.Text.Mark |= LEAF
+ c.cursym.Func().Text.Mark |= LEAF
}
}
p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
c.cursym.Set(obj.AttrLeaf, true)
if p.From.Sym.NoFrame() {
break
@@ -344,7 +344,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
}
- if c.cursym.Func.Text.From.Sym.Wrapper() && c.cursym.Func.Text.Mark&LEAF == 0 {
+ if c.cursym.Func().Text.From.Sym.Wrapper() && c.cursym.Func().Text.Mark&LEAF == 0 {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), R1
@@ -438,7 +438,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
p.To.Sym = nil
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = AJMP
p.From = obj.Addr{}
@@ -540,7 +540,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
if c.ctxt.Arch.Family == sys.MIPS {
// rewrite MOVD into two MOVF in 32-bit mode to avoid unaligned memory access
- for p = c.cursym.Func.Text; p != nil; p = p1 {
+ for p = c.cursym.Func().Text; p != nil; p = p1 {
p1 = p.Link
if p.As != AMOVD {
@@ -580,7 +580,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
if nosched {
// if we don't do instruction scheduling, simply add
// NOP after each branch instruction.
- for p = c.cursym.Func.Text; p != nil; p = p.Link {
+ for p = c.cursym.Func().Text; p != nil; p = p.Link {
if p.Mark&BRANCH != 0 {
c.addnop(p)
}
@@ -589,10 +589,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// instruction scheduling
- q = nil // p - 1
- q1 = c.cursym.Func.Text // top of block
- o := 0 // count of instructions
- for p = c.cursym.Func.Text; p != nil; p = p1 {
+ q = nil // p - 1
+ q1 = c.cursym.Func().Text // top of block
+ o := 0 // count of instructions
+ for p = c.cursym.Func().Text; p != nil; p = p1 {
p1 = p.Link
o++
if p.Mark&NOSCHED != 0 {
@@ -791,7 +791,7 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.To.Type = obj.TYPE_BRANCH
if c.cursym.CFunc() {
p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
- } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
} else {
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
@@ -805,7 +805,7 @@ func (c *ctxt0) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
p.As = AJMP
p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(c.cursym.Func.Text.Link)
+ p.To.SetTarget(c.cursym.Func().Text.Link)
p.Mark |= BRANCH
// placeholder for q1's jump target
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index fa60c9ad6d..bb58b4f0c2 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -16,6 +16,8 @@ import (
"encoding/binary"
"fmt"
"io"
+ "log"
+ "os"
"path/filepath"
"sort"
"strings"
@@ -147,14 +149,20 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
// Data indexes
h.Offsets[goobj.BlkDataIdx] = w.Offset()
- dataOff := uint32(0)
+ dataOff := int64(0)
for _, list := range lists {
for _, s := range list {
- w.Uint32(dataOff)
- dataOff += uint32(len(s.P))
+ w.Uint32(uint32(dataOff))
+ dataOff += int64(len(s.P))
+ if file := s.File(); file != nil {
+ dataOff += int64(file.Size)
+ }
}
}
- w.Uint32(dataOff)
+ if int64(uint32(dataOff)) != dataOff {
+ log.Fatalf("data too large")
+ }
+ w.Uint32(uint32(dataOff))
// Relocs
h.Offsets[goobj.BlkReloc] = w.Offset()
@@ -179,6 +187,9 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
for _, list := range lists {
for _, s := range list {
w.Bytes(s.P)
+ if file := s.File(); file != nil {
+ w.writeFile(ctxt, file)
+ }
}
}
@@ -189,8 +200,8 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
// object file, and the Pcln variables haven't been filled in. As such, we
// need to check that Pcsp exists, and assume the other pcln variables exist
// as well. Tests like test/fixedbugs/issue22200.go demonstrate this issue.
- if s.Func != nil && s.Func.Pcln.Pcsp != nil {
- pc := &s.Func.Pcln
+ if fn := s.Func(); fn != nil && fn.Pcln.Pcsp != nil {
+ pc := &fn.Pcln
w.Bytes(pc.Pcsp.P)
w.Bytes(pc.Pcfile.P)
w.Bytes(pc.Pcline.P)
@@ -218,6 +229,7 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
type writer struct {
*goobj.Writer
+ filebuf []byte
ctxt *Link
pkgpath string // the package import path (escaped), "" if unknown
pkglist []string // list of packages referenced, indexed by ctxt.pkgIdx
@@ -232,6 +244,35 @@ func (w *writer) init() {
}
}
+func (w *writer) writeFile(ctxt *Link, file *FileInfo) {
+ f, err := os.Open(file.Name)
+ if err != nil {
+ ctxt.Diag("%v", err)
+ return
+ }
+ defer f.Close()
+ if w.filebuf == nil {
+ w.filebuf = make([]byte, 1024)
+ }
+ buf := w.filebuf
+ written := int64(0)
+ for {
+ n, err := f.Read(buf)
+ w.Bytes(buf[:n])
+ written += int64(n)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ ctxt.Diag("%v", err)
+ return
+ }
+ }
+ if written != file.Size {
+ ctxt.Diag("copy %s: unexpected length %d != %d", file.Name, written, file.Size)
+ }
+}
+
func (w *writer) StringTable() {
w.AddString("")
for _, p := range w.ctxt.Imports {
@@ -261,6 +302,10 @@ func (w *writer) StringTable() {
}
}
+// cutoff is the maximum data section size permitted by the linker
+// (see issue #9862).
+const cutoff = int64(2e9) // 2 GB (or so; looks better in errors than 2^31)
+
func (w *writer) Sym(s *LSym) {
abi := uint16(s.ABI())
if s.Static() {
@@ -303,8 +348,8 @@ func (w *writer) Sym(s *LSym) {
name = filepath.ToSlash(name)
}
var align uint32
- if s.Func != nil {
- align = uint32(s.Func.Align)
+ if fn := s.Func(); fn != nil {
+ align = uint32(fn.Align)
}
if s.ContentAddressable() {
// We generally assume data symbols are natually aligned,
@@ -325,6 +370,9 @@ func (w *writer) Sym(s *LSym) {
// don't bother setting align to 1.
}
}
+ if s.Size > cutoff {
+ w.ctxt.Diag("%s: symbol too large (%d bytes > %d bytes)", s.Name, s.Size, cutoff)
+ }
var o goobj.Sym
o.SetName(name, w.Writer)
o.SetABI(abi)
@@ -470,38 +518,38 @@ func (w *writer) Aux(s *LSym) {
if s.Gotype != nil {
w.aux1(goobj.AuxGotype, s.Gotype)
}
- if s.Func != nil {
- w.aux1(goobj.AuxFuncInfo, s.Func.FuncInfoSym)
+ if fn := s.Func(); fn != nil {
+ w.aux1(goobj.AuxFuncInfo, fn.FuncInfoSym)
- for _, d := range s.Func.Pcln.Funcdata {
+ for _, d := range fn.Pcln.Funcdata {
w.aux1(goobj.AuxFuncdata, d)
}
- if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
- w.aux1(goobj.AuxDwarfInfo, s.Func.dwarfInfoSym)
+ if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfInfo, fn.dwarfInfoSym)
}
- if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
- w.aux1(goobj.AuxDwarfLoc, s.Func.dwarfLocSym)
+ if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfLoc, fn.dwarfLocSym)
}
- if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
- w.aux1(goobj.AuxDwarfRanges, s.Func.dwarfRangesSym)
+ if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfRanges, fn.dwarfRangesSym)
}
- if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
- w.aux1(goobj.AuxDwarfLines, s.Func.dwarfDebugLinesSym)
+ if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
+ w.aux1(goobj.AuxDwarfLines, fn.dwarfDebugLinesSym)
}
- if s.Func.Pcln.Pcsp != nil && s.Func.Pcln.Pcsp.Size != 0 {
- w.aux1(goobj.AuxPcsp, s.Func.Pcln.Pcsp)
+ if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
+ w.aux1(goobj.AuxPcsp, fn.Pcln.Pcsp)
}
- if s.Func.Pcln.Pcfile != nil && s.Func.Pcln.Pcfile.Size != 0 {
- w.aux1(goobj.AuxPcfile, s.Func.Pcln.Pcfile)
+ if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
+ w.aux1(goobj.AuxPcfile, fn.Pcln.Pcfile)
}
- if s.Func.Pcln.Pcline != nil && s.Func.Pcln.Pcline.Size != 0 {
- w.aux1(goobj.AuxPcline, s.Func.Pcln.Pcline)
+ if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
+ w.aux1(goobj.AuxPcline, fn.Pcln.Pcline)
}
- if s.Func.Pcln.Pcinline != nil && s.Func.Pcln.Pcinline.Size != 0 {
- w.aux1(goobj.AuxPcinline, s.Func.Pcln.Pcinline)
+ if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
+ w.aux1(goobj.AuxPcinline, fn.Pcln.Pcinline)
}
- for _, pcSym := range s.Func.Pcln.Pcdata {
+ for _, pcSym := range fn.Pcln.Pcdata {
w.aux1(goobj.AuxPcdata, pcSym)
}
@@ -571,34 +619,34 @@ func nAuxSym(s *LSym) int {
if s.Gotype != nil {
n++
}
- if s.Func != nil {
+ if fn := s.Func(); fn != nil {
// FuncInfo is an aux symbol, each Funcdata is an aux symbol
- n += 1 + len(s.Func.Pcln.Funcdata)
- if s.Func.dwarfInfoSym != nil && s.Func.dwarfInfoSym.Size != 0 {
+ n += 1 + len(fn.Pcln.Funcdata)
+ if fn.dwarfInfoSym != nil && fn.dwarfInfoSym.Size != 0 {
n++
}
- if s.Func.dwarfLocSym != nil && s.Func.dwarfLocSym.Size != 0 {
+ if fn.dwarfLocSym != nil && fn.dwarfLocSym.Size != 0 {
n++
}
- if s.Func.dwarfRangesSym != nil && s.Func.dwarfRangesSym.Size != 0 {
+ if fn.dwarfRangesSym != nil && fn.dwarfRangesSym.Size != 0 {
n++
}
- if s.Func.dwarfDebugLinesSym != nil && s.Func.dwarfDebugLinesSym.Size != 0 {
+ if fn.dwarfDebugLinesSym != nil && fn.dwarfDebugLinesSym.Size != 0 {
n++
}
- if s.Func.Pcln.Pcsp != nil && s.Func.Pcln.Pcsp.Size != 0 {
+ if fn.Pcln.Pcsp != nil && fn.Pcln.Pcsp.Size != 0 {
n++
}
- if s.Func.Pcln.Pcfile != nil && s.Func.Pcln.Pcfile.Size != 0 {
+ if fn.Pcln.Pcfile != nil && fn.Pcln.Pcfile.Size != 0 {
n++
}
- if s.Func.Pcln.Pcline != nil && s.Func.Pcln.Pcline.Size != 0 {
+ if fn.Pcln.Pcline != nil && fn.Pcln.Pcline.Size != 0 {
n++
}
- if s.Func.Pcln.Pcinline != nil && s.Func.Pcln.Pcinline.Size != 0 {
+ if fn.Pcln.Pcinline != nil && fn.Pcln.Pcinline.Size != 0 {
n++
}
- n += len(s.Func.Pcln.Pcdata)
+ n += len(fn.Pcln.Pcdata)
}
return n
}
@@ -620,15 +668,16 @@ func genFuncInfoSyms(ctxt *Link) {
var b bytes.Buffer
symidx := int32(len(ctxt.defs))
for _, s := range ctxt.Text {
- if s.Func == nil {
+ fn := s.Func()
+ if fn == nil {
continue
}
o := goobj.FuncInfo{
- Args: uint32(s.Func.Args),
- Locals: uint32(s.Func.Locals),
- FuncID: objabi.FuncID(s.Func.FuncID),
+ Args: uint32(fn.Args),
+ Locals: uint32(fn.Locals),
+ FuncID: objabi.FuncID(fn.FuncID),
}
- pc := &s.Func.Pcln
+ pc := &fn.Pcln
o.Pcsp = makeSymRef(preparePcSym(pc.Pcsp))
o.Pcfile = makeSymRef(preparePcSym(pc.Pcfile))
o.Pcline = makeSymRef(preparePcSym(pc.Pcline))
@@ -670,10 +719,10 @@ func genFuncInfoSyms(ctxt *Link) {
isym.Set(AttrIndexed, true)
symidx++
infosyms = append(infosyms, isym)
- s.Func.FuncInfoSym = isym
+ fn.FuncInfoSym = isym
b.Reset()
- dwsyms := []*LSym{s.Func.dwarfRangesSym, s.Func.dwarfLocSym, s.Func.dwarfDebugLinesSym, s.Func.dwarfInfoSym}
+ dwsyms := []*LSym{fn.dwarfRangesSym, fn.dwarfLocSym, fn.dwarfDebugLinesSym, fn.dwarfInfoSym}
for _, s := range dwsyms {
if s == nil || s.Size == 0 {
continue
@@ -744,14 +793,15 @@ func (ctxt *Link) writeSymDebugNamed(s *LSym, name string) {
}
fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
if s.Type == objabi.STEXT {
- fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(s.Func.Args), uint64(s.Func.Locals), uint64(s.Func.FuncID))
+ fn := s.Func()
+ fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x funcid=%#x", uint64(fn.Args), uint64(fn.Locals), uint64(fn.FuncID))
if s.Leaf() {
fmt.Fprintf(ctxt.Bso, " leaf")
}
}
fmt.Fprintf(ctxt.Bso, "\n")
if s.Type == objabi.STEXT {
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
fmt.Fprintf(ctxt.Bso, "\t%#04x ", uint(int(p.Pc)))
if ctxt.Debugasm > 1 {
io.WriteString(ctxt.Bso, p.String())
diff --git a/src/cmd/internal/obj/objfile_test.go b/src/cmd/internal/obj/objfile_test.go
index 155701fa4e..146627b62b 100644
--- a/src/cmd/internal/obj/objfile_test.go
+++ b/src/cmd/internal/obj/objfile_test.go
@@ -5,9 +5,16 @@
package obj
import (
+ "bytes"
"cmd/internal/goobj"
"cmd/internal/sys"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
"testing"
+ "unsafe"
)
var dummyArch = LinkArch{Arch: sys.ArchAMD64}
@@ -85,3 +92,32 @@ func TestContentHash(t *testing.T) {
}
}
}
+
+func TestSymbolTooLarge(t *testing.T) { // Issue 42054
+ testenv.MustHaveGoBuild(t)
+ if unsafe.Sizeof(uintptr(0)) < 8 {
+ t.Skip("skip on 32-bit architectures")
+ }
+
+ tmpdir, err := ioutil.TempDir("", "TestSymbolTooLarge")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ src := filepath.Join(tmpdir, "p.go")
+ err = ioutil.WriteFile(src, []byte("package p; var x [1<<32]byte"), 0666)
+ if err != nil {
+ t.Fatalf("failed to write source file: %v\n", err)
+ }
+ obj := filepath.Join(tmpdir, "p.o")
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", obj, src)
+ out, err := cmd.CombinedOutput()
+ if err == nil {
+ t.Fatalf("did not fail\noutput: %s", out)
+ }
+ const want = "symbol too large"
+ if !bytes.Contains(out, []byte(want)) {
+ t.Errorf("unexpected error message: want: %q, got: %s", want, out)
+ }
+}
diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go
index 09d520b4e9..01657dd4f6 100644
--- a/src/cmd/internal/obj/pass.go
+++ b/src/cmd/internal/obj/pass.go
@@ -118,7 +118,7 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) {
}
func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
- for p := sym.Func.Text; p != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil; p = p.Link {
checkaddr(ctxt, p, &p.From)
if p.GetFrom3() != nil {
checkaddr(ctxt, p, p.GetFrom3())
@@ -138,7 +138,7 @@ func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
if p.To.Sym != nil {
continue
}
- q := sym.Func.Text
+ q := sym.Func().Text
for q != nil && p.To.Offset != q.Pc {
if q.Forwd != nil && p.To.Offset >= q.Forwd.Pc {
q = q.Forwd
@@ -164,7 +164,7 @@ func linkpatch(ctxt *Link, sym *LSym, newprog ProgAlloc) {
}
// Collapse series of jumps to jumps.
- for p := sym.Func.Text; p != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil; p = p.Link {
if p.To.Target() == nil {
continue
}
diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go
index ce0d3714c0..67c4f9a62b 100644
--- a/src/cmd/internal/obj/pcln.go
+++ b/src/cmd/internal/obj/pcln.go
@@ -35,20 +35,21 @@ func funcpctab(ctxt *Link, func_ *LSym, desc string, valfunc func(*Link, *LSym,
val := int32(-1)
oldval := val
- if func_.Func.Text == nil {
+ fn := func_.Func()
+ if fn.Text == nil {
// Return the emtpy symbol we've built so far.
return sym
}
- pc := func_.Func.Text.Pc
+ pc := fn.Text.Pc
if dbg {
- ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Func.Text)
+ ctxt.Logf("%6x %6d %v\n", uint64(pc), val, fn.Text)
}
buf := make([]byte, binary.MaxVarintLen32)
started := false
- for p := func_.Func.Text; p != nil; p = p.Link {
+ for p := fn.Text; p != nil; p = p.Link {
// Update val. If it's not changing, keep going.
val = valfunc(ctxt, func_, val, p, 0, arg)
@@ -107,7 +108,7 @@ func funcpctab(ctxt *Link, func_ *LSym, desc string, valfunc func(*Link, *LSym,
if started {
if dbg {
- ctxt.Logf("%6x done\n", uint64(func_.Func.Text.Pc+func_.Size))
+ ctxt.Logf("%6x done\n", uint64(fn.Text.Pc+func_.Size))
}
v := (func_.Size - pc) / int64(ctxt.Arch.MinLC)
if v < 0 {
@@ -257,12 +258,12 @@ func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg i
}
func linkpcln(ctxt *Link, cursym *LSym) {
- pcln := &cursym.Func.Pcln
+ pcln := &cursym.Func().Pcln
pcln.UsedFiles = make(map[goobj.CUFileIndex]struct{})
npcdata := 0
nfuncdata := 0
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
// Find the highest ID of any used PCDATA table. This ignores PCDATA table
// that consist entirely of "-1", since that's the assumed default value.
// From.Offset is table ID
@@ -288,11 +289,12 @@ func linkpcln(ctxt *Link, cursym *LSym) {
// Check that all the Progs used as inline markers are still reachable.
// See issue #40473.
- inlMarkProgs := make(map[*Prog]struct{}, len(cursym.Func.InlMarks))
- for _, inlMark := range cursym.Func.InlMarks {
+ fn := cursym.Func()
+ inlMarkProgs := make(map[*Prog]struct{}, len(fn.InlMarks))
+ for _, inlMark := range fn.InlMarks {
inlMarkProgs[inlMark.p] = struct{}{}
}
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := fn.Text; p != nil; p = p.Link {
if _, ok := inlMarkProgs[p]; ok {
delete(inlMarkProgs, p)
}
@@ -303,7 +305,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
pcinlineState := new(pcinlineState)
pcln.Pcinline = funcpctab(ctxt, cursym, "pctoinline", pcinlineState.pctoinline, nil)
- for _, inlMark := range cursym.Func.InlMarks {
+ for _, inlMark := range fn.InlMarks {
pcinlineState.setParentPC(ctxt, int(inlMark.id), int32(inlMark.p.Pc))
}
pcln.InlTree = pcinlineState.localTree
@@ -316,7 +318,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
// tabulate which pc and func data we have.
havepc := make([]uint32, (npcdata+31)/32)
havefunc := make([]uint32, (nfuncdata+31)/32)
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := fn.Text; p != nil; p = p.Link {
if p.As == AFUNCDATA {
if (havefunc[p.From.Offset/32]>>uint64(p.From.Offset%32))&1 != 0 {
ctxt.Diag("multiple definitions for FUNCDATA $%d", p.From.Offset)
@@ -344,7 +346,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
// funcdata
if nfuncdata > 0 {
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := fn.Text; p != nil; p = p.Link {
if p.As != AFUNCDATA {
continue
}
diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go
index 6e33f29959..eb54c67f6a 100644
--- a/src/cmd/internal/obj/plist.go
+++ b/src/cmd/internal/obj/plist.go
@@ -81,7 +81,7 @@ func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string
continue
}
found := false
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == objabi.FUNCDATA_ArgsPointerMaps {
found = true
break
@@ -89,7 +89,7 @@ func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string
}
if !found {
- p := Appendp(s.Func.Text, newprog)
+ p := Appendp(s.Func().Text, newprog)
p.As = AFUNCDATA
p.From.Type = TYPE_CONST
p.From.Offset = objabi.FUNCDATA_ArgsPointerMaps
@@ -120,15 +120,15 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
// func _() { }
return
}
- if s.Func != nil {
+ if s.Func() != nil {
ctxt.Diag("InitTextSym double init for %s", s.Name)
}
- s.Func = new(FuncInfo)
+ s.NewFuncInfo()
if s.OnList() {
ctxt.Diag("symbol %s listed multiple times", s.Name)
}
name := strings.Replace(s.Name, "\"\"", ctxt.Pkgpath, -1)
- s.Func.FuncID = objabi.GetFuncID(name, flag&WRAPPER != 0)
+ s.Func().FuncID = objabi.GetFuncID(name, flag&WRAPPER != 0)
s.Set(AttrOnList, true)
s.Set(AttrDuplicateOK, flag&DUPOK != 0)
s.Set(AttrNoSplit, flag&NOSPLIT != 0)
@@ -185,7 +185,7 @@ func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
// Similar to EmitEntryLiveness, but just emit stack map.
func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
- pcdata.Pos = s.Func.Text.Pos
+ pcdata.Pos = s.Func().Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_StackMapIndex
@@ -198,7 +198,7 @@ func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
// Similar to EmitEntryLiveness, but just emit register map.
func (ctxt *Link) EmitEntryRegMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
- pcdata.Pos = s.Func.Text.Pos
+ pcdata.Pos = s.Func().Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 9f06bdf8b3..090fefb4d8 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -663,8 +663,8 @@ func addpad(pc, a int64, ctxt *obj.Link, cursym *obj.LSym) int {
// the function alignment is not changed which might
// result in 16 byte alignment but that is still fine.
// TODO: alignment on AIX
- if ctxt.Headtype != objabi.Haix && cursym.Func.Align < 32 {
- cursym.Func.Align = 32
+ if ctxt.Headtype != objabi.Haix && cursym.Func().Align < 32 {
+ cursym.Func().Align = 32
}
default:
ctxt.Diag("Unexpected alignment: %d for PCALIGN directive\n", a)
@@ -673,7 +673,7 @@ func addpad(pc, a int64, ctxt *obj.Link, cursym *obj.LSym) int {
}
func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- p := cursym.Func.Text
+ p := cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -722,7 +722,7 @@ func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
for bflag != 0 {
bflag = 0
pc = 0
- for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p = c.cursym.Func().Text.Link; p != nil; p = p.Link {
p.Pc = pc
o = c.oplook(p)
@@ -784,7 +784,7 @@ func span9(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
bp := c.cursym.P
var i int32
var out [6]uint32
- for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text.Link; p != nil; p = p.Link {
c.pc = p.Pc
o = c.oplook(p)
if int(o.size) > 4*len(out) {
@@ -1279,6 +1279,9 @@ func buildop(ctxt *obj.Link) {
case AREMD:
opset(AREMDU, r0)
+ case AMULLW:
+ opset(AMULLD, r0)
+
case ADIVW: /* op Rb[,Ra],Rd */
opset(AMULHW, r0)
@@ -1312,7 +1315,6 @@ func buildop(ctxt *obj.Link) {
opset(AMULHDCC, r0)
opset(AMULHDU, r0)
opset(AMULHDUCC, r0)
- opset(AMULLD, r0)
opset(AMULLDCC, r0)
opset(AMULLDVCC, r0)
opset(AMULLDV, r0)
@@ -1996,7 +1998,6 @@ func buildop(ctxt *obj.Link) {
AMOVB, /* macro: move byte with sign extension */
AMOVBU, /* macro: move byte with sign extension & update */
AMOVFL,
- AMULLW,
/* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
ASUBC, /* op r1,$s,r3; op r1[,r2],r3 */
ASTSW,
@@ -2158,7 +2159,7 @@ func AOP_DQ(op uint32, d uint32, a uint32, b uint32) uint32 {
/* Z23-form, 3-register operands + CY field */
func AOP_Z23I(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
- return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (c&3)<<7
+ return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (c&3)<<9
}
/* X-form, 3-register operands + EH field */
@@ -2749,7 +2750,7 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
me := int(d)
sh := c.regoff(&p.From)
if me < 0 || me > 63 || sh > 63 {
- c.ctxt.Diag("Invalid me or sh for RLDICR: %x %x\n%v", int(d), sh)
+ c.ctxt.Diag("Invalid me or sh for RLDICR: %x %x\n%v", int(d), sh, p)
}
o1 = AOP_RLDIC(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(sh), uint32(me))
@@ -2757,19 +2758,19 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
mb := int(d)
sh := c.regoff(&p.From)
if mb < 0 || mb > 63 || sh > 63 {
- c.ctxt.Diag("Invalid mb or sh for RLDIC, RLDICL: %x %x\n%v", mb, sh)
+ c.ctxt.Diag("Invalid mb or sh for RLDIC, RLDICL: %x %x\n%v", mb, sh, p)
}
o1 = AOP_RLDIC(c.oprrr(p.As), uint32(p.To.Reg), uint32(r), uint32(sh), uint32(mb))
case ACLRLSLDI:
// This is an extended mnemonic defined in the ISA section C.8.1
- // clrlsldi ra,rs,n,b --> rldic ra,rs,n,b-n
+ // clrlsldi ra,rs,b,n --> rldic ra,rs,n,b-n
// It maps onto RLDIC so is directly generated here based on the operands from
// the clrlsldi.
- b := int(d)
- n := c.regoff(&p.From)
- if n > int32(b) || b > 63 {
- c.ctxt.Diag("Invalid n or b for CLRLSLDI: %x %x\n%v", n, b)
+ n := int32(d)
+ b := c.regoff(&p.From)
+ if n > b || b > 63 {
+ c.ctxt.Diag("Invalid n or b for CLRLSLDI: %x %x\n%v", n, b, p)
}
o1 = AOP_RLDIC(OP_RLDIC, uint32(p.To.Reg), uint32(r), uint32(n), uint32(b)-uint32(n))
@@ -3395,14 +3396,15 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
v := c.regoff(&p.From)
switch p.As {
case ACLRLSLWI:
- b := c.regoff(p.GetFrom3())
+ n := c.regoff(p.GetFrom3())
// This is an extended mnemonic described in the ISA C.8.2
- // clrlslwi ra,rs,n,b -> rlwinm ra,rs,n,b-n,31-n
+ // clrlslwi ra,rs,b,n -> rlwinm ra,rs,n,b-n,31-n
// It maps onto rlwinm which is directly generated here.
- if v < 0 || v > 32 || b > 32 {
- c.ctxt.Diag("Invalid n or b for CLRLSLWI: %x %x\n%v", v, b)
+ if n > v || v >= 32 {
+ c.ctxt.Diag("Invalid n or b for CLRLSLWI: %x %x\n%v", v, n, p)
}
- o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.Reg), uint32(v), uint32(b-v), uint32(31-v))
+
+ o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.Reg), uint32(n), uint32(v-n), uint32(31-n))
default:
var mask [2]uint8
c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
@@ -3414,16 +3416,16 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
v := c.regoff(&p.From)
switch p.As {
case ACLRLSLWI:
- b := c.regoff(p.GetFrom3())
- if v > b || b > 32 {
+ n := c.regoff(p.GetFrom3())
+ if n > v || v >= 32 {
// Message will match operands from the ISA even though in the
// code it uses 'v'
- c.ctxt.Diag("Invalid n or b for CLRLSLWI: %x %x\n%v", v, b)
+ c.ctxt.Diag("Invalid n or b for CLRLSLWI: %x %x\n%v", v, n, p)
}
// This is an extended mnemonic described in the ISA C.8.2
- // clrlslwi ra,rs,n,b -> rlwinm ra,rs,n,b-n,31-n
+ // clrlslwi ra,rs,b,n -> rlwinm ra,rs,n,b-n,31-n
// It generates the rlwinm directly here.
- o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.Reg), uint32(v), uint32(b-v), uint32(31-v))
+ o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.Reg), uint32(n), uint32(v-n), uint32(31-n))
default:
var mask [2]uint8
c.maskgen(p, mask[:], uint32(c.regoff(p.GetFrom3())))
@@ -4989,8 +4991,8 @@ func (c *ctxt9) opirr(a obj.As) uint32 {
case ADARN:
return OPVCC(31, 755, 0, 0) /* darn - v3.00 */
- case AMULLW:
- return OPVCC(7, 0, 0, 0)
+ case AMULLW, AMULLD:
+ return OPVCC(7, 0, 0, 0) /* mulli works with MULLW or MULLD */
case AOR:
return OPVCC(24, 0, 0, 0)
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index c012762a18..3ab19de602 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -402,13 +402,13 @@ func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// TODO(minux): add morestack short-cuts with small fixed frame-size.
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
textstksiz := p.To.Offset
if textstksiz == -8 {
// Compatibility hack.
@@ -424,8 +424,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
+ c.cursym.Func().Args = p.To.Val.(int32)
+ c.cursym.Func().Locals = int32(textstksiz)
/*
* find leaf subroutines
@@ -435,7 +435,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
var q *obj.Prog
var q1 *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
/* too hard, just leave alone */
case obj.ATEXT:
@@ -541,7 +541,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ABCL,
obj.ADUFFZERO,
obj.ADUFFCOPY:
- c.cursym.Func.Text.Mark &^= LEAF
+ c.cursym.Func().Text.Mark &^= LEAF
fallthrough
case ABC,
@@ -598,7 +598,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
autosize := int32(0)
var p1 *obj.Prog
var p2 *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
@@ -664,7 +664,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
rel.Type = objabi.R_ADDRPOWER_PCREL
}
- if !c.cursym.Func.Text.From.Sym.NoSplit() {
+ if !c.cursym.Func().Text.From.Sym.NoSplit() {
q = c.stacksplit(q, autosize) // emit split check
}
@@ -732,14 +732,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
}
- } else if c.cursym.Func.Text.Mark&LEAF == 0 {
+ } else if c.cursym.Func().Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// (e.g. gogo) are not identified as leaves but still have
// no frame.
- c.cursym.Func.Text.Mark |= LEAF
+ c.cursym.Func().Text.Mark |= LEAF
}
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
c.cursym.Set(obj.AttrLeaf, true)
break
}
@@ -755,7 +755,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.To.Offset = 24
}
- if c.cursym.Func.Text.From.Sym.Wrapper() {
+ if c.cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVD g_panic(g), R3
@@ -853,7 +853,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
retTarget := p.To.Sym
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" {
p.As = ABR
p.From = obj.Addr{}
@@ -1161,7 +1161,7 @@ func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
var morestacksym *obj.LSym
if c.cursym.CFunc() {
morestacksym = c.ctxt.Lookup("runtime.morestackc")
- } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
} else {
morestacksym = c.ctxt.Lookup("runtime.morestack")
diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go
index 482f9e0b6d..b1324b62a0 100644
--- a/src/cmd/internal/obj/riscv/cpu.go
+++ b/src/cmd/internal/obj/riscv/cpu.go
@@ -109,7 +109,7 @@ const (
REG_RA = REG_X1 // aka REG_LR
REG_SP = REG_X2
REG_GP = REG_X3 // aka REG_SB
- REG_TP = REG_X4 // aka REG_G
+ REG_TP = REG_X4
REG_T0 = REG_X5
REG_T1 = REG_X6
REG_T2 = REG_X7
@@ -132,17 +132,17 @@ const (
REG_S8 = REG_X24
REG_S9 = REG_X25
REG_S10 = REG_X26
- REG_S11 = REG_X27
+ REG_S11 = REG_X27 // aka REG_G
REG_T3 = REG_X28
REG_T4 = REG_X29
REG_T5 = REG_X30
REG_T6 = REG_X31 // aka REG_TMP
// Go runtime register names.
- REG_G = REG_TP // G pointer.
- REG_CTXT = REG_S4 // Context for closures.
- REG_LR = REG_RA // Link register.
- REG_TMP = REG_T6 // Reserved for assembler use.
+ REG_G = REG_S11 // G pointer.
+ REG_CTXT = REG_S4 // Context for closures.
+ REG_LR = REG_RA // Link register.
+ REG_TMP = REG_T6 // Reserved for assembler use.
// ABI names for floating point registers.
REG_FT0 = REG_F0
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 841b30d85c..5301e44002 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -33,7 +33,7 @@ func buildop(ctxt *obj.Link) {}
// lr is the link register to use for the JALR.
// p must be a CALL, JMP or RET.
func jalrToSym(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, lr int16) *obj.Prog {
- if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET {
+ if p.As != obj.ACALL && p.As != obj.AJMP && p.As != obj.ARET && p.As != obj.ADUFFZERO && p.As != obj.ADUFFCOPY {
ctxt.Diag("unexpected Prog in jalrToSym: %v", p)
return p
}
@@ -252,19 +252,7 @@ func rewriteMOV(ctxt *obj.Link, newprog obj.ProgAlloc, p *obj.Prog) {
switch p.To.Type {
case obj.TYPE_REG:
switch p.As {
- case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
- p.As = AADDI
- p.Reg = p.From.Reg
- p.From = obj.Addr{Type: obj.TYPE_CONST}
-
- case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb
- p.As = AFSGNJS
- p.Reg = p.From.Reg
-
- case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb
- p.As = AFSGNJD
- p.Reg = p.From.Reg
-
+ case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
default:
ctxt.Diag("unsupported register-register move at %v", p)
}
@@ -427,9 +415,9 @@ func InvertBranch(as obj.As) obj.As {
// instruction. Must be called after progedit.
func containsCall(sym *obj.LSym) bool {
// CALLs are CALL or JAL(R) with link register LR.
- for p := sym.Func.Text; p != nil; p = p.Link {
+ for p := sym.Func().Text; p != nil; p = p.Link {
switch p.As {
- case obj.ACALL:
+ case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
return true
case AJAL, AJALR:
if p.From.Type == obj.TYPE_REG && p.From.Reg == REG_LR {
@@ -499,12 +487,12 @@ func stackOffset(a *obj.Addr, stacksize int64) {
// concrete, real RISC-V instructions or directive pseudo-ops like TEXT,
// PCDATA, and FUNCDATA.
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
// Generate the prologue.
- text := cursym.Func.Text
+ text := cursym.Func().Text
if text.As != obj.ATEXT {
ctxt.Diag("preprocess: found symbol that does not start with TEXT directive")
return
@@ -538,12 +526,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
stacksize += ctxt.FixedFrameSize()
}
- cursym.Func.Args = text.To.Val.(int32)
- cursym.Func.Locals = int32(stacksize)
+ cursym.Func().Args = text.To.Val.(int32)
+ cursym.Func().Locals = int32(stacksize)
prologue := text
- if !cursym.Func.Text.From.Sym.NoSplit() {
+ if !cursym.Func().Text.From.Sym.NoSplit() {
prologue = stacksplit(ctxt, prologue, cursym, newprog, stacksize) // emit split check
}
@@ -567,7 +555,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
prologue = ctxt.EndUnsafePoint(prologue, newprog, -1)
}
- if cursym.Func.Text.From.Sym.Wrapper() {
+ if cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOV g_panic(g), X11
@@ -647,13 +635,13 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Update stack-based offsets.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
stackOffset(&p.From, stacksize)
stackOffset(&p.To, stacksize)
}
// Additional instruction rewriting.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.AGETCALLERPC:
if cursym.Leaf() {
@@ -668,7 +656,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Reg = REG_SP
}
- case obj.ACALL:
+ case obj.ACALL, obj.ADUFFZERO, obj.ADUFFCOPY:
switch p.To.Type {
case obj.TYPE_MEM:
jalrToSym(ctxt, p, newprog, REG_LR)
@@ -733,7 +721,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// Rewrite MOV pseudo-instructions. This cannot be done in
// progedit, as SP offsets need to be applied before we split
// up some of the Addrs.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
rewriteMOV(ctxt, newprog, p)
@@ -741,7 +729,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Split immediates larger than 12-bits.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
// <opi> $imm, REG, TO
case AADDI, AANDI, AORI, AXORI:
@@ -858,9 +846,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// a fixed point will be reached). No attempt to handle functions > 2GiB.
for {
rescan := false
- setPCs(cursym.Func.Text, 0)
+ setPCs(cursym.Func().Text, 0)
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ:
if p.To.Type != obj.TYPE_BRANCH {
@@ -917,7 +905,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// Now that there are no long branches, resolve branch and jump targets.
// At this point, instruction rewriting which changes the number of
// instructions will break everything--don't do it!
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, AJAL:
switch p.To.Type {
@@ -940,7 +928,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
// Validate all instructions - this provides nice error messages.
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
for _, ins := range instructionsForProg(p) {
ins.validate(ctxt)
}
@@ -1068,7 +1056,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgA
p.To.Type = obj.TYPE_BRANCH
if cursym.CFunc() {
p.To.Sym = ctxt.Lookup("runtime.morestackc")
- } else if !cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !cursym.Func().Text.From.Sym.NeedCtxt() {
p.To.Sym = ctxt.Lookup("runtime.morestack_noctxt")
} else {
p.To.Sym = ctxt.Lookup("runtime.morestack")
@@ -1083,7 +1071,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, cursym *obj.LSym, newprog obj.ProgA
p.As = AJAL
p.To = obj.Addr{Type: obj.TYPE_BRANCH}
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_ZERO}
- p.To.SetTarget(cursym.Func.Text.Link)
+ p.To.SetTarget(cursym.Func().Text.Link)
// placeholder for to_done's jump target
p = obj.Appendp(p, newprog)
@@ -1708,6 +1696,8 @@ var encodings = [ALAST & obj.AMask]encoding{
obj.APCDATA: pseudoOpEncoding,
obj.ATEXT: pseudoOpEncoding,
obj.ANOP: pseudoOpEncoding,
+ obj.ADUFFZERO: pseudoOpEncoding,
+ obj.ADUFFCOPY: pseudoOpEncoding,
}
// encodingForAs returns the encoding for an obj.As.
@@ -1805,6 +1795,44 @@ func instructionsForProg(p *obj.Prog) []*instruction {
}
ins.imm = p.To.Offset
+ case AMOV, AMOVB, AMOVH, AMOVW, AMOVBU, AMOVHU, AMOVWU, AMOVF, AMOVD:
+ // Handle register to register moves.
+ if p.From.Type != obj.TYPE_REG || p.To.Type != obj.TYPE_REG {
+ break
+ }
+ switch p.As {
+ case AMOV: // MOV Ra, Rb -> ADDI $0, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AADDI, uint32(p.From.Reg), obj.REG_NONE, 0
+ case AMOVW: // MOVW Ra, Rb -> ADDIW $0, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AADDIW, uint32(p.From.Reg), obj.REG_NONE, 0
+ case AMOVBU: // MOVBU Ra, Rb -> ANDI $255, Ra, Rb
+ ins.as, ins.rs1, ins.rs2, ins.imm = AANDI, uint32(p.From.Reg), obj.REG_NONE, 255
+ case AMOVF: // MOVF Ra, Rb -> FSGNJS Ra, Ra, Rb
+ ins.as, ins.rs1 = AFSGNJS, uint32(p.From.Reg)
+ case AMOVD: // MOVD Ra, Rb -> FSGNJD Ra, Ra, Rb
+ ins.as, ins.rs1 = AFSGNJD, uint32(p.From.Reg)
+ case AMOVB, AMOVH:
+ // Use SLLI/SRAI to extend.
+ ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
+ if p.As == AMOVB {
+ ins.imm = 56
+ } else if p.As == AMOVH {
+ ins.imm = 48
+ }
+ ins2 := &instruction{as: ASRAI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
+ inss = append(inss, ins2)
+ case AMOVHU, AMOVWU:
+ // Use SLLI/SRLI to extend.
+ ins.as, ins.rs1, ins.rs2 = ASLLI, uint32(p.From.Reg), obj.REG_NONE
+ if p.As == AMOVHU {
+ ins.imm = 48
+ } else if p.As == AMOVWU {
+ ins.imm = 32
+ }
+ ins2 := &instruction{as: ASRLI, rd: ins.rd, rs1: ins.rd, imm: ins.imm}
+ inss = append(inss, ins2)
+ }
+
case ALW, ALWU, ALH, ALHU, ALB, ALBU, ALD, AFLW, AFLD:
if p.From.Type != obj.TYPE_MEM {
p.Ctxt.Diag("%v requires memory for source", p)
@@ -1859,13 +1887,13 @@ func instructionsForProg(p *obj.Prog) []*instruction {
} else {
ins.as = AFEQD
}
- ins = &instruction{
+ ins2 := &instruction{
as: AXORI, // [bit] xor 1 = not [bit]
rd: ins.rd,
rs1: ins.rd,
imm: 1,
}
- inss = append(inss, ins)
+ inss = append(inss, ins2)
case AFSQRTS, AFSQRTD:
// These instructions expect a zero (i.e. float register 0)
@@ -1926,7 +1954,7 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
var symcode []uint32
- for p := cursym.Func.Text; p != nil; p = p.Link {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case AJALR:
if p.To.Sym != nil {
@@ -1958,6 +1986,13 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Diag("AUIPC needing PC-relative reloc missing symbol")
break
}
+ if addr.Sym.Type == objabi.STLSBSS {
+ if rt == objabi.R_RISCV_PCREL_ITYPE {
+ rt = objabi.R_RISCV_TLS_IE_ITYPE
+ } else if rt == objabi.R_RISCV_PCREL_STYPE {
+ rt = objabi.R_RISCV_TLS_IE_STYPE
+ }
+ }
rel := obj.Addrel(cursym)
rel.Off = int32(p.Pc)
@@ -1981,7 +2016,7 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Arch.ByteOrder.PutUint32(p, symcode[i])
}
- obj.MarkUnsafePoints(ctxt, cursym.Func.Text, newprog, isUnsafePoint, nil)
+ obj.MarkUnsafePoints(ctxt, cursym.Func().Text, newprog, isUnsafePoint, nil)
}
func isUnsafePoint(p *obj.Prog) bool {
diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go
index cb3a2c3196..da14dd3c41 100644
--- a/src/cmd/internal/obj/s390x/asmz.go
+++ b/src/cmd/internal/obj/s390x/asmz.go
@@ -447,7 +447,7 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Retpoline = false // don't keep printing
}
- p := cursym.Func.Text
+ p := cursym.Func().Text
if p == nil || p.Link == nil { // handle external functions and ELF section symbols
return
}
@@ -473,7 +473,7 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
c.cursym.R[nrelocs0+i] = obj.Reloc{}
}
c.cursym.R = c.cursym.R[:nrelocs0] // preserve marker relocations generated by the compiler
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
pc := int64(len(buffer))
if pc != p.Pc {
changed = true
@@ -504,7 +504,7 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// We use REGTMP as a scratch register during call injection,
// so instruction sequences that use REGTMP are unsafe to
// preempt asynchronously.
- obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, nil)
+ obj.MarkUnsafePoints(c.ctxt, c.cursym.Func().Text, c.newprog, c.isUnsafePoint, nil)
}
// Return whether p is an unsafe point.
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
index 625bb0f7b4..970cf827d6 100644
--- a/src/cmd/internal/obj/s390x/objz.go
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -205,13 +205,13 @@ func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// TODO(minux): add morestack short-cuts with small fixed frame-size.
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog}
- p := c.cursym.Func.Text
+ p := c.cursym.Func().Text
textstksiz := p.To.Offset
if textstksiz == -8 {
// Compatibility hack.
@@ -227,8 +227,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
}
- c.cursym.Func.Args = p.To.Val.(int32)
- c.cursym.Func.Locals = int32(textstksiz)
+ c.cursym.Func().Args = p.To.Val.(int32)
+ c.cursym.Func().Locals = int32(textstksiz)
/*
* find leaf subroutines
@@ -237,7 +237,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
*/
var q *obj.Prog
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case obj.ATEXT:
q = p
@@ -245,7 +245,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case ABL, ABCL:
q = p
- c.cursym.Func.Text.Mark &^= LEAF
+ c.cursym.Func().Text.Mark &^= LEAF
fallthrough
case ABC,
@@ -294,7 +294,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
var pPre *obj.Prog
var pPreempt *obj.Prog
wasSplit := false
- for p := c.cursym.Func.Text; p != nil; p = p.Link {
+ for p := c.cursym.Func().Text; p != nil; p = p.Link {
pLast = p
switch p.As {
case obj.ATEXT:
@@ -356,19 +356,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Spadj = autosize
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
- } else if c.cursym.Func.Text.Mark&LEAF == 0 {
+ } else if c.cursym.Func().Text.Mark&LEAF == 0 {
// A very few functions that do not return to their caller
// (e.g. gogo) are not identified as leaves but still have
// no frame.
- c.cursym.Func.Text.Mark |= LEAF
+ c.cursym.Func().Text.Mark |= LEAF
}
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
c.cursym.Set(obj.AttrLeaf, true)
break
}
- if c.cursym.Func.Text.From.Sym.Wrapper() {
+ if c.cursym.Func().Text.From.Sym.Wrapper() {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVD g_panic(g), R3
@@ -461,7 +461,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
case obj.ARET:
retTarget := p.To.Sym
- if c.cursym.Func.Text.Mark&LEAF != 0 {
+ if c.cursym.Func().Text.Mark&LEAF != 0 {
if autosize == 0 {
p.As = ABR
p.From = obj.Addr{}
@@ -497,8 +497,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGSP
p.From.Offset = 0
- p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_LR
+ p.To = obj.Addr{
+ Type: obj.TYPE_REG,
+ Reg: REG_LR,
+ }
q = p
@@ -696,7 +698,7 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
p.To.Type = obj.TYPE_BRANCH
if c.cursym.CFunc() {
p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
- } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
+ } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
} else {
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
@@ -709,7 +711,7 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog,
p.As = ABR
p.To.Type = obj.TYPE_BRANCH
- p.To.SetTarget(c.cursym.Func.Text.Link)
+ p.To.SetTarget(c.cursym.Func().Text.Link)
return p
}
diff --git a/src/cmd/internal/obj/sizeof_test.go b/src/cmd/internal/obj/sizeof_test.go
index b5e170c694..69e60473f5 100644
--- a/src/cmd/internal/obj/sizeof_test.go
+++ b/src/cmd/internal/obj/sizeof_test.go
@@ -21,7 +21,7 @@ func TestSizeof(t *testing.T) {
_64bit uintptr // size on 64bit platforms
}{
{Addr{}, 32, 48},
- {LSym{}, 76, 128},
+ {LSym{}, 72, 120},
{Prog{}, 132, 200},
}
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index e5d7b2cbfd..4515bdd0d3 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -205,7 +205,7 @@ func (ctxt *Link) NumberSyms() {
// if Pkgpath is unknown, cannot hash symbols with relocations, as it
// may reference named symbols whose names are not fully expanded.
if s.ContentAddressable() && (ctxt.Pkgpath != "" || len(s.R) == 0) {
- if len(s.P) <= 8 && len(s.R) == 0 && !strings.HasPrefix(s.Name, "type.") {
+ if s.Size <= 8 && len(s.R) == 0 && !strings.HasPrefix(s.Name, "type.") {
// We can use short hash only for symbols without relocations.
// Don't use short hash for type symbols, as they need special handling.
s.PkgIdx = goobj.PkgIdxHashed64
@@ -358,7 +358,8 @@ func (ctxt *Link) traverseSyms(flag traverseFlag, fn func(*LSym)) {
}
func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent *LSym, aux *LSym)) {
- pc := &fsym.Func.Pcln
+ fninfo := fsym.Func()
+ pc := &fninfo.Pcln
if flag&traverseAux == 0 {
// NB: should it become necessary to walk aux sym reloc references
// without walking the aux syms themselves, this can be changed.
@@ -389,7 +390,8 @@ func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent
fn(fsym, filesym)
}
}
- dwsyms := []*LSym{fsym.Func.dwarfRangesSym, fsym.Func.dwarfLocSym, fsym.Func.dwarfDebugLinesSym, fsym.Func.dwarfInfoSym}
+
+ dwsyms := []*LSym{fninfo.dwarfRangesSym, fninfo.dwarfLocSym, fninfo.dwarfDebugLinesSym, fninfo.dwarfInfoSym}
for _, dws := range dwsyms {
if dws == nil || dws.Size == 0 {
continue
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index a30ccf0564..21e28807a6 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -210,13 +210,30 @@ func (ctxt *Link) CanReuseProgs() bool {
return ctxt.Debugasm == 0
}
+// Dconv accepts an argument 'a' within a prog 'p' and returns a string
+// with a formatted version of the argument.
func Dconv(p *Prog, a *Addr) string {
buf := new(bytes.Buffer)
- WriteDconv(buf, p, a)
+ writeDconv(buf, p, a, false)
return buf.String()
}
+// DconvDconvWithABIDetail accepts an argument 'a' within a prog 'p'
+// and returns a string with a formatted version of the argument, in
+// which text symbols are rendered with explicit ABI selectors.
+func DconvWithABIDetail(p *Prog, a *Addr) string {
+ buf := new(bytes.Buffer)
+ writeDconv(buf, p, a, true)
+ return buf.String()
+}
+
+// WriteDconv accepts an argument 'a' within a prog 'p'
+// and writes a formatted version of the arg to the writer.
func WriteDconv(w io.Writer, p *Prog, a *Addr) {
+ writeDconv(w, p, a, false)
+}
+
+func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
switch a.Type {
default:
fmt.Fprintf(w, "type=%d", a.Type)
@@ -250,7 +267,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
case TYPE_BRANCH:
if a.Sym != nil {
- fmt.Fprintf(w, "%s(SB)", a.Sym.Name)
+ fmt.Fprintf(w, "%s%s(SB)", a.Sym.Name, abiDecorate(a, abiDetail))
} else if a.Target() != nil {
fmt.Fprint(w, a.Target().Pc)
} else {
@@ -259,7 +276,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
case TYPE_INDIR:
io.WriteString(w, "*")
- a.WriteNameTo(w)
+ a.writeNameTo(w, abiDetail)
case TYPE_MEM:
a.WriteNameTo(w)
@@ -299,7 +316,7 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
case TYPE_ADDR:
io.WriteString(w, "$")
- a.WriteNameTo(w)
+ a.writeNameTo(w, abiDetail)
case TYPE_SHIFT:
v := int(a.Offset)
@@ -335,6 +352,11 @@ func WriteDconv(w io.Writer, p *Prog, a *Addr) {
}
func (a *Addr) WriteNameTo(w io.Writer) {
+ a.writeNameTo(w, false)
+}
+
+func (a *Addr) writeNameTo(w io.Writer, abiDetail bool) {
+
switch a.Name {
default:
fmt.Fprintf(w, "name=%d", a.Name)
@@ -356,7 +378,7 @@ func (a *Addr) WriteNameTo(w io.Writer) {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
- fmt.Fprintf(w, "%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
+ fmt.Fprintf(w, "%s%s%s(%s)", a.Sym.Name, abiDecorate(a, abiDetail), offConv(a.Offset), reg)
} else {
fmt.Fprintf(w, "%s(%s)", offConv(a.Offset), reg)
}
@@ -596,3 +618,10 @@ func Bool2int(b bool) int {
}
return i
}
+
+func abiDecorate(a *Addr, abiDetail bool) string {
+ if !abiDetail || a.Sym == nil {
+ return ""
+ }
+ return fmt.Sprintf("<%s>", a.Sym.ABI())
+}
diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go
index a9e093a8ad..f7f66a1255 100644
--- a/src/cmd/internal/obj/wasm/wasmobj.go
+++ b/src/cmd/internal/obj/wasm/wasmobj.go
@@ -182,14 +182,14 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
return p
}
- framesize := s.Func.Text.To.Offset
+ framesize := s.Func().Text.To.Offset
if framesize < 0 {
panic("bad framesize")
}
- s.Func.Args = s.Func.Text.To.Val.(int32)
- s.Func.Locals = int32(framesize)
+ s.Func().Args = s.Func().Text.To.Val.(int32)
+ s.Func().Locals = int32(framesize)
- if s.Func.Text.From.Sym.Wrapper() {
+ if s.Func().Text.From.Sym.Wrapper() {
// if g._panic != nil && g._panic.argp == FP {
// g._panic.argp = bottom-of-frame
// }
@@ -222,7 +222,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
Offset: 0, // panic.argp
}
- p := s.Func.Text
+ p := s.Func().Text
p = appendp(p, AMOVD, gpanic, regAddr(REG_R0))
p = appendp(p, AGet, regAddr(REG_R0))
@@ -245,7 +245,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
if framesize > 0 {
- p := s.Func.Text
+ p := s.Func().Text
p = appendp(p, AGet, regAddr(REG_SP))
p = appendp(p, AI32Const, constAddr(framesize))
p = appendp(p, AI32Sub)
@@ -260,8 +260,8 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
pc := int64(0) // pc is only incremented when necessary, this avoids bloat of the BrTable instruction
var tableIdxs []uint64
tablePC := int64(0)
- base := ctxt.PosTable.Pos(s.Func.Text.Pos).Base()
- for p := s.Func.Text; p != nil; p = p.Link {
+ base := ctxt.PosTable.Pos(s.Func().Text.Pos).Base()
+ for p := s.Func().Text; p != nil; p = p.Link {
prevBase := base
base = ctxt.PosTable.Pos(p.Pos).Base()
switch p.As {
@@ -313,8 +313,8 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
tableIdxs = append(tableIdxs, uint64(numResumePoints))
s.Size = pc + 1
- if !s.Func.Text.From.Sym.NoSplit() {
- p := s.Func.Text
+ if !s.Func().Text.From.Sym.NoSplit() {
+ p := s.Func().Text
if framesize <= objabi.StackSmall {
// small stack: SP <= stackguard
@@ -352,7 +352,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
p = appendp(p, AIf)
p = appendp(p, obj.ACALL, constAddr(0))
- if s.Func.Text.From.Sym.NeedCtxt() {
+ if s.Func().Text.From.Sym.NeedCtxt() {
p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: morestack}
} else {
p.To = obj.Addr{Type: obj.TYPE_MEM, Name: obj.NAME_EXTERN, Sym: morestackNoCtxt}
@@ -365,7 +365,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
var entryPointLoopBranches []*obj.Prog
var unwindExitBranches []*obj.Prog
currentDepth := 0
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABlock, ALoop, AIf:
currentDepth++
@@ -562,7 +562,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
}
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
switch p.From.Name {
case obj.NAME_AUTO:
p.From.Offset += int64(framesize)
@@ -712,7 +712,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
{
- p := s.Func.Text
+ p := s.Func().Text
if len(unwindExitBranches) > 0 {
p = appendp(p, ABlock) // unwindExit, used to return 1 when unwinding the stack
for _, b := range unwindExitBranches {
@@ -749,7 +749,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
currentDepth = 0
blockDepths := make(map[*obj.Prog]int)
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABlock, ALoop, AIf:
currentDepth++
@@ -850,7 +850,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
hasLocalSP = true
var regUsed [MAXREG - MINREG]bool
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
if p.From.Reg != 0 {
regUsed[p.From.Reg-MINREG] = true
}
@@ -896,7 +896,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
updateLocalSP(w)
}
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
switch p.As {
case AGet:
if p.From.Type != obj.TYPE_REG {
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 4940c79eaa..c412f4945d 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -2050,7 +2050,7 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
ctxt.Diag("x86 tables not initialized, call x86.instinit first")
}
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
if p.To.Type == obj.TYPE_BRANCH && p.To.Target() == nil {
p.To.SetTarget(p)
}
@@ -2085,7 +2085,7 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
var count int64 // rough count of number of instructions
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
count++
p.Back = branchShort // use short branches first time through
if q := p.To.Target(); q != nil && (q.Back&branchShort != 0) {
@@ -2113,7 +2113,7 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
c = 0
var pPrev *obj.Prog
nops = nops[:0]
- for p := s.Func.Text; p != nil; p = p.Link {
+ for p := s.Func().Text; p != nil; p = p.Link {
c0 := c
c = pjc.padJump(ctxt, s, p, c)
@@ -2227,7 +2227,7 @@ func span6(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
// the first instruction.)
return p.From.Index == REG_TLS
}
- obj.MarkUnsafePoints(ctxt, s.Func.Text, newprog, useTLS, nil)
+ obj.MarkUnsafePoints(ctxt, s.Func().Text, newprog, useTLS, nil)
}
}
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 18a6afcd77..e11fa13f65 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -563,11 +563,11 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
}
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
+ if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
return
}
- p := cursym.Func.Text
+ p := cursym.Func().Text
autoffset := int32(p.To.Offset)
if autoffset < 0 {
autoffset = 0
@@ -602,12 +602,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
textarg := int64(p.To.Val.(int32))
- cursym.Func.Args = int32(textarg)
- cursym.Func.Locals = int32(p.To.Offset)
+ cursym.Func().Args = int32(textarg)
+ cursym.Func().Locals = int32(p.To.Offset)
// TODO(rsc): Remove.
- if ctxt.Arch.Family == sys.I386 && cursym.Func.Locals < 0 {
- cursym.Func.Locals = 0
+ if ctxt.Arch.Family == sys.I386 && cursym.Func().Locals < 0 {
+ cursym.Func().Locals = 0
}
// TODO(rsc): Remove 'ctxt.Arch.Family == sys.AMD64 &&'.
@@ -642,7 +642,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p = load_g_cx(ctxt, p, newprog) // load g into CX
}
- if !cursym.Func.Text.From.Sym.NoSplit() {
+ if !cursym.Func().Text.From.Sym.NoSplit() {
p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg)) // emit split check
}
@@ -690,7 +690,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.To.Reg = REG_BP
}
- if cursym.Func.Text.From.Sym.Wrapper() {
+ if cursym.Func().Text.From.Sym.Wrapper() {
// if g._panic != nil && g._panic.argp == FP {
// g._panic.argp = bottom-of-frame
// }
@@ -808,7 +808,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
}
var deltasp int32
- for p = cursym.Func.Text; p != nil; p = p.Link {
+ for p = cursym.Func().Text; p != nil; p = p.Link {
pcsize := ctxt.Arch.RegSize
switch p.From.Name {
case obj.NAME_AUTO:
@@ -1103,7 +1103,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
end := ctxt.EndUnsafePoint(jls, newprog, -1)
var last *obj.Prog
- for last = cursym.Func.Text; last.Link != nil; last = last.Link {
+ for last = cursym.Func().Text; last.Link != nil; last = last.Link {
}
// Now we are at the end of the function, but logically
@@ -1117,7 +1117,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
pcdata = ctxt.StartUnsafePoint(pcdata, newprog)
call := obj.Appendp(pcdata, newprog)
- call.Pos = cursym.Func.Text.Pos
+ call.Pos = cursym.Func().Text.Pos
call.As = obj.ACALL
call.To.Type = obj.TYPE_BRANCH
call.To.Name = obj.NAME_EXTERN
@@ -1125,7 +1125,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
switch {
case cursym.CFunc():
morestack = "runtime.morestackc"
- case !cursym.Func.Text.From.Sym.NeedCtxt():
+ case !cursym.Func().Text.From.Sym.NeedCtxt():
morestack = "runtime.morestack_noctxt"
}
call.To.Sym = ctxt.Lookup(morestack)
@@ -1144,7 +1144,7 @@ func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgA
jmp := obj.Appendp(pcdata, newprog)
jmp.As = obj.AJMP
jmp.To.Type = obj.TYPE_BRANCH
- jmp.To.SetTarget(cursym.Func.Text.Link)
+ jmp.To.SetTarget(cursym.Func().Text.Link)
jmp.Spadj = +framesize
jls.To.SetTarget(call)
diff --git a/src/cmd/internal/objabi/funcid.go b/src/cmd/internal/objabi/funcid.go
index 6c9336f31c..1d098ee172 100644
--- a/src/cmd/internal/objabi/funcid.go
+++ b/src/cmd/internal/objabi/funcid.go
@@ -26,7 +26,7 @@ const (
FuncID_gcBgMarkWorker
FuncID_systemstack_switch
FuncID_systemstack
- FuncID_cgocallback_gofunc
+ FuncID_cgocallback
FuncID_gogo
FuncID_externalthreadhandler
FuncID_debugCallV1
@@ -70,8 +70,8 @@ func GetFuncID(name string, isWrapper bool) FuncID {
return FuncID_systemstack_switch
case "runtime.systemstack":
return FuncID_systemstack
- case "runtime.cgocallback_gofunc":
- return FuncID_cgocallback_gofunc
+ case "runtime.cgocallback":
+ return FuncID_cgocallback
case "runtime.gogo":
return FuncID_gogo
case "runtime.externalthreadhandler":
diff --git a/src/cmd/internal/objabi/path.go b/src/cmd/internal/objabi/path.go
index 2a42179a36..fd1c9981c6 100644
--- a/src/cmd/internal/objabi/path.go
+++ b/src/cmd/internal/objabi/path.go
@@ -39,3 +39,25 @@ func PathToPrefix(s string) string {
return string(p)
}
+
+// IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it
+// belongs to the collection of "runtime-related" packages, including
+// "runtime" itself, "reflect", "syscall", and the
+// "runtime/internal/*" packages. The compiler and/or assembler in
+// some cases need to be aware of when they are building such a
+// package, for example to enable features such as ABI selectors in
+// assembly sources.
+func IsRuntimePackagePath(pkgpath string) bool {
+ rval := false
+ switch pkgpath {
+ case "runtime":
+ rval = true
+ case "reflect":
+ rval = true
+ case "syscall":
+ rval = true
+ default:
+ rval = strings.HasPrefix(pkgpath, "runtime/internal")
+ }
+ return rval
+}
diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go
index 9e2e4a150a..938954e07a 100644
--- a/src/cmd/internal/objabi/reloctype.go
+++ b/src/cmd/internal/objabi/reloctype.go
@@ -223,6 +223,14 @@ const (
// AUIPC + S-type instruction pair.
R_RISCV_PCREL_STYPE
+ // R_RISCV_TLS_IE_ITYPE resolves a 32-bit TLS initial-exec TOC offset
+ // address using an AUIPC + I-type instruction pair.
+ R_RISCV_TLS_IE_ITYPE
+
+ // R_RISCV_TLS_IE_STYPE resolves a 32-bit TLS initial-exec TOC offset
+ // address using an AUIPC + S-type instruction pair.
+ R_RISCV_TLS_IE_STYPE
+
// R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses.
// TODO(mundaym): remove once variants can be serialized - see issue 14218.
R_PCRELDBL
diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go
index 01df4cce62..693d9631f5 100644
--- a/src/cmd/internal/objabi/reloctype_string.go
+++ b/src/cmd/internal/objabi/reloctype_string.go
@@ -59,17 +59,19 @@ func _() {
_ = x[R_ADDRPOWER_TOCREL_DS-49]
_ = x[R_RISCV_PCREL_ITYPE-50]
_ = x[R_RISCV_PCREL_STYPE-51]
- _ = x[R_PCRELDBL-52]
- _ = x[R_ADDRMIPSU-53]
- _ = x[R_ADDRMIPSTLS-54]
- _ = x[R_ADDRCUOFF-55]
- _ = x[R_WASMIMPORT-56]
- _ = x[R_XCOFFREF-57]
+ _ = x[R_RISCV_TLS_IE_ITYPE-52]
+ _ = x[R_RISCV_TLS_IE_STYPE-53]
+ _ = x[R_PCRELDBL-54]
+ _ = x[R_ADDRMIPSU-55]
+ _ = x[R_ADDRMIPSTLS-56]
+ _ = x[R_ADDRCUOFF-57]
+ _ = x[R_WASMIMPORT-58]
+ _ = x[R_XCOFFREF-59]
}
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 234, 245, 256, 266, 275, 288, 302, 316, 330, 346, 357, 370, 383, 397, 411, 426, 440, 454, 465, 479, 494, 511, 529, 550, 569, 588, 598, 609, 622, 633, 645, 655}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 234, 245, 256, 266, 275, 288, 302, 316, 330, 346, 357, 370, 383, 397, 411, 426, 440, 454, 465, 479, 494, 511, 529, 550, 569, 588, 608, 628, 638, 649, 662, 673, 685, 695}
func (i RelocType) String() string {
i -= 1
diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go
index 7f74a8256c..f19bec5dcb 100644
--- a/src/cmd/internal/objfile/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -267,13 +267,11 @@ func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
}
b := r.BytesAt(r.DataOff(isym), r.DataSize(isym))
var info *goobj.FuncInfo
- lengths := info.ReadFuncInfoLengths(b)
pcline := getSymData(info.ReadPcline(b))
line := int(pcValue(pcline, pc-addr, f.arch))
pcfile := getSymData(info.ReadPcfile(b))
fileID := pcValue(pcfile, pc-addr, f.arch)
- globalFileID := info.ReadFile(b, lengths.FileOff, uint32(fileID))
- fileName := r.File(int(globalFileID))
+ fileName := r.File(int(fileID))
// Note: we provide only the name in the Func structure.
// We could provide more if needed.
return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: osym.Name(r)}}
diff --git a/src/cmd/internal/pkgpath/pkgpath.go b/src/cmd/internal/pkgpath/pkgpath.go
new file mode 100644
index 0000000000..0b24468be6
--- /dev/null
+++ b/src/cmd/internal/pkgpath/pkgpath.go
@@ -0,0 +1,114 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkgpath determines the package path used by gccgo/GoLLVM symbols.
+// This package is not used for the gc compiler.
+package pkgpath
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strings"
+)
+
+// ToSymbolFunc returns a function that may be used to convert a
+// package path into a string suitable for use as a symbol.
+// cmd is the gccgo/GoLLVM compiler in use, and tmpdir is a temporary
+// directory to pass to ioutil.TempFile.
+// For example, this returns a function that converts "net/http"
+// into a string like "net..z2fhttp". The actual string varies for
+// different gccgo/GoLLVM versions, which is why this returns a function
+// that does the conversion appropriate for the compiler in use.
+func ToSymbolFunc(cmd, tmpdir string) (func(string) string, error) {
+ // To determine the scheme used by cmd, we compile a small
+ // file and examine the assembly code. Older versions of gccgo
+ // use a simple mangling scheme where there can be collisions
+ // between packages whose paths are different but mangle to
+ // the same string. More recent versions use a new mangler
+ // that avoids these collisions.
+ const filepat = "*_gccgo_manglechck.go"
+ f, err := ioutil.TempFile(tmpdir, filepat)
+ if err != nil {
+ return nil, err
+ }
+ gofilename := f.Name()
+ f.Close()
+ defer os.Remove(gofilename)
+
+ if err := ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0644); err != nil {
+ return nil, err
+ }
+
+ command := exec.Command(cmd, "-S", "-o", "-", gofilename)
+ buf, err := command.Output()
+ if err != nil {
+ return nil, err
+ }
+
+ // New mangling: expect go.l..u00e4ufer.Run
+ // Old mangling: expect go.l__ufer.Run
+ if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) {
+ return toSymbolV2, nil
+ } else if bytes.Contains(buf, []byte("go.l__ufer.Run")) {
+ return toSymbolV1, nil
+ } else {
+ return nil, errors.New(cmd + ": unrecognized mangling scheme")
+ }
+}
+
+// mangleCheckCode is the package we compile to determine the mangling scheme.
+const mangleCheckCode = `
+package läufer
+func Run(x int) int {
+ return 1
+}
+`
+
+// toSymbolV1 converts a package path using the original mangling scheme.
+func toSymbolV1(ppath string) string {
+ clean := func(r rune) rune {
+ switch {
+ case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
+ '0' <= r && r <= '9':
+ return r
+ }
+ return '_'
+ }
+ return strings.Map(clean, ppath)
+}
+
+// toSymbolV2 converts a package path using the newer mangling scheme.
+func toSymbolV2(ppath string) string {
+ // This has to build at boostrap time, so it has to build
+ // with Go 1.4, so we don't use strings.Builder.
+ bsl := make([]byte, 0, len(ppath))
+ changed := false
+ for _, c := range ppath {
+ if ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_' {
+ bsl = append(bsl, byte(c))
+ continue
+ }
+ var enc string
+ switch {
+ case c == '.':
+ enc = ".x2e"
+ case c < 0x80:
+ enc = fmt.Sprintf("..z%02x", c)
+ case c < 0x10000:
+ enc = fmt.Sprintf("..u%04x", c)
+ default:
+ enc = fmt.Sprintf("..U%08x", c)
+ }
+ bsl = append(bsl, enc...)
+ changed = true
+ }
+ if !changed {
+ return ppath
+ }
+ return string(bsl)
+}
diff --git a/src/cmd/internal/pkgpath/pkgpath_test.go b/src/cmd/internal/pkgpath/pkgpath_test.go
new file mode 100644
index 0000000000..7355f81bae
--- /dev/null
+++ b/src/cmd/internal/pkgpath/pkgpath_test.go
@@ -0,0 +1,121 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkgpath
+
+import (
+ "os"
+ "testing"
+)
+
+const testEnvName = "GO_PKGPATH_TEST_COMPILER"
+
+// This init function supports TestToSymbolFunc. For simplicity,
+// we use the test binary itself as a sample gccgo driver.
+// We set an environment variable to specify how it should behave.
+func init() {
+ switch os.Getenv(testEnvName) {
+ case "":
+ return
+ case "v1":
+ os.Stdout.WriteString(`.string "go.l__ufer.Run"`)
+ os.Exit(0)
+ case "v2":
+ os.Stdout.WriteString(`.string "go.l..u00e4ufer.Run"`)
+ os.Exit(0)
+ case "error":
+ os.Stdout.WriteString(`unknown string`)
+ os.Exit(0)
+ }
+}
+
+func TestToSymbolFunc(t *testing.T) {
+ const input = "pä世🜃"
+ tests := []struct {
+ env string
+ fail bool
+ mangled string
+ }{
+ {
+ env: "v1",
+ mangled: "p___",
+ },
+ {
+ env: "v2",
+ mangled: "p..u00e4..u4e16..U0001f703",
+ },
+ {
+ env: "error",
+ fail: true,
+ },
+ }
+
+ cmd := os.Args[0]
+ tmpdir := t.TempDir()
+
+ defer os.Unsetenv(testEnvName)
+
+ for _, test := range tests {
+ t.Run(test.env, func(t *testing.T) {
+ os.Setenv(testEnvName, test.env)
+
+ fn, err := ToSymbolFunc(cmd, tmpdir)
+ if err != nil {
+ if !test.fail {
+ t.Errorf("ToSymbolFunc(%q, %q): unexpected error %v", cmd, tmpdir, err)
+ }
+ } else if test.fail {
+ t.Errorf("ToSymbolFunc(%q, %q) succeeded but expected to fail", cmd, tmpdir)
+ } else if got, want := fn(input), test.mangled; got != want {
+ t.Errorf("ToSymbolFunc(%q, %q)(%q) = %q, want %q", cmd, tmpdir, input, got, want)
+ }
+ })
+ }
+}
+
+var symbolTests = []struct {
+ input, v1, v2 string
+}{
+ {
+ "",
+ "",
+ "",
+ },
+ {
+ "bytes",
+ "bytes",
+ "bytes",
+ },
+ {
+ "net/http",
+ "net_http",
+ "net..z2fhttp",
+ },
+ {
+ "golang.org/x/net/http",
+ "golang_org_x_net_http",
+ "golang.x2eorg..z2fx..z2fnet..z2fhttp",
+ },
+ {
+ "pä世.🜃",
+ "p____",
+ "p..u00e4..u4e16.x2e..U0001f703",
+ },
+}
+
+func TestV1(t *testing.T) {
+ for _, test := range symbolTests {
+ if got, want := toSymbolV1(test.input), test.v1; got != want {
+ t.Errorf("toSymbolV1(%q) = %q, want %q", test.input, got, want)
+ }
+ }
+}
+
+func TestV2(t *testing.T) {
+ for _, test := range symbolTests {
+ if got, want := toSymbolV2(test.input), test.v2; got != want {
+ t.Errorf("toSymbolV2(%q) = %q, want %q", test.input, got, want)
+ }
+ }
+}
diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go
index b2b3b02bf6..1d813bbb47 100644
--- a/src/cmd/internal/sys/supported.go
+++ b/src/cmd/internal/sys/supported.go
@@ -32,6 +32,7 @@ func MSanSupported(goos, goarch string) bool {
}
// MustLinkExternal reports whether goos/goarch requires external linking.
+// (This is the opposite of internal/testenv.CanInternalLink. Keep them in sync.)
func MustLinkExternal(goos, goarch string) bool {
switch goos {
case "android":
@@ -66,10 +67,10 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
case "c-shared":
switch platform {
- case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x",
+ case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/riscv64", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64",
- "darwin/amd64",
+ "darwin/amd64", "darwin/arm64",
"windows/amd64", "windows/386":
return true
}
@@ -83,10 +84,11 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
case "pie":
switch platform {
- case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
+ case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
"android/amd64", "android/arm", "android/arm64", "android/386",
"freebsd/amd64",
- "darwin/amd64",
+ "darwin/amd64", "darwin/arm64",
+ "ios/amd64", "ios/arm64",
"aix/ppc64",
"windows/386", "windows/amd64", "windows/arm":
return true
@@ -95,7 +97,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
case "shared":
switch platform {
- case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
+ case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/riscv64", "linux/s390x":
return true
}
return false
@@ -104,7 +106,7 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/s390x", "linux/ppc64le",
"android/amd64", "android/arm", "android/arm64", "android/386",
- "darwin/amd64",
+ "darwin/amd64", "darwin/arm64",
"freebsd/amd64":
return true
}
@@ -114,3 +116,14 @@ func BuildModeSupported(compiler, buildmode, goos, goarch string) bool {
return false
}
}
+
+func InternalLinkPIESupported(goos, goarch string) bool {
+ switch goos + "/" + goarch {
+ case "darwin/amd64", "darwin/arm64",
+ "linux/amd64", "linux/arm64",
+ "android/arm64",
+ "windows-amd64", "windows-386", "windows-arm":
+ return true
+ }
+ return false
+}
diff --git a/src/cmd/internal/sys/supported_test.go b/src/cmd/internal/sys/supported_test.go
new file mode 100644
index 0000000000..1217814af5
--- /dev/null
+++ b/src/cmd/internal/sys/supported_test.go
@@ -0,0 +1,18 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+import (
+ "internal/testenv"
+ "runtime"
+ "testing"
+)
+
+func TestMustLinkExternalMatchesTestenv(t *testing.T) {
+ // MustLinkExternal and testenv.CanInternalLink are the exact opposite.
+ if b := MustLinkExternal(runtime.GOOS, runtime.GOARCH); b != !testenv.CanInternalLink() {
+ t.Fatalf("MustLinkExternal() == %v, testenv.CanInternalLink() == %v, don't match", b, testenv.CanInternalLink())
+ }
+}
diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go
index 88480064dd..db710bed6a 100644
--- a/src/cmd/link/dwarf_test.go
+++ b/src/cmd/link/dwarf_test.go
@@ -195,14 +195,18 @@ func TestDWARFiOS(t *testing.T) {
}
// Check to see if the ios tools are installed. It's possible to have the command line tools
// installed without the iOS sdk.
- if output, err := exec.Command("xcodebuild -showsdks").CombinedOutput(); err != nil {
+ if output, err := exec.Command("xcodebuild", "-showsdks").CombinedOutput(); err != nil {
t.Skipf("error running xcodebuild, required for iOS cross build: %v", err)
} else if !strings.Contains(string(output), "iOS SDK") {
t.Skipf("iOS SDK not detected.")
}
cc := "CC=" + runtime.GOROOT() + "/misc/ios/clangwrap.sh"
// iOS doesn't allow unmapped segments, so iOS executables don't have DWARF.
- testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64")
+ t.Run("exe", func(t *testing.T) {
+ testDWARF(t, "", false, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64")
+ })
// However, c-archive iOS objects have embedded DWARF.
- testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=darwin", "GOARCH=arm64")
+ t.Run("c-archive", func(t *testing.T) {
+ testDWARF(t, "c-archive", true, cc, "CGO_ENABLED=1", "GOOS=ios", "GOARCH=arm64")
+ })
}
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index e5a6ef51b0..360c5338ba 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -76,9 +76,9 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
targType = ldr.SymType(targ)
}
- switch r.Type() {
+ switch rt := r.Type(); rt {
default:
- if r.Type() >= objabi.ElfRelocOffset {
+ if rt >= objabi.ElfRelocOffset {
ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
return false
}
@@ -167,13 +167,24 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
- // TODO: What is the difference between all these?
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_ADDR)
if targType == sym.SDYNIMPORT {
ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
}
+ if target.IsPIE() && target.IsInternal() {
+ // For internal linking PIE, this R_ADDR relocation cannot
+ // be resolved statically. We need to generate a dynamic
+ // relocation. Let the code below handle it.
+ if rt == objabi.MachoRelocOffset+ld.MACHO_X86_64_RELOC_UNSIGNED*2 {
+ break
+ } else {
+ // MACHO_X86_64_RELOC_SIGNED or MACHO_X86_64_RELOC_BRANCH
+ // Can this happen? The object is expected to be PIC.
+ ldr.Errorf(s, "unsupported relocation for PIE: %v", rt)
+ }
+ }
return true
case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
@@ -223,7 +234,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
if targType != sym.SDYNIMPORT {
ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
}
- ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_X86_64_GLOB_DAT))
+ ld.AddGotSym(target, ldr, syms, targ, 0)
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_PCREL)
su.SetRelocSym(rIdx, syms.GOT)
@@ -343,7 +354,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela := ldr.MakeSymbolUpdater(syms.Rela)
rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
if r.Siz() == 8 {
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
+ rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
} else {
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
@@ -355,28 +366,15 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
return true
}
- if target.IsDarwin() && ldr.SymSize(s) == int64(target.Arch.PtrSize) && r.Off() == 0 {
+ if target.IsDarwin() {
// Mach-O relocations are a royal pain to lay out.
- // They use a compact stateful bytecode representation
- // that is too much bother to deal with.
- // Instead, interpret the C declaration
- // void *_Cvar_stderr = &stderr;
- // as making _Cvar_stderr the name of a GOT entry
- // for stderr. This is separate from the usual GOT entry,
- // just in case the C code assigns to the variable,
- // and of course it only works for single pointers,
- // but we only need to support cgo and that's all it needs.
- ld.Adddynsym(ldr, target, syms, targ)
-
- got := ldr.MakeSymbolUpdater(syms.GOT)
- su := ldr.MakeSymbolUpdater(s)
- su.SetType(got.Type())
- got.AddInteriorSym(s)
- su.SetValue(got.Size())
- got.AddUint64(target.Arch, 0)
- leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
- leg.AddUint32(target.Arch, uint32(ldr.SymDynid(targ)))
- su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
+ // They use a compact stateful bytecode representation.
+ // Here we record what are needed and encode them later.
+ ld.MachoAddRebase(s, int64(r.Off()))
+ // Not mark r done here. So we still apply it statically,
+ // so in the file content we'll also have the right offset
+ // to the relocation target. So it can be examined statically
+ // (e.g. go version).
return true
}
}
@@ -622,31 +620,21 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
sDynid := ldr.SymDynid(s)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
rela.AddUint64(target.Arch, 0)
ldr.SetPlt(s, int32(plt.Size()-16))
} else if target.IsDarwin() {
- // To do lazy symbol lookup right, we're supposed
- // to tell the dynamic loader which library each
- // symbol comes from and format the link info
- // section just so. I'm too lazy (ha!) to do that
- // so for now we'll just use non-lazy pointers,
- // which don't need to be told which library to use.
- //
- // https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
- // has details about what we're avoiding.
-
- ld.AddGotSym(target, ldr, syms, s, uint32(elf.R_X86_64_GLOB_DAT))
- plt := ldr.MakeSymbolUpdater(syms.PLT)
+ ld.AddGotSym(target, ldr, syms, s, 0)
sDynid := ldr.SymDynid(s)
lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
lep.AddUint32(target.Arch, uint32(sDynid))
- // jmpq *got+size(IP)
+ plt := ldr.MakeSymbolUpdater(syms.PLT)
ldr.SetPlt(s, int32(plt.Size()))
+ // jmpq *got+size(IP)
plt.AddUint8(0xff)
plt.AddUint8(0x25)
plt.AddPCRelPlus(target.Arch, syms.GOT, int64(ldr.SymGot(s)))
@@ -654,6 +642,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
ldr.Errorf(s, "addpltsym: unsupported binary format")
}
}
+
func tlsIEtoLE(P []byte, off, size int) {
// Transform the PC-relative instruction into a constant load.
// That is,
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index 611c96ce35..755b472694 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -231,7 +231,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
ld.Adddynsym(ldr, target, syms, targ)
rel := ldr.MakeSymbolUpdater(syms.Rel)
rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(targ)), uint32(elf.R_ARM_GLOB_DAT))) // we need a nil + A dynamic reloc
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
su.SetRelocSym(rIdx, 0)
@@ -629,7 +629,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
// rel
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_JUMP_SLOT)))
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), uint32(elf.R_ARM_JUMP_SLOT)))
} else {
ldr.Errorf(s, "addpltsym: unsupported binary format")
}
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 945b83822c..cb16180657 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -71,13 +71,13 @@ func gentext(ctxt *ld.Link, ldr *loader.Loader) {
}
func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
-
targ := r.Sym()
var targType sym.SymKind
if targ != 0 {
targType = ldr.SymType(targ)
}
+ const pcrel = 1
switch r.Type() {
default:
if r.Type() >= objabi.ElfRelocOffset {
@@ -201,6 +201,75 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_ARM64_LDST128)
return true
+
+ // Handle relocations found in Mach-O object files.
+ case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_UNSIGNED*2:
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
+ }
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ADDR)
+ if target.IsPIE() && target.IsInternal() {
+ // For internal linking PIE, this R_ADDR relocation cannot
+ // be resolved statically. We need to generate a dynamic
+ // relocation. Let the code below handle it.
+ break
+ }
+ return true
+
+ case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_BRANCH26*2 + pcrel:
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_CALLARM64)
+ if targType == sym.SDYNIMPORT {
+ addpltsym(target, ldr, syms, targ)
+ su.SetRelocSym(rIdx, syms.PLT)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
+ }
+ return true
+
+ case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGE21*2 + pcrel,
+ objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_PAGEOFF12*2:
+ if targType == sym.SDYNIMPORT {
+ ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
+ }
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
+ return true
+
+ case objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21*2 + pcrel,
+ objabi.MachoRelocOffset + ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12*2:
+ if targType != sym.SDYNIMPORT {
+ // have symbol
+ // turn MOVD sym@GOT (adrp+ldr) into MOVD $sym (adrp+add)
+ data := ldr.Data(s)
+ off := r.Off()
+ if int(off+3) >= len(data) {
+ ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
+ return false
+ }
+ o := target.Arch.ByteOrder.Uint32(data[off:])
+ su := ldr.MakeSymbolUpdater(s)
+ switch {
+ case (o>>24)&0x9f == 0x90: // adrp
+ // keep instruction unchanged, change relocation type below
+ case o>>24 == 0xf9: // ldr
+ // rewrite to add
+ o = (0x91 << 24) | (o & (1<<22 - 1))
+ su.MakeWritable()
+ su.SetUint32(target.Arch, int64(off), o)
+ default:
+ ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
+ return false
+ }
+ su.SetRelocType(rIdx, objabi.R_ARM64_PCREL)
+ return true
+ }
+ ld.AddGotSym(target, ldr, syms, targ, 0)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocType(rIdx, objabi.R_ARM64_GOT)
+ su.SetRelocSym(rIdx, syms.GOT)
+ su.SetRelocAdd(rIdx, int64(ldr.SymGot(targ)))
+ return true
}
// Reread the reloc to incorporate any changes in type above.
@@ -219,6 +288,16 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
// External linker will do this relocation.
return true
}
+ // Internal linking.
+ if r.Add() != 0 {
+ ldr.Errorf(s, "PLT call with non-zero addend (%v)", r.Add())
+ }
+ // Build a PLT entry and change the relocation target to that entry.
+ addpltsym(target, ldr, syms, targ)
+ su := ldr.MakeSymbolUpdater(s)
+ su.SetRelocSym(rIdx, syms.PLT)
+ su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
+ return true
case objabi.R_ADDR:
if ldr.SymType(s) == sym.STEXT && target.IsElf() {
@@ -302,7 +381,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela := ldr.MakeSymbolUpdater(syms.Rela)
rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
if r.Siz() == 8 {
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
+ rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_AARCH64_RELATIVE)))
} else {
ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
}
@@ -313,6 +392,18 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
// (e.g. go version).
return true
}
+
+ if target.IsDarwin() {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation.
+ // Here we record what are needed and encode them later.
+ ld.MachoAddRebase(s, int64(r.Off()))
+ // Not mark r done here. So we still apply it statically,
+ // so in the file content we'll also have the right offset
+ // to the relocation target. So it can be examined statically
+ // (e.g. go version).
+ return true
+ }
}
return false
}
@@ -371,7 +462,7 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
rt := r.Type
siz := r.Size
- if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ADDRARM64 {
+ if ldr.SymType(rs) == sym.SHOSTOBJ || rt == objabi.R_CALLARM64 || rt == objabi.R_ADDRARM64 || rt == objabi.R_ARM64_GOTPCREL {
if ldr.SymDynid(rs) < 0 {
ldr.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
return false
@@ -415,6 +506,22 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy
}
v |= 1 << 24 // pc-relative bit
v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
+ case objabi.R_ARM64_GOTPCREL:
+ siz = 4
+ // Two relocation entries: MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 MACHO_ARM64_RELOC_GOT_LOAD_PAGE21
+ // if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
+ if r.Xadd != 0 {
+ out.Write32(uint32(sectoff + 4))
+ out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
+ }
+ out.Write32(uint32(sectoff + 4))
+ out.Write32(v | (ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 << 28) | (2 << 25))
+ if r.Xadd != 0 {
+ out.Write32(uint32(sectoff))
+ out.Write32((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
+ }
+ v |= 1 << 24 // pc-relative bit
+ v |= ld.MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 << 28
}
switch siz {
@@ -457,7 +564,7 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
}
nExtReloc = 2 // need two ELF/Mach-O relocations. see elfreloc1/machoreloc1
- if target.IsDarwin() && rt == objabi.R_ADDRARM64 && xadd != 0 {
+ if target.IsDarwin() && xadd != 0 {
nExtReloc = 4 // need another two relocations for non-zero addend
}
@@ -633,14 +740,28 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
}
o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
return val | int64(o0), noExtReloc, isOk
- } else if (val>>24)&0x91 == 0x91 {
- // R_AARCH64_ADD_ABS_LO12_NC
+ } else if (val>>24)&0x9f == 0x91 {
+ // ELF R_AARCH64_ADD_ABS_LO12_NC or Mach-O ARM64_RELOC_PAGEOFF12
// patch instruction: add
t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
o1 := uint32(t&0xfff) << 10
return val | int64(o1), noExtReloc, isOk
+ } else if (val>>24)&0x3b == 0x39 {
+ // Mach-O ARM64_RELOC_PAGEOFF12
+ // patch ldr/str(b/h/w/d/q) (integer or vector) instructions, which have different scaling factors.
+ // Mach-O uses same relocation type for them.
+ shift := uint32(val) >> 30
+ if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
+ shift = 4
+ }
+ t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
+ if t&(1<<shift-1) != 0 {
+ ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
+ }
+ o1 := (uint32(t&0xfff) >> shift) << 10
+ return val | int64(o1), noExtReloc, isOk
} else {
- ldr.Errorf(s, "unsupported instruction for %x R_PCRELARM64", val)
+ ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
}
case objabi.R_ARM64_LDST8:
@@ -792,10 +913,38 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela.AddAddrPlus(target.Arch, gotplt.Sym(), gotplt.Size()-8)
sDynid := ldr.SymDynid(s)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_AARCH64_JUMP_SLOT)))
rela.AddUint64(target.Arch, 0)
ldr.SetPlt(s, int32(plt.Size()-16))
+ } else if target.IsDarwin() {
+ ld.AddGotSym(target, ldr, syms, s, 0)
+
+ sDynid := ldr.SymDynid(s)
+ lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
+ lep.AddUint32(target.Arch, uint32(sDynid))
+
+ plt := ldr.MakeSymbolUpdater(syms.PLT)
+ ldr.SetPlt(s, int32(plt.Size()))
+
+ // adrp x16, GOT
+ plt.AddUint32(target.Arch, 0x90000010)
+ r, _ := plt.AddRel(objabi.R_ARM64_GOT)
+ r.SetOff(int32(plt.Size() - 4))
+ r.SetSiz(4)
+ r.SetSym(syms.GOT)
+ r.SetAdd(int64(ldr.SymGot(s)))
+
+ // ldr x17, [x16, <offset>]
+ plt.AddUint32(target.Arch, 0xf9400211)
+ r, _ = plt.AddRel(objabi.R_ARM64_GOT)
+ r.SetOff(int32(plt.Size() - 4))
+ r.SetSiz(4)
+ r.SetSym(syms.GOT)
+ r.SetAdd(int64(ldr.SymGot(s)))
+
+ // br x17
+ plt.AddUint32(target.Arch, 0xd61f0220)
} else {
ldr.Errorf(s, "addpltsym: unsupported binary format")
}
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index a980cfee52..ab3dfd99f7 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -102,7 +102,7 @@ func archinit(ctxt *ld.Link) {
case objabi.Hdarwin: /* apple MACH */
ld.HEADR = ld.INITIAL_MACHO_HEADR
if *ld.FlagTextAddr == -1 {
- *ld.FlagTextAddr = 4096 + int64(ld.HEADR)
+ *ld.FlagTextAddr = 1<<32 + int64(ld.HEADR)
}
if *ld.FlagRound == -1 {
*ld.FlagRound = 16384 // 16K page alignment
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 9aa59fa3e3..54a94cebba 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -35,11 +35,15 @@ func (mode *BuildMode) Set(s string) error {
default:
return fmt.Errorf("invalid buildmode: %q", s)
case "exe":
+ if objabi.GOOS == "darwin" && objabi.GOARCH == "arm64" {
+ *mode = BuildModePIE // On darwin/arm64 everything is PIE.
+ break
+ }
*mode = BuildModeExe
case "pie":
switch objabi.GOOS {
- case "aix", "android", "linux", "windows":
- case "darwin", "freebsd":
+ case "aix", "android", "linux", "windows", "darwin", "ios":
+ case "freebsd":
switch objabi.GOARCH {
case "amd64":
default:
@@ -95,7 +99,13 @@ func (mode *BuildMode) Set(s string) error {
default:
return badmode()
}
- case "darwin", "freebsd":
+ case "darwin":
+ switch objabi.GOARCH {
+ case "amd64", "arm64":
+ default:
+ return badmode()
+ }
+ case "freebsd":
switch objabi.GOARCH {
case "amd64":
default:
@@ -175,7 +185,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
}()
}
- if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) {
+ if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) && !(objabi.GOOS == "darwin" && objabi.GOARCH == "arm64") { // XXX allow internal linking for darwin/arm64 but not change the default
return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH)
}
@@ -186,7 +196,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/14449
// https://golang.org/issue/21961
- if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64) {
+ if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64, sys.RISCV64) {
return true, objabi.GOARCH + " does not support internal cgo"
}
if iscgo && objabi.GOOS == "android" {
@@ -210,6 +220,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
switch objabi.GOOS + "/" + objabi.GOARCH {
case "linux/amd64", "linux/arm64", "android/arm64":
case "windows/386", "windows/amd64", "windows/arm":
+ case "darwin/amd64", "darwin/arm64":
default:
// Internal linking does not support TLS_IE.
return true, "buildmode=pie"
@@ -250,6 +261,8 @@ func determineLinkMode(ctxt *Link) {
default:
if extNeeded || (iscgo && externalobj) {
ctxt.LinkMode = LinkExternal
+ } else if ctxt.IsDarwin() && ctxt.IsARM64() {
+ ctxt.LinkMode = LinkExternal // default to external linking for now
} else {
ctxt.LinkMode = LinkInternal
}
@@ -263,8 +276,6 @@ func determineLinkMode(ctxt *Link) {
}
case LinkExternal:
switch {
- case objabi.GOARCH == "riscv64":
- Exitf("external linking not supported for %s/riscv64", objabi.GOOS)
case objabi.GOARCH == "ppc64" && objabi.GOOS != "aix":
Exitf("external linking not supported for %s/ppc64", objabi.GOOS)
}
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 3cd7b4ad0b..00130044ab 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -951,6 +951,9 @@ func writeBlock(ctxt *Link, out *OutBuf, ldr *loader.Loader, syms []loader.Sym,
}
P := out.WriteSym(ldr, s)
st.relocsym(s, P)
+ if f, ok := ctxt.generatorSyms[s]; ok {
+ f(ctxt, s)
+ }
addr += int64(len(P))
siz := ldr.SymSize(s)
if addr < val+siz {
@@ -2188,7 +2191,7 @@ func (ctxt *Link) textaddress() {
ctxt.Textp[0] = text
}
- va := uint64(*FlagTextAddr)
+ va := uint64(Rnd(*FlagTextAddr, int64(Funcalign)))
n := 1
sect.Vaddr = va
ntramps := 0
@@ -2214,7 +2217,7 @@ func (ctxt *Link) textaddress() {
// Set the address of the start/end symbols, if not already
// (i.e. not darwin+dynlink or AIX+external, see above).
ldr.SetSymValue(etext, int64(va))
- ldr.SetSymValue(text, *FlagTextAddr)
+ ldr.SetSymValue(text, int64(Segtext.Sections[0].Vaddr))
}
// merge tramps into Textp, keeping Textp in address order
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index 74d61fa495..d8813fa936 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -62,6 +62,12 @@ func (d *deadcodePass) init() {
}
}
names = append(names, *flagEntrySymbol)
+ if !d.ctxt.linkShared && d.ctxt.BuildMode != BuildModePlugin {
+ // runtime.buildVersion and runtime.modinfo are referenced in .go.buildinfo section
+ // (see function buildinfo in data.go). They should normally be reachable from the
+ // runtime. Just make it explicit, in case.
+ names = append(names, "runtime.buildVersion", "runtime.modinfo")
+ }
if d.ctxt.BuildMode == BuildModePlugin {
names = append(names, objabi.PathToPrefix(*flagPluginPath)+"..inittask", objabi.PathToPrefix(*flagPluginPath)+".main", "go.plugin.tabs")
diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go
index 22948521f5..a66506d392 100644
--- a/src/cmd/link/internal/ld/dwarf_test.go
+++ b/src/cmd/link/internal/ld/dwarf_test.go
@@ -238,6 +238,10 @@ func TestSizes(t *testing.T) {
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
}
+
+ // External linking may bring in C symbols with unknown size. Skip.
+ testenv.MustInternalLink(t)
+
t.Parallel()
// DWARF sizes should never be -1.
@@ -919,6 +923,7 @@ func TestAbstractOriginSanityIssue26237(t *testing.T) {
func TestRuntimeTypeAttrInternal(t *testing.T) {
testenv.MustHaveGoBuild(t)
+ testenv.MustInternalLink(t)
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
@@ -1018,6 +1023,9 @@ func main() {
t.Fatalf("*main.X DIE had no runtime type attr. DIE: %v", dies[0])
}
+ if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+ return // everything is PIE on ARM64, addresses are relocated
+ }
if rtAttr.(uint64)+types.Addr != addr {
t.Errorf("DWARF type offset was %#x+%#x, but test program said %#x", rtAttr.(uint64), types.Addr, addr)
}
@@ -1203,6 +1211,15 @@ func main() {
}
}
+ // When external linking, we put all symbols in the symbol table (so the
+ // external linker can find them). Skip the symbol table check.
+ // TODO: maybe there is some way to tell the external linker not to put
+ // those symbols in the executable's symbol table? Prefix the symbol name
+ // with "." or "L" to pretend it is a label?
+ if !testenv.CanInternalLink() {
+ return
+ }
+
syms, err := f.Symbols()
if err != nil {
t.Fatalf("error reading symbols: %v", err)
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index f5a2f899fc..37b2dc640d 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -10,6 +10,7 @@ import (
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"crypto/sha1"
+ "debug/elf"
"encoding/binary"
"encoding/hex"
"fmt"
@@ -75,255 +76,6 @@ type elfNote struct {
nType uint32
}
-const (
- EI_MAG0 = 0
- EI_MAG1 = 1
- EI_MAG2 = 2
- EI_MAG3 = 3
- EI_CLASS = 4
- EI_DATA = 5
- EI_VERSION = 6
- EI_OSABI = 7
- EI_ABIVERSION = 8
- OLD_EI_BRAND = 8
- EI_PAD = 9
- EI_NIDENT = 16
- ELFMAG0 = 0x7f
- ELFMAG1 = 'E'
- ELFMAG2 = 'L'
- ELFMAG3 = 'F'
- SELFMAG = 4
- EV_NONE = 0
- EV_CURRENT = 1
- ELFCLASSNONE = 0
- ELFCLASS32 = 1
- ELFCLASS64 = 2
- ELFDATANONE = 0
- ELFDATA2LSB = 1
- ELFDATA2MSB = 2
- ELFOSABI_NONE = 0
- ELFOSABI_HPUX = 1
- ELFOSABI_NETBSD = 2
- ELFOSABI_LINUX = 3
- ELFOSABI_HURD = 4
- ELFOSABI_86OPEN = 5
- ELFOSABI_SOLARIS = 6
- ELFOSABI_AIX = 7
- ELFOSABI_IRIX = 8
- ELFOSABI_FREEBSD = 9
- ELFOSABI_TRU64 = 10
- ELFOSABI_MODESTO = 11
- ELFOSABI_OPENBSD = 12
- ELFOSABI_OPENVMS = 13
- ELFOSABI_NSK = 14
- ELFOSABI_ARM = 97
- ELFOSABI_STANDALONE = 255
- ELFOSABI_SYSV = ELFOSABI_NONE
- ELFOSABI_MONTEREY = ELFOSABI_AIX
- ET_NONE = 0
- ET_REL = 1
- ET_EXEC = 2
- ET_DYN = 3
- ET_CORE = 4
- ET_LOOS = 0xfe00
- ET_HIOS = 0xfeff
- ET_LOPROC = 0xff00
- ET_HIPROC = 0xffff
- EM_NONE = 0
- EM_M32 = 1
- EM_SPARC = 2
- EM_386 = 3
- EM_68K = 4
- EM_88K = 5
- EM_860 = 7
- EM_MIPS = 8
- EM_S370 = 9
- EM_MIPS_RS3_LE = 10
- EM_PARISC = 15
- EM_VPP500 = 17
- EM_SPARC32PLUS = 18
- EM_960 = 19
- EM_PPC = 20
- EM_PPC64 = 21
- EM_S390 = 22
- EM_V800 = 36
- EM_FR20 = 37
- EM_RH32 = 38
- EM_RCE = 39
- EM_ARM = 40
- EM_SH = 42
- EM_SPARCV9 = 43
- EM_TRICORE = 44
- EM_ARC = 45
- EM_H8_300 = 46
- EM_H8_300H = 47
- EM_H8S = 48
- EM_H8_500 = 49
- EM_IA_64 = 50
- EM_MIPS_X = 51
- EM_COLDFIRE = 52
- EM_68HC12 = 53
- EM_MMA = 54
- EM_PCP = 55
- EM_NCPU = 56
- EM_NDR1 = 57
- EM_STARCORE = 58
- EM_ME16 = 59
- EM_ST100 = 60
- EM_TINYJ = 61
- EM_X86_64 = 62
- EM_AARCH64 = 183
- EM_486 = 6
- EM_MIPS_RS4_BE = 10
- EM_ALPHA_STD = 41
- EM_ALPHA = 0x9026
- EM_RISCV = 243
- SHN_UNDEF = 0
- SHN_LORESERVE = 0xff00
- SHN_LOPROC = 0xff00
- SHN_HIPROC = 0xff1f
- SHN_LOOS = 0xff20
- SHN_HIOS = 0xff3f
- SHN_ABS = 0xfff1
- SHN_COMMON = 0xfff2
- SHN_XINDEX = 0xffff
- SHN_HIRESERVE = 0xffff
- SHT_NULL = 0
- SHT_PROGBITS = 1
- SHT_SYMTAB = 2
- SHT_STRTAB = 3
- SHT_RELA = 4
- SHT_HASH = 5
- SHT_DYNAMIC = 6
- SHT_NOTE = 7
- SHT_NOBITS = 8
- SHT_REL = 9
- SHT_SHLIB = 10
- SHT_DYNSYM = 11
- SHT_INIT_ARRAY = 14
- SHT_FINI_ARRAY = 15
- SHT_PREINIT_ARRAY = 16
- SHT_GROUP = 17
- SHT_SYMTAB_SHNDX = 18
- SHT_LOOS = 0x60000000
- SHT_HIOS = 0x6fffffff
- SHT_GNU_VERDEF = 0x6ffffffd
- SHT_GNU_VERNEED = 0x6ffffffe
- SHT_GNU_VERSYM = 0x6fffffff
- SHT_LOPROC = 0x70000000
- SHT_ARM_ATTRIBUTES = 0x70000003
- SHT_HIPROC = 0x7fffffff
- SHT_LOUSER = 0x80000000
- SHT_HIUSER = 0xffffffff
- SHF_WRITE = 0x1
- SHF_ALLOC = 0x2
- SHF_EXECINSTR = 0x4
- SHF_MERGE = 0x10
- SHF_STRINGS = 0x20
- SHF_INFO_LINK = 0x40
- SHF_LINK_ORDER = 0x80
- SHF_OS_NONCONFORMING = 0x100
- SHF_GROUP = 0x200
- SHF_TLS = 0x400
- SHF_MASKOS = 0x0ff00000
- SHF_MASKPROC = 0xf0000000
- PT_NULL = 0
- PT_LOAD = 1
- PT_DYNAMIC = 2
- PT_INTERP = 3
- PT_NOTE = 4
- PT_SHLIB = 5
- PT_PHDR = 6
- PT_TLS = 7
- PT_LOOS = 0x60000000
- PT_HIOS = 0x6fffffff
- PT_LOPROC = 0x70000000
- PT_HIPROC = 0x7fffffff
- PT_GNU_STACK = 0x6474e551
- PT_GNU_RELRO = 0x6474e552
- PT_PAX_FLAGS = 0x65041580
- PT_SUNWSTACK = 0x6ffffffb
- PF_X = 0x1
- PF_W = 0x2
- PF_R = 0x4
- PF_MASKOS = 0x0ff00000
- PF_MASKPROC = 0xf0000000
- DT_NULL = 0
- DT_NEEDED = 1
- DT_PLTRELSZ = 2
- DT_PLTGOT = 3
- DT_HASH = 4
- DT_STRTAB = 5
- DT_SYMTAB = 6
- DT_RELA = 7
- DT_RELASZ = 8
- DT_RELAENT = 9
- DT_STRSZ = 10
- DT_SYMENT = 11
- DT_INIT = 12
- DT_FINI = 13
- DT_SONAME = 14
- DT_RPATH = 15
- DT_SYMBOLIC = 16
- DT_REL = 17
- DT_RELSZ = 18
- DT_RELENT = 19
- DT_PLTREL = 20
- DT_DEBUG = 21
- DT_TEXTREL = 22
- DT_JMPREL = 23
- DT_BIND_NOW = 24
- DT_INIT_ARRAY = 25
- DT_FINI_ARRAY = 26
- DT_INIT_ARRAYSZ = 27
- DT_FINI_ARRAYSZ = 28
- DT_RUNPATH = 29
- DT_FLAGS = 30
- DT_ENCODING = 32
- DT_PREINIT_ARRAY = 32
- DT_PREINIT_ARRAYSZ = 33
- DT_LOOS = 0x6000000d
- DT_HIOS = 0x6ffff000
- DT_LOPROC = 0x70000000
- DT_HIPROC = 0x7fffffff
- DT_VERNEED = 0x6ffffffe
- DT_VERNEEDNUM = 0x6fffffff
- DT_VERSYM = 0x6ffffff0
- DT_PPC64_GLINK = DT_LOPROC + 0
- DT_PPC64_OPT = DT_LOPROC + 3
- DF_ORIGIN = 0x0001
- DF_SYMBOLIC = 0x0002
- DF_TEXTREL = 0x0004
- DF_BIND_NOW = 0x0008
- DF_STATIC_TLS = 0x0010
- NT_PRSTATUS = 1
- NT_FPREGSET = 2
- NT_PRPSINFO = 3
- STB_LOCAL = 0
- STB_GLOBAL = 1
- STB_WEAK = 2
- STB_LOOS = 10
- STB_HIOS = 12
- STB_LOPROC = 13
- STB_HIPROC = 15
- STT_NOTYPE = 0
- STT_OBJECT = 1
- STT_FUNC = 2
- STT_SECTION = 3
- STT_FILE = 4
- STT_COMMON = 5
- STT_TLS = 6
- STT_LOOS = 10
- STT_HIOS = 12
- STT_LOPROC = 13
- STT_HIPROC = 15
- STV_DEFAULT = 0x0
- STV_INTERNAL = 0x1
- STV_HIDDEN = 0x2
- STV_PROTECTED = 0x3
- STN_UNDEF = 0
-)
-
/* For accessing the fields of r_info. */
/* For constructing r_info from field values. */
@@ -348,53 +100,20 @@ const (
/*
* ELF header.
*/
-type ElfEhdr struct {
- ident [EI_NIDENT]uint8
- type_ uint16
- machine uint16
- version uint32
- entry uint64
- phoff uint64
- shoff uint64
- flags uint32
- ehsize uint16
- phentsize uint16
- phnum uint16
- shentsize uint16
- shnum uint16
- shstrndx uint16
-}
+type ElfEhdr elf.Header64
/*
* Section header.
*/
type ElfShdr struct {
- name uint32
- type_ uint32
- flags uint64
- addr uint64
- off uint64
- size uint64
- link uint32
- info uint32
- addralign uint64
- entsize uint64
- shnum int
+ elf.Section64
+ shnum elf.SectionIndex
}
/*
* Program header.
*/
-type ElfPhdr struct {
- type_ uint32
- flags uint32
- off uint64
- vaddr uint64
- paddr uint64
- filesz uint64
- memsz uint64
- align uint64
-}
+type ElfPhdr elf.ProgHeader
/* For accessing the fields of r_info. */
@@ -497,22 +216,25 @@ func Elfinit(ctxt *Link) {
// 64-bit architectures
case sys.PPC64, sys.S390X:
if ctxt.Arch.ByteOrder == binary.BigEndian {
- ehdr.flags = 1 /* Version 1 ABI */
+ ehdr.Flags = 1 /* Version 1 ABI */
} else {
- ehdr.flags = 2 /* Version 2 ABI */
+ ehdr.Flags = 2 /* Version 2 ABI */
}
fallthrough
case sys.AMD64, sys.ARM64, sys.MIPS64, sys.RISCV64:
if ctxt.Arch.Family == sys.MIPS64 {
- ehdr.flags = 0x20000004 /* MIPS 3 CPIC */
+ ehdr.Flags = 0x20000004 /* MIPS 3 CPIC */
+ }
+ if ctxt.Arch.Family == sys.RISCV64 {
+ ehdr.Flags = 0x4 /* RISCV Float ABI Double */
}
elf64 = true
- ehdr.phoff = ELF64HDRSIZE /* Must be ELF64HDRSIZE: first PHdr must follow ELF header */
- ehdr.shoff = ELF64HDRSIZE /* Will move as we add PHeaders */
- ehdr.ehsize = ELF64HDRSIZE /* Must be ELF64HDRSIZE */
- ehdr.phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
- ehdr.shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
+ ehdr.Phoff = ELF64HDRSIZE /* Must be ELF64HDRSIZE: first PHdr must follow ELF header */
+ ehdr.Shoff = ELF64HDRSIZE /* Will move as we add PHeaders */
+ ehdr.Ehsize = ELF64HDRSIZE /* Must be ELF64HDRSIZE */
+ ehdr.Phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
+ ehdr.Shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
// 32-bit architectures
case sys.ARM, sys.MIPS:
@@ -527,19 +249,19 @@ func Elfinit(ctxt *Link) {
// produced by the host C compiler. parseArmAttributes in
// ldelf.go reads that information and updates this field as
// appropriate.
- ehdr.flags = 0x5000002 // has entry point, Version5 EABI
+ ehdr.Flags = 0x5000002 // has entry point, Version5 EABI
}
} else if ctxt.Arch.Family == sys.MIPS {
- ehdr.flags = 0x50001004 /* MIPS 32 CPIC O32*/
+ ehdr.Flags = 0x50001004 /* MIPS 32 CPIC O32*/
}
fallthrough
default:
- ehdr.phoff = ELF32HDRSIZE
+ ehdr.Phoff = ELF32HDRSIZE
/* Must be ELF32HDRSIZE: first PHdr must follow ELF header */
- ehdr.shoff = ELF32HDRSIZE /* Will move as we add PHeaders */
- ehdr.ehsize = ELF32HDRSIZE /* Must be ELF32HDRSIZE */
- ehdr.phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
- ehdr.shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
+ ehdr.Shoff = ELF32HDRSIZE /* Will move as we add PHeaders */
+ ehdr.Ehsize = ELF32HDRSIZE /* Must be ELF32HDRSIZE */
+ ehdr.Phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
+ ehdr.Shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
}
}
@@ -549,83 +271,83 @@ func Elfinit(ctxt *Link) {
// but buggy ELF loaders like the one in some
// versions of QEMU and UPX won't.
func fixElfPhdr(e *ElfPhdr) {
- frag := int(e.vaddr & (e.align - 1))
+ frag := int(e.Vaddr & (e.Align - 1))
- e.off -= uint64(frag)
- e.vaddr -= uint64(frag)
- e.paddr -= uint64(frag)
- e.filesz += uint64(frag)
- e.memsz += uint64(frag)
+ e.Off -= uint64(frag)
+ e.Vaddr -= uint64(frag)
+ e.Paddr -= uint64(frag)
+ e.Filesz += uint64(frag)
+ e.Memsz += uint64(frag)
}
func elf64phdr(out *OutBuf, e *ElfPhdr) {
- if e.type_ == PT_LOAD {
+ if e.Type == elf.PT_LOAD {
fixElfPhdr(e)
}
- out.Write32(e.type_)
- out.Write32(e.flags)
- out.Write64(e.off)
- out.Write64(e.vaddr)
- out.Write64(e.paddr)
- out.Write64(e.filesz)
- out.Write64(e.memsz)
- out.Write64(e.align)
+ out.Write32(uint32(e.Type))
+ out.Write32(uint32(e.Flags))
+ out.Write64(e.Off)
+ out.Write64(e.Vaddr)
+ out.Write64(e.Paddr)
+ out.Write64(e.Filesz)
+ out.Write64(e.Memsz)
+ out.Write64(e.Align)
}
func elf32phdr(out *OutBuf, e *ElfPhdr) {
- if e.type_ == PT_LOAD {
+ if e.Type == elf.PT_LOAD {
fixElfPhdr(e)
}
- out.Write32(e.type_)
- out.Write32(uint32(e.off))
- out.Write32(uint32(e.vaddr))
- out.Write32(uint32(e.paddr))
- out.Write32(uint32(e.filesz))
- out.Write32(uint32(e.memsz))
- out.Write32(e.flags)
- out.Write32(uint32(e.align))
+ out.Write32(uint32(e.Type))
+ out.Write32(uint32(e.Off))
+ out.Write32(uint32(e.Vaddr))
+ out.Write32(uint32(e.Paddr))
+ out.Write32(uint32(e.Filesz))
+ out.Write32(uint32(e.Memsz))
+ out.Write32(uint32(e.Flags))
+ out.Write32(uint32(e.Align))
}
func elf64shdr(out *OutBuf, e *ElfShdr) {
- out.Write32(e.name)
- out.Write32(e.type_)
- out.Write64(e.flags)
- out.Write64(e.addr)
- out.Write64(e.off)
- out.Write64(e.size)
- out.Write32(e.link)
- out.Write32(e.info)
- out.Write64(e.addralign)
- out.Write64(e.entsize)
+ out.Write32(e.Name)
+ out.Write32(uint32(e.Type))
+ out.Write64(uint64(e.Flags))
+ out.Write64(e.Addr)
+ out.Write64(e.Off)
+ out.Write64(e.Size)
+ out.Write32(e.Link)
+ out.Write32(e.Info)
+ out.Write64(e.Addralign)
+ out.Write64(e.Entsize)
}
func elf32shdr(out *OutBuf, e *ElfShdr) {
- out.Write32(e.name)
- out.Write32(e.type_)
- out.Write32(uint32(e.flags))
- out.Write32(uint32(e.addr))
- out.Write32(uint32(e.off))
- out.Write32(uint32(e.size))
- out.Write32(e.link)
- out.Write32(e.info)
- out.Write32(uint32(e.addralign))
- out.Write32(uint32(e.entsize))
+ out.Write32(e.Name)
+ out.Write32(uint32(e.Type))
+ out.Write32(uint32(e.Flags))
+ out.Write32(uint32(e.Addr))
+ out.Write32(uint32(e.Off))
+ out.Write32(uint32(e.Size))
+ out.Write32(e.Link)
+ out.Write32(e.Info)
+ out.Write32(uint32(e.Addralign))
+ out.Write32(uint32(e.Entsize))
}
func elfwriteshdrs(out *OutBuf) uint32 {
if elf64 {
- for i := 0; i < int(ehdr.shnum); i++ {
+ for i := 0; i < int(ehdr.Shnum); i++ {
elf64shdr(out, shdr[i])
}
- return uint32(ehdr.shnum) * ELF64SHDRSIZE
+ return uint32(ehdr.Shnum) * ELF64SHDRSIZE
}
- for i := 0; i < int(ehdr.shnum); i++ {
+ for i := 0; i < int(ehdr.Shnum); i++ {
elf32shdr(out, shdr[i])
}
- return uint32(ehdr.shnum) * ELF32SHDRSIZE
+ return uint32(ehdr.Shnum) * ELF32SHDRSIZE
}
func elfsetstring(ctxt *Link, s loader.Sym, str string, off int) {
@@ -641,43 +363,43 @@ func elfsetstring(ctxt *Link, s loader.Sym, str string, off int) {
func elfwritephdrs(out *OutBuf) uint32 {
if elf64 {
- for i := 0; i < int(ehdr.phnum); i++ {
+ for i := 0; i < int(ehdr.Phnum); i++ {
elf64phdr(out, phdr[i])
}
- return uint32(ehdr.phnum) * ELF64PHDRSIZE
+ return uint32(ehdr.Phnum) * ELF64PHDRSIZE
}
- for i := 0; i < int(ehdr.phnum); i++ {
+ for i := 0; i < int(ehdr.Phnum); i++ {
elf32phdr(out, phdr[i])
}
- return uint32(ehdr.phnum) * ELF32PHDRSIZE
+ return uint32(ehdr.Phnum) * ELF32PHDRSIZE
}
func newElfPhdr() *ElfPhdr {
e := new(ElfPhdr)
- if ehdr.phnum >= NSECT {
+ if ehdr.Phnum >= NSECT {
Errorf(nil, "too many phdrs")
} else {
- phdr[ehdr.phnum] = e
- ehdr.phnum++
+ phdr[ehdr.Phnum] = e
+ ehdr.Phnum++
}
if elf64 {
- ehdr.shoff += ELF64PHDRSIZE
+ ehdr.Shoff += ELF64PHDRSIZE
} else {
- ehdr.shoff += ELF32PHDRSIZE
+ ehdr.Shoff += ELF32PHDRSIZE
}
return e
}
func newElfShdr(name int64) *ElfShdr {
e := new(ElfShdr)
- e.name = uint32(name)
- e.shnum = int(ehdr.shnum)
- if ehdr.shnum >= NSECT {
+ e.Name = uint32(name)
+ e.shnum = elf.SectionIndex(ehdr.Shnum)
+ if ehdr.Shnum >= NSECT {
Errorf(nil, "too many shdrs")
} else {
- shdr[ehdr.shnum] = e
- ehdr.shnum++
+ shdr[ehdr.Shnum] = e
+ ehdr.Shnum++
}
return e
@@ -688,38 +410,38 @@ func getElfEhdr() *ElfEhdr {
}
func elf64writehdr(out *OutBuf) uint32 {
- out.Write(ehdr.ident[:])
- out.Write16(ehdr.type_)
- out.Write16(ehdr.machine)
- out.Write32(ehdr.version)
- out.Write64(ehdr.entry)
- out.Write64(ehdr.phoff)
- out.Write64(ehdr.shoff)
- out.Write32(ehdr.flags)
- out.Write16(ehdr.ehsize)
- out.Write16(ehdr.phentsize)
- out.Write16(ehdr.phnum)
- out.Write16(ehdr.shentsize)
- out.Write16(ehdr.shnum)
- out.Write16(ehdr.shstrndx)
+ out.Write(ehdr.Ident[:])
+ out.Write16(uint16(ehdr.Type))
+ out.Write16(uint16(ehdr.Machine))
+ out.Write32(uint32(ehdr.Version))
+ out.Write64(ehdr.Entry)
+ out.Write64(ehdr.Phoff)
+ out.Write64(ehdr.Shoff)
+ out.Write32(ehdr.Flags)
+ out.Write16(ehdr.Ehsize)
+ out.Write16(ehdr.Phentsize)
+ out.Write16(ehdr.Phnum)
+ out.Write16(ehdr.Shentsize)
+ out.Write16(ehdr.Shnum)
+ out.Write16(ehdr.Shstrndx)
return ELF64HDRSIZE
}
func elf32writehdr(out *OutBuf) uint32 {
- out.Write(ehdr.ident[:])
- out.Write16(ehdr.type_)
- out.Write16(ehdr.machine)
- out.Write32(ehdr.version)
- out.Write32(uint32(ehdr.entry))
- out.Write32(uint32(ehdr.phoff))
- out.Write32(uint32(ehdr.shoff))
- out.Write32(ehdr.flags)
- out.Write16(ehdr.ehsize)
- out.Write16(ehdr.phentsize)
- out.Write16(ehdr.phnum)
- out.Write16(ehdr.shentsize)
- out.Write16(ehdr.shnum)
- out.Write16(ehdr.shstrndx)
+ out.Write(ehdr.Ident[:])
+ out.Write16(uint16(ehdr.Type))
+ out.Write16(uint16(ehdr.Machine))
+ out.Write32(uint32(ehdr.Version))
+ out.Write32(uint32(ehdr.Entry))
+ out.Write32(uint32(ehdr.Phoff))
+ out.Write32(uint32(ehdr.Shoff))
+ out.Write32(ehdr.Flags)
+ out.Write16(ehdr.Ehsize)
+ out.Write16(ehdr.Phentsize)
+ out.Write16(ehdr.Phnum)
+ out.Write16(ehdr.Shentsize)
+ out.Write16(ehdr.Shnum)
+ out.Write16(ehdr.Shstrndx)
return ELF32HDRSIZE
}
@@ -743,11 +465,11 @@ func elfhash(name string) uint32 {
return h
}
-func elfWriteDynEntSym(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
+func elfWriteDynEntSym(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
Elfwritedynentsymplus(ctxt, s, tag, t, 0)
}
-func Elfwritedynent(arch *sys.Arch, s *loader.SymbolBuilder, tag int, val uint64) {
+func Elfwritedynent(arch *sys.Arch, s *loader.SymbolBuilder, tag elf.DynTag, val uint64) {
if elf64 {
s.AddUint64(arch, uint64(tag))
s.AddUint64(arch, val)
@@ -757,11 +479,11 @@ func Elfwritedynent(arch *sys.Arch, s *loader.SymbolBuilder, tag int, val uint64
}
}
-func elfwritedynentsym(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
+func elfwritedynentsym(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
Elfwritedynentsymplus(ctxt, s, tag, t, 0)
}
-func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym, add int64) {
+func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym, add int64) {
if elf64 {
s.AddUint64(ctxt.Arch, uint64(tag))
} else {
@@ -770,7 +492,7 @@ func Elfwritedynentsymplus(ctxt *Link, s *loader.SymbolBuilder, tag int, t loade
s.AddAddrPlus(ctxt.Arch, t, add)
}
-func elfwritedynentsymsize(ctxt *Link, s *loader.SymbolBuilder, tag int, t loader.Sym) {
+func elfwritedynentsymsize(ctxt *Link, s *loader.SymbolBuilder, tag elf.DynTag, t loader.Sym) {
if elf64 {
s.AddUint64(ctxt.Arch, uint64(tag))
} else {
@@ -782,30 +504,30 @@ func elfwritedynentsymsize(ctxt *Link, s *loader.SymbolBuilder, tag int, t loade
func elfinterp(sh *ElfShdr, startva uint64, resoff uint64, p string) int {
interp = p
n := len(interp) + 1
- sh.addr = startva + resoff - uint64(n)
- sh.off = resoff - uint64(n)
- sh.size = uint64(n)
+ sh.Addr = startva + resoff - uint64(n)
+ sh.Off = resoff - uint64(n)
+ sh.Size = uint64(n)
return n
}
func elfwriteinterp(out *OutBuf) int {
sh := elfshname(".interp")
- out.SeekSet(int64(sh.off))
+ out.SeekSet(int64(sh.Off))
out.WriteString(interp)
out.Write8(0)
- return int(sh.size)
+ return int(sh.Size)
}
func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
n := 3*4 + uint64(sz) + resoff%4
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
- sh.addralign = 4
- sh.addr = startva + resoff - n
- sh.off = resoff - n
- sh.size = n - resoff%4
+ sh.Type = uint32(elf.SHT_NOTE)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = 4
+ sh.Addr = startva + resoff - n
+ sh.Off = resoff - n
+ sh.Size = n - resoff%4
return int(n)
}
@@ -814,7 +536,7 @@ func elfwritenotehdr(out *OutBuf, str string, namesz uint32, descsz uint32, tag
sh := elfshname(str)
// Write Elf_Note header.
- out.SeekSet(int64(sh.off))
+ out.SeekSet(int64(sh.Off))
out.Write32(namesz)
out.Write32(descsz)
@@ -851,7 +573,7 @@ func elfwritenetbsdsig(out *OutBuf) int {
out.Write8(0)
out.Write32(ELF_NOTE_NETBSD_VERSION)
- return int(sh.size)
+ return int(sh.Size)
}
// The race detector can't handle ASLR (address space layout randomization).
@@ -870,7 +592,7 @@ func elfwritenetbsdpax(out *OutBuf) int {
}
out.Write([]byte("PaX\x00"))
out.Write32(0x20) // 0x20 = Force disable ASLR
- return int(sh.size)
+ return int(sh.Size)
}
// OpenBSD Signature
@@ -901,7 +623,7 @@ func elfwriteopenbsdsig(out *OutBuf) int {
out.Write32(ELF_NOTE_OPENBSD_VERSION)
- return int(sh.size)
+ return int(sh.Size)
}
func addbuildinfo(val string) {
@@ -960,7 +682,7 @@ func elfwritebuildinfo(out *OutBuf) int {
var zero = make([]byte, 4)
out.Write(zero[:int(Rnd(int64(len(buildinfo)), 4)-int64(len(buildinfo)))])
- return int(sh.size)
+ return int(sh.Size)
}
func elfwritegobuildid(out *OutBuf) int {
@@ -974,7 +696,7 @@ func elfwritegobuildid(out *OutBuf) int {
var zero = make([]byte, 4)
out.Write(zero[:int(Rnd(int64(len(*flagBuildid)), 4)-int64(len(*flagBuildid)))])
- return int(sh.size)
+ return int(sh.Size)
}
// Go specific notes
@@ -1145,56 +867,56 @@ func elfdynhash(ctxt *Link) {
s = ldr.CreateSymForUpdate(".dynamic", 0)
elfverneed = nfile
if elfverneed != 0 {
- elfWriteDynEntSym(ctxt, s, DT_VERNEED, gnuVersionR.Sym())
- Elfwritedynent(ctxt.Arch, s, DT_VERNEEDNUM, uint64(nfile))
- elfWriteDynEntSym(ctxt, s, DT_VERSYM, gnuVersion.Sym())
+ elfWriteDynEntSym(ctxt, s, elf.DT_VERNEED, gnuVersionR.Sym())
+ Elfwritedynent(ctxt.Arch, s, elf.DT_VERNEEDNUM, uint64(nfile))
+ elfWriteDynEntSym(ctxt, s, elf.DT_VERSYM, gnuVersion.Sym())
}
sy := ldr.CreateSymForUpdate(elfRelType+".plt", 0)
if sy.Size() > 0 {
if elfRelType == ".rela" {
- Elfwritedynent(ctxt.Arch, s, DT_PLTREL, DT_RELA)
+ Elfwritedynent(ctxt.Arch, s, elf.DT_PLTREL, uint64(elf.DT_RELA))
} else {
- Elfwritedynent(ctxt.Arch, s, DT_PLTREL, DT_REL)
+ Elfwritedynent(ctxt.Arch, s, elf.DT_PLTREL, uint64(elf.DT_REL))
}
- elfwritedynentsymsize(ctxt, s, DT_PLTRELSZ, sy.Sym())
- elfWriteDynEntSym(ctxt, s, DT_JMPREL, sy.Sym())
+ elfwritedynentsymsize(ctxt, s, elf.DT_PLTRELSZ, sy.Sym())
+ elfWriteDynEntSym(ctxt, s, elf.DT_JMPREL, sy.Sym())
}
- Elfwritedynent(ctxt.Arch, s, DT_NULL, 0)
+ Elfwritedynent(ctxt.Arch, s, elf.DT_NULL, 0)
}
func elfphload(seg *sym.Segment) *ElfPhdr {
ph := newElfPhdr()
- ph.type_ = PT_LOAD
+ ph.Type = elf.PT_LOAD
if seg.Rwx&4 != 0 {
- ph.flags |= PF_R
+ ph.Flags |= elf.PF_R
}
if seg.Rwx&2 != 0 {
- ph.flags |= PF_W
+ ph.Flags |= elf.PF_W
}
if seg.Rwx&1 != 0 {
- ph.flags |= PF_X
+ ph.Flags |= elf.PF_X
}
- ph.vaddr = seg.Vaddr
- ph.paddr = seg.Vaddr
- ph.memsz = seg.Length
- ph.off = seg.Fileoff
- ph.filesz = seg.Filelen
- ph.align = uint64(*FlagRound)
+ ph.Vaddr = seg.Vaddr
+ ph.Paddr = seg.Vaddr
+ ph.Memsz = seg.Length
+ ph.Off = seg.Fileoff
+ ph.Filesz = seg.Filelen
+ ph.Align = uint64(*FlagRound)
return ph
}
func elfphrelro(seg *sym.Segment) {
ph := newElfPhdr()
- ph.type_ = PT_GNU_RELRO
- ph.vaddr = seg.Vaddr
- ph.paddr = seg.Vaddr
- ph.memsz = seg.Length
- ph.off = seg.Fileoff
- ph.filesz = seg.Filelen
- ph.align = uint64(*FlagRound)
+ ph.Type = elf.PT_GNU_RELRO
+ ph.Vaddr = seg.Vaddr
+ ph.Paddr = seg.Vaddr
+ ph.Memsz = seg.Length
+ ph.Off = seg.Fileoff
+ ph.Filesz = seg.Filelen
+ ph.Align = uint64(*FlagRound)
}
func elfshname(name string) *ElfShdr {
@@ -1203,9 +925,9 @@ func elfshname(name string) *ElfShdr {
continue
}
off := elfstr[i].off
- for i = 0; i < int(ehdr.shnum); i++ {
+ for i = 0; i < int(ehdr.Shnum); i++ {
sh := shdr[i]
- if sh.name == uint32(off) {
+ if sh.Name == uint32(off) {
return sh
}
}
@@ -1250,7 +972,7 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
// If this section has already been set up as a note, we assume type_ and
// flags are already correct, but the other fields still need filling in.
- if sh.type_ == SHT_NOTE {
+ if sh.Type == uint32(elf.SHT_NOTE) {
if linkmode != LinkExternal {
// TODO(mwhudson): the approach here will work OK when
// linking internally for notes that we want to be included
@@ -1259,44 +981,44 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
// list note). The real fix is probably to define new values
// for Symbol.Type corresponding to mapped and unmapped notes
// and handle them in dodata().
- Errorf(nil, "sh.type_ == SHT_NOTE in elfshbits when linking internally")
+ Errorf(nil, "sh.Type == SHT_NOTE in elfshbits when linking internally")
}
- sh.addralign = uint64(sect.Align)
- sh.size = sect.Length
- sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
+ sh.Addralign = uint64(sect.Align)
+ sh.Size = sect.Length
+ sh.Off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
return sh
}
- if sh.type_ > 0 {
+ if sh.Type > 0 {
return sh
}
if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
- sh.type_ = SHT_PROGBITS
+ sh.Type = uint32(elf.SHT_PROGBITS)
} else {
- sh.type_ = SHT_NOBITS
+ sh.Type = uint32(elf.SHT_NOBITS)
}
- sh.flags = SHF_ALLOC
+ sh.Flags = uint64(elf.SHF_ALLOC)
if sect.Rwx&1 != 0 {
- sh.flags |= SHF_EXECINSTR
+ sh.Flags |= uint64(elf.SHF_EXECINSTR)
}
if sect.Rwx&2 != 0 {
- sh.flags |= SHF_WRITE
+ sh.Flags |= uint64(elf.SHF_WRITE)
}
if sect.Name == ".tbss" {
- sh.flags |= SHF_TLS
- sh.type_ = SHT_NOBITS
+ sh.Flags |= uint64(elf.SHF_TLS)
+ sh.Type = uint32(elf.SHT_NOBITS)
}
if strings.HasPrefix(sect.Name, ".debug") || strings.HasPrefix(sect.Name, ".zdebug") {
- sh.flags = 0
+ sh.Flags = 0
}
if linkmode != LinkExternal {
- sh.addr = sect.Vaddr
+ sh.Addr = sect.Vaddr
}
- sh.addralign = uint64(sect.Align)
- sh.size = sect.Length
+ sh.Addralign = uint64(sect.Align)
+ sh.Size = sect.Length
if sect.Name != ".tbss" {
- sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
+ sh.Off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
}
return sh
@@ -1311,13 +1033,13 @@ func elfshreloc(arch *sys.Arch, sect *sym.Section) *ElfShdr {
if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
return nil
}
- if sect.Elfsect.(*ElfShdr).type_ == SHT_NOTE {
+ if sect.Elfsect.(*ElfShdr).Type == uint32(elf.SHT_NOTE) {
return nil
}
- typ := SHT_REL
+ typ := elf.SHT_REL
if elfRelType == ".rela" {
- typ = SHT_RELA
+ typ = elf.SHT_RELA
}
sh := elfshname(elfRelType + sect.Name)
@@ -1325,21 +1047,21 @@ func elfshreloc(arch *sys.Arch, sect *sym.Section) *ElfShdr {
// its own .rela.text.
if sect.Name == ".text" {
- if sh.info != 0 && sh.info != uint32(sect.Elfsect.(*ElfShdr).shnum) {
+ if sh.Info != 0 && sh.Info != uint32(sect.Elfsect.(*ElfShdr).shnum) {
sh = elfshnamedup(elfRelType + sect.Name)
}
}
- sh.type_ = uint32(typ)
- sh.entsize = uint64(arch.RegSize) * 2
- if typ == SHT_RELA {
- sh.entsize += uint64(arch.RegSize)
+ sh.Type = uint32(typ)
+ sh.Entsize = uint64(arch.RegSize) * 2
+ if typ == elf.SHT_RELA {
+ sh.Entsize += uint64(arch.RegSize)
}
- sh.link = uint32(elfshname(".symtab").shnum)
- sh.info = uint32(sect.Elfsect.(*ElfShdr).shnum)
- sh.off = sect.Reloff
- sh.size = sect.Rellen
- sh.addralign = uint64(arch.RegSize)
+ sh.Link = uint32(elfshname(".symtab").shnum)
+ sh.Info = uint32(sect.Elfsect.(*ElfShdr).shnum)
+ sh.Off = sect.Reloff
+ sh.Size = sect.Rellen
+ sh.Addralign = uint64(arch.RegSize)
return sh
}
@@ -1652,47 +1374,47 @@ func (ctxt *Link) doelf() {
/*
* .dynamic table
*/
- elfwritedynentsym(ctxt, dynamic, DT_HASH, hash.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_HASH, hash.Sym())
- elfwritedynentsym(ctxt, dynamic, DT_SYMTAB, dynsym.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_SYMTAB, dynsym.Sym())
if elf64 {
- Elfwritedynent(ctxt.Arch, dynamic, DT_SYMENT, ELF64SYMSIZE)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF64SYMSIZE)
} else {
- Elfwritedynent(ctxt.Arch, dynamic, DT_SYMENT, ELF32SYMSIZE)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_SYMENT, ELF32SYMSIZE)
}
- elfwritedynentsym(ctxt, dynamic, DT_STRTAB, dynstr.Sym())
- elfwritedynentsymsize(ctxt, dynamic, DT_STRSZ, dynstr.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_STRTAB, dynstr.Sym())
+ elfwritedynentsymsize(ctxt, dynamic, elf.DT_STRSZ, dynstr.Sym())
if elfRelType == ".rela" {
rela := ldr.LookupOrCreateSym(".rela", 0)
- elfwritedynentsym(ctxt, dynamic, DT_RELA, rela)
- elfwritedynentsymsize(ctxt, dynamic, DT_RELASZ, rela)
- Elfwritedynent(ctxt.Arch, dynamic, DT_RELAENT, ELF64RELASIZE)
+ elfwritedynentsym(ctxt, dynamic, elf.DT_RELA, rela)
+ elfwritedynentsymsize(ctxt, dynamic, elf.DT_RELASZ, rela)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RELAENT, ELF64RELASIZE)
} else {
rel := ldr.LookupOrCreateSym(".rel", 0)
- elfwritedynentsym(ctxt, dynamic, DT_REL, rel)
- elfwritedynentsymsize(ctxt, dynamic, DT_RELSZ, rel)
- Elfwritedynent(ctxt.Arch, dynamic, DT_RELENT, ELF32RELSIZE)
+ elfwritedynentsym(ctxt, dynamic, elf.DT_REL, rel)
+ elfwritedynentsymsize(ctxt, dynamic, elf.DT_RELSZ, rel)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RELENT, ELF32RELSIZE)
}
if rpath.val != "" {
- Elfwritedynent(ctxt.Arch, dynamic, DT_RUNPATH, uint64(dynstr.Addstring(rpath.val)))
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_RUNPATH, uint64(dynstr.Addstring(rpath.val)))
}
if ctxt.IsPPC64() {
- elfwritedynentsym(ctxt, dynamic, DT_PLTGOT, plt.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_PLTGOT, plt.Sym())
} else {
- elfwritedynentsym(ctxt, dynamic, DT_PLTGOT, gotplt.Sym())
+ elfwritedynentsym(ctxt, dynamic, elf.DT_PLTGOT, gotplt.Sym())
}
if ctxt.IsPPC64() {
- Elfwritedynent(ctxt.Arch, dynamic, DT_PPC64_OPT, 0)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_PPC64_OPT, 0)
}
// Solaris dynamic linker can't handle an empty .rela.plt if
- // DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
- // DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
+ // DT_JMPREL is emitted so we have to defer generation of elf.DT_PLTREL,
+ // DT_PLTRELSZ, and elf.DT_JMPREL dynamic entries until after we know the
// size of .rel(a).plt section.
- Elfwritedynent(ctxt.Arch, dynamic, DT_DEBUG, 0)
+ Elfwritedynent(ctxt.Arch, dynamic, elf.DT_DEBUG, 0)
}
if ctxt.IsShared() {
@@ -1731,20 +1453,20 @@ func shsym(sh *ElfShdr, ldr *loader.Loader, s loader.Sym) {
panic("bad symbol in shsym2")
}
addr := ldr.SymValue(s)
- if sh.flags&SHF_ALLOC != 0 {
- sh.addr = uint64(addr)
+ if sh.Flags&uint64(elf.SHF_ALLOC) != 0 {
+ sh.Addr = uint64(addr)
}
- sh.off = uint64(datoff(ldr, s, addr))
- sh.size = uint64(ldr.SymSize(s))
+ sh.Off = uint64(datoff(ldr, s, addr))
+ sh.Size = uint64(ldr.SymSize(s))
}
func phsh(ph *ElfPhdr, sh *ElfShdr) {
- ph.vaddr = sh.addr
- ph.paddr = ph.vaddr
- ph.off = sh.off
- ph.filesz = sh.size
- ph.memsz = sh.size
- ph.align = sh.addralign
+ ph.Vaddr = sh.Addr
+ ph.Paddr = ph.Vaddr
+ ph.Off = sh.Off
+ ph.Filesz = sh.Size
+ ph.Memsz = sh.Size
+ ph.Align = sh.Addralign
}
func Asmbelfsetup() {
@@ -1796,21 +1518,21 @@ func asmbElf(ctxt *Link) {
default:
Exitf("unknown architecture in asmbelf: %v", ctxt.Arch.Family)
case sys.MIPS, sys.MIPS64:
- eh.machine = EM_MIPS
+ eh.Machine = uint16(elf.EM_MIPS)
case sys.ARM:
- eh.machine = EM_ARM
+ eh.Machine = uint16(elf.EM_ARM)
case sys.AMD64:
- eh.machine = EM_X86_64
+ eh.Machine = uint16(elf.EM_X86_64)
case sys.ARM64:
- eh.machine = EM_AARCH64
+ eh.Machine = uint16(elf.EM_AARCH64)
case sys.I386:
- eh.machine = EM_386
+ eh.Machine = uint16(elf.EM_386)
case sys.PPC64:
- eh.machine = EM_PPC64
+ eh.Machine = uint16(elf.EM_PPC64)
case sys.RISCV64:
- eh.machine = EM_RISCV
+ eh.Machine = uint16(elf.EM_RISCV)
case sys.S390X:
- eh.machine = EM_S390
+ eh.Machine = uint16(elf.EM_S390)
}
elfreserve := int64(ELFRESERVE)
@@ -1840,30 +1562,30 @@ func asmbElf(ctxt *Link) {
sh := elfshname(".note.netbsd.pax")
resoff -= int64(elfnetbsdpax(sh, uint64(startva), uint64(resoff)))
pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
+ pnote.Type = elf.PT_NOTE
+ pnote.Flags = elf.PF_R
phsh(pnote, sh)
}
if ctxt.LinkMode == LinkExternal {
/* skip program headers */
- eh.phoff = 0
+ eh.Phoff = 0
- eh.phentsize = 0
+ eh.Phentsize = 0
if ctxt.BuildMode == BuildModeShared {
sh := elfshname(".note.go.pkg-list")
- sh.type_ = SHT_NOTE
+ sh.Type = uint32(elf.SHT_NOTE)
sh = elfshname(".note.go.abihash")
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
+ sh.Type = uint32(elf.SHT_NOTE)
+ sh.Flags = uint64(elf.SHF_ALLOC)
sh = elfshname(".note.go.deps")
- sh.type_ = SHT_NOTE
+ sh.Type = uint32(elf.SHT_NOTE)
}
if *flagBuildid != "" {
sh := elfshname(".note.go.buildid")
- sh.type_ = SHT_NOTE
- sh.flags = SHF_ALLOC
+ sh.Type = uint32(elf.SHT_NOTE)
+ sh.Flags = uint64(elf.SHF_ALLOC)
}
goto elfobj
@@ -1872,22 +1594,22 @@ func asmbElf(ctxt *Link) {
/* program header info */
pph = newElfPhdr()
- pph.type_ = PT_PHDR
- pph.flags = PF_R
- pph.off = uint64(eh.ehsize)
- pph.vaddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
- pph.paddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
- pph.align = uint64(*FlagRound)
+ pph.Type = elf.PT_PHDR
+ pph.Flags = elf.PF_R
+ pph.Off = uint64(eh.Ehsize)
+ pph.Vaddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.Off
+ pph.Paddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.Off
+ pph.Align = uint64(*FlagRound)
/*
* PHDR must be in a loaded segment. Adjust the text
* segment boundaries downwards to include it.
*/
{
- o := int64(Segtext.Vaddr - pph.vaddr)
+ o := int64(Segtext.Vaddr - pph.Vaddr)
Segtext.Vaddr -= uint64(o)
Segtext.Length += uint64(o)
- o = int64(Segtext.Fileoff - pph.off)
+ o = int64(Segtext.Fileoff - pph.Off)
Segtext.Fileoff -= uint64(o)
Segtext.Filelen += uint64(o)
}
@@ -1896,9 +1618,9 @@ func asmbElf(ctxt *Link) {
/* interpreter */
sh := elfshname(".interp")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC
- sh.addralign = 1
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = 1
if interpreter == "" && objabi.GO_LDSO != "" {
interpreter = objabi.GO_LDSO
@@ -1936,8 +1658,8 @@ func asmbElf(ctxt *Link) {
resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter))
ph := newElfPhdr()
- ph.type_ = PT_INTERP
- ph.flags = PF_R
+ ph.Type = elf.PT_INTERP
+ ph.Flags = elf.PF_R
phsh(ph, sh)
}
@@ -1955,8 +1677,8 @@ func asmbElf(ctxt *Link) {
}
pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
+ pnote.Type = elf.PT_NOTE
+ pnote.Flags = elf.PF_R
phsh(pnote, sh)
}
@@ -1966,8 +1688,8 @@ func asmbElf(ctxt *Link) {
if pnote == nil {
pnote = newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
+ pnote.Type = elf.PT_NOTE
+ pnote.Flags = elf.PF_R
}
phsh(pnote, sh)
@@ -1978,8 +1700,8 @@ func asmbElf(ctxt *Link) {
resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff)))
pnote := newElfPhdr()
- pnote.type_ = PT_NOTE
- pnote.flags = PF_R
+ pnote.Type = elf.PT_NOTE
+ pnote.Flags = elf.PF_R
phsh(pnote, sh)
}
@@ -1998,15 +1720,15 @@ func asmbElf(ctxt *Link) {
/* Dynamic linking sections */
if !*FlagD {
sh := elfshname(".dynsym")
- sh.type_ = SHT_DYNSYM
- sh.flags = SHF_ALLOC
+ sh.Type = uint32(elf.SHT_DYNSYM)
+ sh.Flags = uint64(elf.SHF_ALLOC)
if elf64 {
- sh.entsize = ELF64SYMSIZE
+ sh.Entsize = ELF64SYMSIZE
} else {
- sh.entsize = ELF32SYMSIZE
+ sh.Entsize = ELF32SYMSIZE
}
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynstr").shnum)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".dynstr").shnum)
// sh.info is the index of first non-local symbol (number of local symbols)
s := ldr.Lookup(".dynsym", 0)
@@ -2017,134 +1739,134 @@ func asmbElf(ctxt *Link) {
break
}
}
- sh.info = i
+ sh.Info = i
shsym(sh, ldr, s)
sh = elfshname(".dynstr")
- sh.type_ = SHT_STRTAB
- sh.flags = SHF_ALLOC
- sh.addralign = 1
+ sh.Type = uint32(elf.SHT_STRTAB)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = 1
shsym(sh, ldr, ldr.Lookup(".dynstr", 0))
if elfverneed != 0 {
sh := elfshname(".gnu.version")
- sh.type_ = SHT_GNU_VERSYM
- sh.flags = SHF_ALLOC
- sh.addralign = 2
- sh.link = uint32(elfshname(".dynsym").shnum)
- sh.entsize = 2
+ sh.Type = uint32(elf.SHT_GNU_VERSYM)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = 2
+ sh.Link = uint32(elfshname(".dynsym").shnum)
+ sh.Entsize = 2
shsym(sh, ldr, ldr.Lookup(".gnu.version", 0))
sh = elfshname(".gnu.version_r")
- sh.type_ = SHT_GNU_VERNEED
- sh.flags = SHF_ALLOC
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.info = uint32(elfverneed)
- sh.link = uint32(elfshname(".dynstr").shnum)
+ sh.Type = uint32(elf.SHT_GNU_VERNEED)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Info = uint32(elfverneed)
+ sh.Link = uint32(elfshname(".dynstr").shnum)
shsym(sh, ldr, ldr.Lookup(".gnu.version_r", 0))
}
if elfRelType == ".rela" {
sh := elfshname(".rela.plt")
- sh.type_ = SHT_RELA
- sh.flags = SHF_ALLOC
- sh.entsize = ELF64RELASIZE
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynsym").shnum)
- sh.info = uint32(elfshname(".plt").shnum)
+ sh.Type = uint32(elf.SHT_RELA)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = ELF64RELASIZE
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".dynsym").shnum)
+ sh.Info = uint32(elfshname(".plt").shnum)
shsym(sh, ldr, ldr.Lookup(".rela.plt", 0))
sh = elfshname(".rela")
- sh.type_ = SHT_RELA
- sh.flags = SHF_ALLOC
- sh.entsize = ELF64RELASIZE
- sh.addralign = 8
- sh.link = uint32(elfshname(".dynsym").shnum)
+ sh.Type = uint32(elf.SHT_RELA)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = ELF64RELASIZE
+ sh.Addralign = 8
+ sh.Link = uint32(elfshname(".dynsym").shnum)
shsym(sh, ldr, ldr.Lookup(".rela", 0))
} else {
sh := elfshname(".rel.plt")
- sh.type_ = SHT_REL
- sh.flags = SHF_ALLOC
- sh.entsize = ELF32RELSIZE
- sh.addralign = 4
- sh.link = uint32(elfshname(".dynsym").shnum)
+ sh.Type = uint32(elf.SHT_REL)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = ELF32RELSIZE
+ sh.Addralign = 4
+ sh.Link = uint32(elfshname(".dynsym").shnum)
shsym(sh, ldr, ldr.Lookup(".rel.plt", 0))
sh = elfshname(".rel")
- sh.type_ = SHT_REL
- sh.flags = SHF_ALLOC
- sh.entsize = ELF32RELSIZE
- sh.addralign = 4
- sh.link = uint32(elfshname(".dynsym").shnum)
+ sh.Type = uint32(elf.SHT_REL)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = ELF32RELSIZE
+ sh.Addralign = 4
+ sh.Link = uint32(elfshname(".dynsym").shnum)
shsym(sh, ldr, ldr.Lookup(".rel", 0))
}
- if eh.machine == EM_PPC64 {
+ if elf.Machine(eh.Machine) == elf.EM_PPC64 {
sh := elfshname(".glink")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_EXECINSTR
- sh.addralign = 4
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_EXECINSTR)
+ sh.Addralign = 4
shsym(sh, ldr, ldr.Lookup(".glink", 0))
}
sh = elfshname(".plt")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_EXECINSTR
- if eh.machine == EM_X86_64 {
- sh.entsize = 16
- } else if eh.machine == EM_S390 {
- sh.entsize = 32
- } else if eh.machine == EM_PPC64 {
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_EXECINSTR)
+ if elf.Machine(eh.Machine) == elf.EM_X86_64 {
+ sh.Entsize = 16
+ } else if elf.Machine(eh.Machine) == elf.EM_S390 {
+ sh.Entsize = 32
+ } else if elf.Machine(eh.Machine) == elf.EM_PPC64 {
// On ppc64, this is just a table of addresses
// filled by the dynamic linker
- sh.type_ = SHT_NOBITS
+ sh.Type = uint32(elf.SHT_NOBITS)
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = 8
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
+ sh.Entsize = 8
} else {
- sh.entsize = 4
+ sh.Entsize = 4
}
- sh.addralign = sh.entsize
+ sh.Addralign = sh.Entsize
shsym(sh, ldr, ldr.Lookup(".plt", 0))
// On ppc64, .got comes from the input files, so don't
// create it here, and .got.plt is not used.
- if eh.machine != EM_PPC64 {
+ if elf.Machine(eh.Machine) != elf.EM_PPC64 {
sh := elfshname(".got")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
+ sh.Entsize = uint64(ctxt.Arch.RegSize)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
shsym(sh, ldr, ldr.Lookup(".got", 0))
sh = elfshname(".got.plt")
- sh.type_ = SHT_PROGBITS
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
+ sh.Entsize = uint64(ctxt.Arch.RegSize)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
shsym(sh, ldr, ldr.Lookup(".got.plt", 0))
}
sh = elfshname(".hash")
- sh.type_ = SHT_HASH
- sh.flags = SHF_ALLOC
- sh.entsize = 4
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynsym").shnum)
+ sh.Type = uint32(elf.SHT_HASH)
+ sh.Flags = uint64(elf.SHF_ALLOC)
+ sh.Entsize = 4
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".dynsym").shnum)
shsym(sh, ldr, ldr.Lookup(".hash", 0))
- /* sh and PT_DYNAMIC for .dynamic section */
+ /* sh and elf.PT_DYNAMIC for .dynamic section */
sh = elfshname(".dynamic")
- sh.type_ = SHT_DYNAMIC
- sh.flags = SHF_ALLOC + SHF_WRITE
- sh.entsize = 2 * uint64(ctxt.Arch.RegSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".dynstr").shnum)
+ sh.Type = uint32(elf.SHT_DYNAMIC)
+ sh.Flags = uint64(elf.SHF_ALLOC + elf.SHF_WRITE)
+ sh.Entsize = 2 * uint64(ctxt.Arch.RegSize)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".dynstr").shnum)
shsym(sh, ldr, ldr.Lookup(".dynamic", 0))
ph := newElfPhdr()
- ph.type_ = PT_DYNAMIC
- ph.flags = PF_R + PF_W
+ ph.Type = elf.PT_DYNAMIC
+ ph.Flags = elf.PF_R + elf.PF_W
phsh(ph, sh)
/*
@@ -2158,35 +1880,35 @@ func asmbElf(ctxt *Link) {
}
if tlssize != 0 {
ph := newElfPhdr()
- ph.type_ = PT_TLS
- ph.flags = PF_R
- ph.memsz = tlssize
- ph.align = uint64(ctxt.Arch.RegSize)
+ ph.Type = elf.PT_TLS
+ ph.Flags = elf.PF_R
+ ph.Memsz = tlssize
+ ph.Align = uint64(ctxt.Arch.RegSize)
}
}
if ctxt.HeadType == objabi.Hlinux {
ph := newElfPhdr()
- ph.type_ = PT_GNU_STACK
- ph.flags = PF_W + PF_R
- ph.align = uint64(ctxt.Arch.RegSize)
+ ph.Type = elf.PT_GNU_STACK
+ ph.Flags = elf.PF_W + elf.PF_R
+ ph.Align = uint64(ctxt.Arch.RegSize)
ph = newElfPhdr()
- ph.type_ = PT_PAX_FLAGS
- ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
- ph.align = uint64(ctxt.Arch.RegSize)
+ ph.Type = elf.PT_PAX_FLAGS
+ ph.Flags = 0x2a00 // mprotect, randexec, emutramp disabled
+ ph.Align = uint64(ctxt.Arch.RegSize)
} else if ctxt.HeadType == objabi.Hsolaris {
ph := newElfPhdr()
- ph.type_ = PT_SUNWSTACK
- ph.flags = PF_W + PF_R
+ ph.Type = elf.PT_SUNWSTACK
+ ph.Flags = elf.PF_W + elf.PF_R
}
elfobj:
sh := elfshname(".shstrtab")
- sh.type_ = SHT_STRTAB
- sh.addralign = 1
+ sh.Type = uint32(elf.SHT_STRTAB)
+ sh.Addralign = 1
shsym(sh, ldr, ldr.Lookup(".shstrtab", 0))
- eh.shstrndx = uint16(sh.shnum)
+ eh.Shstrndx = uint16(sh.shnum)
// put these sections early in the list
if !*FlagS {
@@ -2230,72 +1952,73 @@ elfobj:
// add a .note.GNU-stack section to mark the stack as non-executable
sh := elfshname(".note.GNU-stack")
- sh.type_ = SHT_PROGBITS
- sh.addralign = 1
- sh.flags = 0
+ sh.Type = uint32(elf.SHT_PROGBITS)
+ sh.Addralign = 1
+ sh.Flags = 0
}
if !*FlagS {
sh := elfshname(".symtab")
- sh.type_ = SHT_SYMTAB
- sh.off = uint64(symo)
- sh.size = uint64(symSize)
- sh.addralign = uint64(ctxt.Arch.RegSize)
- sh.entsize = 8 + 2*uint64(ctxt.Arch.RegSize)
- sh.link = uint32(elfshname(".strtab").shnum)
- sh.info = uint32(elfglobalsymndx)
+ sh.Type = uint32(elf.SHT_SYMTAB)
+ sh.Off = uint64(symo)
+ sh.Size = uint64(symSize)
+ sh.Addralign = uint64(ctxt.Arch.RegSize)
+ sh.Entsize = 8 + 2*uint64(ctxt.Arch.RegSize)
+ sh.Link = uint32(elfshname(".strtab").shnum)
+ sh.Info = uint32(elfglobalsymndx)
sh = elfshname(".strtab")
- sh.type_ = SHT_STRTAB
- sh.off = uint64(symo) + uint64(symSize)
- sh.size = uint64(len(Elfstrdat))
- sh.addralign = 1
+ sh.Type = uint32(elf.SHT_STRTAB)
+ sh.Off = uint64(symo) + uint64(symSize)
+ sh.Size = uint64(len(Elfstrdat))
+ sh.Addralign = 1
}
/* Main header */
- eh.ident[EI_MAG0] = '\177'
-
- eh.ident[EI_MAG1] = 'E'
- eh.ident[EI_MAG2] = 'L'
- eh.ident[EI_MAG3] = 'F'
- if ctxt.HeadType == objabi.Hfreebsd {
- eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
- } else if ctxt.HeadType == objabi.Hnetbsd {
- eh.ident[EI_OSABI] = ELFOSABI_NETBSD
- } else if ctxt.HeadType == objabi.Hopenbsd {
- eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
- } else if ctxt.HeadType == objabi.Hdragonfly {
- eh.ident[EI_OSABI] = ELFOSABI_NONE
+ copy(eh.Ident[:], elf.ELFMAG)
+
+ var osabi elf.OSABI
+ switch ctxt.HeadType {
+ case objabi.Hfreebsd:
+ osabi = elf.ELFOSABI_FREEBSD
+ case objabi.Hnetbsd:
+ osabi = elf.ELFOSABI_NETBSD
+ case objabi.Hopenbsd:
+ osabi = elf.ELFOSABI_OPENBSD
+ case objabi.Hdragonfly:
+ osabi = elf.ELFOSABI_NONE
}
+ eh.Ident[elf.EI_OSABI] = byte(osabi)
+
if elf64 {
- eh.ident[EI_CLASS] = ELFCLASS64
+ eh.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS64)
} else {
- eh.ident[EI_CLASS] = ELFCLASS32
+ eh.Ident[elf.EI_CLASS] = byte(elf.ELFCLASS32)
}
if ctxt.Arch.ByteOrder == binary.BigEndian {
- eh.ident[EI_DATA] = ELFDATA2MSB
+ eh.Ident[elf.EI_DATA] = byte(elf.ELFDATA2MSB)
} else {
- eh.ident[EI_DATA] = ELFDATA2LSB
+ eh.Ident[elf.EI_DATA] = byte(elf.ELFDATA2LSB)
}
- eh.ident[EI_VERSION] = EV_CURRENT
+ eh.Ident[elf.EI_VERSION] = byte(elf.EV_CURRENT)
if ctxt.LinkMode == LinkExternal {
- eh.type_ = ET_REL
+ eh.Type = uint16(elf.ET_REL)
} else if ctxt.BuildMode == BuildModePIE {
- eh.type_ = ET_DYN
+ eh.Type = uint16(elf.ET_DYN)
} else {
- eh.type_ = ET_EXEC
+ eh.Type = uint16(elf.ET_EXEC)
}
if ctxt.LinkMode != LinkExternal {
- eh.entry = uint64(Entryvalue(ctxt))
+ eh.Entry = uint64(Entryvalue(ctxt))
}
- eh.version = EV_CURRENT
+ eh.Version = uint32(elf.EV_CURRENT)
if pph != nil {
- pph.filesz = uint64(eh.phnum) * uint64(eh.phentsize)
- pph.memsz = pph.filesz
+ pph.Filesz = uint64(eh.Phnum) * uint64(eh.Phentsize)
+ pph.Memsz = pph.Filesz
}
ctxt.Out.SeekSet(0)
@@ -2345,21 +2068,21 @@ func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.S
if elf64 {
/* type */
- t := STB_GLOBAL << 4
+ var t uint8
if cgoexp && st == sym.STEXT {
- t |= STT_FUNC
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
} else {
- t |= STT_OBJECT
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_OBJECT)
}
- d.AddUint8(uint8(t))
+ d.AddUint8(t)
/* reserved */
d.AddUint8(0)
/* section where symbol is defined */
if st == sym.SDYNIMPORT {
- d.AddUint16(target.Arch, SHN_UNDEF)
+ d.AddUint16(target.Arch, uint16(elf.SHN_UNDEF))
} else {
d.AddUint16(target.Arch, 1)
}
@@ -2378,7 +2101,7 @@ func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.S
if target.Arch.Family == sys.AMD64 && !cgoeDynamic && dil != "" && !seenlib[dil] {
du := ldr.MakeSymbolUpdater(syms.Dynamic)
- Elfwritedynent(target.Arch, du, DT_NEEDED, uint64(dstru.Addstring(dil)))
+ Elfwritedynent(target.Arch, du, elf.DT_NEEDED, uint64(dstru.Addstring(dil)))
seenlib[dil] = true
}
} else {
@@ -2394,80 +2117,24 @@ func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.S
d.AddUint32(target.Arch, uint32(len(ldr.Data(s))))
/* type */
- t := STB_GLOBAL << 4
+ var t uint8
// TODO(mwhudson): presumably the behavior should actually be the same on both arm and 386.
if target.Arch.Family == sys.I386 && cgoexp && st == sym.STEXT {
- t |= STT_FUNC
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
} else if target.Arch.Family == sys.ARM && cgoeDynamic && st == sym.STEXT {
- t |= STT_FUNC
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_FUNC)
} else {
- t |= STT_OBJECT
+ t = elf.ST_INFO(elf.STB_GLOBAL, elf.STT_OBJECT)
}
- d.AddUint8(uint8(t))
+ d.AddUint8(t)
d.AddUint8(0)
/* shndx */
if st == sym.SDYNIMPORT {
- d.AddUint16(target.Arch, SHN_UNDEF)
+ d.AddUint16(target.Arch, uint16(elf.SHN_UNDEF))
} else {
d.AddUint16(target.Arch, 1)
}
}
}
-
-func ELF32_R_SYM(info uint32) uint32 {
- return info >> 8
-}
-
-func ELF32_R_TYPE(info uint32) uint32 {
- return uint32(uint8(info))
-}
-
-func ELF32_R_INFO(sym uint32, type_ uint32) uint32 {
- return sym<<8 | type_
-}
-
-func ELF32_ST_BIND(info uint8) uint8 {
- return info >> 4
-}
-
-func ELF32_ST_TYPE(info uint8) uint8 {
- return info & 0xf
-}
-
-func ELF32_ST_INFO(bind uint8, type_ uint8) uint8 {
- return bind<<4 | type_&0xf
-}
-
-func ELF32_ST_VISIBILITY(oth uint8) uint8 {
- return oth & 3
-}
-
-func ELF64_R_SYM(info uint64) uint32 {
- return uint32(info >> 32)
-}
-
-func ELF64_R_TYPE(info uint64) uint32 {
- return uint32(info)
-}
-
-func ELF64_R_INFO(sym uint32, type_ uint32) uint64 {
- return uint64(sym)<<32 | uint64(type_)
-}
-
-func ELF64_ST_BIND(info uint8) uint8 {
- return info >> 4
-}
-
-func ELF64_ST_TYPE(info uint8) uint8 {
- return info & 0xf
-}
-
-func ELF64_ST_INFO(bind uint8, type_ uint8) uint8 {
- return bind<<4 | type_&0xf
-}
-
-func ELF64_ST_VISIBILITY(oth uint8) uint8 {
- return oth & 3
-}
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index b3541c46c0..a6cd4c0541 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -13,6 +13,7 @@ import (
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
+ "debug/elf"
"encoding/json"
"fmt"
"io"
@@ -302,7 +303,7 @@ func adddynlib(ctxt *Link, lib string) {
dsu.Addstring("")
}
du := ctxt.loader.MakeSymbolUpdater(ctxt.Dynamic)
- Elfwritedynent(ctxt.Arch, du, DT_NEEDED, uint64(dsu.Addstring(lib)))
+ Elfwritedynent(ctxt.Arch, du, elf.DT_NEEDED, uint64(dsu.Addstring(lib)))
} else {
Errorf(nil, "adddynlib: unsupported binary format")
}
diff --git a/src/cmd/link/internal/ld/ld_test.go b/src/cmd/link/internal/ld/ld_test.go
index db339b484d..cdfaadb17d 100644
--- a/src/cmd/link/internal/ld/ld_test.go
+++ b/src/cmd/link/internal/ld/ld_test.go
@@ -5,6 +5,7 @@
package ld
import (
+ "debug/pe"
"fmt"
"internal/testenv"
"io/ioutil"
@@ -17,8 +18,13 @@ import (
)
func TestUndefinedRelocErrors(t *testing.T) {
- t.Parallel()
testenv.MustHaveGoBuild(t)
+
+ // When external linking, symbols may be defined externally, so we allow
+ // undefined symbols and let external linker resolve. Skip the test.
+ testenv.MustInternalLink(t)
+
+ t.Parallel()
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatal(err)
@@ -167,3 +173,72 @@ func TestPPC64LargeTextSectionSplitting(t *testing.T) {
t.Fatal(err)
}
}
+
+func TestWindowsBuildmodeCSharedASLR(t *testing.T) {
+ platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
+ switch platform {
+ case "windows/amd64", "windows/386":
+ default:
+ t.Skip("skipping windows amd64/386 only test")
+ }
+
+ t.Run("aslr", func(t *testing.T) {
+ testWindowsBuildmodeCSharedASLR(t, true)
+ })
+ t.Run("no-aslr", func(t *testing.T) {
+ testWindowsBuildmodeCSharedASLR(t, false)
+ })
+}
+
+func testWindowsBuildmodeCSharedASLR(t *testing.T, useASLR bool) {
+ t.Parallel()
+ testenv.MustHaveGoBuild(t)
+
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ srcfile := filepath.Join(dir, "test.go")
+ objfile := filepath.Join(dir, "test.dll")
+ if err := ioutil.WriteFile(srcfile, []byte(`package main; func main() { print("hello") }`), 0666); err != nil {
+ t.Fatal(err)
+ }
+ argv := []string{"build", "-buildmode=c-shared"}
+ if !useASLR {
+ argv = append(argv, "-ldflags", "-aslr=false")
+ }
+ argv = append(argv, "-o", objfile, srcfile)
+ out, err := exec.Command(testenv.GoToolPath(t), argv...).CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failure: %s\n%s\n", err, string(out))
+ }
+
+ f, err := pe.Open(objfile)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ var dc uint16
+ switch oh := f.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ dc = oh.DllCharacteristics
+ case *pe.OptionalHeader64:
+ dc = oh.DllCharacteristics
+ hasHEVA := (dc & pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) != 0
+ if useASLR && !hasHEVA {
+ t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag is not set")
+ } else if !useASLR && hasHEVA {
+ t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag should not be set")
+ }
+ default:
+ t.Fatalf("unexpected optional header type of %T", f.OptionalHeader)
+ }
+ hasASLR := (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) != 0
+ if useASLR && !hasASLR {
+ t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set")
+ } else if !useASLR && hasASLR {
+ t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag should not be set")
+ }
+}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index f5d41a0b4a..73e0b35bc0 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -247,12 +247,16 @@ type Arch struct {
Elfreloc1 func(*Link, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int, int64) bool
ElfrelocSize uint32 // size of an ELF relocation record, must match Elfreloc1.
Elfsetupplt func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
- Gentext func(*Link, *loader.Loader)
+ Gentext func(*Link, *loader.Loader) // Generate text before addressing has been performed.
Machoreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
MachorelocSize uint32 // size of an Mach-O relocation record, must match Machoreloc1.
PEreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
Xcoffreloc1 func(*sys.Arch, *OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool
+ // Generate additional symbols for the native symbol table just prior to
+ // code generation.
+ GenSymsLate func(*Link, *loader.Loader)
+
// TLSIEtoLE converts a TLS Initial Executable relocation to
// a TLS Local Executable relocation.
//
@@ -1254,7 +1258,9 @@ func (ctxt *Link) hostlink() {
// -headerpad is incompatible with -fembed-bitcode.
argv = append(argv, "-Wl,-headerpad,1144")
}
- if ctxt.DynlinkingGo() && !ctxt.Arch.InFamily(sys.ARM, sys.ARM64) {
+ if ctxt.DynlinkingGo() && objabi.GOOS != "ios" {
+ // -flat_namespace is deprecated on iOS.
+ // It is useful for supporting plugins. We don't support plugins on iOS.
argv = append(argv, "-Wl,-flat_namespace")
}
if !combineDwarf {
@@ -1290,6 +1296,17 @@ func (ctxt *Link) hostlink() {
argv = append(argv, "-Wl,-bbigtoc")
}
+ // Enable ASLR on Windows.
+ addASLRargs := func(argv []string) []string {
+ // Enable ASLR.
+ argv = append(argv, "-Wl,--dynamicbase")
+ // enable high-entropy ASLR on 64-bit.
+ if ctxt.Arch.PtrSize >= 8 {
+ argv = append(argv, "-Wl,--high-entropy-va")
+ }
+ return argv
+ }
+
switch ctxt.BuildMode {
case BuildModeExe:
if ctxt.HeadType == objabi.Hdarwin {
@@ -1302,12 +1319,7 @@ func (ctxt *Link) hostlink() {
switch ctxt.HeadType {
case objabi.Hdarwin, objabi.Haix:
case objabi.Hwindows:
- // Enable ASLR.
- argv = append(argv, "-Wl,--dynamicbase")
- // enable high-entropy ASLR on 64-bit.
- if ctxt.Arch.PtrSize >= 8 {
- argv = append(argv, "-Wl,--high-entropy-va")
- }
+ argv = addASLRargs(argv)
// Work around binutils limitation that strips relocation table for dynamicbase.
// See https://sourceware.org/bugzilla/show_bug.cgi?id=19011
argv = append(argv, "-Wl,--export-all-symbols")
@@ -1321,9 +1333,6 @@ func (ctxt *Link) hostlink() {
case BuildModeCShared:
if ctxt.HeadType == objabi.Hdarwin {
argv = append(argv, "-dynamiclib")
- if ctxt.Arch.Family != sys.AMD64 {
- argv = append(argv, "-Wl,-read_only_relocs,suppress")
- }
} else {
// ELF.
argv = append(argv, "-Wl,-Bsymbolic")
@@ -1331,7 +1340,11 @@ func (ctxt *Link) hostlink() {
argv = append(argv, "-Wl,-z,relro")
}
argv = append(argv, "-shared")
- if ctxt.HeadType != objabi.Hwindows {
+ if ctxt.HeadType == objabi.Hwindows {
+ if *flagAslr {
+ argv = addASLRargs(argv)
+ }
+ } else {
// Pass -z nodelete to mark the shared library as
// non-closeable: a dlclose will do nothing.
argv = append(argv, "-Wl,-z,nodelete")
@@ -1601,12 +1614,12 @@ func (ctxt *Link) hostlink() {
if combineDwarf {
dsym := filepath.Join(*flagTmpdir, "go.dwarf")
- if out, err := exec.Command("dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
+ if out, err := exec.Command("xcrun", "dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
}
// Remove STAB (symbolic debugging) symbols after we are done with them (by dsymutil).
// They contain temporary file paths and make the build not reproducible.
- if out, err := exec.Command("strip", "-S", *flagOutfile).CombinedOutput(); err != nil {
+ if out, err := exec.Command("xcrun", "strip", "-S", *flagOutfile).CombinedOutput(); err != nil {
Exitf("%s: running strip failed: %v\n%s", os.Args[0], err, out)
}
// Skip combining if `dsymutil` didn't generate a file. See #11994.
@@ -1757,12 +1770,12 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
if magic == 0x7f454c46 { // \x7F E L F
ldelf := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
- textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.flags)
+ textp, flags, err := loadelf.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn, ehdr.Flags)
if err != nil {
Errorf(nil, "%v", err)
return
}
- ehdr.flags = flags
+ ehdr.Flags = flags
ctxt.Textp = append(ctxt.Textp, textp...)
}
return ldhostobj(ldelf, ctxt.HeadType, f, pkg, length, pn, file)
@@ -2507,16 +2520,22 @@ func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym,
if target.Arch.PtrSize == 8 {
rela := ldr.MakeSymbolUpdater(syms.Rela)
rela.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
- rela.AddUint64(target.Arch, ELF64_R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
rela.AddUint64(target.Arch, 0)
} else {
rel := ldr.MakeSymbolUpdater(syms.Rel)
rel.AddAddrPlus(target.Arch, got.Sym(), int64(ldr.SymGot(s)))
- rel.AddUint32(target.Arch, ELF32_R_INFO(uint32(ldr.SymDynid(s)), elfRelocTyp))
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(s)), elfRelocTyp))
}
} else if target.IsDarwin() {
leg := ldr.MakeSymbolUpdater(syms.LinkEditGOT)
leg.AddUint32(target.Arch, uint32(ldr.SymDynid(s)))
+ if target.IsPIE() && target.IsInternal() {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation.
+ // Here we record what are needed and encode them later.
+ MachoAddBind(int64(ldr.SymGot(s)), s)
+ }
} else {
ldr.Errorf(s, "addgotsym: unsupported binary format")
}
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index 9765ce18d3..155769c48f 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -76,36 +76,38 @@ const (
)
const (
- MACHO_CPU_AMD64 = 1<<24 | 7
- MACHO_CPU_386 = 7
- MACHO_SUBCPU_X86 = 3
- MACHO_CPU_ARM = 12
- MACHO_SUBCPU_ARM = 0
- MACHO_SUBCPU_ARMV7 = 9
- MACHO_CPU_ARM64 = 1<<24 | 12
- MACHO_SUBCPU_ARM64_ALL = 0
- MACHO32SYMSIZE = 12
- MACHO64SYMSIZE = 16
- MACHO_X86_64_RELOC_UNSIGNED = 0
- MACHO_X86_64_RELOC_SIGNED = 1
- MACHO_X86_64_RELOC_BRANCH = 2
- MACHO_X86_64_RELOC_GOT_LOAD = 3
- MACHO_X86_64_RELOC_GOT = 4
- MACHO_X86_64_RELOC_SUBTRACTOR = 5
- MACHO_X86_64_RELOC_SIGNED_1 = 6
- MACHO_X86_64_RELOC_SIGNED_2 = 7
- MACHO_X86_64_RELOC_SIGNED_4 = 8
- MACHO_ARM_RELOC_VANILLA = 0
- MACHO_ARM_RELOC_PAIR = 1
- MACHO_ARM_RELOC_SECTDIFF = 2
- MACHO_ARM_RELOC_BR24 = 5
- MACHO_ARM64_RELOC_UNSIGNED = 0
- MACHO_ARM64_RELOC_BRANCH26 = 2
- MACHO_ARM64_RELOC_PAGE21 = 3
- MACHO_ARM64_RELOC_PAGEOFF12 = 4
- MACHO_ARM64_RELOC_ADDEND = 10
- MACHO_GENERIC_RELOC_VANILLA = 0
- MACHO_FAKE_GOTPCREL = 100
+ MACHO_CPU_AMD64 = 1<<24 | 7
+ MACHO_CPU_386 = 7
+ MACHO_SUBCPU_X86 = 3
+ MACHO_CPU_ARM = 12
+ MACHO_SUBCPU_ARM = 0
+ MACHO_SUBCPU_ARMV7 = 9
+ MACHO_CPU_ARM64 = 1<<24 | 12
+ MACHO_SUBCPU_ARM64_ALL = 0
+ MACHO32SYMSIZE = 12
+ MACHO64SYMSIZE = 16
+ MACHO_X86_64_RELOC_UNSIGNED = 0
+ MACHO_X86_64_RELOC_SIGNED = 1
+ MACHO_X86_64_RELOC_BRANCH = 2
+ MACHO_X86_64_RELOC_GOT_LOAD = 3
+ MACHO_X86_64_RELOC_GOT = 4
+ MACHO_X86_64_RELOC_SUBTRACTOR = 5
+ MACHO_X86_64_RELOC_SIGNED_1 = 6
+ MACHO_X86_64_RELOC_SIGNED_2 = 7
+ MACHO_X86_64_RELOC_SIGNED_4 = 8
+ MACHO_ARM_RELOC_VANILLA = 0
+ MACHO_ARM_RELOC_PAIR = 1
+ MACHO_ARM_RELOC_SECTDIFF = 2
+ MACHO_ARM_RELOC_BR24 = 5
+ MACHO_ARM64_RELOC_UNSIGNED = 0
+ MACHO_ARM64_RELOC_BRANCH26 = 2
+ MACHO_ARM64_RELOC_PAGE21 = 3
+ MACHO_ARM64_RELOC_PAGEOFF12 = 4
+ MACHO_ARM64_RELOC_GOT_LOAD_PAGE21 = 5
+ MACHO_ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6
+ MACHO_ARM64_RELOC_ADDEND = 10
+ MACHO_GENERIC_RELOC_VANILLA = 0
+ MACHO_FAKE_GOTPCREL = 100
)
const (
@@ -116,6 +118,8 @@ const (
MH_EXECUTE = 0x2
MH_NOUNDEFS = 0x1
+ MH_DYLDLINK = 0x4
+ MH_PIE = 0x200000
)
const (
@@ -191,6 +195,56 @@ const (
PLATFORM_BRIDGEOS MachoPlatform = 5
)
+// rebase table opcode
+const (
+ REBASE_TYPE_POINTER = 1
+ REBASE_TYPE_TEXT_ABSOLUTE32 = 2
+ REBASE_TYPE_TEXT_PCREL32 = 3
+
+ REBASE_OPCODE_MASK = 0xF0
+ REBASE_IMMEDIATE_MASK = 0x0F
+ REBASE_OPCODE_DONE = 0x00
+ REBASE_OPCODE_SET_TYPE_IMM = 0x10
+ REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x20
+ REBASE_OPCODE_ADD_ADDR_ULEB = 0x30
+ REBASE_OPCODE_ADD_ADDR_IMM_SCALED = 0x40
+ REBASE_OPCODE_DO_REBASE_IMM_TIMES = 0x50
+ REBASE_OPCODE_DO_REBASE_ULEB_TIMES = 0x60
+ REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB = 0x70
+ REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB = 0x80
+)
+
+// bind table opcode
+const (
+ BIND_TYPE_POINTER = 1
+ BIND_TYPE_TEXT_ABSOLUTE32 = 2
+ BIND_TYPE_TEXT_PCREL32 = 3
+
+ BIND_SPECIAL_DYLIB_SELF = 0
+ BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1
+ BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2
+ BIND_SPECIAL_DYLIB_WEAK_LOOKUP = -3
+
+ BIND_OPCODE_MASK = 0xF0
+ BIND_IMMEDIATE_MASK = 0x0F
+ BIND_OPCODE_DONE = 0x00
+ BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10
+ BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20
+ BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30
+ BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40
+ BIND_OPCODE_SET_TYPE_IMM = 0x50
+ BIND_OPCODE_SET_ADDEND_SLEB = 0x60
+ BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70
+ BIND_OPCODE_ADD_ADDR_ULEB = 0x80
+ BIND_OPCODE_DO_BIND = 0x90
+ BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0
+ BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0
+ BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0
+ BIND_OPCODE_THREADED = 0xD0
+ BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB = 0x00
+ BIND_SUBOPCODE_THREADED_APPLY = 0x01
+)
+
// Mach-O file writing
// https://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
@@ -277,7 +331,7 @@ var dylib []string
var linkoff int64
-func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
+func machowrite(ctxt *Link, arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
o1 := out.Offset()
loadsize := 4 * 4 * ndebug
@@ -306,11 +360,14 @@ func machowrite(arch *sys.Arch, out *OutBuf, linkmode LinkMode) int {
}
out.Write32(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
out.Write32(uint32(loadsize))
+ flags := uint32(0)
if nkind[SymKindUndef] == 0 {
- out.Write32(MH_NOUNDEFS) /* flags - no undefines */
- } else {
- out.Write32(0) /* flags */
+ flags |= MH_NOUNDEFS
+ }
+ if ctxt.IsPIE() && linkmode == LinkInternal {
+ flags |= MH_PIE | MH_DYLDLINK
}
+ out.Write32(flags) /* flags */
if arch.PtrSize == 8 {
out.Write32(0) /* reserved */
}
@@ -473,6 +530,18 @@ func (ctxt *Link) domacho() {
sb.SetReachable(true)
sb.AddUint8(0)
}
+
+ // Do not export C symbols dynamically in plugins, as runtime C symbols like crosscall2
+ // are in pclntab and end up pointing at the host binary, breaking unwinding.
+ // See Issue #18190.
+ if ctxt.BuildMode == BuildModePlugin {
+ for _, name := range []string{"_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2"} {
+ s := ctxt.loader.Lookup(name, 0)
+ if s != 0 {
+ ctxt.loader.SetAttrCgoExportDynamic(s, false)
+ }
+ }
+ }
}
func machoadddynlib(lib string, linkmode LinkMode) {
@@ -682,11 +751,9 @@ func asmbMacho(ctxt *Link) {
ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
case sys.ARM64:
- ml := newMachoLoad(ctxt.Arch, LC_UNIXTHREAD, 68+2)
- ml.data[0] = 6 /* thread type */
- ml.data[1] = 68 /* word count */
- ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */
- ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32)
+ ml := newMachoLoad(ctxt.Arch, LC_MAIN, 4)
+ ml.data[0] = uint32(uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR)))
+ ml.data[1] = uint32((uint64(Entryvalue(ctxt)) - (Segtext.Vaddr - uint64(HEADR))) >> 32)
}
}
@@ -698,15 +765,17 @@ func asmbMacho(ctxt *Link) {
s2 := ldr.SymSize(ctxt.ArchSyms.LinkEditPLT)
s3 := ldr.SymSize(ctxt.ArchSyms.LinkEditGOT)
s4 := ldr.SymSize(ldr.Lookup(".machosymstr", 0))
+ s5 := ldr.SymSize(ldr.Lookup(".machorebase", 0))
+ s6 := ldr.SymSize(ldr.Lookup(".machobind", 0))
if ctxt.LinkMode != LinkExternal {
ms := newMachoSeg("__LINKEDIT", 0)
ms.vaddr = uint64(Rnd(int64(Segdata.Vaddr+Segdata.Length), int64(*FlagRound)))
- ms.vsize = uint64(s1) + uint64(s2) + uint64(s3) + uint64(s4)
+ ms.vsize = uint64(s1 + s2 + s3 + s4 + s5 + s6)
ms.fileoffset = uint64(linkoff)
ms.filesize = ms.vsize
- ms.prot1 = 7
- ms.prot2 = 3
+ ms.prot1 = 1
+ ms.prot2 = 1
}
ml := newMachoLoad(ctxt.Arch, LC_SYMTAB, 4)
@@ -731,9 +800,23 @@ func asmbMacho(ctxt *Link) {
stringtouint32(ml.data[4:], lib)
}
}
+
+ if ctxt.LinkMode != LinkExternal && ctxt.IsPIE() {
+ ml := newMachoLoad(ctxt.Arch, LC_DYLD_INFO_ONLY, 10)
+ ml.data[0] = uint32(linkoff + s1 + s2 + s3 + s4) // rebase off
+ ml.data[1] = uint32(s5) // rebase size
+ ml.data[2] = uint32(linkoff + s1 + s2 + s3 + s4 + s5) // bind off
+ ml.data[3] = uint32(s6) // bind size
+ ml.data[4] = 0 // weak bind off
+ ml.data[5] = 0 // weak bind size
+ ml.data[6] = 0 // lazy bind off
+ ml.data[7] = 0 // lazy bind size
+ ml.data[8] = 0 // export
+ ml.data[9] = 0 // export size
+ }
}
- a := machowrite(ctxt.Arch, ctxt.Out, ctxt.LinkMode)
+ a := machowrite(ctxt, ctxt.Arch, ctxt.Out, ctxt.LinkMode)
if int32(a) > HEADR {
Exitf("HEADR too small: %d > %d", a, HEADR)
}
@@ -818,12 +901,10 @@ func collectmachosyms(ctxt *Link) {
switch objabi.GOARCH {
case "amd64":
ldr.SetSymExtname(s, n+"$INODE64")
- case "386":
- ldr.SetSymExtname(s, n+"$INODE64$UNIX2003")
}
case "readdir_r", "getfsstat":
switch objabi.GOARCH {
- case "amd64", "386":
+ case "amd64":
ldr.SetSymExtname(s, n+"$INODE64")
}
}
@@ -897,19 +978,12 @@ func machosymtab(ctxt *Link) {
symtab.AddUint32(ctxt.Arch, uint32(symstr.Size()))
export := machoShouldExport(ctxt, ldr, s)
- isGoSymbol := strings.Contains(ldr.SymExtname(s), ".")
-
- // In normal buildmodes, only add _ to C symbols, as
- // Go symbols have dot in the name.
- //
- // Do not export C symbols in plugins, as runtime C
- // symbols like crosscall2 are in pclntab and end up
- // pointing at the host binary, breaking unwinding.
- // See Issue #18190.
- cexport := !isGoSymbol && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(ldr.SymName(s)))
- if cexport || export || isGoSymbol {
- symstr.AddUint8('_')
- }
+
+ // Prefix symbol names with "_" to match the system toolchain.
+ // (We used to only prefix C symbols, which is all required for the build.
+ // But some tools don't recognize Go symbols as symbols, so we prefix them
+ // as well.)
+ symstr.AddUint8('_')
// replace "·" as ".", because DTrace cannot handle it.
symstr.Addstring(strings.Replace(ldr.SymExtname(s), "·", ".", -1))
@@ -920,10 +994,13 @@ func machosymtab(ctxt *Link) {
symtab.AddUint16(ctxt.Arch, 0) // desc
symtab.AddUintXX(ctxt.Arch, 0, ctxt.Arch.PtrSize) // no value
} else {
- if ldr.AttrCgoExport(s) || export {
- symtab.AddUint8(0x0f)
+ if export || ldr.AttrCgoExportDynamic(s) {
+ symtab.AddUint8(0x0f) // N_SECT | N_EXT
+ } else if ldr.AttrCgoExportStatic(s) {
+ // Only export statically, not dynamically. (N_PEXT is like hidden visibility)
+ symtab.AddUint8(0x1f) // N_SECT | N_EXT | N_PEXT
} else {
- symtab.AddUint8(0x0e)
+ symtab.AddUint8(0x0e) // N_SECT
}
o := s
if outer := ldr.OuterSym(o); outer != 0 {
@@ -981,6 +1058,8 @@ func machodysymtab(ctxt *Link) {
func doMachoLink(ctxt *Link) int64 {
machosymtab(ctxt)
+ machoDyldInfo(ctxt)
+
ldr := ctxt.loader
// write data that will be linkedit section
@@ -988,6 +1067,8 @@ func doMachoLink(ctxt *Link) int64 {
s2 := ctxt.ArchSyms.LinkEditPLT
s3 := ctxt.ArchSyms.LinkEditGOT
s4 := ldr.Lookup(".machosymstr", 0)
+ s5 := ldr.Lookup(".machorebase", 0)
+ s6 := ldr.Lookup(".machobind", 0)
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@@ -1011,7 +1092,7 @@ func doMachoLink(ctxt *Link) int64 {
s4b.AddUint8(0)
}
- size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4))
+ size := int(ldr.SymSize(s1) + ldr.SymSize(s2) + ldr.SymSize(s3) + ldr.SymSize(s4) + ldr.SymSize(s5) + ldr.SymSize(s6))
if size > 0 {
linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segrelrodata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
@@ -1021,6 +1102,8 @@ func doMachoLink(ctxt *Link) int64 {
ctxt.Out.Write(ldr.Data(s2))
ctxt.Out.Write(ldr.Data(s3))
ctxt.Out.Write(ldr.Data(s4))
+ ctxt.Out.Write(ldr.Data(s5))
+ ctxt.Out.Write(ldr.Data(s6))
}
return Rnd(int64(size), int64(*FlagRound))
@@ -1164,3 +1247,134 @@ func peekMachoPlatform(m *macho.File) (*MachoPlatformLoad, error) {
}
return nil, nil
}
+
+// A rebase entry tells the dynamic linker the data at sym+off needs to be
+// relocated when the in-memory image moves. (This is somewhat like, say,
+// ELF R_X86_64_RELATIVE).
+// For now, the only kind of entry we support is that the data is an absolute
+// address. That seems all we need.
+// In the binary it uses a compact stateful bytecode encoding. So we record
+// entries as we go and build the table at the end.
+type machoRebaseRecord struct {
+ sym loader.Sym
+ off int64
+}
+
+var machorebase []machoRebaseRecord
+
+func MachoAddRebase(s loader.Sym, off int64) {
+ machorebase = append(machorebase, machoRebaseRecord{s, off})
+}
+
+// A bind entry tells the dynamic linker the data at GOT+off should be bound
+// to the address of the target symbol, which is a dynamic import.
+// For now, the only kind of entry we support is that the data is an absolute
+// address, and the source symbol is always the GOT. That seems all we need.
+// In the binary it uses a compact stateful bytecode encoding. So we record
+// entries as we go and build the table at the end.
+type machoBindRecord struct {
+ off int64
+ targ loader.Sym
+}
+
+var machobind []machoBindRecord
+
+func MachoAddBind(off int64, targ loader.Sym) {
+ machobind = append(machobind, machoBindRecord{off, targ})
+}
+
+// Generate data for the dynamic linker, used in LC_DYLD_INFO_ONLY load command.
+// See mach-o/loader.h, struct dyld_info_command, for the encoding.
+// e.g. https://opensource.apple.com/source/xnu/xnu-6153.81.5/EXTERNAL_HEADERS/mach-o/loader.h
+func machoDyldInfo(ctxt *Link) {
+ ldr := ctxt.loader
+ rebase := ldr.CreateSymForUpdate(".machorebase", 0)
+ bind := ldr.CreateSymForUpdate(".machobind", 0)
+
+ if !(ctxt.IsPIE() && ctxt.IsInternal()) {
+ return
+ }
+
+ segId := func(seg *sym.Segment) uint8 {
+ switch seg {
+ case &Segtext:
+ return 1
+ case &Segrelrodata:
+ return 2
+ case &Segdata:
+ if Segrelrodata.Length > 0 {
+ return 3
+ }
+ return 2
+ }
+ panic("unknown segment")
+ }
+
+ dylibId := func(s loader.Sym) int {
+ slib := ldr.SymDynimplib(s)
+ for i, lib := range dylib {
+ if lib == slib {
+ return i + 1
+ }
+ }
+ return BIND_SPECIAL_DYLIB_FLAT_LOOKUP // don't know where it is from
+ }
+
+ // Rebase table.
+ // TODO: use more compact encoding. The encoding is stateful, and
+ // we can use delta encoding.
+ rebase.AddUint8(REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER)
+ for _, r := range machorebase {
+ seg := ldr.SymSect(r.sym).Seg
+ off := uint64(ldr.SymValue(r.sym)+r.off) - seg.Vaddr
+ rebase.AddUint8(REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
+ rebase.AddUleb(off)
+
+ rebase.AddUint8(REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1)
+ }
+ rebase.AddUint8(REBASE_OPCODE_DONE)
+ sz := Rnd(rebase.Size(), 8)
+ rebase.Grow(sz)
+ rebase.SetSize(sz)
+
+ // Bind table.
+ // TODO: compact encoding, as above.
+ // TODO: lazy binding?
+ got := ctxt.GOT
+ seg := ldr.SymSect(got).Seg
+ gotAddr := ldr.SymValue(got)
+ bind.AddUint8(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER)
+ for _, r := range machobind {
+ off := uint64(gotAddr+r.off) - seg.Vaddr
+ bind.AddUint8(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segId(seg))
+ bind.AddUleb(off)
+
+ d := dylibId(r.targ)
+ if d > 0 && d < 128 {
+ bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | uint8(d)&0xf)
+ } else if d >= 128 {
+ bind.AddUint8(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB)
+ bind.AddUleb(uint64(d))
+ } else { // d <= 0
+ bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
+ }
+
+ bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
+ // target symbol name as a C string, with _ prefix
+ bind.AddUint8('_')
+ bind.Addstring(ldr.SymExtname(r.targ))
+
+ bind.AddUint8(BIND_OPCODE_DO_BIND)
+ }
+ bind.AddUint8(BIND_OPCODE_DONE)
+ sz = Rnd(bind.Size(), 16) // make it 16-byte aligned, see the comment in doMachoLink
+ bind.Grow(sz)
+ bind.SetSize(sz)
+
+ // TODO: export table.
+ // The symbols names are encoded as a trie. I'm really too lazy to do that
+ // for now.
+ // Without it, the symbols are not dynamically exported, so they cannot be
+ // e.g. dlsym'd. But internal linking is not the default in that case, so
+ // it is fine.
+}
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 778b0e9245..5c8293810f 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -36,14 +36,12 @@ import (
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/benchmark"
- "cmd/link/internal/loader"
"flag"
"log"
"os"
"runtime"
"runtime/pprof"
"strings"
- "sync"
)
var (
@@ -67,6 +65,7 @@ var (
flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph")
flagRace = flag.Bool("race", false, "enable race detector")
flagMsan = flag.Bool("msan", false, "enable MSan interface")
+ flagAslr = flag.Bool("aslr", true, "enable ASLR for buildmode=c-shared on windows")
flagFieldTrack = flag.String("k", "", "set field tracking `symbol`")
flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable")
@@ -159,11 +158,16 @@ func Main(arch *sys.Arch, theArch Arch) {
ctxt.HeadType.Set(objabi.GOOS)
}
+ if !*flagAslr && ctxt.BuildMode != BuildModeCShared {
+ Errorf(nil, "-aslr=false is only allowed for -buildmode=c-shared")
+ usage()
+ }
+
checkStrictDups = *FlagStrictDups
startProfile()
if ctxt.BuildMode == BuildModeUnset {
- ctxt.BuildMode = BuildModeExe
+ ctxt.BuildMode.Set("exe")
}
if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 {
@@ -325,16 +329,14 @@ func Main(arch *sys.Arch, theArch Arch) {
// will be applied directly there.
bench.Start("Asmb")
asmb(ctxt)
- // Generate large symbols.
- var wg sync.WaitGroup
- for s, f := range ctxt.generatorSyms {
- wg.Add(1)
- go func(f generatorFunc, s loader.Sym) {
- defer wg.Done()
- f(ctxt, s)
- }(f, s)
+
+ // Generate additional symbols for the native symbol table just prior
+ // to code generation.
+ bench.Start("GenSymsLate")
+ if thearch.GenSymsLate != nil {
+ thearch.GenSymsLate(ctxt, ctxt.loader)
}
- wg.Wait()
+
bench.Start("Asmb2")
asmb2(ctxt)
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 75e63248df..facb30fe15 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -13,7 +13,6 @@ import (
"fmt"
"os"
"path/filepath"
- "strings"
)
// pclntab holds the state needed for pclntab generation.
@@ -113,23 +112,7 @@ func makePclntab(ctxt *Link, container loader.Bitmap) (*pclntab, []*sym.Compilat
return state, compUnits, funcs
}
-// onlycsymbol looks at a symbol's name to report whether this is a
-// symbol that is referenced by C code
-func onlycsymbol(sname string) bool {
- switch sname {
- case "_cgo_topofstack", "__cgo_topofstack", "_cgo_panic", "crosscall2":
- return true
- }
- if strings.HasPrefix(sname, "_cgoexp_") {
- return true
- }
- return false
-}
-
func emitPcln(ctxt *Link, s loader.Sym, container loader.Bitmap) bool {
- if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(ctxt.loader.SymName(s)) {
- return false
- }
// We want to generate func table entries only for the "lowest
// level" symbols, not containers of subsymbols.
return !container.Has(s)
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index dd82963a41..2e2e392c59 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -34,6 +34,7 @@ import (
"cmd/internal/objabi"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
+ "debug/elf"
"fmt"
"path/filepath"
"strings"
@@ -53,10 +54,10 @@ func putelfstr(s string) int {
return off
}
-func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx int, other int) {
+func putelfsyment(out *OutBuf, off int, addr int64, size int64, info uint8, shndx elf.SectionIndex, other int) {
if elf64 {
out.Write32(uint32(off))
- out.Write8(uint8(info))
+ out.Write8(info)
out.Write8(uint8(other))
out.Write16(uint16(shndx))
out.Write64(uint64(addr))
@@ -66,14 +67,14 @@ func putelfsyment(out *OutBuf, off int, addr int64, size int64, info int, shndx
out.Write32(uint32(off))
out.Write32(uint32(addr))
out.Write32(uint32(size))
- out.Write8(uint8(info))
+ out.Write8(info)
out.Write8(uint8(other))
out.Write16(uint16(shndx))
symSize += ELF32SYMSIZE
}
}
-func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
+func putelfsym(ctxt *Link, x loader.Sym, typ elf.SymType, curbind elf.SymBind) {
ldr := ctxt.loader
addr := ldr.SymValue(x)
size := ldr.SymSize(x)
@@ -85,9 +86,9 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
xot := ldr.SymType(xo)
xosect := ldr.SymSect(xo)
- var elfshnum int
+ var elfshnum elf.SectionIndex
if xot == sym.SDYNIMPORT || xot == sym.SHOSTOBJ || xot == sym.SUNDEFEXT {
- elfshnum = SHN_UNDEF
+ elfshnum = elf.SHN_UNDEF
size = 0
} else {
if xosect == nil {
@@ -101,11 +102,11 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
elfshnum = xosect.Elfsect.(*ElfShdr).shnum
}
- // One pass for each binding: STB_LOCAL, STB_GLOBAL,
- // maybe one day STB_WEAK.
- bind := STB_GLOBAL
+ // One pass for each binding: elf.STB_LOCAL, elf.STB_GLOBAL,
+ // maybe one day elf.STB_WEAK.
+ bind := elf.STB_GLOBAL
if ldr.IsFileLocal(x) || ldr.AttrVisibilityHidden(x) || ldr.AttrLocal(x) {
- bind = STB_LOCAL
+ bind = elf.STB_LOCAL
}
// In external linking mode, we have to invoke gcc with -rdynamic
@@ -113,23 +114,23 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
// To avoid filling the dynamic table with lots of unnecessary symbols,
// mark all Go symbols local (not global) in the final executable.
// But when we're dynamically linking, we need all those global symbols.
- if !ctxt.DynlinkingGo() && ctxt.IsExternal() && !ldr.AttrCgoExportStatic(x) && elfshnum != SHN_UNDEF {
- bind = STB_LOCAL
+ if !ctxt.DynlinkingGo() && ctxt.IsExternal() && !ldr.AttrCgoExportStatic(x) && elfshnum != elf.SHN_UNDEF {
+ bind = elf.STB_LOCAL
}
- if ctxt.LinkMode == LinkExternal && elfshnum != SHN_UNDEF {
+ if ctxt.LinkMode == LinkExternal && elfshnum != elf.SHN_UNDEF {
addr -= int64(xosect.Vaddr)
}
- other := STV_DEFAULT
+ other := int(elf.STV_DEFAULT)
if ldr.AttrVisibilityHidden(x) {
// TODO(mwhudson): We only set AttrVisibilityHidden in ldelf, i.e. when
// internally linking. But STV_HIDDEN visibility only matters in object
// files and shared libraries, and as we are a long way from implementing
// internal linking for shared libraries and only create object files when
// externally linking, I don't think this makes a lot of sense.
- other = STV_HIDDEN
+ other = int(elf.STV_HIDDEN)
}
- if ctxt.IsPPC64() && typ == STT_FUNC && ldr.AttrShared(x) && ldr.SymName(x) != "runtime.duffzero" && ldr.SymName(x) != "runtime.duffcopy" {
+ if ctxt.IsPPC64() && typ == elf.STT_FUNC && ldr.AttrShared(x) && ldr.SymName(x) != "runtime.duffzero" && ldr.SymName(x) != "runtime.duffcopy" {
// On ppc64 the top three bits of the st_other field indicate how
// many instructions separate the global and local entry points. In
// our case it is two instructions, indicated by the value 3.
@@ -149,7 +150,7 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
sname = strings.Replace(sname, "·", ".", -1)
}
- if ctxt.DynlinkingGo() && bind == STB_GLOBAL && curbind == STB_LOCAL && ldr.SymType(x) == sym.STEXT {
+ if ctxt.DynlinkingGo() && bind == elf.STB_GLOBAL && curbind == elf.STB_LOCAL && ldr.SymType(x) == sym.STEXT {
// When dynamically linking, we want references to functions defined
// in this module to always be to the function object, not to the
// PLT. We force this by writing an additional local symbol for every
@@ -158,7 +159,7 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
// (*sym.Symbol).ElfsymForReloc). This is approximately equivalent to the
// ELF linker -Bsymbolic-functions option, but that is buggy on
// several platforms.
- putelfsyment(ctxt.Out, putelfstr("local."+sname), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other)
+ putelfsyment(ctxt.Out, putelfstr("local."+sname), addr, size, elf.ST_INFO(elf.STB_LOCAL, typ), elfshnum, other)
ldr.SetSymLocalElfSym(x, int32(ctxt.numelfsym))
ctxt.numelfsym++
return
@@ -166,23 +167,23 @@ func putelfsym(ctxt *Link, x loader.Sym, typ int, curbind int) {
return
}
- putelfsyment(ctxt.Out, putelfstr(sname), addr, size, bind<<4|typ&0xf, elfshnum, other)
+ putelfsyment(ctxt.Out, putelfstr(sname), addr, size, elf.ST_INFO(bind, typ), elfshnum, other)
ldr.SetSymElfSym(x, int32(ctxt.numelfsym))
ctxt.numelfsym++
}
-func putelfsectionsym(ctxt *Link, out *OutBuf, s loader.Sym, shndx int) {
- putelfsyment(out, 0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
+func putelfsectionsym(ctxt *Link, out *OutBuf, s loader.Sym, shndx elf.SectionIndex) {
+ putelfsyment(out, 0, 0, 0, elf.ST_INFO(elf.STB_LOCAL, elf.STT_SECTION), shndx, 0)
ctxt.loader.SetSymElfSym(s, int32(ctxt.numelfsym))
ctxt.numelfsym++
}
-func genelfsym(ctxt *Link, elfbind int) {
+func genelfsym(ctxt *Link, elfbind elf.SymBind) {
ldr := ctxt.loader
// runtime.text marker symbol(s).
s := ldr.Lookup("runtime.text", 0)
- putelfsym(ctxt, s, STT_FUNC, elfbind)
+ putelfsym(ctxt, s, elf.STT_FUNC, elfbind)
for k, sect := range Segtext.Sections[1:] {
n := k + 1
if sect.Name != ".text" || (ctxt.IsAIX() && ctxt.IsExternal()) {
@@ -196,18 +197,18 @@ func genelfsym(ctxt *Link, elfbind int) {
if ldr.SymType(s) != sym.STEXT {
panic("unexpected type for runtime.text symbol")
}
- putelfsym(ctxt, s, STT_FUNC, elfbind)
+ putelfsym(ctxt, s, elf.STT_FUNC, elfbind)
}
// Text symbols.
for _, s := range ctxt.Textp {
- putelfsym(ctxt, s, STT_FUNC, elfbind)
+ putelfsym(ctxt, s, elf.STT_FUNC, elfbind)
}
// runtime.etext marker symbol.
s = ldr.Lookup("runtime.etext", 0)
if ldr.SymType(s) == sym.STEXT {
- putelfsym(ctxt, s, STT_FUNC, elfbind)
+ putelfsym(ctxt, s, elf.STT_FUNC, elfbind)
}
shouldBeInSymbolTable := func(s loader.Sym) bool {
@@ -236,12 +237,12 @@ func genelfsym(ctxt *Link, elfbind int) {
}
st := ldr.SymType(s)
if st >= sym.SELFRXSECT && st < sym.SXREF {
- typ := STT_OBJECT
+ typ := elf.STT_OBJECT
if st == sym.STLSBSS {
if ctxt.IsInternal() {
continue
}
- typ = STT_TLS
+ typ = elf.STT_TLS
}
if !shouldBeInSymbolTable(s) {
continue
@@ -250,7 +251,7 @@ func genelfsym(ctxt *Link, elfbind int) {
continue
}
if st == sym.SHOSTOBJ || st == sym.SDYNIMPORT || st == sym.SUNDEFEXT {
- putelfsym(ctxt, s, int(ldr.SymElfType(s)), elfbind)
+ putelfsym(ctxt, s, ldr.SymElfType(s), elfbind)
}
}
}
@@ -258,7 +259,7 @@ func genelfsym(ctxt *Link, elfbind int) {
func asmElfSym(ctxt *Link) {
// the first symbol entry is reserved
- putelfsyment(ctxt.Out, 0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
+ putelfsyment(ctxt.Out, 0, 0, 0, elf.ST_INFO(elf.STB_LOCAL, elf.STT_NOTYPE), 0, 0)
dwarfaddelfsectionsyms(ctxt)
@@ -266,12 +267,12 @@ func asmElfSym(ctxt *Link) {
// Avoid having the working directory inserted into the symbol table.
// It is added with a name to avoid problems with external linking
// encountered on some versions of Solaris. See issue #14957.
- putelfsyment(ctxt.Out, putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
+ putelfsyment(ctxt.Out, putelfstr("go.go"), 0, 0, elf.ST_INFO(elf.STB_LOCAL, elf.STT_FILE), elf.SHN_ABS, 0)
ctxt.numelfsym++
- bindings := []int{STB_LOCAL, STB_GLOBAL}
+ bindings := []elf.SymBind{elf.STB_LOCAL, elf.STB_GLOBAL}
for _, elfbind := range bindings {
- if elfbind == STB_GLOBAL {
+ if elfbind == elf.STB_GLOBAL {
elfglobalsymndx = ctxt.numelfsym
}
genelfsym(ctxt, elfbind)
@@ -580,8 +581,12 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind {
symGroupType[s] = sym.SGOFUNC
ldr.SetAttrNotInSymbolTable(s, true)
ldr.SetCarrierSym(s, symgofunc)
- const align = 4
- ldr.SetSymAlign(s, align)
+ align := int32(4)
+ if a := ldr.SymAlign(s); a < align {
+ ldr.SetSymAlign(s, align)
+ } else {
+ align = a
+ }
liveness += (ldr.SymSize(s) + int64(align) - 1) &^ (int64(align) - 1)
}
}
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 19d8d98b1e..d861efcb13 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -1791,6 +1791,11 @@ func (l *Loader) SortSub(s Sym) Sym {
return sl[0].s
}
+// SortSyms sorts a list of symbols by their value.
+func (l *Loader) SortSyms(ss []Sym) {
+ sort.SliceStable(ss, func(i, j int) bool { return l.SymValue(ss[i]) < l.SymValue(ss[j]) })
+}
+
// Insure that reachable bitmap and its siblings have enough size.
func (l *Loader) growAttrBitmaps(reqLen int) {
if reqLen > l.attrReachable.Len() {
@@ -2617,11 +2622,15 @@ func (l *Loader) Dump() {
fmt.Println("Nsyms:", len(l.objSyms))
fmt.Println("syms")
for i := Sym(1); i < Sym(len(l.objSyms)); i++ {
- pi := interface{}("")
+ pi := ""
if l.IsExternal(i) {
pi = fmt.Sprintf("<ext %d>", l.extIndex(i))
}
- fmt.Println(i, l.SymName(i), l.SymType(i), pi)
+ sect := ""
+ if l.SymSect(i) != nil {
+ sect = l.SymSect(i).Name
+ }
+ fmt.Printf("%v %v %v %v %x %v\n", i, l.SymName(i), l.SymType(i), pi, l.SymValue(i), sect)
}
fmt.Println("symsByName")
for name, i := range l.symsByName[0] {
diff --git a/src/cmd/link/internal/loader/symbolbuilder.go b/src/cmd/link/internal/loader/symbolbuilder.go
index c0c723d7f0..5d37da8ac6 100644
--- a/src/cmd/link/internal/loader/symbolbuilder.go
+++ b/src/cmd/link/internal/loader/symbolbuilder.go
@@ -420,3 +420,21 @@ func (sb *SymbolBuilder) MakeWritable() {
sb.l.SetAttrReadOnly(sb.symIdx, false)
}
}
+
+func (sb *SymbolBuilder) AddUleb(v uint64) {
+ if v < 128 { // common case: 1 byte
+ sb.AddUint8(uint8(v))
+ return
+ }
+ for {
+ c := uint8(v & 0x7f)
+ v >>= 7
+ if v != 0 {
+ c |= 0x80
+ }
+ sb.AddUint8(c)
+ if c&0x80 == 0 {
+ break
+ }
+ }
+}
diff --git a/src/cmd/link/internal/loadmacho/ldmacho.go b/src/cmd/link/internal/loadmacho/ldmacho.go
index 864d80835b..d12f2bc2ac 100644
--- a/src/cmd/link/internal/loadmacho/ldmacho.go
+++ b/src/cmd/link/internal/loadmacho/ldmacho.go
@@ -43,7 +43,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
-// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld
+// TODO(crawshaw): de-duplicate these symbols with cmd/link/internal/ld
const (
MACHO_X86_64_RELOC_UNSIGNED = 0
MACHO_X86_64_RELOC_SIGNED = 1
@@ -172,11 +172,12 @@ const (
LdMachoCpuVax = 1
LdMachoCpu68000 = 6
LdMachoCpu386 = 7
- LdMachoCpuAmd64 = 0x1000007
+ LdMachoCpuAmd64 = 1<<24 | 7
LdMachoCpuMips = 8
LdMachoCpu98000 = 10
LdMachoCpuHppa = 11
LdMachoCpuArm = 12
+ LdMachoCpuArm64 = 1<<24 | 12
LdMachoCpu88000 = 13
LdMachoCpuSparc = 14
LdMachoCpu860 = 15
@@ -471,11 +472,14 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
switch arch.Family {
default:
return errorf("mach-o %s unimplemented", arch.Name)
-
case sys.AMD64:
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
return errorf("mach-o object but not amd64")
}
+ case sys.ARM64:
+ if e != binary.LittleEndian || m.cputype != LdMachoCpuArm64 {
+ return errorf("mach-o object but not arm64")
+ }
}
m.cmd = make([]ldMachoCmd, ncmd)
@@ -633,7 +637,9 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
}
bld.SetType(l.SymType(outer))
- l.AddInteriorSym(outer, s)
+ if l.SymSize(outer) != 0 { // skip empty section (0-sized symbol)
+ l.AddInteriorSym(outer, s)
+ }
bld.SetValue(int64(machsym.value - sect.addr))
if !l.AttrCgoExportDynamic(s) {
@@ -722,27 +728,28 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
// Handle X86_64_RELOC_SIGNED referencing a section (rel.extrn == 0).
p := l.Data(s)
- if arch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
- // Calculate the addend as the offset into the section.
- //
- // The rip-relative offset stored in the object file is encoded
- // as follows:
- //
- // movsd 0x00000360(%rip),%xmm0
- //
- // To get the absolute address of the value this rip-relative address is pointing
- // to, we must add the address of the next instruction to it. This is done by
- // taking the address of the relocation and adding 4 to it (since the rip-relative
- // offset can at most be 32 bits long). To calculate the offset into the section the
- // relocation is referencing, we subtract the vaddr of the start of the referenced
- // section found in the original object file.
- //
- // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
- secaddr := c.seg.sect[rel.symnum-1].addr
-
- rAdd = int64(uint64(int64(int32(e.Uint32(p[rOff:])))+int64(rOff)+4) - secaddr)
- } else {
- rAdd = int64(int32(e.Uint32(p[rOff:])))
+ if arch.Family == sys.AMD64 {
+ if rel.extrn == 0 && rel.type_ == MACHO_X86_64_RELOC_SIGNED {
+ // Calculate the addend as the offset into the section.
+ //
+ // The rip-relative offset stored in the object file is encoded
+ // as follows:
+ //
+ // movsd 0x00000360(%rip),%xmm0
+ //
+ // To get the absolute address of the value this rip-relative address is pointing
+ // to, we must add the address of the next instruction to it. This is done by
+ // taking the address of the relocation and adding 4 to it (since the rip-relative
+ // offset can at most be 32 bits long). To calculate the offset into the section the
+ // relocation is referencing, we subtract the vaddr of the start of the referenced
+ // section found in the original object file.
+ //
+ // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+ secaddr := c.seg.sect[rel.symnum-1].addr
+ rAdd = int64(uint64(int64(int32(e.Uint32(p[rOff:])))+int64(rOff)+4) - secaddr)
+ } else {
+ rAdd = int64(int32(e.Uint32(p[rOff:])))
+ }
}
// An unsigned internal relocation has a value offset
diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go
index d2dc20f5c1..01d89a209c 100644
--- a/src/cmd/link/internal/mips64/obj.go
+++ b/src/cmd/link/internal/mips64/obj.go
@@ -60,7 +60,7 @@ func Init() (*sys.Arch, ld.Arch) {
Linuxdynld: "/lib64/ld64.so.1",
Freebsddynld: "XXX",
- Openbsddynld: "XXX",
+ Openbsddynld: "/usr/libexec/ld.so",
Netbsddynld: "XXX",
Dragonflydynld: "XXX",
Solarisdynld: "XXX",
@@ -84,7 +84,8 @@ func archinit(ctxt *ld.Link) {
*ld.FlagRound = 16 * 1024
}
- case objabi.Hlinux: /* mips64 elf */
+ case objabi.Hlinux, /* mips64 elf */
+ objabi.Hopenbsd:
ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
if *ld.FlagTextAddr == -1 {
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index dc522e6a38..5bf3898eb9 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -313,7 +313,7 @@ func addelfdynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s lo
rela := ldr.MakeSymbolUpdater(syms.Rela)
rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_PPC64_ADDR64)))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_PPC64_ADDR64)))
rela.AddUint64(target.Arch, uint64(r.Add()))
su.SetRelocType(rIdx, objabi.ElfRelocOffset) // ignore during relocsym
}
@@ -994,9 +994,10 @@ func addpltsym(ctxt *ld.Link, ldr *loader.Loader, s loader.Sym) {
ldr.SetPlt(s, int32(plt.Size()))
plt.Grow(plt.Size() + 8)
+ plt.SetSize(plt.Size() + 8)
rela.AddAddrPlus(ctxt.Arch, plt.Sym(), int64(ldr.SymPlt(s)))
- rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_PPC64_JMP_SLOT)))
+ rela.AddUint64(ctxt.Arch, elf.R_INFO(uint32(ldr.SymDynid(s)), uint32(elf.R_PPC64_JMP_SLOT)))
rela.AddUint64(ctxt.Arch, 0)
} else {
ctxt.Errorf(s, "addpltsym: unsupported binary format")
@@ -1052,7 +1053,7 @@ func ensureglinkresolver(ctxt *ld.Link, ldr *loader.Loader) *loader.SymbolBuilde
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
// before the first symbol resolver stub.
du := ldr.MakeSymbolUpdater(ctxt.Dynamic)
- ld.Elfwritedynentsymplus(ctxt, du, ld.DT_PPC64_GLINK, glink.Sym(), glink.Size()-32)
+ ld.Elfwritedynentsymplus(ctxt, du, elf.DT_PPC64_GLINK, glink.Sym(), glink.Size()-32)
return glink
}
diff --git a/src/cmd/link/internal/riscv64/asm.go b/src/cmd/link/internal/riscv64/asm.go
index 1236145fb1..c18e0540d8 100644
--- a/src/cmd/link/internal/riscv64/asm.go
+++ b/src/cmd/link/internal/riscv64/asm.go
@@ -11,20 +11,143 @@ import (
"cmd/link/internal/ld"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
+ "debug/elf"
"fmt"
"log"
+ "sort"
)
+// fakeLabelName matches the RISCV_FAKE_LABEL_NAME from binutils.
+const fakeLabelName = ".L0 "
+
func gentext(ctxt *ld.Link, ldr *loader.Loader) {
}
+func genSymsLate(ctxt *ld.Link, ldr *loader.Loader) {
+ if ctxt.LinkMode != ld.LinkExternal {
+ return
+ }
+
+ // Generate a local text symbol for each relocation target, as the
+ // R_RISCV_PCREL_LO12_* relocations generated by elfreloc1 need it.
+ if ctxt.Textp == nil {
+ log.Fatal("genSymsLate called before Textp has been assigned")
+ }
+ var hi20Syms []loader.Sym
+ for _, s := range ctxt.Textp {
+ relocs := ldr.Relocs(s)
+ for ri := 0; ri < relocs.Count(); ri++ {
+ r := relocs.At(ri)
+ if r.Type() != objabi.R_RISCV_PCREL_ITYPE && r.Type() != objabi.R_RISCV_PCREL_STYPE &&
+ r.Type() != objabi.R_RISCV_TLS_IE_ITYPE && r.Type() != objabi.R_RISCV_TLS_IE_STYPE {
+ continue
+ }
+ if r.Off() == 0 && ldr.SymType(s) == sym.STEXT {
+ // Use the symbol for the function instead of creating
+ // an overlapping symbol.
+ continue
+ }
+
+ // TODO(jsing): Consider generating ELF symbols without needing
+ // loader symbols, in order to reduce memory consumption. This
+ // would require changes to genelfsym so that it called
+ // putelfsym and putelfsyment as appropriate.
+ sb := ldr.MakeSymbolBuilder(fakeLabelName)
+ sb.SetType(sym.STEXT)
+ sb.SetValue(ldr.SymValue(s) + int64(r.Off()))
+ sb.SetLocal(true)
+ sb.SetReachable(true)
+ sb.SetVisibilityHidden(true)
+ sb.SetSect(ldr.SymSect(s))
+ if outer := ldr.OuterSym(s); outer != 0 {
+ ldr.AddInteriorSym(outer, sb.Sym())
+ }
+ hi20Syms = append(hi20Syms, sb.Sym())
+ }
+ }
+ ctxt.Textp = append(ctxt.Textp, hi20Syms...)
+ ldr.SortSyms(ctxt.Textp)
+}
+
+func findHI20Symbol(ctxt *ld.Link, ldr *loader.Loader, val int64) loader.Sym {
+ idx := sort.Search(len(ctxt.Textp), func(i int) bool { return ldr.SymValue(ctxt.Textp[i]) >= val })
+ if idx >= len(ctxt.Textp) {
+ return 0
+ }
+ if s := ctxt.Textp[idx]; ldr.SymValue(s) == val && ldr.SymType(s) == sym.STEXT {
+ return s
+ }
+ return 0
+}
+
func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
- log.Fatalf("elfreloc1")
- return false
+ elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
+ switch r.Type {
+ case objabi.R_ADDR, objabi.R_DWARFSECREF:
+ out.Write64(uint64(sectoff))
+ switch r.Size {
+ case 4:
+ out.Write64(uint64(elf.R_RISCV_32) | uint64(elfsym)<<32)
+ case 8:
+ out.Write64(uint64(elf.R_RISCV_64) | uint64(elfsym)<<32)
+ default:
+ ld.Errorf(nil, "unknown size %d for %v relocation", r.Size, r.Type)
+ return false
+ }
+ out.Write64(uint64(r.Xadd))
+
+ case objabi.R_CALLRISCV:
+ // Call relocations are currently handled via R_RISCV_PCREL_ITYPE.
+ // TODO(jsing): Consider generating elf.R_RISCV_CALL instead of a
+ // HI20/LO12_I pair.
+
+ case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
+ // Find the text symbol for the AUIPC instruction targeted
+ // by this relocation.
+ relocs := ldr.Relocs(s)
+ offset := int64(relocs.At(ri).Off())
+ hi20Sym := findHI20Symbol(ctxt, ldr, ldr.SymValue(s)+offset)
+ if hi20Sym == 0 {
+ ld.Errorf(nil, "failed to find text symbol for HI20 relocation at %d (%x)", sectoff, ldr.SymValue(s)+offset)
+ return false
+ }
+ hi20ElfSym := ld.ElfSymForReloc(ctxt, hi20Sym)
+
+ // Emit two relocations - a R_RISCV_PCREL_HI20 relocation and a
+ // corresponding R_RISCV_PCREL_LO12_I or R_RISCV_PCREL_LO12_S relocation.
+ // Note that the LO12 relocation must point to a target that has a valid
+ // HI20 PC-relative relocation text symbol, which in turn points to the
+ // given symbol. For further details see the ELF specification for RISC-V:
+ //
+ // https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#pc-relative-symbol-addresses
+ //
+ var hiRel, loRel elf.R_RISCV
+ switch r.Type {
+ case objabi.R_RISCV_PCREL_ITYPE:
+ hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_I
+ case objabi.R_RISCV_PCREL_STYPE:
+ hiRel, loRel = elf.R_RISCV_PCREL_HI20, elf.R_RISCV_PCREL_LO12_S
+ case objabi.R_RISCV_TLS_IE_ITYPE:
+ hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_I
+ case objabi.R_RISCV_TLS_IE_STYPE:
+ hiRel, loRel = elf.R_RISCV_TLS_GOT_HI20, elf.R_RISCV_PCREL_LO12_S
+ }
+ out.Write64(uint64(sectoff))
+ out.Write64(uint64(hiRel) | uint64(elfsym)<<32)
+ out.Write64(uint64(r.Xadd))
+ out.Write64(uint64(sectoff + 4))
+ out.Write64(uint64(loRel) | uint64(hi20ElfSym)<<32)
+ out.Write64(uint64(0))
+
+ default:
+ return false
+ }
+
+ return true
}
func elfsetupplt(ctxt *ld.Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym) {
- log.Fatalf("elfsetuplt")
+ log.Fatalf("elfsetupplt")
}
func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
@@ -33,13 +156,35 @@ func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtRe
}
func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (o int64, nExtReloc int, ok bool) {
- rs := r.Sym()
- rs = ldr.ResolveABIAlias(rs)
+ if target.IsExternal() {
+ switch r.Type() {
+ case objabi.R_CALLRISCV:
+ return val, 0, true
+
+ case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
+ return val, 2, true
+ }
+
+ return val, 0, false
+ }
+
+ rs := ldr.ResolveABIAlias(r.Sym())
+
switch r.Type() {
case objabi.R_CALLRISCV:
// Nothing to do.
return val, 0, true
+ case objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
+ // TLS relocations are not currently handled for internal linking.
+ // For now, TLS is only used when cgo is in use and cgo currently
+ // requires external linking. However, we need to accept these
+ // relocations so that code containing TLS variables will link,
+ // even when they're not being used. For now, replace these
+ // instructions with EBREAK to detect accidental use.
+ const ebreakIns = 0x00100073
+ return ebreakIns<<32 | ebreakIns, 0, true
+
case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE:
pc := ldr.SymValue(s) + int64(r.Off())
off := ldr.SymValue(rs) + r.Add() - pc
@@ -89,3 +234,11 @@ func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant
log.Fatalf("archrelocvariant")
return -1
}
+
+func extreloc(target *ld.Target, ldr *loader.Loader, r loader.Reloc, s loader.Sym) (loader.ExtReloc, bool) {
+ switch r.Type() {
+ case objabi.R_RISCV_PCREL_ITYPE, objabi.R_RISCV_PCREL_STYPE, objabi.R_RISCV_TLS_IE_ITYPE, objabi.R_RISCV_TLS_IE_STYPE:
+ return ld.ExtrelocViaOuterSym(ldr, r, s), true
+ }
+ return loader.ExtReloc{}, false
+}
diff --git a/src/cmd/link/internal/riscv64/obj.go b/src/cmd/link/internal/riscv64/obj.go
index e66d3cd856..917324d922 100644
--- a/src/cmd/link/internal/riscv64/obj.go
+++ b/src/cmd/link/internal/riscv64/obj.go
@@ -23,9 +23,12 @@ func Init() (*sys.Arch, ld.Arch) {
Archinit: archinit,
Archreloc: archreloc,
Archrelocvariant: archrelocvariant,
+ Extreloc: extreloc,
Elfreloc1: elfreloc1,
+ ElfrelocSize: 24,
Elfsetupplt: elfsetupplt,
Gentext: gentext,
+ GenSymsLate: genSymsLate,
Machoreloc1: machoreloc1,
Linuxdynld: "/lib/ld.so.1",
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index 645b7d4e28..78d2cc81e4 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -444,7 +444,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
sDynid := ldr.SymDynid(s)
- rela.AddUint64(target.Arch, ld.ELF64_R_INFO(uint32(sDynid), uint32(elf.R_390_JMP_SLOT)))
+ rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_390_JMP_SLOT)))
rela.AddUint64(target.Arch, 0)
ldr.SetPlt(s, int32(plt.Size()-32))
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index 9b949ebbf8..af0ce11255 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -303,7 +303,7 @@ func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
ld.Adddynsym(ldr, target, syms, targ)
rel := ldr.MakeSymbolUpdater(syms.Rel)
rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
su := ldr.MakeSymbolUpdater(s)
su.SetRelocType(rIdx, objabi.R_CONST) // write r->add during relocsym
su.SetRelocSym(rIdx, 0)
@@ -483,7 +483,7 @@ func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loade
rel.AddAddrPlus(target.Arch, got.Sym(), got.Size()-4)
sDynid := ldr.SymDynid(s)
- rel.AddUint32(target.Arch, ld.ELF32_R_INFO(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
+ rel.AddUint32(target.Arch, elf.R_INFO32(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
ldr.SetPlt(s, int32(plt.Size()-16))
} else {
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index b7611f207c..204410e976 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -181,6 +181,7 @@ main.x: relocation target main.zero not defined
func TestIssue33979(t *testing.T) {
testenv.MustHaveGoBuild(t)
testenv.MustHaveCGO(t)
+ testenv.MustInternalLink(t)
// Skip test on platforms that do not support cgo internal linking.
switch runtime.GOARCH {
@@ -308,7 +309,7 @@ func TestBuildForTvOS(t *testing.T) {
cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", ar, lib)
cmd.Env = append(os.Environ(),
"CGO_ENABLED=1",
- "GOOS=darwin",
+ "GOOS=ios",
"GOARCH=arm64",
"CC="+strings.Join(CC, " "),
"CGO_CFLAGS=", // ensure CGO_CFLAGS does not contain any flags. Issue #35459
@@ -819,3 +820,56 @@ func TestReadOnly(t *testing.T) {
t.Errorf("running test program did not fail. output:\n%s", out)
}
}
+
+const testIssue38554Src = `
+package main
+
+type T [10<<20]byte
+
+//go:noinline
+func f() T {
+ return T{} // compiler will make a large stmp symbol, but not used.
+}
+
+func main() {
+ x := f()
+ println(x[1])
+}
+`
+
+func TestIssue38554(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ t.Parallel()
+
+ tmpdir, err := ioutil.TempDir("", "TestIssue38554")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ src := filepath.Join(tmpdir, "x.go")
+ err = ioutil.WriteFile(src, []byte(testIssue38554Src), 0666)
+ if err != nil {
+ t.Fatalf("failed to write source file: %v", err)
+ }
+ exe := filepath.Join(tmpdir, "x.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failed: %v\n%s", err, out)
+ }
+
+ fi, err := os.Stat(exe)
+ if err != nil {
+ t.Fatalf("failed to stat output file: %v", err)
+ }
+
+ // The test program is not much different from a helloworld, which is
+ // typically a little over 1 MB. We allow 5 MB. If the bad stmp is live,
+ // it will be over 10 MB.
+ const want = 5 << 20
+ if got := fi.Size(); got > want {
+ t.Errorf("binary too big: got %d, want < %d", got, want)
+ }
+}
diff --git a/src/cmd/nm/nm_cgo_test.go b/src/cmd/nm/nm_cgo_test.go
index 9a257e0ed2..58f2c24908 100644
--- a/src/cmd/nm/nm_cgo_test.go
+++ b/src/cmd/nm/nm_cgo_test.go
@@ -15,6 +15,11 @@ func canInternalLink() bool {
switch runtime.GOOS {
case "aix":
return false
+ case "darwin":
+ switch runtime.GOARCH {
+ case "arm64":
+ return false
+ }
case "dragonfly":
return false
case "freebsd":
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index 413a4eb06f..382446e9fe 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -173,6 +173,9 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
if runtime.GOOS == "windows" {
return true
}
+ if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
+ return true // On darwin/arm64 everything is PIE
+ }
return false
}
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 85d1a2efb0..cb692e7a81 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -106,6 +106,17 @@ var ppcGnuNeed = []string{
"cmpw",
}
+func mustHaveDisasm(t *testing.T) {
+ switch runtime.GOARCH {
+ case "mips", "mipsle", "mips64", "mips64le":
+ t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
+ case "riscv64":
+ t.Skipf("skipping on %s, issue 36738", runtime.GOARCH)
+ case "s390x":
+ t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
+ }
+}
+
var target = flag.String("target", "", "test disassembly of `goos/goarch` binary")
// objdump is fully cross platform: it can handle binaries
@@ -118,6 +129,7 @@ var target = flag.String("target", "", "test disassembly of `goos/goarch` binary
// can handle that one.
func testDisasm(t *testing.T, srcfname string, printCode bool, printGnuAsm bool, flags ...string) {
+ mustHaveDisasm(t)
goarch := runtime.GOARCH
if *target != "" {
f := strings.Split(*target, "/")
@@ -227,71 +239,38 @@ func testGoAndCgoDisasm(t *testing.T, printCode bool, printGnuAsm bool) {
testDisasm(t, "fmthello.go", printCode, printGnuAsm)
if build.Default.CgoEnabled {
if runtime.GOOS == "aix" {
- t.Skipf("skipping on %s, issue 40972", runtime.GOOS)
+ return // issue 40972
}
testDisasm(t, "fmthellocgo.go", printCode, printGnuAsm)
}
}
func TestDisasm(t *testing.T) {
- switch runtime.GOARCH {
- case "mips", "mipsle", "mips64", "mips64le":
- t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
- case "riscv64":
- t.Skipf("skipping on %s, issue 36738", runtime.GOARCH)
- case "s390x":
- t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
- }
testGoAndCgoDisasm(t, false, false)
}
func TestDisasmCode(t *testing.T) {
- switch runtime.GOARCH {
- case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x":
- t.Skipf("skipping on %s, issue 19160", runtime.GOARCH)
- }
testGoAndCgoDisasm(t, true, false)
}
func TestDisasmGnuAsm(t *testing.T) {
- switch runtime.GOARCH {
- case "mips", "mipsle", "mips64", "mips64le", "riscv64", "s390x":
- t.Skipf("skipping on %s, issue 19160", runtime.GOARCH)
- }
testGoAndCgoDisasm(t, false, true)
}
func TestDisasmExtld(t *testing.T) {
+ testenv.MustHaveCGO(t)
switch runtime.GOOS {
case "plan9", "windows":
t.Skipf("skipping on %s", runtime.GOOS)
- }
- switch runtime.GOARCH {
- case "ppc64":
- t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
- case "mips64", "mips64le", "mips", "mipsle":
- t.Skipf("skipping on %s, issue 12559 and 12560", runtime.GOARCH)
- case "riscv64":
- t.Skipf("skipping on %s, no support for external linking, issue 36739", runtime.GOARCH)
- case "s390x":
- t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
- }
- if !build.Default.CgoEnabled {
- t.Skip("skipping because cgo is not enabled")
+ case "aix":
+ t.Skipf("skipping on AIX, see issue 40972")
}
t.Parallel()
testDisasm(t, "fmthello.go", false, false, "-ldflags=-linkmode=external")
}
func TestDisasmGoobj(t *testing.T) {
- switch runtime.GOARCH {
- case "mips", "mipsle", "mips64", "mips64le":
- t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
- case "riscv64":
- t.Skipf("skipping on %s, issue 36738", runtime.GOARCH)
- case "s390x":
- t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
- }
+ mustHaveDisasm(t)
hello := filepath.Join(tmp, "hello.o")
args := []string{"tool", "compile", "-o", hello}
@@ -333,3 +312,42 @@ func TestDisasmGoobj(t *testing.T) {
t.Logf("full disassembly:\n%s", text)
}
}
+
+func TestGoobjFileNumber(t *testing.T) {
+ // Test that file table in Go object file is parsed correctly.
+ testenv.MustHaveGoBuild(t)
+ mustHaveDisasm(t)
+
+ t.Parallel()
+
+ tmpdir, err := ioutil.TempDir("", "TestGoobjFileNumber")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ obj := filepath.Join(tmpdir, "p.a")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", obj)
+ cmd.Dir = filepath.Join("testdata/testfilenum")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("build failed: %v\n%s", err, out)
+ }
+
+ cmd = exec.Command(exe, obj)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("objdump failed: %v\n%s", err, out)
+ }
+
+ text := string(out)
+ for _, s := range []string{"a.go", "b.go", "c.go"} {
+ if !strings.Contains(text, s) {
+ t.Errorf("output missing '%s'", s)
+ }
+ }
+
+ if t.Failed() {
+ t.Logf("output:\n%s", text)
+ }
+}
diff --git a/src/cmd/objdump/testdata/testfilenum/a.go b/src/cmd/objdump/testdata/testfilenum/a.go
new file mode 100644
index 0000000000..2729ae0abf
--- /dev/null
+++ b/src/cmd/objdump/testdata/testfilenum/a.go
@@ -0,0 +1,7 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func A() {}
diff --git a/src/cmd/objdump/testdata/testfilenum/b.go b/src/cmd/objdump/testdata/testfilenum/b.go
new file mode 100644
index 0000000000..a632aafe7b
--- /dev/null
+++ b/src/cmd/objdump/testdata/testfilenum/b.go
@@ -0,0 +1,7 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func B() {}
diff --git a/src/cmd/objdump/testdata/testfilenum/c.go b/src/cmd/objdump/testdata/testfilenum/c.go
new file mode 100644
index 0000000000..d73efa7315
--- /dev/null
+++ b/src/cmd/objdump/testdata/testfilenum/c.go
@@ -0,0 +1,7 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func C() {}
diff --git a/src/cmd/objdump/testdata/testfilenum/go.mod b/src/cmd/objdump/testdata/testfilenum/go.mod
new file mode 100644
index 0000000000..db432883a9
--- /dev/null
+++ b/src/cmd/objdump/testdata/testfilenum/go.mod
@@ -0,0 +1,3 @@
+module objdumptest
+
+go 1.16
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
index c4e116becd..82546ea7dc 100644
--- a/src/cmd/pack/pack.go
+++ b/src/cmd/pack/pack.go
@@ -8,6 +8,7 @@ import (
"cmd/internal/archive"
"fmt"
"io"
+ "io/fs"
"log"
"os"
"path/filepath"
@@ -221,7 +222,7 @@ func (ar *Archive) addFiles() {
// FileLike abstracts the few methods we need, so we can test without needing real files.
type FileLike interface {
Name() string
- Stat() (os.FileInfo, error)
+ Stat() (fs.FileInfo, error)
Read([]byte) (int, error)
Close() error
}
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index 2108330742..9f65705def 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -11,6 +11,7 @@ import (
"fmt"
"internal/testenv"
"io"
+ "io/fs"
"io/ioutil"
"os"
"os/exec"
@@ -327,11 +328,11 @@ var goodbyeFile = &FakeFile{
mode: 0644,
}
-// FakeFile implements FileLike and also os.FileInfo.
+// FakeFile implements FileLike and also fs.FileInfo.
type FakeFile struct {
name string
contents string
- mode os.FileMode
+ mode fs.FileMode
offset int
}
@@ -348,7 +349,7 @@ func (f *FakeFile) Name() string {
return f.name
}
-func (f *FakeFile) Stat() (os.FileInfo, error) {
+func (f *FakeFile) Stat() (fs.FileInfo, error) {
return f, nil
}
@@ -365,13 +366,13 @@ func (f *FakeFile) Close() error {
return nil
}
-// os.FileInfo methods.
+// fs.FileInfo methods.
func (f *FakeFile) Size() int64 {
return int64(len(f.contents))
}
-func (f *FakeFile) Mode() os.FileMode {
+func (f *FakeFile) Mode() fs.FileMode {
return f.mode
}
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 903f9cc1db..11f91cbedb 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -13,7 +13,7 @@ import (
"crypto/tls"
"debug/dwarf"
"fmt"
- "io/ioutil"
+ "io"
"net/http"
"net/url"
"os"
@@ -94,7 +94,7 @@ func getProfile(source string, timeout time.Duration) (*profile.Profile, error)
func statusCodeError(resp *http.Response) error {
if resp.Header.Get("X-Go-Pprof") != "" && strings.Contains(resp.Header.Get("Content-Type"), "text/plain") {
// error is from pprof endpoint
- if body, err := ioutil.ReadAll(resp.Body); err == nil {
+ if body, err := io.ReadAll(resp.Body); err == nil {
return fmt.Errorf("server response: %s - %s", resp.Status, body)
}
}
@@ -171,7 +171,10 @@ func (*objTool) Demangle(names []string) (map[string]string, error) {
return make(map[string]string), nil
}
-func (t *objTool) Disasm(file string, start, end uint64) ([]driver.Inst, error) {
+func (t *objTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]driver.Inst, error) {
+ if intelSyntax {
+ return nil, fmt.Errorf("printing assembly in Intel syntax is not supported")
+ }
d, err := t.cachedDisasm(file)
if err != nil {
return nil, err
diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go
index dd12e8cd20..ea0cc6f880 100644
--- a/src/cmd/trace/trace_test.go
+++ b/src/cmd/trace/trace_test.go
@@ -10,7 +10,7 @@ import (
"cmd/internal/traceviewer"
"context"
"internal/trace"
- "io/ioutil"
+ "io"
rtrace "runtime/trace"
"strings"
"sync"
@@ -78,7 +78,7 @@ func TestGoroutineCount(t *testing.T) {
// Use the default viewerDataTraceConsumer but replace
// consumeViewerEvent to intercept the ViewerEvents for testing.
- c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1)
+ c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
if ev.Name == "Goroutines" {
cnt := ev.Arg.(*goroutineCountersArg)
@@ -131,7 +131,7 @@ func TestGoroutineFilter(t *testing.T) {
gs: map[uint64]bool{10: true},
}
- c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1)
+ c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
if err := generateTrace(params, c); err != nil {
t.Fatalf("generateTrace failed: %v", err)
}
@@ -163,7 +163,7 @@ func TestPreemptedMarkAssist(t *testing.T) {
endTime: int64(1<<63 - 1),
}
- c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1)
+ c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
marks := 0
c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
@@ -214,7 +214,7 @@ func TestFoo(t *testing.T) {
tasks: []*taskDesc{task},
}
- c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1)
+ c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
var logBeforeTaskEnd, logAfterTaskEnd bool
c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
diff --git a/src/cmd/trace/trace_unix_test.go b/src/cmd/trace/trace_unix_test.go
index 645978e0f8..c569b40bb2 100644
--- a/src/cmd/trace/trace_unix_test.go
+++ b/src/cmd/trace/trace_unix_test.go
@@ -10,7 +10,7 @@ import (
"bytes"
"cmd/internal/traceviewer"
traceparser "internal/trace"
- "io/ioutil"
+ "io"
"runtime"
"runtime/trace"
"sync"
@@ -83,7 +83,7 @@ func TestGoroutineInSyscall(t *testing.T) {
// Check only one thread for the pipe read goroutine is
// considered in-syscall.
- c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1)
+ c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1)
c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) {
if ev.Name == "Threads" {
arg := ev.Arg.(*threadCountersArg)
diff --git a/src/cmd/vendor/github.com/google/pprof/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/driver/driver.go
index 9bcbc8295a..e65bc2f417 100644
--- a/src/cmd/vendor/github.com/google/pprof/driver/driver.go
+++ b/src/cmd/vendor/github.com/google/pprof/driver/driver.go
@@ -142,7 +142,7 @@ type ObjTool interface {
// Disasm disassembles the named object file, starting at
// the start address and stopping at (before) the end address.
- Disasm(file string, start, end uint64) ([]Inst, error)
+ Disasm(file string, start, end uint64, intelSyntax bool) ([]Inst, error)
}
// An Inst is a single instruction in an assembly listing.
@@ -269,8 +269,8 @@ func (f *internalObjFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym,
return pluginSyms, nil
}
-func (o *internalObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
- insts, err := o.ObjTool.Disasm(file, start, end)
+func (o *internalObjTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) {
+ insts, err := o.ObjTool.Disasm(file, start, end, intelSyntax)
if err != nil {
return nil, err
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
index 967726d1fa..4b67cc4ab0 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
@@ -19,6 +19,7 @@ import (
"debug/elf"
"debug/macho"
"encoding/binary"
+ "errors"
"fmt"
"io"
"os"
@@ -26,6 +27,7 @@ import (
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"sync"
@@ -39,6 +41,8 @@ type Binutils struct {
rep *binrep
}
+var objdumpLLVMVerRE = regexp.MustCompile(`LLVM version (?:(\d*)\.(\d*)\.(\d*)|.*(trunk).*)`)
+
// binrep is an immutable representation for Binutils. It is atomically
// replaced on every mutation to provide thread-safe access.
type binrep struct {
@@ -51,6 +55,7 @@ type binrep struct {
nmFound bool
objdump string
objdumpFound bool
+ isLLVMObjdump bool
// if fast, perform symbolization using nm (symbol names only),
// instead of file-line detail from the slower addr2line.
@@ -132,15 +137,103 @@ func initTools(b *binrep, config string) {
}
defaultPath := paths[""]
- b.llvmSymbolizer, b.llvmSymbolizerFound = findExe("llvm-symbolizer", append(paths["llvm-symbolizer"], defaultPath...))
- b.addr2line, b.addr2lineFound = findExe("addr2line", append(paths["addr2line"], defaultPath...))
- if !b.addr2lineFound {
- // On MacOS, brew installs addr2line under gaddr2line name, so search for
- // that if the tool is not found by its default name.
- b.addr2line, b.addr2lineFound = findExe("gaddr2line", append(paths["addr2line"], defaultPath...))
+ b.llvmSymbolizer, b.llvmSymbolizerFound = chooseExe([]string{"llvm-symbolizer"}, []string{}, append(paths["llvm-symbolizer"], defaultPath...))
+ b.addr2line, b.addr2lineFound = chooseExe([]string{"addr2line"}, []string{"gaddr2line"}, append(paths["addr2line"], defaultPath...))
+ // The "-n" option is supported by LLVM since 2011. The output of llvm-nm
+ // and GNU nm with "-n" option is interchangeable for our purposes, so we do
+ // not need to differrentiate them.
+ b.nm, b.nmFound = chooseExe([]string{"llvm-nm", "nm"}, []string{"gnm"}, append(paths["nm"], defaultPath...))
+ b.objdump, b.objdumpFound, b.isLLVMObjdump = findObjdump(append(paths["objdump"], defaultPath...))
+}
+
+// findObjdump finds and returns path to preferred objdump binary.
+// Order of preference is: llvm-objdump, objdump.
+// On MacOS only, also looks for gobjdump with least preference.
+// Accepts a list of paths and returns:
+// a string with path to the preferred objdump binary if found,
+// or an empty string if not found;
+// a boolean if any acceptable objdump was found;
+// a boolean indicating if it is an LLVM objdump.
+func findObjdump(paths []string) (string, bool, bool) {
+ objdumpNames := []string{"llvm-objdump", "objdump"}
+ if runtime.GOOS == "darwin" {
+ objdumpNames = append(objdumpNames, "gobjdump")
+ }
+
+ for _, objdumpName := range objdumpNames {
+ if objdump, objdumpFound := findExe(objdumpName, paths); objdumpFound {
+ cmdOut, err := exec.Command(objdump, "--version").Output()
+ if err != nil {
+ continue
+ }
+ if isLLVMObjdump(string(cmdOut)) {
+ return objdump, true, true
+ }
+ if isBuObjdump(string(cmdOut)) {
+ return objdump, true, false
+ }
+ }
}
- b.nm, b.nmFound = findExe("nm", append(paths["nm"], defaultPath...))
- b.objdump, b.objdumpFound = findExe("objdump", append(paths["objdump"], defaultPath...))
+ return "", false, false
+}
+
+// chooseExe finds and returns path to preferred binary. names is a list of
+// names to search on both Linux and OSX. osxNames is a list of names specific
+// to OSX. names always has a higher priority than osxNames. The order of
+// the name within each list decides its priority (e.g. the first name has a
+// higher priority than the second name in the list).
+//
+// It returns a string with path to the binary and a boolean indicating if any
+// acceptable binary was found.
+func chooseExe(names, osxNames []string, paths []string) (string, bool) {
+ if runtime.GOOS == "darwin" {
+ names = append(names, osxNames...)
+ }
+ for _, name := range names {
+ if binary, found := findExe(name, paths); found {
+ return binary, true
+ }
+ }
+ return "", false
+}
+
+// isLLVMObjdump accepts a string with path to an objdump binary,
+// and returns a boolean indicating if the given binary is an LLVM
+// objdump binary of an acceptable version.
+func isLLVMObjdump(output string) bool {
+ fields := objdumpLLVMVerRE.FindStringSubmatch(output)
+ if len(fields) != 5 {
+ return false
+ }
+ if fields[4] == "trunk" {
+ return true
+ }
+ verMajor, err := strconv.Atoi(fields[1])
+ if err != nil {
+ return false
+ }
+ verPatch, err := strconv.Atoi(fields[3])
+ if err != nil {
+ return false
+ }
+ if runtime.GOOS == "linux" && verMajor >= 8 {
+ // Ensure LLVM objdump is at least version 8.0 on Linux.
+ // Some flags, like --demangle, and double dashes for options are
+ // not supported by previous versions.
+ return true
+ }
+ if runtime.GOOS == "darwin" {
+ // Ensure LLVM objdump is at least version 10.0.1 on MacOS.
+ return verMajor > 10 || (verMajor == 10 && verPatch >= 1)
+ }
+ return false
+}
+
+// isBuObjdump accepts a string with path to an objdump binary,
+// and returns a boolean indicating if the given binary is a GNU
+// binutils objdump binary. No version check is performed.
+func isBuObjdump(output string) bool {
+ return strings.Contains(output, "GNU objdump")
}
// findExe looks for an executable command on a set of paths.
@@ -157,12 +250,25 @@ func findExe(cmd string, paths []string) (string, bool) {
// Disasm returns the assembly instructions for the specified address range
// of a binary.
-func (bu *Binutils) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
+func (bu *Binutils) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) {
b := bu.get()
- cmd := exec.Command(b.objdump, "-d", "-C", "--no-show-raw-insn", "-l",
- fmt.Sprintf("--start-address=%#x", start),
- fmt.Sprintf("--stop-address=%#x", end),
- file)
+ if !b.objdumpFound {
+ return nil, errors.New("cannot disasm: no objdump tool available")
+ }
+ args := []string{"--disassemble-all", "--demangle", "--no-show-raw-insn",
+ "--line-numbers", fmt.Sprintf("--start-address=%#x", start),
+ fmt.Sprintf("--stop-address=%#x", end)}
+
+ if intelSyntax {
+ if b.isLLVMObjdump {
+ args = append(args, "--x86-asm-syntax=intel")
+ } else {
+ args = append(args, "-M", "intel")
+ }
+ }
+
+ args = append(args, file)
+ cmd := exec.Command(b.objdump, args...)
out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("%v: %v", cmd.Args, err)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go
index 28c89aa163..d0be614bdc 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go
@@ -25,10 +25,11 @@ import (
)
var (
- nmOutputRE = regexp.MustCompile(`^\s*([[:xdigit:]]+)\s+(.)\s+(.*)`)
- objdumpAsmOutputRE = regexp.MustCompile(`^\s*([[:xdigit:]]+):\s+(.*)`)
- objdumpOutputFileLine = regexp.MustCompile(`^(.*):([0-9]+)`)
- objdumpOutputFunction = regexp.MustCompile(`^(\S.*)\(\):`)
+ nmOutputRE = regexp.MustCompile(`^\s*([[:xdigit:]]+)\s+(.)\s+(.*)`)
+ objdumpAsmOutputRE = regexp.MustCompile(`^\s*([[:xdigit:]]+):\s+(.*)`)
+ objdumpOutputFileLine = regexp.MustCompile(`^;?\s?(.*):([0-9]+)`)
+ objdumpOutputFunction = regexp.MustCompile(`^;?\s?(\S.*)\(\):`)
+ objdumpOutputFunctionLLVM = regexp.MustCompile(`^([[:xdigit:]]+)?\s?(.*):`)
)
func findSymbols(syms []byte, file string, r *regexp.Regexp, address uint64) ([]*plugin.Sym, error) {
@@ -143,6 +144,11 @@ func disassemble(asm []byte) ([]plugin.Inst, error) {
if fields := objdumpOutputFunction.FindStringSubmatch(input); len(fields) == 2 {
function = fields[1]
continue
+ } else {
+ if fields := objdumpOutputFunctionLLVM.FindStringSubmatch(input); len(fields) == 3 {
+ function = fields[2]
+ continue
+ }
}
// Reset on unrecognized lines.
function, file, line = "", "", 0
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go
index 9fc1eea1f0..492400c5f3 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go
@@ -69,8 +69,9 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
flagHTTP := flag.String("http", "", "Present interactive web UI at the specified http host:port")
flagNoBrowser := flag.Bool("no_browser", false, "Skip opening a browswer for the interactive web UI")
- // Flags used during command processing
- installedFlags := installFlags(flag)
+ // Flags that set configuration properties.
+ cfg := currentConfig()
+ configFlagSetter := installConfigFlags(flag, &cfg)
flagCommands := make(map[string]*bool)
flagParamCommands := make(map[string]*string)
@@ -107,8 +108,8 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
}
}
- // Report conflicting options
- if err := updateFlags(installedFlags); err != nil {
+ // Apply any specified flags to cfg.
+ if err := configFlagSetter(); err != nil {
return nil, nil, err
}
@@ -124,7 +125,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
return nil, nil, errors.New("-no_browser only makes sense with -http")
}
- si := pprofVariables["sample_index"].value
+ si := cfg.SampleIndex
si = sampleIndex(flagTotalDelay, si, "delay", "-total_delay", o.UI)
si = sampleIndex(flagMeanDelay, si, "delay", "-mean_delay", o.UI)
si = sampleIndex(flagContentions, si, "contentions", "-contentions", o.UI)
@@ -132,10 +133,10 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
si = sampleIndex(flagInUseObjects, si, "inuse_objects", "-inuse_objects", o.UI)
si = sampleIndex(flagAllocSpace, si, "alloc_space", "-alloc_space", o.UI)
si = sampleIndex(flagAllocObjects, si, "alloc_objects", "-alloc_objects", o.UI)
- pprofVariables.set("sample_index", si)
+ cfg.SampleIndex = si
if *flagMeanDelay {
- pprofVariables.set("mean", "true")
+ cfg.Mean = true
}
source := &source{
@@ -154,7 +155,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
return nil, nil, err
}
- normalize := pprofVariables["normalize"].boolValue()
+ normalize := cfg.Normalize
if normalize && len(source.Base) == 0 {
return nil, nil, errors.New("must have base profile to normalize by")
}
@@ -163,6 +164,8 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
if bu, ok := o.Obj.(*binutils.Binutils); ok {
bu.SetTools(*flagTools)
}
+
+ setCurrentConfig(cfg)
return source, cmd, nil
}
@@ -194,66 +197,72 @@ func dropEmpty(list []*string) []string {
return l
}
-// installFlags creates command line flags for pprof variables.
-func installFlags(flag plugin.FlagSet) flagsInstalled {
- f := flagsInstalled{
- ints: make(map[string]*int),
- bools: make(map[string]*bool),
- floats: make(map[string]*float64),
- strings: make(map[string]*string),
- }
- for n, v := range pprofVariables {
- switch v.kind {
- case boolKind:
- if v.group != "" {
- // Set all radio variables to false to identify conflicts.
- f.bools[n] = flag.Bool(n, false, v.help)
+// installConfigFlags creates command line flags for configuration
+// fields and returns a function which can be called after flags have
+// been parsed to copy any flags specified on the command line to
+// *cfg.
+func installConfigFlags(flag plugin.FlagSet, cfg *config) func() error {
+ // List of functions for setting the different parts of a config.
+ var setters []func()
+ var err error // Holds any errors encountered while running setters.
+
+ for _, field := range configFields {
+ n := field.name
+ help := configHelp[n]
+ var setter func()
+ switch ptr := cfg.fieldPtr(field).(type) {
+ case *bool:
+ f := flag.Bool(n, *ptr, help)
+ setter = func() { *ptr = *f }
+ case *int:
+ f := flag.Int(n, *ptr, help)
+ setter = func() { *ptr = *f }
+ case *float64:
+ f := flag.Float64(n, *ptr, help)
+ setter = func() { *ptr = *f }
+ case *string:
+ if len(field.choices) == 0 {
+ f := flag.String(n, *ptr, help)
+ setter = func() { *ptr = *f }
} else {
- f.bools[n] = flag.Bool(n, v.boolValue(), v.help)
+ // Make a separate flag per possible choice.
+ // Set all flags to initially false so we can
+ // identify conflicts.
+ bools := make(map[string]*bool)
+ for _, choice := range field.choices {
+ bools[choice] = flag.Bool(choice, false, configHelp[choice])
+ }
+ setter = func() {
+ var set []string
+ for k, v := range bools {
+ if *v {
+ set = append(set, k)
+ }
+ }
+ switch len(set) {
+ case 0:
+ // Leave as default value.
+ case 1:
+ *ptr = set[0]
+ default:
+ err = fmt.Errorf("conflicting options set: %v", set)
+ }
+ }
}
- case intKind:
- f.ints[n] = flag.Int(n, v.intValue(), v.help)
- case floatKind:
- f.floats[n] = flag.Float64(n, v.floatValue(), v.help)
- case stringKind:
- f.strings[n] = flag.String(n, v.value, v.help)
}
+ setters = append(setters, setter)
}
- return f
-}
-// updateFlags updates the pprof variables according to the flags
-// parsed in the command line.
-func updateFlags(f flagsInstalled) error {
- vars := pprofVariables
- groups := map[string]string{}
- for n, v := range f.bools {
- vars.set(n, fmt.Sprint(*v))
- if *v {
- g := vars[n].group
- if g != "" && groups[g] != "" {
- return fmt.Errorf("conflicting options %q and %q set", n, groups[g])
+ return func() error {
+ // Apply the setter for every flag.
+ for _, setter := range setters {
+ setter()
+ if err != nil {
+ return err
}
- groups[g] = n
}
+ return nil
}
- for n, v := range f.ints {
- vars.set(n, fmt.Sprint(*v))
- }
- for n, v := range f.floats {
- vars.set(n, fmt.Sprint(*v))
- }
- for n, v := range f.strings {
- vars.set(n, *v)
- }
- return nil
-}
-
-type flagsInstalled struct {
- ints map[string]*int
- bools map[string]*bool
- floats map[string]*float64
- strings map[string]*string
}
// isBuildID determines if the profile may contain a build ID, by
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go
index f52471490a..4397e253e0 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/commands.go
@@ -22,7 +22,6 @@ import (
"os/exec"
"runtime"
"sort"
- "strconv"
"strings"
"time"
@@ -70,9 +69,7 @@ func AddCommand(cmd string, format int, post PostProcessor, desc, usage string)
// SetVariableDefault sets the default value for a pprof
// variable. This enables extensions to set their own defaults.
func SetVariableDefault(variable, value string) {
- if v := pprofVariables[variable]; v != nil {
- v.value = value
- }
+ configure(variable, value)
}
// PostProcessor is a function that applies post-processing to the report output
@@ -124,130 +121,132 @@ var pprofCommands = commands{
"weblist": {report.WebList, nil, invokeVisualizer("html", browsers()), true, "Display annotated source in a web browser", listHelp("weblist", false)},
}
-// pprofVariables are the configuration parameters that affect the
-// reported generated by pprof.
-var pprofVariables = variables{
+// configHelp contains help text per configuration parameter.
+var configHelp = map[string]string{
// Filename for file-based output formats, stdout by default.
- "output": &variable{stringKind, "", "", helpText("Output filename for file-based outputs")},
+ "output": helpText("Output filename for file-based outputs"),
// Comparisons.
- "drop_negative": &variable{boolKind, "f", "", helpText(
+ "drop_negative": helpText(
"Ignore negative differences",
- "Do not show any locations with values <0.")},
+ "Do not show any locations with values <0."),
// Graph handling options.
- "call_tree": &variable{boolKind, "f", "", helpText(
+ "call_tree": helpText(
"Create a context-sensitive call tree",
- "Treat locations reached through different paths as separate.")},
+ "Treat locations reached through different paths as separate."),
// Display options.
- "relative_percentages": &variable{boolKind, "f", "", helpText(
+ "relative_percentages": helpText(
"Show percentages relative to focused subgraph",
"If unset, percentages are relative to full graph before focusing",
- "to facilitate comparison with original graph.")},
- "unit": &variable{stringKind, "minimum", "", helpText(
+ "to facilitate comparison with original graph."),
+ "unit": helpText(
"Measurement units to display",
"Scale the sample values to this unit.",
"For time-based profiles, use seconds, milliseconds, nanoseconds, etc.",
"For memory profiles, use megabytes, kilobytes, bytes, etc.",
- "Using auto will scale each value independently to the most natural unit.")},
- "compact_labels": &variable{boolKind, "f", "", "Show minimal headers"},
- "source_path": &variable{stringKind, "", "", "Search path for source files"},
- "trim_path": &variable{stringKind, "", "", "Path to trim from source paths before search"},
+ "Using auto will scale each value independently to the most natural unit."),
+ "compact_labels": "Show minimal headers",
+ "source_path": "Search path for source files",
+ "trim_path": "Path to trim from source paths before search",
+ "intel_syntax": helpText(
+ "Show assembly in Intel syntax",
+ "Only applicable to commands `disasm` and `weblist`"),
// Filtering options
- "nodecount": &variable{intKind, "-1", "", helpText(
+ "nodecount": helpText(
"Max number of nodes to show",
"Uses heuristics to limit the number of locations to be displayed.",
- "On graphs, dotted edges represent paths through nodes that have been removed.")},
- "nodefraction": &variable{floatKind, "0.005", "", "Hide nodes below <f>*total"},
- "edgefraction": &variable{floatKind, "0.001", "", "Hide edges below <f>*total"},
- "trim": &variable{boolKind, "t", "", helpText(
+ "On graphs, dotted edges represent paths through nodes that have been removed."),
+ "nodefraction": "Hide nodes below <f>*total",
+ "edgefraction": "Hide edges below <f>*total",
+ "trim": helpText(
"Honor nodefraction/edgefraction/nodecount defaults",
- "Set to false to get the full profile, without any trimming.")},
- "focus": &variable{stringKind, "", "", helpText(
+ "Set to false to get the full profile, without any trimming."),
+ "focus": helpText(
"Restricts to samples going through a node matching regexp",
"Discard samples that do not include a node matching this regexp.",
- "Matching includes the function name, filename or object name.")},
- "ignore": &variable{stringKind, "", "", helpText(
+ "Matching includes the function name, filename or object name."),
+ "ignore": helpText(
"Skips paths going through any nodes matching regexp",
"If set, discard samples that include a node matching this regexp.",
- "Matching includes the function name, filename or object name.")},
- "prune_from": &variable{stringKind, "", "", helpText(
+ "Matching includes the function name, filename or object name."),
+ "prune_from": helpText(
"Drops any functions below the matched frame.",
"If set, any frames matching the specified regexp and any frames",
- "below it will be dropped from each sample.")},
- "hide": &variable{stringKind, "", "", helpText(
+ "below it will be dropped from each sample."),
+ "hide": helpText(
"Skips nodes matching regexp",
"Discard nodes that match this location.",
"Other nodes from samples that include this location will be shown.",
- "Matching includes the function name, filename or object name.")},
- "show": &variable{stringKind, "", "", helpText(
+ "Matching includes the function name, filename or object name."),
+ "show": helpText(
"Only show nodes matching regexp",
"If set, only show nodes that match this location.",
- "Matching includes the function name, filename or object name.")},
- "show_from": &variable{stringKind, "", "", helpText(
+ "Matching includes the function name, filename or object name."),
+ "show_from": helpText(
"Drops functions above the highest matched frame.",
"If set, all frames above the highest match are dropped from every sample.",
- "Matching includes the function name, filename or object name.")},
- "tagfocus": &variable{stringKind, "", "", helpText(
+ "Matching includes the function name, filename or object name."),
+ "tagfocus": helpText(
"Restricts to samples with tags in range or matched by regexp",
"Use name=value syntax to limit the matching to a specific tag.",
"Numeric tag filter examples: 1kb, 1kb:10kb, memory=32mb:",
- "String tag filter examples: foo, foo.*bar, mytag=foo.*bar")},
- "tagignore": &variable{stringKind, "", "", helpText(
+ "String tag filter examples: foo, foo.*bar, mytag=foo.*bar"),
+ "tagignore": helpText(
"Discard samples with tags in range or matched by regexp",
"Use name=value syntax to limit the matching to a specific tag.",
"Numeric tag filter examples: 1kb, 1kb:10kb, memory=32mb:",
- "String tag filter examples: foo, foo.*bar, mytag=foo.*bar")},
- "tagshow": &variable{stringKind, "", "", helpText(
+ "String tag filter examples: foo, foo.*bar, mytag=foo.*bar"),
+ "tagshow": helpText(
"Only consider tags matching this regexp",
- "Discard tags that do not match this regexp")},
- "taghide": &variable{stringKind, "", "", helpText(
+ "Discard tags that do not match this regexp"),
+ "taghide": helpText(
"Skip tags matching this regexp",
- "Discard tags that match this regexp")},
+ "Discard tags that match this regexp"),
// Heap profile options
- "divide_by": &variable{floatKind, "1", "", helpText(
+ "divide_by": helpText(
"Ratio to divide all samples before visualization",
- "Divide all samples values by a constant, eg the number of processors or jobs.")},
- "mean": &variable{boolKind, "f", "", helpText(
+ "Divide all samples values by a constant, eg the number of processors or jobs."),
+ "mean": helpText(
"Average sample value over first value (count)",
"For memory profiles, report average memory per allocation.",
- "For time-based profiles, report average time per event.")},
- "sample_index": &variable{stringKind, "", "", helpText(
+ "For time-based profiles, report average time per event."),
+ "sample_index": helpText(
"Sample value to report (0-based index or name)",
"Profiles contain multiple values per sample.",
- "Use sample_index=i to select the ith value (starting at 0).")},
- "normalize": &variable{boolKind, "f", "", helpText(
- "Scales profile based on the base profile.")},
+ "Use sample_index=i to select the ith value (starting at 0)."),
+ "normalize": helpText(
+ "Scales profile based on the base profile."),
// Data sorting criteria
- "flat": &variable{boolKind, "t", "cumulative", helpText("Sort entries based on own weight")},
- "cum": &variable{boolKind, "f", "cumulative", helpText("Sort entries based on cumulative weight")},
+ "flat": helpText("Sort entries based on own weight"),
+ "cum": helpText("Sort entries based on cumulative weight"),
// Output granularity
- "functions": &variable{boolKind, "t", "granularity", helpText(
+ "functions": helpText(
"Aggregate at the function level.",
- "Ignores the filename where the function was defined.")},
- "filefunctions": &variable{boolKind, "t", "granularity", helpText(
+ "Ignores the filename where the function was defined."),
+ "filefunctions": helpText(
"Aggregate at the function level.",
- "Takes into account the filename where the function was defined.")},
- "files": &variable{boolKind, "f", "granularity", "Aggregate at the file level."},
- "lines": &variable{boolKind, "f", "granularity", "Aggregate at the source code line level."},
- "addresses": &variable{boolKind, "f", "granularity", helpText(
+ "Takes into account the filename where the function was defined."),
+ "files": "Aggregate at the file level.",
+ "lines": "Aggregate at the source code line level.",
+ "addresses": helpText(
"Aggregate at the address level.",
- "Includes functions' addresses in the output.")},
- "noinlines": &variable{boolKind, "f", "", helpText(
+ "Includes functions' addresses in the output."),
+ "noinlines": helpText(
"Ignore inlines.",
- "Attributes inlined functions to their first out-of-line caller.")},
+ "Attributes inlined functions to their first out-of-line caller."),
}
func helpText(s ...string) string {
return strings.Join(s, "\n") + "\n"
}
-// usage returns a string describing the pprof commands and variables.
-// if commandLine is set, the output reflect cli usage.
+// usage returns a string describing the pprof commands and configuration
+// options. if commandLine is set, the output reflect cli usage.
func usage(commandLine bool) string {
var prefix string
if commandLine {
@@ -269,40 +268,33 @@ func usage(commandLine bool) string {
} else {
help = " Commands:\n"
commands = append(commands, fmtHelp("o/options", "List options and their current values"))
- commands = append(commands, fmtHelp("quit/exit/^D", "Exit pprof"))
+ commands = append(commands, fmtHelp("q/quit/exit/^D", "Exit pprof"))
}
help = help + strings.Join(commands, "\n") + "\n\n" +
" Options:\n"
- // Print help for variables after sorting them.
- // Collect radio variables by their group name to print them together.
- radioOptions := make(map[string][]string)
+ // Print help for configuration options after sorting them.
+ // Collect choices for multi-choice options print them together.
var variables []string
- for name, vr := range pprofVariables {
- if vr.group != "" {
- radioOptions[vr.group] = append(radioOptions[vr.group], name)
+ var radioStrings []string
+ for _, f := range configFields {
+ if len(f.choices) == 0 {
+ variables = append(variables, fmtHelp(prefix+f.name, configHelp[f.name]))
continue
}
- variables = append(variables, fmtHelp(prefix+name, vr.help))
- }
- sort.Strings(variables)
-
- help = help + strings.Join(variables, "\n") + "\n\n" +
- " Option groups (only set one per group):\n"
-
- var radioStrings []string
- for radio, ops := range radioOptions {
- sort.Strings(ops)
- s := []string{fmtHelp(radio, "")}
- for _, op := range ops {
- s = append(s, " "+fmtHelp(prefix+op, pprofVariables[op].help))
+ // Format help for for this group.
+ s := []string{fmtHelp(f.name, "")}
+ for _, choice := range f.choices {
+ s = append(s, " "+fmtHelp(prefix+choice, configHelp[choice]))
}
-
radioStrings = append(radioStrings, strings.Join(s, "\n"))
}
+ sort.Strings(variables)
sort.Strings(radioStrings)
- return help + strings.Join(radioStrings, "\n")
+ return help + strings.Join(variables, "\n") + "\n\n" +
+ " Option groups (only set one per group):\n" +
+ strings.Join(radioStrings, "\n")
}
func reportHelp(c string, cum, redirect bool) string {
@@ -445,105 +437,8 @@ func invokeVisualizer(suffix string, visualizers []string) PostProcessor {
}
}
-// variables describe the configuration parameters recognized by pprof.
-type variables map[string]*variable
-
-// variable is a single configuration parameter.
-type variable struct {
- kind int // How to interpret the value, must be one of the enums below.
- value string // Effective value. Only values appropriate for the Kind should be set.
- group string // boolKind variables with the same Group != "" cannot be set simultaneously.
- help string // Text describing the variable, in multiple lines separated by newline.
-}
-
-const (
- // variable.kind must be one of these variables.
- boolKind = iota
- intKind
- floatKind
- stringKind
-)
-
-// set updates the value of a variable, checking that the value is
-// suitable for the variable Kind.
-func (vars variables) set(name, value string) error {
- v := vars[name]
- if v == nil {
- return fmt.Errorf("no variable %s", name)
- }
- var err error
- switch v.kind {
- case boolKind:
- var b bool
- if b, err = stringToBool(value); err == nil {
- if v.group != "" && !b {
- err = fmt.Errorf("%q can only be set to true", name)
- }
- }
- case intKind:
- _, err = strconv.Atoi(value)
- case floatKind:
- _, err = strconv.ParseFloat(value, 64)
- case stringKind:
- // Remove quotes, particularly useful for empty values.
- if len(value) > 1 && strings.HasPrefix(value, `"`) && strings.HasSuffix(value, `"`) {
- value = value[1 : len(value)-1]
- }
- }
- if err != nil {
- return err
- }
- vars[name].value = value
- if group := vars[name].group; group != "" {
- for vname, vvar := range vars {
- if vvar.group == group && vname != name {
- vvar.value = "f"
- }
- }
- }
- return err
-}
-
-// boolValue returns the value of a boolean variable.
-func (v *variable) boolValue() bool {
- b, err := stringToBool(v.value)
- if err != nil {
- panic("unexpected value " + v.value + " for bool ")
- }
- return b
-}
-
-// intValue returns the value of an intKind variable.
-func (v *variable) intValue() int {
- i, err := strconv.Atoi(v.value)
- if err != nil {
- panic("unexpected value " + v.value + " for int ")
- }
- return i
-}
-
-// floatValue returns the value of a Float variable.
-func (v *variable) floatValue() float64 {
- f, err := strconv.ParseFloat(v.value, 64)
- if err != nil {
- panic("unexpected value " + v.value + " for float ")
- }
- return f
-}
-
-// stringValue returns a canonical representation for a variable.
-func (v *variable) stringValue() string {
- switch v.kind {
- case boolKind:
- return fmt.Sprint(v.boolValue())
- case intKind:
- return fmt.Sprint(v.intValue())
- case floatKind:
- return fmt.Sprint(v.floatValue())
- }
- return v.value
-}
-
+// stringToBool is a custom parser for bools. We avoid using strconv.ParseBool
+// to remain compatible with old pprof behavior (e.g., treating "" as true).
func stringToBool(s string) (bool, error) {
switch strings.ToLower(s) {
case "true", "t", "yes", "y", "1", "":
@@ -554,13 +449,3 @@ func stringToBool(s string) (bool, error) {
return false, fmt.Errorf(`illegal value "%s" for bool variable`, s)
}
}
-
-// makeCopy returns a duplicate of a set of shell variables.
-func (vars variables) makeCopy() variables {
- varscopy := make(variables, len(vars))
- for n, v := range vars {
- vcopy := *v
- varscopy[n] = &vcopy
- }
- return varscopy
-}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/config.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/config.go
new file mode 100644
index 0000000000..b3f82f22c9
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/config.go
@@ -0,0 +1,367 @@
+package driver
+
+import (
+ "fmt"
+ "net/url"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// config holds settings for a single named config.
+// The JSON tag name for a field is used both for JSON encoding and as
+// a named variable.
+type config struct {
+ // Filename for file-based output formats, stdout by default.
+ Output string `json:"-"`
+
+ // Display options.
+ CallTree bool `json:"call_tree,omitempty"`
+ RelativePercentages bool `json:"relative_percentages,omitempty"`
+ Unit string `json:"unit,omitempty"`
+ CompactLabels bool `json:"compact_labels,omitempty"`
+ SourcePath string `json:"-"`
+ TrimPath string `json:"-"`
+ IntelSyntax bool `json:"intel_syntax,omitempty"`
+ Mean bool `json:"mean,omitempty"`
+ SampleIndex string `json:"-"`
+ DivideBy float64 `json:"-"`
+ Normalize bool `json:"normalize,omitempty"`
+ Sort string `json:"sort,omitempty"`
+
+ // Filtering options
+ DropNegative bool `json:"drop_negative,omitempty"`
+ NodeCount int `json:"nodecount,omitempty"`
+ NodeFraction float64 `json:"nodefraction,omitempty"`
+ EdgeFraction float64 `json:"edgefraction,omitempty"`
+ Trim bool `json:"trim,omitempty"`
+ Focus string `json:"focus,omitempty"`
+ Ignore string `json:"ignore,omitempty"`
+ PruneFrom string `json:"prune_from,omitempty"`
+ Hide string `json:"hide,omitempty"`
+ Show string `json:"show,omitempty"`
+ ShowFrom string `json:"show_from,omitempty"`
+ TagFocus string `json:"tagfocus,omitempty"`
+ TagIgnore string `json:"tagignore,omitempty"`
+ TagShow string `json:"tagshow,omitempty"`
+ TagHide string `json:"taghide,omitempty"`
+ NoInlines bool `json:"noinlines,omitempty"`
+
+ // Output granularity
+ Granularity string `json:"granularity,omitempty"`
+}
+
+// defaultConfig returns the default configuration values; it is unaffected by
+// flags and interactive assignments.
+func defaultConfig() config {
+ return config{
+ Unit: "minimum",
+ NodeCount: -1,
+ NodeFraction: 0.005,
+ EdgeFraction: 0.001,
+ Trim: true,
+ DivideBy: 1.0,
+ Sort: "flat",
+ Granularity: "functions",
+ }
+}
+
+// currentConfig holds the current configuration values; it is affected by
+// flags and interactive assignments.
+var currentCfg = defaultConfig()
+var currentMu sync.Mutex
+
+func currentConfig() config {
+ currentMu.Lock()
+ defer currentMu.Unlock()
+ return currentCfg
+}
+
+func setCurrentConfig(cfg config) {
+ currentMu.Lock()
+ defer currentMu.Unlock()
+ currentCfg = cfg
+}
+
+// configField contains metadata for a single configuration field.
+type configField struct {
+ name string // JSON field name/key in variables
+ urlparam string // URL parameter name
+ saved bool // Is field saved in settings?
+ field reflect.StructField // Field in config
+ choices []string // Name Of variables in group
+ defaultValue string // Default value for this field.
+}
+
+var (
+ configFields []configField // Precomputed metadata per config field
+
+ // configFieldMap holds an entry for every config field as well as an
+ // entry for every valid choice for a multi-choice field.
+ configFieldMap map[string]configField
+)
+
+func init() {
+ // Config names for fields that are not saved in settings and therefore
+ // do not have a JSON name.
+ notSaved := map[string]string{
+ // Not saved in settings, but present in URLs.
+ "SampleIndex": "sample_index",
+
+ // Following fields are also not placed in URLs.
+ "Output": "output",
+ "SourcePath": "source_path",
+ "TrimPath": "trim_path",
+ "DivideBy": "divide_by",
+ }
+
+ // choices holds the list of allowed values for config fields that can
+ // take on one of a bounded set of values.
+ choices := map[string][]string{
+ "sort": {"cum", "flat"},
+ "granularity": {"functions", "filefunctions", "files", "lines", "addresses"},
+ }
+
+ // urlparam holds the mapping from a config field name to the URL
+ // parameter used to hold that config field. If no entry is present for
+ // a name, the corresponding field is not saved in URLs.
+ urlparam := map[string]string{
+ "drop_negative": "dropneg",
+ "call_tree": "calltree",
+ "relative_percentages": "rel",
+ "unit": "unit",
+ "compact_labels": "compact",
+ "intel_syntax": "intel",
+ "nodecount": "n",
+ "nodefraction": "nf",
+ "edgefraction": "ef",
+ "trim": "trim",
+ "focus": "f",
+ "ignore": "i",
+ "prune_from": "prunefrom",
+ "hide": "h",
+ "show": "s",
+ "show_from": "sf",
+ "tagfocus": "tf",
+ "tagignore": "ti",
+ "tagshow": "ts",
+ "taghide": "th",
+ "mean": "mean",
+ "sample_index": "si",
+ "normalize": "norm",
+ "sort": "sort",
+ "granularity": "g",
+ "noinlines": "noinlines",
+ }
+
+ def := defaultConfig()
+ configFieldMap = map[string]configField{}
+ t := reflect.TypeOf(config{})
+ for i, n := 0, t.NumField(); i < n; i++ {
+ field := t.Field(i)
+ js := strings.Split(field.Tag.Get("json"), ",")
+ if len(js) == 0 {
+ continue
+ }
+ // Get the configuration name for this field.
+ name := js[0]
+ if name == "-" {
+ name = notSaved[field.Name]
+ if name == "" {
+ // Not a configurable field.
+ continue
+ }
+ }
+ f := configField{
+ name: name,
+ urlparam: urlparam[name],
+ saved: (name == js[0]),
+ field: field,
+ choices: choices[name],
+ }
+ f.defaultValue = def.get(f)
+ configFields = append(configFields, f)
+ configFieldMap[f.name] = f
+ for _, choice := range f.choices {
+ configFieldMap[choice] = f
+ }
+ }
+}
+
+// fieldPtr returns a pointer to the field identified by f in *cfg.
+func (cfg *config) fieldPtr(f configField) interface{} {
+ // reflect.ValueOf: converts to reflect.Value
+ // Elem: dereferences cfg to make *cfg
+ // FieldByIndex: fetches the field
+ // Addr: takes address of field
+ // Interface: converts back from reflect.Value to a regular value
+ return reflect.ValueOf(cfg).Elem().FieldByIndex(f.field.Index).Addr().Interface()
+}
+
+// get returns the value of field f in cfg.
+func (cfg *config) get(f configField) string {
+ switch ptr := cfg.fieldPtr(f).(type) {
+ case *string:
+ return *ptr
+ case *int:
+ return fmt.Sprint(*ptr)
+ case *float64:
+ return fmt.Sprint(*ptr)
+ case *bool:
+ return fmt.Sprint(*ptr)
+ }
+ panic(fmt.Sprintf("unsupported config field type %v", f.field.Type))
+}
+
+// set sets the value of field f in cfg to value.
+func (cfg *config) set(f configField, value string) error {
+ switch ptr := cfg.fieldPtr(f).(type) {
+ case *string:
+ if len(f.choices) > 0 {
+ // Verify that value is one of the allowed choices.
+ for _, choice := range f.choices {
+ if choice == value {
+ *ptr = value
+ return nil
+ }
+ }
+ return fmt.Errorf("invalid %q value %q", f.name, value)
+ }
+ *ptr = value
+ case *int:
+ v, err := strconv.Atoi(value)
+ if err != nil {
+ return err
+ }
+ *ptr = v
+ case *float64:
+ v, err := strconv.ParseFloat(value, 64)
+ if err != nil {
+ return err
+ }
+ *ptr = v
+ case *bool:
+ v, err := stringToBool(value)
+ if err != nil {
+ return err
+ }
+ *ptr = v
+ default:
+ panic(fmt.Sprintf("unsupported config field type %v", f.field.Type))
+ }
+ return nil
+}
+
+// isConfigurable returns true if name is either the name of a config field, or
+// a valid value for a multi-choice config field.
+func isConfigurable(name string) bool {
+ _, ok := configFieldMap[name]
+ return ok
+}
+
+// isBoolConfig returns true if name is either name of a boolean config field,
+// or a valid value for a multi-choice config field.
+func isBoolConfig(name string) bool {
+ f, ok := configFieldMap[name]
+ if !ok {
+ return false
+ }
+ if name != f.name {
+ return true // name must be one possible value for the field
+ }
+ var cfg config
+ _, ok = cfg.fieldPtr(f).(*bool)
+ return ok
+}
+
+// completeConfig returns the list of configurable names starting with prefix.
+func completeConfig(prefix string) []string {
+ var result []string
+ for v := range configFieldMap {
+ if strings.HasPrefix(v, prefix) {
+ result = append(result, v)
+ }
+ }
+ return result
+}
+
+// configure stores the name=value mapping into the current config, correctly
+// handling the case when name identifies a particular choice in a field.
+func configure(name, value string) error {
+ currentMu.Lock()
+ defer currentMu.Unlock()
+ f, ok := configFieldMap[name]
+ if !ok {
+ return fmt.Errorf("unknown config field %q", name)
+ }
+ if f.name == name {
+ return currentCfg.set(f, value)
+ }
+ // name must be one of the choices. If value is true, set field-value
+ // to name.
+ if v, err := strconv.ParseBool(value); v && err == nil {
+ return currentCfg.set(f, name)
+ }
+ return fmt.Errorf("unknown config field %q", name)
+}
+
+// resetTransient sets all transient fields in *cfg to their currently
+// configured values.
+func (cfg *config) resetTransient() {
+ current := currentConfig()
+ cfg.Output = current.Output
+ cfg.SourcePath = current.SourcePath
+ cfg.TrimPath = current.TrimPath
+ cfg.DivideBy = current.DivideBy
+ cfg.SampleIndex = current.SampleIndex
+}
+
+// applyURL updates *cfg based on params.
+func (cfg *config) applyURL(params url.Values) error {
+ for _, f := range configFields {
+ var value string
+ if f.urlparam != "" {
+ value = params.Get(f.urlparam)
+ }
+ if value == "" {
+ continue
+ }
+ if err := cfg.set(f, value); err != nil {
+ return fmt.Errorf("error setting config field %s: %v", f.name, err)
+ }
+ }
+ return nil
+}
+
+// makeURL returns a URL based on initialURL that contains the config contents
+// as parameters. The second result is true iff a parameter value was changed.
+func (cfg *config) makeURL(initialURL url.URL) (url.URL, bool) {
+ q := initialURL.Query()
+ changed := false
+ for _, f := range configFields {
+ if f.urlparam == "" || !f.saved {
+ continue
+ }
+ v := cfg.get(f)
+ if v == f.defaultValue {
+ v = "" // URL for of default value is the empty string.
+ } else if f.field.Type.Kind() == reflect.Bool {
+ // Shorten bool values to "f" or "t"
+ v = v[:1]
+ }
+ if q.Get(f.urlparam) == v {
+ continue
+ }
+ changed = true
+ if v == "" {
+ q.Del(f.urlparam)
+ } else {
+ q.Set(f.urlparam, v)
+ }
+ }
+ if changed {
+ initialURL.RawQuery = q.Encode()
+ }
+ return initialURL, changed
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
index 1be749aa32..878f2e1ead 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
@@ -50,7 +50,7 @@ func PProf(eo *plugin.Options) error {
}
if cmd != nil {
- return generateReport(p, cmd, pprofVariables, o)
+ return generateReport(p, cmd, currentConfig(), o)
}
if src.HTTPHostport != "" {
@@ -59,7 +59,7 @@ func PProf(eo *plugin.Options) error {
return interactive(p, o)
}
-func generateRawReport(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) (*command, *report.Report, error) {
+func generateRawReport(p *profile.Profile, cmd []string, cfg config, o *plugin.Options) (*command, *report.Report, error) {
p = p.Copy() // Prevent modification to the incoming profile.
// Identify units of numeric tags in profile.
@@ -71,16 +71,16 @@ func generateRawReport(p *profile.Profile, cmd []string, vars variables, o *plug
panic("unexpected nil command")
}
- vars = applyCommandOverrides(cmd[0], c.format, vars)
+ cfg = applyCommandOverrides(cmd[0], c.format, cfg)
// Delay focus after configuring report to get percentages on all samples.
- relative := vars["relative_percentages"].boolValue()
+ relative := cfg.RelativePercentages
if relative {
- if err := applyFocus(p, numLabelUnits, vars, o.UI); err != nil {
+ if err := applyFocus(p, numLabelUnits, cfg, o.UI); err != nil {
return nil, nil, err
}
}
- ropt, err := reportOptions(p, numLabelUnits, vars)
+ ropt, err := reportOptions(p, numLabelUnits, cfg)
if err != nil {
return nil, nil, err
}
@@ -95,19 +95,19 @@ func generateRawReport(p *profile.Profile, cmd []string, vars variables, o *plug
rpt := report.New(p, ropt)
if !relative {
- if err := applyFocus(p, numLabelUnits, vars, o.UI); err != nil {
+ if err := applyFocus(p, numLabelUnits, cfg, o.UI); err != nil {
return nil, nil, err
}
}
- if err := aggregate(p, vars); err != nil {
+ if err := aggregate(p, cfg); err != nil {
return nil, nil, err
}
return c, rpt, nil
}
-func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) error {
- c, rpt, err := generateRawReport(p, cmd, vars, o)
+func generateReport(p *profile.Profile, cmd []string, cfg config, o *plugin.Options) error {
+ c, rpt, err := generateRawReport(p, cmd, cfg, o)
if err != nil {
return err
}
@@ -129,7 +129,7 @@ func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.
}
// If no output is specified, use default visualizer.
- output := vars["output"].value
+ output := cfg.Output
if output == "" {
if c.visualizer != nil {
return c.visualizer(src, os.Stdout, o.UI)
@@ -151,7 +151,7 @@ func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.
return out.Close()
}
-func applyCommandOverrides(cmd string, outputFormat int, v variables) variables {
+func applyCommandOverrides(cmd string, outputFormat int, cfg config) config {
// Some report types override the trim flag to false below. This is to make
// sure the default heuristics of excluding insignificant nodes and edges
// from the call graph do not apply. One example where it is important is
@@ -160,55 +160,55 @@ func applyCommandOverrides(cmd string, outputFormat int, v variables) variables
// data is selected. So, with trimming enabled, the report could end up
// showing no data if the specified function is "uninteresting" as far as the
// trimming is concerned.
- trim := v["trim"].boolValue()
+ trim := cfg.Trim
switch cmd {
case "disasm", "weblist":
trim = false
- v.set("addresses", "t")
+ cfg.Granularity = "addresses"
// Force the 'noinlines' mode so that source locations for a given address
// collapse and there is only one for the given address. Without this
// cumulative metrics would be double-counted when annotating the assembly.
// This is because the merge is done by address and in case of an inlined
// stack each of the inlined entries is a separate callgraph node.
- v.set("noinlines", "t")
+ cfg.NoInlines = true
case "peek":
trim = false
case "list":
trim = false
- v.set("lines", "t")
+ cfg.Granularity = "lines"
// Do not force 'noinlines' to be false so that specifying
// "-list foo -noinlines" is supported and works as expected.
case "text", "top", "topproto":
- if v["nodecount"].intValue() == -1 {
- v.set("nodecount", "0")
+ if cfg.NodeCount == -1 {
+ cfg.NodeCount = 0
}
default:
- if v["nodecount"].intValue() == -1 {
- v.set("nodecount", "80")
+ if cfg.NodeCount == -1 {
+ cfg.NodeCount = 80
}
}
switch outputFormat {
case report.Proto, report.Raw, report.Callgrind:
trim = false
- v.set("addresses", "t")
- v.set("noinlines", "f")
+ cfg.Granularity = "addresses"
+ cfg.NoInlines = false
}
if !trim {
- v.set("nodecount", "0")
- v.set("nodefraction", "0")
- v.set("edgefraction", "0")
+ cfg.NodeCount = 0
+ cfg.NodeFraction = 0
+ cfg.EdgeFraction = 0
}
- return v
+ return cfg
}
-func aggregate(prof *profile.Profile, v variables) error {
+func aggregate(prof *profile.Profile, cfg config) error {
var function, filename, linenumber, address bool
- inlines := !v["noinlines"].boolValue()
- switch {
- case v["addresses"].boolValue():
+ inlines := !cfg.NoInlines
+ switch cfg.Granularity {
+ case "addresses":
if inlines {
return nil
}
@@ -216,15 +216,15 @@ func aggregate(prof *profile.Profile, v variables) error {
filename = true
linenumber = true
address = true
- case v["lines"].boolValue():
+ case "lines":
function = true
filename = true
linenumber = true
- case v["files"].boolValue():
+ case "files":
filename = true
- case v["functions"].boolValue():
+ case "functions":
function = true
- case v["filefunctions"].boolValue():
+ case "filefunctions":
function = true
filename = true
default:
@@ -233,8 +233,8 @@ func aggregate(prof *profile.Profile, v variables) error {
return prof.Aggregate(inlines, function, filename, linenumber, address)
}
-func reportOptions(p *profile.Profile, numLabelUnits map[string]string, vars variables) (*report.Options, error) {
- si, mean := vars["sample_index"].value, vars["mean"].boolValue()
+func reportOptions(p *profile.Profile, numLabelUnits map[string]string, cfg config) (*report.Options, error) {
+ si, mean := cfg.SampleIndex, cfg.Mean
value, meanDiv, sample, err := sampleFormat(p, si, mean)
if err != nil {
return nil, err
@@ -245,29 +245,37 @@ func reportOptions(p *profile.Profile, numLabelUnits map[string]string, vars var
stype = "mean_" + stype
}
- if vars["divide_by"].floatValue() == 0 {
+ if cfg.DivideBy == 0 {
return nil, fmt.Errorf("zero divisor specified")
}
var filters []string
- for _, k := range []string{"focus", "ignore", "hide", "show", "show_from", "tagfocus", "tagignore", "tagshow", "taghide"} {
- v := vars[k].value
+ addFilter := func(k string, v string) {
if v != "" {
filters = append(filters, k+"="+v)
}
}
+ addFilter("focus", cfg.Focus)
+ addFilter("ignore", cfg.Ignore)
+ addFilter("hide", cfg.Hide)
+ addFilter("show", cfg.Show)
+ addFilter("show_from", cfg.ShowFrom)
+ addFilter("tagfocus", cfg.TagFocus)
+ addFilter("tagignore", cfg.TagIgnore)
+ addFilter("tagshow", cfg.TagShow)
+ addFilter("taghide", cfg.TagHide)
ropt := &report.Options{
- CumSort: vars["cum"].boolValue(),
- CallTree: vars["call_tree"].boolValue(),
- DropNegative: vars["drop_negative"].boolValue(),
+ CumSort: cfg.Sort == "cum",
+ CallTree: cfg.CallTree,
+ DropNegative: cfg.DropNegative,
- CompactLabels: vars["compact_labels"].boolValue(),
- Ratio: 1 / vars["divide_by"].floatValue(),
+ CompactLabels: cfg.CompactLabels,
+ Ratio: 1 / cfg.DivideBy,
- NodeCount: vars["nodecount"].intValue(),
- NodeFraction: vars["nodefraction"].floatValue(),
- EdgeFraction: vars["edgefraction"].floatValue(),
+ NodeCount: cfg.NodeCount,
+ NodeFraction: cfg.NodeFraction,
+ EdgeFraction: cfg.EdgeFraction,
ActiveFilters: filters,
NumLabelUnits: numLabelUnits,
@@ -277,10 +285,12 @@ func reportOptions(p *profile.Profile, numLabelUnits map[string]string, vars var
SampleType: stype,
SampleUnit: sample.Unit,
- OutputUnit: vars["unit"].value,
+ OutputUnit: cfg.Unit,
- SourcePath: vars["source_path"].stringValue(),
- TrimPath: vars["trim_path"].stringValue(),
+ SourcePath: cfg.SourcePath,
+ TrimPath: cfg.TrimPath,
+
+ IntelSyntax: cfg.IntelSyntax,
}
if len(p.Mapping) > 0 && p.Mapping[0].File != "" {
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.go
index af7b8d478a..fd05adb146 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.go
@@ -28,15 +28,15 @@ import (
var tagFilterRangeRx = regexp.MustCompile("([+-]?[[:digit:]]+)([[:alpha:]]+)?")
// applyFocus filters samples based on the focus/ignore options
-func applyFocus(prof *profile.Profile, numLabelUnits map[string]string, v variables, ui plugin.UI) error {
- focus, err := compileRegexOption("focus", v["focus"].value, nil)
- ignore, err := compileRegexOption("ignore", v["ignore"].value, err)
- hide, err := compileRegexOption("hide", v["hide"].value, err)
- show, err := compileRegexOption("show", v["show"].value, err)
- showfrom, err := compileRegexOption("show_from", v["show_from"].value, err)
- tagfocus, err := compileTagFilter("tagfocus", v["tagfocus"].value, numLabelUnits, ui, err)
- tagignore, err := compileTagFilter("tagignore", v["tagignore"].value, numLabelUnits, ui, err)
- prunefrom, err := compileRegexOption("prune_from", v["prune_from"].value, err)
+func applyFocus(prof *profile.Profile, numLabelUnits map[string]string, cfg config, ui plugin.UI) error {
+ focus, err := compileRegexOption("focus", cfg.Focus, nil)
+ ignore, err := compileRegexOption("ignore", cfg.Ignore, err)
+ hide, err := compileRegexOption("hide", cfg.Hide, err)
+ show, err := compileRegexOption("show", cfg.Show, err)
+ showfrom, err := compileRegexOption("show_from", cfg.ShowFrom, err)
+ tagfocus, err := compileTagFilter("tagfocus", cfg.TagFocus, numLabelUnits, ui, err)
+ tagignore, err := compileTagFilter("tagignore", cfg.TagIgnore, numLabelUnits, ui, err)
+ prunefrom, err := compileRegexOption("prune_from", cfg.PruneFrom, err)
if err != nil {
return err
}
@@ -54,11 +54,11 @@ func applyFocus(prof *profile.Profile, numLabelUnits map[string]string, v variab
warnNoMatches(tagfocus == nil || tfm, "TagFocus", ui)
warnNoMatches(tagignore == nil || tim, "TagIgnore", ui)
- tagshow, err := compileRegexOption("tagshow", v["tagshow"].value, err)
- taghide, err := compileRegexOption("taghide", v["taghide"].value, err)
+ tagshow, err := compileRegexOption("tagshow", cfg.TagShow, err)
+ taghide, err := compileRegexOption("taghide", cfg.TagHide, err)
tns, tnh := prof.FilterTagsByName(tagshow, taghide)
warnNoMatches(tagshow == nil || tns, "TagShow", ui)
- warnNoMatches(tagignore == nil || tnh, "TagHide", ui)
+ warnNoMatches(taghide == nil || tnh, "TagHide", ui)
if prunefrom != nil {
prof.PruneFrom(prunefrom)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go
index 13613cff86..fbeb765dbc 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go
@@ -38,7 +38,10 @@ type treeNode struct {
func (ui *webInterface) flamegraph(w http.ResponseWriter, req *http.Request) {
// Force the call tree so that the graph is a tree.
// Also do not trim the tree so that the flame graph contains all functions.
- rpt, errList := ui.makeReport(w, req, []string{"svg"}, "call_tree", "true", "trim", "false")
+ rpt, errList := ui.makeReport(w, req, []string{"svg"}, func(cfg *config) {
+ cfg.CallTree = true
+ cfg.Trim = false
+ })
if rpt == nil {
return // error already reported
}
@@ -96,7 +99,7 @@ func (ui *webInterface) flamegraph(w http.ResponseWriter, req *http.Request) {
return
}
- ui.render(w, "flamegraph", rpt, errList, config.Labels, webArgs{
+ ui.render(w, req, "flamegraph", rpt, errList, config.Labels, webArgs{
FlameGraph: template.JS(b),
Nodes: nodeArr,
})
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go
index 3a458b0b77..777fb90bfb 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go
@@ -34,17 +34,14 @@ var tailDigitsRE = regexp.MustCompile("[0-9]+$")
func interactive(p *profile.Profile, o *plugin.Options) error {
// Enter command processing loop.
o.UI.SetAutoComplete(newCompleter(functionNames(p)))
- pprofVariables.set("compact_labels", "true")
- pprofVariables["sample_index"].help += fmt.Sprintf("Or use sample_index=name, with name in %v.\n", sampleTypes(p))
+ configure("compact_labels", "true")
+ configHelp["sample_index"] += fmt.Sprintf("Or use sample_index=name, with name in %v.\n", sampleTypes(p))
// Do not wait for the visualizer to complete, to allow multiple
// graphs to be visualized simultaneously.
interactiveMode = true
shortcuts := profileShortcuts(p)
- // Get all groups in pprofVariables to allow for clearer error messages.
- groups := groupOptions(pprofVariables)
-
greetings(p, o.UI)
for {
input, err := o.UI.ReadLine("(pprof) ")
@@ -69,7 +66,12 @@ func interactive(p *profile.Profile, o *plugin.Options) error {
}
value = strings.TrimSpace(value)
}
- if v := pprofVariables[name]; v != nil {
+ if isConfigurable(name) {
+ // All non-bool options require inputs
+ if len(s) == 1 && !isBoolConfig(name) {
+ o.UI.PrintErr(fmt.Errorf("please specify a value, e.g. %s=<val>", name))
+ continue
+ }
if name == "sample_index" {
// Error check sample_index=xxx to ensure xxx is a valid sample type.
index, err := p.SampleIndexByName(value)
@@ -77,22 +79,16 @@ func interactive(p *profile.Profile, o *plugin.Options) error {
o.UI.PrintErr(err)
continue
}
+ if index < 0 || index >= len(p.SampleType) {
+ o.UI.PrintErr(fmt.Errorf("invalid sample_index %q", value))
+ continue
+ }
value = p.SampleType[index].Type
}
- if err := pprofVariables.set(name, value); err != nil {
- o.UI.PrintErr(err)
- }
- continue
- }
- // Allow group=variable syntax by converting into variable="".
- if v := pprofVariables[value]; v != nil && v.group == name {
- if err := pprofVariables.set(value, ""); err != nil {
+ if err := configure(name, value); err != nil {
o.UI.PrintErr(err)
}
continue
- } else if okValues := groups[name]; okValues != nil {
- o.UI.PrintErr(fmt.Errorf("unrecognized value for %s: %q. Use one of %s", name, value, strings.Join(okValues, ", ")))
- continue
}
}
@@ -105,16 +101,16 @@ func interactive(p *profile.Profile, o *plugin.Options) error {
case "o", "options":
printCurrentOptions(p, o.UI)
continue
- case "exit", "quit":
+ case "exit", "quit", "q":
return nil
case "help":
commandHelp(strings.Join(tokens[1:], " "), o.UI)
continue
}
- args, vars, err := parseCommandLine(tokens)
+ args, cfg, err := parseCommandLine(tokens)
if err == nil {
- err = generateReportWrapper(p, args, vars, o)
+ err = generateReportWrapper(p, args, cfg, o)
}
if err != nil {
@@ -124,30 +120,13 @@ func interactive(p *profile.Profile, o *plugin.Options) error {
}
}
-// groupOptions returns a map containing all non-empty groups
-// mapped to an array of the option names in that group in
-// sorted order.
-func groupOptions(vars variables) map[string][]string {
- groups := make(map[string][]string)
- for name, option := range vars {
- group := option.group
- if group != "" {
- groups[group] = append(groups[group], name)
- }
- }
- for _, names := range groups {
- sort.Strings(names)
- }
- return groups
-}
-
var generateReportWrapper = generateReport // For testing purposes.
// greetings prints a brief welcome and some overall profile
// information before accepting interactive commands.
func greetings(p *profile.Profile, ui plugin.UI) {
numLabelUnits := identifyNumLabelUnits(p, ui)
- ropt, err := reportOptions(p, numLabelUnits, pprofVariables)
+ ropt, err := reportOptions(p, numLabelUnits, currentConfig())
if err == nil {
rpt := report.New(p, ropt)
ui.Print(strings.Join(report.ProfileLabels(rpt), "\n"))
@@ -200,27 +179,16 @@ func sampleTypes(p *profile.Profile) []string {
func printCurrentOptions(p *profile.Profile, ui plugin.UI) {
var args []string
- type groupInfo struct {
- set string
- values []string
- }
- groups := make(map[string]*groupInfo)
- for n, o := range pprofVariables {
- v := o.stringValue()
+ current := currentConfig()
+ for _, f := range configFields {
+ n := f.name
+ v := current.get(f)
comment := ""
- if g := o.group; g != "" {
- gi, ok := groups[g]
- if !ok {
- gi = &groupInfo{}
- groups[g] = gi
- }
- if o.boolValue() {
- gi.set = n
- }
- gi.values = append(gi.values, n)
- continue
- }
switch {
+ case len(f.choices) > 0:
+ values := append([]string{}, f.choices...)
+ sort.Strings(values)
+ comment = "[" + strings.Join(values, " | ") + "]"
case n == "sample_index":
st := sampleTypes(p)
if v == "" {
@@ -242,18 +210,13 @@ func printCurrentOptions(p *profile.Profile, ui plugin.UI) {
}
args = append(args, fmt.Sprintf(" %-25s = %-20s %s", n, v, comment))
}
- for g, vars := range groups {
- sort.Strings(vars.values)
- comment := commentStart + " [" + strings.Join(vars.values, " | ") + "]"
- args = append(args, fmt.Sprintf(" %-25s = %-20s %s", g, vars.set, comment))
- }
sort.Strings(args)
ui.Print(strings.Join(args, "\n"))
}
// parseCommandLine parses a command and returns the pprof command to
-// execute and a set of variables for the report.
-func parseCommandLine(input []string) ([]string, variables, error) {
+// execute and the configuration to use for the report.
+func parseCommandLine(input []string) ([]string, config, error) {
cmd, args := input[:1], input[1:]
name := cmd[0]
@@ -267,25 +230,32 @@ func parseCommandLine(input []string) ([]string, variables, error) {
}
}
if c == nil {
- return nil, nil, fmt.Errorf("unrecognized command: %q", name)
+ if _, ok := configHelp[name]; ok {
+ value := "<val>"
+ if len(args) > 0 {
+ value = args[0]
+ }
+ return nil, config{}, fmt.Errorf("did you mean: %s=%s", name, value)
+ }
+ return nil, config{}, fmt.Errorf("unrecognized command: %q", name)
}
if c.hasParam {
if len(args) == 0 {
- return nil, nil, fmt.Errorf("command %s requires an argument", name)
+ return nil, config{}, fmt.Errorf("command %s requires an argument", name)
}
cmd = append(cmd, args[0])
args = args[1:]
}
- // Copy the variables as options set in the command line are not persistent.
- vcopy := pprofVariables.makeCopy()
+ // Copy config since options set in the command line should not persist.
+ vcopy := currentConfig()
var focus, ignore string
for i := 0; i < len(args); i++ {
t := args[i]
- if _, err := strconv.ParseInt(t, 10, 32); err == nil {
- vcopy.set("nodecount", t)
+ if n, err := strconv.ParseInt(t, 10, 32); err == nil {
+ vcopy.NodeCount = int(n)
continue
}
switch t[0] {
@@ -294,14 +264,14 @@ func parseCommandLine(input []string) ([]string, variables, error) {
if outputFile == "" {
i++
if i >= len(args) {
- return nil, nil, fmt.Errorf("unexpected end of line after >")
+ return nil, config{}, fmt.Errorf("unexpected end of line after >")
}
outputFile = args[i]
}
- vcopy.set("output", outputFile)
+ vcopy.Output = outputFile
case '-':
if t == "--cum" || t == "-cum" {
- vcopy.set("cum", "t")
+ vcopy.Sort = "cum"
continue
}
ignore = catRegex(ignore, t[1:])
@@ -311,30 +281,27 @@ func parseCommandLine(input []string) ([]string, variables, error) {
}
if name == "tags" {
- updateFocusIgnore(vcopy, "tag", focus, ignore)
+ if focus != "" {
+ vcopy.TagFocus = focus
+ }
+ if ignore != "" {
+ vcopy.TagIgnore = ignore
+ }
} else {
- updateFocusIgnore(vcopy, "", focus, ignore)
+ if focus != "" {
+ vcopy.Focus = focus
+ }
+ if ignore != "" {
+ vcopy.Ignore = ignore
+ }
}
-
- if vcopy["nodecount"].intValue() == -1 && (name == "text" || name == "top") {
- vcopy.set("nodecount", "10")
+ if vcopy.NodeCount == -1 && (name == "text" || name == "top") {
+ vcopy.NodeCount = 10
}
return cmd, vcopy, nil
}
-func updateFocusIgnore(v variables, prefix, f, i string) {
- if f != "" {
- focus := prefix + "focus"
- v.set(focus, catRegex(v[focus].value, f))
- }
-
- if i != "" {
- ignore := prefix + "ignore"
- v.set(ignore, catRegex(v[ignore].value, i))
- }
-}
-
func catRegex(a, b string) string {
if a != "" && b != "" {
return a + "|" + b
@@ -362,8 +329,8 @@ func commandHelp(args string, ui plugin.UI) {
return
}
- if v := pprofVariables[args]; v != nil {
- ui.Print(v.help + "\n")
+ if help, ok := configHelp[args]; ok {
+ ui.Print(help + "\n")
return
}
@@ -373,18 +340,17 @@ func commandHelp(args string, ui plugin.UI) {
// newCompleter creates an autocompletion function for a set of commands.
func newCompleter(fns []string) func(string) string {
return func(line string) string {
- v := pprofVariables
switch tokens := strings.Fields(line); len(tokens) {
case 0:
// Nothing to complete
case 1:
// Single token -- complete command name
- if match := matchVariableOrCommand(v, tokens[0]); match != "" {
+ if match := matchVariableOrCommand(tokens[0]); match != "" {
return match
}
case 2:
if tokens[0] == "help" {
- if match := matchVariableOrCommand(v, tokens[1]); match != "" {
+ if match := matchVariableOrCommand(tokens[1]); match != "" {
return tokens[0] + " " + match
}
return line
@@ -408,26 +374,19 @@ func newCompleter(fns []string) func(string) string {
}
// matchVariableOrCommand attempts to match a string token to the prefix of a Command.
-func matchVariableOrCommand(v variables, token string) string {
+func matchVariableOrCommand(token string) string {
token = strings.ToLower(token)
- found := ""
+ var matches []string
for cmd := range pprofCommands {
if strings.HasPrefix(cmd, token) {
- if found != "" {
- return ""
- }
- found = cmd
+ matches = append(matches, cmd)
}
}
- for variable := range v {
- if strings.HasPrefix(variable, token) {
- if found != "" {
- return ""
- }
- found = variable
- }
+ matches = append(matches, completeConfig(token)...)
+ if len(matches) == 1 {
+ return matches[0]
}
- return found
+ return ""
}
// functionCompleter replaces provided substring with a function
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go
new file mode 100644
index 0000000000..f72314b185
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go
@@ -0,0 +1,157 @@
+package driver
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/url"
+ "os"
+ "path/filepath"
+)
+
+// settings holds pprof settings.
+type settings struct {
+ // Configs holds a list of named UI configurations.
+ Configs []namedConfig `json:"configs"`
+}
+
+// namedConfig associates a name with a config.
+type namedConfig struct {
+ Name string `json:"name"`
+ config
+}
+
+// settingsFileName returns the name of the file where settings should be saved.
+func settingsFileName() (string, error) {
+ // Return "pprof/settings.json" under os.UserConfigDir().
+ dir, err := os.UserConfigDir()
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(dir, "pprof", "settings.json"), nil
+}
+
+// readSettings reads settings from fname.
+func readSettings(fname string) (*settings, error) {
+ data, err := ioutil.ReadFile(fname)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return &settings{}, nil
+ }
+ return nil, fmt.Errorf("could not read settings: %w", err)
+ }
+ settings := &settings{}
+ if err := json.Unmarshal(data, settings); err != nil {
+ return nil, fmt.Errorf("could not parse settings: %w", err)
+ }
+ for i := range settings.Configs {
+ settings.Configs[i].resetTransient()
+ }
+ return settings, nil
+}
+
+// writeSettings saves settings to fname.
+func writeSettings(fname string, settings *settings) error {
+ data, err := json.MarshalIndent(settings, "", " ")
+ if err != nil {
+ return fmt.Errorf("could not encode settings: %w", err)
+ }
+
+ // create the settings directory if it does not exist
+ // XDG specifies permissions 0700 when creating settings dirs:
+ // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil {
+ return fmt.Errorf("failed to create settings directory: %w", err)
+ }
+
+ if err := ioutil.WriteFile(fname, data, 0644); err != nil {
+ return fmt.Errorf("failed to write settings: %w", err)
+ }
+ return nil
+}
+
+// configMenuEntry holds information for a single config menu entry.
+type configMenuEntry struct {
+ Name string
+ URL string
+ Current bool // Is this the currently selected config?
+ UserConfig bool // Is this a user-provided config?
+}
+
+// configMenu returns a list of items to add to a menu in the web UI.
+func configMenu(fname string, url url.URL) []configMenuEntry {
+ // Start with system configs.
+ configs := []namedConfig{{Name: "Default", config: defaultConfig()}}
+ if settings, err := readSettings(fname); err == nil {
+ // Add user configs.
+ configs = append(configs, settings.Configs...)
+ }
+
+ // Convert to menu entries.
+ result := make([]configMenuEntry, len(configs))
+ lastMatch := -1
+ for i, cfg := range configs {
+ dst, changed := cfg.config.makeURL(url)
+ if !changed {
+ lastMatch = i
+ }
+ result[i] = configMenuEntry{
+ Name: cfg.Name,
+ URL: dst.String(),
+ UserConfig: (i != 0),
+ }
+ }
+ // Mark the last matching config as currennt
+ if lastMatch >= 0 {
+ result[lastMatch].Current = true
+ }
+ return result
+}
+
+// editSettings edits settings by applying fn to them.
+func editSettings(fname string, fn func(s *settings) error) error {
+ settings, err := readSettings(fname)
+ if err != nil {
+ return err
+ }
+ if err := fn(settings); err != nil {
+ return err
+ }
+ return writeSettings(fname, settings)
+}
+
+// setConfig saves the config specified in request to fname.
+func setConfig(fname string, request url.URL) error {
+ q := request.Query()
+ name := q.Get("config")
+ if name == "" {
+ return fmt.Errorf("invalid config name")
+ }
+ cfg := currentConfig()
+ if err := cfg.applyURL(q); err != nil {
+ return err
+ }
+ return editSettings(fname, func(s *settings) error {
+ for i, c := range s.Configs {
+ if c.Name == name {
+ s.Configs[i].config = cfg
+ return nil
+ }
+ }
+ s.Configs = append(s.Configs, namedConfig{Name: name, config: cfg})
+ return nil
+ })
+}
+
+// removeConfig removes config from fname.
+func removeConfig(fname, config string) error {
+ return editSettings(fname, func(s *settings) error {
+ for i, c := range s.Configs {
+ if c.Name == config {
+ s.Configs = append(s.Configs[:i], s.Configs[i+1:]...)
+ return nil
+ }
+ }
+ return fmt.Errorf("config %s not found", config)
+ })
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/tempfile.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/tempfile.go
index 28679f1c15..b6c8776ff8 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/tempfile.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/tempfile.go
@@ -24,9 +24,11 @@ import (
// newTempFile returns a new output file in dir with the provided prefix and suffix.
func newTempFile(dir, prefix, suffix string) (*os.File, error) {
for index := 1; index < 10000; index++ {
- path := filepath.Join(dir, fmt.Sprintf("%s%03d%s", prefix, index, suffix))
- if _, err := os.Stat(path); err != nil {
- return os.Create(path)
+ switch f, err := os.OpenFile(filepath.Join(dir, fmt.Sprintf("%s%03d%s", prefix, index, suffix)), os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666); {
+ case err == nil:
+ return f, nil
+ case !os.IsExist(err):
+ return nil, err
}
}
// Give up
@@ -44,11 +46,15 @@ func deferDeleteTempFile(path string) {
}
// cleanupTempFiles removes any temporary files selected for deferred cleaning.
-func cleanupTempFiles() {
+func cleanupTempFiles() error {
tempFilesMu.Lock()
+ defer tempFilesMu.Unlock()
+ var lastErr error
for _, f := range tempFiles {
- os.Remove(f)
+ if err := os.Remove(f); err != nil {
+ lastErr = err
+ }
}
tempFiles = nil
- tempFilesMu.Unlock()
+ return lastErr
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go
index 89b8882a6b..4f7610c7e5 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go
@@ -166,6 +166,73 @@ a {
color: gray;
pointer-events: none;
}
+.menu-check-mark {
+ position: absolute;
+ left: 2px;
+}
+.menu-delete-btn {
+ position: absolute;
+ right: 2px;
+}
+
+{{/* Used to disable events when a modal dialog is displayed */}}
+#dialog-overlay {
+ display: none;
+ position: fixed;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(1,1,1,0.1);
+}
+
+.dialog {
+ {{/* Displayed centered horizontally near the top */}}
+ display: none;
+ position: fixed;
+ margin: 0px;
+ top: 60px;
+ left: 50%;
+ transform: translateX(-50%);
+
+ z-index: 3;
+ font-size: 125%;
+ background-color: #ffffff;
+ box-shadow: 0 1px 5px rgba(0,0,0,.3);
+}
+.dialog-header {
+ font-size: 120%;
+ border-bottom: 1px solid #CCCCCC;
+ width: 100%;
+ text-align: center;
+ background: #EEEEEE;
+ user-select: none;
+}
+.dialog-footer {
+ border-top: 1px solid #CCCCCC;
+ width: 100%;
+ text-align: right;
+ padding: 10px;
+}
+.dialog-error {
+ margin: 10px;
+ color: red;
+}
+.dialog input {
+ margin: 10px;
+ font-size: inherit;
+}
+.dialog button {
+ margin-left: 10px;
+ font-size: inherit;
+}
+#save-dialog, #delete-dialog {
+ width: 50%;
+ max-width: 20em;
+}
+#delete-prompt {
+ padding: 10px;
+}
#content {
overflow-y: scroll;
@@ -200,6 +267,8 @@ table thead {
font-family: 'Roboto Medium', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}
table tr th {
+ position: sticky;
+ top: 0;
background-color: #ddd;
text-align: right;
padding: .3em .5em;
@@ -282,6 +351,24 @@ table tr td {
</div>
</div>
+ <div id="config" class="menu-item">
+ <div class="menu-name">
+ Config
+ <i class="downArrow"></i>
+ </div>
+ <div class="submenu">
+ <a title="{{.Help.save_config}}" id="save-config">Save as ...</a>
+ <hr>
+ {{range .Configs}}
+ <a href="{{.URL}}">
+ {{if .Current}}<span class="menu-check-mark">✓</span>{{end}}
+ {{.Name}}
+ {{if .UserConfig}}<span class="menu-delete-btn" data-config={{.Name}}>🗙</span>{{end}}
+ </a>
+ {{end}}
+ </div>
+ </div>
+
<div>
<input id="search" type="text" placeholder="Search regexp" autocomplete="off" autocapitalize="none" size=40>
</div>
@@ -294,6 +381,31 @@ table tr td {
</div>
</div>
+<div id="dialog-overlay"></div>
+
+<div class="dialog" id="save-dialog">
+ <div class="dialog-header">Save options as</div>
+ <datalist id="config-list">
+ {{range .Configs}}{{if .UserConfig}}<option value="{{.Name}}" />{{end}}{{end}}
+ </datalist>
+ <input id="save-name" type="text" list="config-list" placeholder="New config" />
+ <div class="dialog-footer">
+ <span class="dialog-error" id="save-error"></span>
+ <button id="save-cancel">Cancel</button>
+ <button id="save-confirm">Save</button>
+ </div>
+</div>
+
+<div class="dialog" id="delete-dialog">
+ <div class="dialog-header" id="delete-dialog-title">Delete config</div>
+ <div id="delete-prompt"></div>
+ <div class="dialog-footer">
+ <span class="dialog-error" id="delete-error"></span>
+ <button id="delete-cancel">Cancel</button>
+ <button id="delete-confirm">Delete</button>
+ </div>
+</div>
+
<div id="errors">{{range .Errors}}<div>{{.}}</div>{{end}}</div>
{{end}}
@@ -583,6 +695,131 @@ function initMenus() {
}, { passive: true, capture: true });
}
+function sendURL(method, url, done) {
+ fetch(url.toString(), {method: method})
+ .then((response) => { done(response.ok); })
+ .catch((error) => { done(false); });
+}
+
+// Initialize handlers for saving/loading configurations.
+function initConfigManager() {
+ 'use strict';
+
+ // Initialize various elements.
+ function elem(id) {
+ const result = document.getElementById(id);
+ if (!result) console.warn('element ' + id + ' not found');
+ return result;
+ }
+ const overlay = elem('dialog-overlay');
+ const saveDialog = elem('save-dialog');
+ const saveInput = elem('save-name');
+ const saveError = elem('save-error');
+ const delDialog = elem('delete-dialog');
+ const delPrompt = elem('delete-prompt');
+ const delError = elem('delete-error');
+
+ let currentDialog = null;
+ let currentDeleteTarget = null;
+
+ function showDialog(dialog) {
+ if (currentDialog != null) {
+ overlay.style.display = 'none';
+ currentDialog.style.display = 'none';
+ }
+ currentDialog = dialog;
+ if (dialog != null) {
+ overlay.style.display = 'block';
+ dialog.style.display = 'block';
+ }
+ }
+
+ function cancelDialog(e) {
+ showDialog(null);
+ }
+
+ // Show dialog for saving the current config.
+ function showSaveDialog(e) {
+ saveError.innerText = '';
+ showDialog(saveDialog);
+ saveInput.focus();
+ }
+
+ // Commit save config.
+ function commitSave(e) {
+ const name = saveInput.value;
+ const url = new URL(document.URL);
+ // Set path relative to existing path.
+ url.pathname = new URL('./saveconfig', document.URL).pathname;
+ url.searchParams.set('config', name);
+ saveError.innerText = '';
+ sendURL('POST', url, (ok) => {
+ if (!ok) {
+ saveError.innerText = 'Save failed';
+ } else {
+ showDialog(null);
+ location.reload(); // Reload to show updated config menu
+ }
+ });
+ }
+
+ function handleSaveInputKey(e) {
+ if (e.key === 'Enter') commitSave(e);
+ }
+
+ function deleteConfig(e, elem) {
+ e.preventDefault();
+ const config = elem.dataset.config;
+ delPrompt.innerText = 'Delete ' + config + '?';
+ currentDeleteTarget = elem;
+ showDialog(delDialog);
+ }
+
+ function commitDelete(e, elem) {
+ if (!currentDeleteTarget) return;
+ const config = currentDeleteTarget.dataset.config;
+ const url = new URL('./deleteconfig', document.URL);
+ url.searchParams.set('config', config);
+ delError.innerText = '';
+ sendURL('DELETE', url, (ok) => {
+ if (!ok) {
+ delError.innerText = 'Delete failed';
+ return;
+ }
+ showDialog(null);
+ // Remove menu entry for this config.
+ if (currentDeleteTarget && currentDeleteTarget.parentElement) {
+ currentDeleteTarget.parentElement.remove();
+ }
+ });
+ }
+
+ // Bind event on elem to fn.
+ function bind(event, elem, fn) {
+ if (elem == null) return;
+ elem.addEventListener(event, fn);
+ if (event == 'click') {
+ // Also enable via touch.
+ elem.addEventListener('touchstart', fn);
+ }
+ }
+
+ bind('click', elem('save-config'), showSaveDialog);
+ bind('click', elem('save-cancel'), cancelDialog);
+ bind('click', elem('save-confirm'), commitSave);
+ bind('keydown', saveInput, handleSaveInputKey);
+
+ bind('click', elem('delete-cancel'), cancelDialog);
+ bind('click', elem('delete-confirm'), commitDelete);
+
+ // Activate deletion button for all config entries in menu.
+ for (const del of Array.from(document.getElementsByClassName('menu-delete-btn'))) {
+ bind('click', del, (e) => {
+ deleteConfig(e, del);
+ });
+ }
+}
+
function viewer(baseUrl, nodes) {
'use strict';
@@ -875,6 +1112,7 @@ function viewer(baseUrl, nodes) {
}
addAction('details', handleDetails);
+ initConfigManager();
search.addEventListener('input', handleSearch);
search.addEventListener('keydown', handleKey);
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go
index 4006085538..52dc68809c 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go
@@ -35,22 +35,28 @@ import (
// webInterface holds the state needed for serving a browser based interface.
type webInterface struct {
- prof *profile.Profile
- options *plugin.Options
- help map[string]string
- templates *template.Template
+ prof *profile.Profile
+ options *plugin.Options
+ help map[string]string
+ templates *template.Template
+ settingsFile string
}
-func makeWebInterface(p *profile.Profile, opt *plugin.Options) *webInterface {
+func makeWebInterface(p *profile.Profile, opt *plugin.Options) (*webInterface, error) {
+ settingsFile, err := settingsFileName()
+ if err != nil {
+ return nil, err
+ }
templates := template.New("templategroup")
addTemplates(templates)
report.AddSourceTemplates(templates)
return &webInterface{
- prof: p,
- options: opt,
- help: make(map[string]string),
- templates: templates,
- }
+ prof: p,
+ options: opt,
+ help: make(map[string]string),
+ templates: templates,
+ settingsFile: settingsFile,
+ }, nil
}
// maxEntries is the maximum number of entries to print for text interfaces.
@@ -80,6 +86,7 @@ type webArgs struct {
TextBody string
Top []report.TextItem
FlameGraph template.JS
+ Configs []configMenuEntry
}
func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options, disableBrowser bool) error {
@@ -88,16 +95,20 @@ func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options, d
return err
}
interactiveMode = true
- ui := makeWebInterface(p, o)
+ ui, err := makeWebInterface(p, o)
+ if err != nil {
+ return err
+ }
for n, c := range pprofCommands {
ui.help[n] = c.description
}
- for n, v := range pprofVariables {
- ui.help[n] = v.help
+ for n, help := range configHelp {
+ ui.help[n] = help
}
ui.help["details"] = "Show information about the profile and this view"
ui.help["graph"] = "Display profile as a directed graph"
ui.help["reset"] = "Show the entire profile"
+ ui.help["save_config"] = "Save current settings"
server := o.HTTPServer
if server == nil {
@@ -108,12 +119,14 @@ func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options, d
Host: host,
Port: port,
Handlers: map[string]http.Handler{
- "/": http.HandlerFunc(ui.dot),
- "/top": http.HandlerFunc(ui.top),
- "/disasm": http.HandlerFunc(ui.disasm),
- "/source": http.HandlerFunc(ui.source),
- "/peek": http.HandlerFunc(ui.peek),
- "/flamegraph": http.HandlerFunc(ui.flamegraph),
+ "/": http.HandlerFunc(ui.dot),
+ "/top": http.HandlerFunc(ui.top),
+ "/disasm": http.HandlerFunc(ui.disasm),
+ "/source": http.HandlerFunc(ui.source),
+ "/peek": http.HandlerFunc(ui.peek),
+ "/flamegraph": http.HandlerFunc(ui.flamegraph),
+ "/saveconfig": http.HandlerFunc(ui.saveConfig),
+ "/deleteconfig": http.HandlerFunc(ui.deleteConfig),
},
}
@@ -206,21 +219,9 @@ func isLocalhost(host string) bool {
func openBrowser(url string, o *plugin.Options) {
// Construct URL.
- u, _ := gourl.Parse(url)
- q := u.Query()
- for _, p := range []struct{ param, key string }{
- {"f", "focus"},
- {"s", "show"},
- {"sf", "show_from"},
- {"i", "ignore"},
- {"h", "hide"},
- {"si", "sample_index"},
- } {
- if v := pprofVariables[p.key].value; v != "" {
- q.Set(p.param, v)
- }
- }
- u.RawQuery = q.Encode()
+ baseURL, _ := gourl.Parse(url)
+ current := currentConfig()
+ u, _ := current.makeURL(*baseURL)
// Give server a little time to get ready.
time.Sleep(time.Millisecond * 500)
@@ -240,28 +241,23 @@ func openBrowser(url string, o *plugin.Options) {
o.UI.PrintErr(u.String())
}
-func varsFromURL(u *gourl.URL) variables {
- vars := pprofVariables.makeCopy()
- vars["focus"].value = u.Query().Get("f")
- vars["show"].value = u.Query().Get("s")
- vars["show_from"].value = u.Query().Get("sf")
- vars["ignore"].value = u.Query().Get("i")
- vars["hide"].value = u.Query().Get("h")
- vars["sample_index"].value = u.Query().Get("si")
- return vars
-}
-
// makeReport generates a report for the specified command.
+// If configEditor is not null, it is used to edit the config used for the report.
func (ui *webInterface) makeReport(w http.ResponseWriter, req *http.Request,
- cmd []string, vars ...string) (*report.Report, []string) {
- v := varsFromURL(req.URL)
- for i := 0; i+1 < len(vars); i += 2 {
- v[vars[i]].value = vars[i+1]
+ cmd []string, configEditor func(*config)) (*report.Report, []string) {
+ cfg := currentConfig()
+ if err := cfg.applyURL(req.URL.Query()); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ ui.options.UI.PrintErr(err)
+ return nil, nil
+ }
+ if configEditor != nil {
+ configEditor(&cfg)
}
catcher := &errorCatcher{UI: ui.options.UI}
options := *ui.options
options.UI = catcher
- _, rpt, err := generateRawReport(ui.prof, cmd, v, &options)
+ _, rpt, err := generateRawReport(ui.prof, cmd, cfg, &options)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
ui.options.UI.PrintErr(err)
@@ -271,7 +267,7 @@ func (ui *webInterface) makeReport(w http.ResponseWriter, req *http.Request,
}
// render generates html using the named template based on the contents of data.
-func (ui *webInterface) render(w http.ResponseWriter, tmpl string,
+func (ui *webInterface) render(w http.ResponseWriter, req *http.Request, tmpl string,
rpt *report.Report, errList, legend []string, data webArgs) {
file := getFromLegend(legend, "File: ", "unknown")
profile := getFromLegend(legend, "Type: ", "unknown")
@@ -281,6 +277,8 @@ func (ui *webInterface) render(w http.ResponseWriter, tmpl string,
data.SampleTypes = sampleTypes(ui.prof)
data.Legend = legend
data.Help = ui.help
+ data.Configs = configMenu(ui.settingsFile, *req.URL)
+
html := &bytes.Buffer{}
if err := ui.templates.ExecuteTemplate(html, tmpl, data); err != nil {
http.Error(w, "internal template error", http.StatusInternalServerError)
@@ -293,7 +291,7 @@ func (ui *webInterface) render(w http.ResponseWriter, tmpl string,
// dot generates a web page containing an svg diagram.
func (ui *webInterface) dot(w http.ResponseWriter, req *http.Request) {
- rpt, errList := ui.makeReport(w, req, []string{"svg"})
+ rpt, errList := ui.makeReport(w, req, []string{"svg"}, nil)
if rpt == nil {
return // error already reported
}
@@ -320,7 +318,7 @@ func (ui *webInterface) dot(w http.ResponseWriter, req *http.Request) {
nodes = append(nodes, n.Info.Name)
}
- ui.render(w, "graph", rpt, errList, legend, webArgs{
+ ui.render(w, req, "graph", rpt, errList, legend, webArgs{
HTMLBody: template.HTML(string(svg)),
Nodes: nodes,
})
@@ -345,7 +343,9 @@ func dotToSvg(dot []byte) ([]byte, error) {
}
func (ui *webInterface) top(w http.ResponseWriter, req *http.Request) {
- rpt, errList := ui.makeReport(w, req, []string{"top"}, "nodecount", "500")
+ rpt, errList := ui.makeReport(w, req, []string{"top"}, func(cfg *config) {
+ cfg.NodeCount = 500
+ })
if rpt == nil {
return // error already reported
}
@@ -355,7 +355,7 @@ func (ui *webInterface) top(w http.ResponseWriter, req *http.Request) {
nodes = append(nodes, item.Name)
}
- ui.render(w, "top", rpt, errList, legend, webArgs{
+ ui.render(w, req, "top", rpt, errList, legend, webArgs{
Top: top,
Nodes: nodes,
})
@@ -364,7 +364,7 @@ func (ui *webInterface) top(w http.ResponseWriter, req *http.Request) {
// disasm generates a web page containing disassembly.
func (ui *webInterface) disasm(w http.ResponseWriter, req *http.Request) {
args := []string{"disasm", req.URL.Query().Get("f")}
- rpt, errList := ui.makeReport(w, req, args)
+ rpt, errList := ui.makeReport(w, req, args, nil)
if rpt == nil {
return // error already reported
}
@@ -377,7 +377,7 @@ func (ui *webInterface) disasm(w http.ResponseWriter, req *http.Request) {
}
legend := report.ProfileLabels(rpt)
- ui.render(w, "plaintext", rpt, errList, legend, webArgs{
+ ui.render(w, req, "plaintext", rpt, errList, legend, webArgs{
TextBody: out.String(),
})
@@ -387,7 +387,7 @@ func (ui *webInterface) disasm(w http.ResponseWriter, req *http.Request) {
// data.
func (ui *webInterface) source(w http.ResponseWriter, req *http.Request) {
args := []string{"weblist", req.URL.Query().Get("f")}
- rpt, errList := ui.makeReport(w, req, args)
+ rpt, errList := ui.makeReport(w, req, args, nil)
if rpt == nil {
return // error already reported
}
@@ -401,7 +401,7 @@ func (ui *webInterface) source(w http.ResponseWriter, req *http.Request) {
}
legend := report.ProfileLabels(rpt)
- ui.render(w, "sourcelisting", rpt, errList, legend, webArgs{
+ ui.render(w, req, "sourcelisting", rpt, errList, legend, webArgs{
HTMLBody: template.HTML(body.String()),
})
}
@@ -409,7 +409,9 @@ func (ui *webInterface) source(w http.ResponseWriter, req *http.Request) {
// peek generates a web page listing callers/callers.
func (ui *webInterface) peek(w http.ResponseWriter, req *http.Request) {
args := []string{"peek", req.URL.Query().Get("f")}
- rpt, errList := ui.makeReport(w, req, args, "lines", "t")
+ rpt, errList := ui.makeReport(w, req, args, func(cfg *config) {
+ cfg.Granularity = "lines"
+ })
if rpt == nil {
return // error already reported
}
@@ -422,11 +424,30 @@ func (ui *webInterface) peek(w http.ResponseWriter, req *http.Request) {
}
legend := report.ProfileLabels(rpt)
- ui.render(w, "plaintext", rpt, errList, legend, webArgs{
+ ui.render(w, req, "plaintext", rpt, errList, legend, webArgs{
TextBody: out.String(),
})
}
+// saveConfig saves URL configuration.
+func (ui *webInterface) saveConfig(w http.ResponseWriter, req *http.Request) {
+ if err := setConfig(ui.settingsFile, *req.URL); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ ui.options.UI.PrintErr(err)
+ return
+ }
+}
+
+// deleteConfig deletes a configuration.
+func (ui *webInterface) deleteConfig(w http.ResponseWriter, req *http.Request) {
+ name := req.URL.Query().Get("config")
+ if err := removeConfig(ui.settingsFile, name); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ ui.options.UI.PrintErr(err)
+ return
+ }
+}
+
// getFromLegend returns the suffix of an entry in legend that starts
// with param. It returns def if no such entry is found.
func getFromLegend(legend []string, param, def string) string {
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go b/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go
index 09debfb007..cde648f20b 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/dotgraph.go
@@ -127,7 +127,7 @@ func (b *builder) addLegend() {
}
title := labels[0]
fmt.Fprintf(b, `subgraph cluster_L { "%s" [shape=box fontsize=16`, title)
- fmt.Fprintf(b, ` label="%s\l"`, strings.Join(labels, `\l`))
+ fmt.Fprintf(b, ` label="%s\l"`, strings.Join(escapeForDot(labels), `\l`))
if b.config.LegendURL != "" {
fmt.Fprintf(b, ` URL="%s" target="_blank"`, b.config.LegendURL)
}
@@ -472,3 +472,14 @@ func min64(a, b int64) int64 {
}
return b
}
+
+// escapeForDot escapes double quotes and backslashes, and replaces Graphviz's
+// "center" character (\n) with a left-justified character.
+// See https://graphviz.org/doc/info/attrs.html#k:escString for more info.
+func escapeForDot(in []string) []string {
+ var out = make([]string, len(in))
+ for i := range in {
+ out[i] = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(in[i], `\`, `\\`), `"`, `\"`), "\n", `\l`)
+ }
+ return out
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
index 4c1db2331f..3a8d0af730 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
@@ -114,7 +114,7 @@ type ObjTool interface {
// Disasm disassembles the named object file, starting at
// the start address and stopping at (before) the end address.
- Disasm(file string, start, end uint64) ([]Inst, error)
+ Disasm(file string, start, end uint64, intelSyntax bool) ([]Inst, error)
}
// An Inst is a single instruction in an assembly listing.
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
index 56083d8abf..bc5685d61e 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
@@ -79,6 +79,8 @@ type Options struct {
Symbol *regexp.Regexp // Symbols to include on disassembly report.
SourcePath string // Search path for source files.
TrimPath string // Paths to trim from source file paths.
+
+ IntelSyntax bool // Whether or not to print assembly in Intel syntax.
}
// Generate generates a report as directed by the Report.
@@ -438,7 +440,7 @@ func PrintAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFuncs int) e
flatSum, cumSum := sns.Sum()
// Get the function assembly.
- insts, err := obj.Disasm(s.sym.File, s.sym.Start, s.sym.End)
+ insts, err := obj.Disasm(s.sym.File, s.sym.Start, s.sym.End, o.IntelSyntax)
if err != nil {
return err
}
@@ -1201,6 +1203,13 @@ func reportLabels(rpt *Report, g *graph.Graph, origCount, droppedNodes, droppedE
nodeCount, origCount))
}
}
+
+ // Help new users understand the graph.
+ // A new line is intentionally added here to better show this message.
+ if fullHeaders {
+ label = append(label, "\nSee https://git.io/JfYMW for how to read the graph")
+ }
+
return label
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
index ab8b64cbab..b480535439 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
@@ -205,7 +205,7 @@ func PrintWebList(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFiles int) er
ff := fileFunction{n.Info.File, n.Info.Name}
fns := fileNodes[ff]
- asm := assemblyPerSourceLine(symbols, fns, ff.fileName, obj)
+ asm := assemblyPerSourceLine(symbols, fns, ff.fileName, obj, o.IntelSyntax)
start, end := sourceCoordinates(asm)
fnodes, path, err := getSourceFromFile(ff.fileName, reader, fns, start, end)
@@ -239,7 +239,7 @@ func sourceCoordinates(asm map[int][]assemblyInstruction) (start, end int) {
// assemblyPerSourceLine disassembles the binary containing a symbol
// and classifies the assembly instructions according to its
// corresponding source line, annotating them with a set of samples.
-func assemblyPerSourceLine(objSyms []*objSymbol, rs graph.Nodes, src string, obj plugin.ObjTool) map[int][]assemblyInstruction {
+func assemblyPerSourceLine(objSyms []*objSymbol, rs graph.Nodes, src string, obj plugin.ObjTool, intelSyntax bool) map[int][]assemblyInstruction {
assembly := make(map[int][]assemblyInstruction)
// Identify symbol to use for this collection of samples.
o := findMatchingSymbol(objSyms, rs)
@@ -248,7 +248,7 @@ func assemblyPerSourceLine(objSyms []*objSymbol, rs graph.Nodes, src string, obj
}
// Extract assembly for matched symbol
- insts, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End)
+ insts, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End, intelSyntax)
if err != nil {
return assembly
}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile.go b/src/cmd/vendor/github.com/google/pprof/profile/profile.go
index c950d8dc7f..d94d8b3d1c 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/profile.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/profile.go
@@ -398,10 +398,12 @@ func (p *Profile) CheckValid() error {
}
}
for _, ln := range l.Line {
- if f := ln.Function; f != nil {
- if f.ID == 0 || functions[f.ID] != f {
- return fmt.Errorf("inconsistent function %p: %d", f, f.ID)
- }
+ f := ln.Function
+ if f == nil {
+ return fmt.Errorf("location id: %d has a line with nil function", l.ID)
+ }
+ if f.ID == 0 || functions[f.ID] != f {
+ return fmt.Errorf("inconsistent function %p: %d", f, f.ID)
}
}
}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
index 9cb8c8c44b..48a4e9790a 100644
--- a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
@@ -112,7 +112,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
case STDCXCC, STWCXCC, STHCXCC, STBCXCC:
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
- case STXVX, STXVD2X, STXVW4X, STXSDX, STVX, STVXL, STVEBX, STVEHX, STVEWX, STXSIWX, STFDX, STFDUX, STFDPX, STFSX, STFSUX:
+ case STXVX, STXVD2X, STXVW4X, STXVH8X, STXVB16X, STXSDX, STVX, STVXL, STVEBX, STVEHX, STVEWX, STXSIWX, STFDX, STFDUX, STFDPX, STFSX, STFSUX:
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
case STXV:
@@ -127,7 +127,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
}
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
- case LXVX, LXVD2X, LXVW4X, LVX, LVXL, LVSR, LVSL, LVEBX, LVEHX, LVEWX, LXSDX, LXSIWAX:
+ case LXVX, LXVD2X, LXVW4X, LXVH8X, LXVB16X, LVX, LVXL, LVSR, LVSL, LVEBX, LVEHX, LVEWX, LXSDX, LXSIWAX:
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
case LXV:
@@ -332,6 +332,7 @@ var plan9OpMap = map[Op]string{
DIVDUO: "DIVDUV",
DIVDUOCC: "DIVDUVCC",
ADDI: "ADD",
+ MULLI: "MULLD",
SRADI: "SRAD",
SUBF: "SUB",
STBCXCC: "STBCCC",
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
index 102f836145..76f96356d2 100644
--- a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
@@ -1,5 +1,5 @@
// DO NOT EDIT
-// generated by: ppc64map -fmt=decoder ../pp64.csv
+// generated by: ppc64map -fmt=decoder pp64.csv
package ppc64asm
@@ -727,6 +727,8 @@ const (
LXVD2X
LXVDSX
LXVW4X
+ LXVH8X
+ LXVB16X
LXV
LXVL
LXVLL
@@ -736,6 +738,8 @@ const (
STXSSPX
STXVD2X
STXVW4X
+ STXVH8X
+ STXVB16X
STXV
STXVL
STXVLL
@@ -883,6 +887,9 @@ const (
XXSEL
XXSLDWI
XXSPLTW
+ XXBRD
+ XXBRW
+ XXBRH
BRINC
EVABS
EVADDIW
@@ -2097,6 +2104,8 @@ var opstr = [...]string{
LXVD2X: "lxvd2x",
LXVDSX: "lxvdsx",
LXVW4X: "lxvw4x",
+ LXVH8X: "lxvh8x",
+ LXVB16X: "lxvb16x",
LXV: "lxv",
LXVL: "lxvl",
LXVLL: "lxvll",
@@ -2106,6 +2115,8 @@ var opstr = [...]string{
STXSSPX: "stxsspx",
STXVD2X: "stxvd2x",
STXVW4X: "stxvw4x",
+ STXVH8X: "stxvh8x",
+ STXVB16X: "stxvb16x",
STXV: "stxv",
STXVL: "stxvl",
STXVLL: "stxvll",
@@ -2253,6 +2264,9 @@ var opstr = [...]string{
XXSEL: "xxsel",
XXSLDWI: "xxsldwi",
XXSPLTW: "xxspltw",
+ XXBRD: "xxbrd",
+ XXBRW: "xxbrw",
+ XXBRH: "xxbrh",
BRINC: "brinc",
EVABS: "evabs",
EVADDIW: "evaddiw",
@@ -4264,13 +4278,17 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{LXVW4X, 0xfc0007fe, 0x7c000618, 0x0, // Load VSX Vector Word*4 Indexed XX1-form (lxvw4x XT,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXVH8X, 0xfc0007fe, 0x7c000658, 0x0, // Load VSX Vector Halfword*8 Indexed XX1-form (lxvh8x XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXVB16X, 0xfc0007fe, 0x7c0006d8, 0x0, // Load VSX Vector Byte*16 Indexed XX1-form (lxvb16x XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{LXV, 0xfc000007, 0xf4000001, 0x0, // Load VSX Vector DQ-form (lxv XT,DQ(RA))
[5]*argField{ap_VecSReg_28_28_6_10, ap_Offset_16_27_shift4, ap_Reg_11_15}},
{LXVL, 0xfc0007fe, 0x7c00021a, 0x0, // Load VSX Vector with Length X-form (lxvl XT,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{LXVLL, 0xfc0007fe, 0x7c00025a, 0x0, // Load VSX Vector Left-justified with Length X-form (lxvll XT,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
- {LXVX, 0xfc0007fe, 0x7c000218, 0x0, // Load VSX Vector Indexed X-form (lxvx XT,RA,RB)
+ {LXVX, 0xfc0007be, 0x7c000218, 0x40, // Load VSX Vector Indexed X-form (lxvx XT,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXSDX, 0xfc0007fe, 0x7c000598, 0x0, // Store VSX Scalar Doubleword Indexed XX1-form (stxsdx XS,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
@@ -4282,6 +4300,10 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXVW4X, 0xfc0007fe, 0x7c000718, 0x0, // Store VSX Vector Word*4 Indexed XX1-form (stxvw4x XS,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXVH8X, 0xfc0007fe, 0x7c000758, 0x0, // Store VSX Vector Halfword*4 Indexed XX1-form (stxvh8x XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXVB16X, 0xfc0007fe, 0x7c0007d8, 0x0, // Store VSX Vector Byte*16 Indexed XX1-form (stxvb16x XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXV, 0xfc000007, 0xf4000005, 0x0, // Store VSX Vector DQ-form (stxv XS,DQ(RA))
[5]*argField{ap_VecSReg_28_28_6_10, ap_Offset_16_27_shift4, ap_Reg_11_15}},
{STXVL, 0xfc0007fe, 0x7c00031a, 0x0, // Store VSX Vector with Length X-form (stxvl XS,RA,RB)
@@ -4576,6 +4598,12 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20, ap_ImmUnsigned_22_23}},
{XXSPLTW, 0xfc0007fc, 0xf0000290, 0x1c0000, // VSX Splat Word XX2-form (xxspltw XT,XB,UIM)
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20, ap_ImmUnsigned_14_15}},
+ {XXBRD, 0xfc1f07fc, 0xf017076c, 0x0, // VSX Vector Byte-Reverse Doubleword XX2-form (xxbrd XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XXBRW, 0xfc1f07fc, 0xf00f076c, 0x0, // VSX Vector Byte-Reverse Word XX2-form (xxbrw XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XXBRH, 0xfc1f07fc, 0xf007076c, 0x0, // VSX Vector Byte-Reverse Halfword XX2-form (xxbrh XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
{BRINC, 0xfc0007ff, 0x1000020f, 0x0, // Bit Reversed Increment EVX-form (brinc RT,RA,RB)
[5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{EVABS, 0xfc0007ff, 0x10000208, 0xf800, // Vector Absolute Value EVX-form (evabs RT,RA)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
index 8c9977355c..8c3c2e7ab9 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
@@ -95,12 +95,13 @@ type Pass struct {
Analyzer *Analyzer // the identity of the current analyzer
// syntax and type information
- Fset *token.FileSet // file position information
- Files []*ast.File // the abstract syntax tree of each file
- OtherFiles []string // names of non-Go files of this package
- Pkg *types.Package // type information about the package
- TypesInfo *types.Info // type information about the syntax trees
- TypesSizes types.Sizes // function for computing sizes of types
+ Fset *token.FileSet // file position information
+ Files []*ast.File // the abstract syntax tree of each file
+ OtherFiles []string // names of non-Go files of this package
+ IgnoredFiles []string // names of ignored source files in this package
+ Pkg *types.Package // type information about the package
+ TypesInfo *types.Info // type information about the syntax trees
+ TypesSizes types.Sizes // function for computing sizes of types
// Report reports a Diagnostic, a finding about a specific location
// in the analyzed source code such as a potential mistake.
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
index fb17a0e415..9fa3302dfb 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
@@ -121,13 +121,14 @@ package being analyzed, and provides operations to the Run function for
reporting diagnostics and other information back to the driver.
type Pass struct {
- Fset *token.FileSet
- Files []*ast.File
- OtherFiles []string
- Pkg *types.Package
- TypesInfo *types.Info
- ResultOf map[*Analyzer]interface{}
- Report func(Diagnostic)
+ Fset *token.FileSet
+ Files []*ast.File
+ OtherFiles []string
+ IgnoredFiles []string
+ Pkg *types.Package
+ TypesInfo *types.Info
+ ResultOf map[*Analyzer]interface{}
+ Report func(Diagnostic)
...
}
@@ -139,6 +140,12 @@ files such as assembly that are part of this package. See the "asmdecl"
or "buildtags" analyzers for examples of loading non-Go files and reporting
diagnostics against them.
+The IgnoredFiles field provides the names, but not the contents,
+of ignored Go and non-Go source files that are not part of this package
+with the current build configuration but may be part of other build
+configurations. See the "buildtags" analyzer for an example of loading
+and checking IgnoredFiles.
+
The ResultOf field provides the results computed by the analyzers
required by this one, as expressed in its Analyzer.Requires field. The
driver runs the required analyzers first and makes their results
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
index e6bfe71539..d63855befd 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
@@ -137,6 +137,7 @@ var (
asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
ppc64Suff = re(`([BHWD])(ZU|Z|U|BR)?$`)
+ abiSuff = re(`^(.+)<ABI.+>$`)
)
func run(pass *analysis.Pass) (interface{}, error) {
@@ -200,6 +201,13 @@ Files:
}
retLine = nil
}
+ trimABI := func(fnName string) string {
+ m := abiSuff.FindStringSubmatch(fnName)
+ if m != nil {
+ return m[1]
+ }
+ return fnName
+ }
for lineno, line := range lines {
lineno++
@@ -268,6 +276,8 @@ Files:
continue
}
}
+ // Trim off optional ABI selector.
+ fnName := trimABI(fnName)
flag := m[3]
fn = knownFunc[fnName][arch]
if fn != nil {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go
index 78176f1011..841b928578 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/buildtag/buildtag.go
@@ -9,6 +9,7 @@ import (
"bytes"
"fmt"
"go/ast"
+ "go/parser"
"strings"
"unicode"
@@ -33,6 +34,20 @@ func runBuildTag(pass *analysis.Pass) (interface{}, error) {
return nil, err
}
}
+ for _, name := range pass.IgnoredFiles {
+ if strings.HasSuffix(name, ".go") {
+ f, err := parser.ParseFile(pass.Fset, name, nil, parser.ParseComments)
+ if err != nil {
+ // Not valid Go source code - not our job to diagnose, so ignore.
+ return nil, nil
+ }
+ checkGoFile(pass, f)
+ } else {
+ if err := checkOtherFile(pass, name); err != nil {
+ return nil, err
+ }
+ }
+ }
return nil, nil
}
@@ -132,13 +147,6 @@ func checkLine(line string, pastCutoff bool) error {
}
func checkArguments(fields []string) error {
- // The original version of this checker in vet could examine
- // files with malformed build tags that would cause the file to
- // be always ignored by "go build". However, drivers for the new
- // analysis API will analyze only the files selected to form a
- // package, so these checks will never fire.
- // TODO(adonovan): rethink this.
-
for _, arg := range fields[1:] {
for _, elem := range strings.Split(arg, ",") {
if strings.HasPrefix(elem, "!!") {
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
index 2ed274949b..713e1380ef 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
@@ -63,6 +63,7 @@ type Config struct {
ImportPath string
GoFiles []string
NonGoFiles []string
+ IgnoredFiles []string
ImportMap map[string]string
PackageFile map[string]string
Standard map[string]bool
@@ -333,6 +334,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
Fset: fset,
Files: files,
OtherFiles: cfg.NonGoFiles,
+ IgnoredFiles: cfg.IgnoredFiles,
Pkg: pkg,
TypesInfo: info,
TypesSizes: tc.Sizes,
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
index 21326f7521..4be3a2b680 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -1,4 +1,4 @@
-# github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
+# github.com/google/pprof v0.0.0-20201007051231-1066cbb265c7
## explicit
github.com/google/pprof/driver
github.com/google/pprof/internal/binutils
@@ -18,7 +18,7 @@ github.com/google/pprof/third_party/svgpan
# github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340
## explicit
github.com/ianlancetaylor/demangle
-# golang.org/x/arch v0.0.0-20200826200359-b19915210f00
+# golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
## explicit
golang.org/x/arch/arm/armasm
golang.org/x/arch/arm64/arm64asm
@@ -45,7 +45,7 @@ golang.org/x/mod/zip
golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/tools v0.0.0-20200918232735-d647fc253266
+# golang.org/x/tools v0.0.0-20201014170642-d1624618ad65
## explicit
golang.org/x/tools/go/analysis
golang.org/x/tools/go/analysis/internal/analysisflags