]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: remove unified IR quirks mode
authorMatthew Dempsky <mdempsky@google.com>
Fri, 11 Feb 2022 19:55:27 +0000 (11:55 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 1 Mar 2022 06:01:28 +0000 (06:01 +0000)
Unified IR quirks mode existed to help bootstrap unified IR by forcing
it to produce bit-for-bit identical output to the original gc noder
and typechecker. However, I believe it's far enough along now to stand
on its own, plus we have good test coverage of generics already for
-G=3 mode.

Change-Id: I8bf412c8bb5d720eadeac3fe31f49dc73679da70
Reviewed-on: https://go-review.googlesource.com/c/go/+/385998
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/base/debug.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/noder/quirks.go
src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/noder/unified.go
src/cmd/compile/internal/noder/unified_test.go [deleted file]
src/cmd/compile/internal/noder/writer.go
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/typecheck/dcl.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/walk/closure.go

index b105e46e353cb4767b610e6dfe6f1293f2c2a526..80b2ff5bd60f63d03a5f080d7e7061932e6fb366 100644 (file)
@@ -39,7 +39,6 @@ type DebugFlags struct {
        TypeAssert           int    `help:"print information about type assertion inlining"`
        TypecheckInl         int    `help:"eager typechecking of inline function bodies"`
        Unified              int    `help:"enable unified IR construction"`
-       UnifiedQuirks        int    `help:"enable unified IR construction's quirks mode"`
        WB                   int    `help:"print information about write barriers"`
        ABIWrap              int    `help:"print information about ABI wrapper generation"`
        MayMoreStack         string `help:"call named function before all stack growth checks"`
index 4c4a724cdf9def00091bee079867df65ae8281bc..5a9a889894a89e39f229b43ca3c44bfebc27fd28 100644 (file)
@@ -32,7 +32,6 @@ import (
        "log"
        "os"
        "runtime"
-       "sort"
 )
 
 // handlePanic ensures that we print out an "internal compiler error" for any panic
@@ -205,17 +204,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
        // removal can skew the results (e.g., #43444).
        pkginit.MakeInit()
 
-       // Stability quirk: sort top-level declarations, so we're not
-       // sensitive to the order that functions are added. In particular,
-       // the order that noder+typecheck add function closures is very
-       // subtle, and not important to reproduce.
-       if base.Debug.UnifiedQuirks != 0 {
-               s := typecheck.Target.Decls
-               sort.SliceStable(s, func(i, j int) bool {
-                       return s[i].Pos().Before(s[j].Pos())
-               })
-       }
-
        // Eliminate some obviously dead code.
        // Must happen after typechecking.
        for _, n := range typecheck.Target.Decls {
index 914c5d2bd7115663dd34df2833e12dd86fa7bdb0..c4cb9b9a2c2e73a5bbe08bbffdc69a88dd979be1 100644 (file)
@@ -9,254 +9,13 @@ package noder
 import (
        "fmt"
 
-       "cmd/compile/internal/base"
-       "cmd/compile/internal/ir"
        "cmd/compile/internal/syntax"
-       "cmd/compile/internal/types2"
-       "cmd/internal/src"
 )
 
 // This file defines helper functions useful for satisfying toolstash
 // -cmp when compared against the legacy frontend behavior, but can be
 // removed after that's no longer a concern.
 
-// quirksMode controls whether behavior specific to satisfying
-// toolstash -cmp is used.
-func quirksMode() bool {
-       return base.Debug.UnifiedQuirks != 0
-}
-
-// posBasesOf returns all of the position bases in the source files,
-// as seen in a straightforward traversal.
-//
-// This is necessary to ensure position bases (and thus file names)
-// get registered in the same order as noder would visit them.
-func posBasesOf(noders []*noder) []*syntax.PosBase {
-       seen := make(map[*syntax.PosBase]bool)
-       var bases []*syntax.PosBase
-
-       for _, p := range noders {
-               syntax.Crawl(p.file, func(n syntax.Node) bool {
-                       if b := n.Pos().Base(); !seen[b] {
-                               bases = append(bases, b)
-                               seen[b] = true
-                       }
-                       return false
-               })
-       }
-
-       return bases
-}
-
-// importedObjsOf returns the imported objects (i.e., referenced
-// objects not declared by curpkg) from the parsed source files, in
-// the order that typecheck used to load their definitions.
-//
-// This is needed because loading the definitions for imported objects
-// can also add file names.
-func importedObjsOf(curpkg *types2.Package, info *types2.Info, noders []*noder) []types2.Object {
-       // This code is complex because it matches the precise order that
-       // typecheck recursively and repeatedly traverses the IR. It's meant
-       // to be thrown away eventually anyway.
-
-       seen := make(map[types2.Object]bool)
-       var objs []types2.Object
-
-       var phase int
-
-       decls := make(map[types2.Object]syntax.Decl)
-       assoc := func(decl syntax.Decl, names ...*syntax.Name) {
-               for _, name := range names {
-                       obj, ok := info.Defs[name]
-                       assert(ok)
-                       decls[obj] = decl
-               }
-       }
-
-       for _, p := range noders {
-               syntax.Crawl(p.file, func(n syntax.Node) bool {
-                       switch n := n.(type) {
-                       case *syntax.ConstDecl:
-                               assoc(n, n.NameList...)
-                       case *syntax.FuncDecl:
-                               assoc(n, n.Name)
-                       case *syntax.TypeDecl:
-                               assoc(n, n.Name)
-                       case *syntax.VarDecl:
-                               assoc(n, n.NameList...)
-                       case *syntax.BlockStmt:
-                               return true
-                       }
-                       return false
-               })
-       }
-
-       var visited map[syntax.Decl]bool
-
-       var resolveDecl func(n syntax.Decl)
-       var resolveNode func(n syntax.Node, top bool)
-
-       resolveDecl = func(n syntax.Decl) {
-               if visited[n] {
-                       return
-               }
-               visited[n] = true
-
-               switch n := n.(type) {
-               case *syntax.ConstDecl:
-                       resolveNode(n.Type, true)
-                       resolveNode(n.Values, true)
-
-               case *syntax.FuncDecl:
-                       if n.Recv != nil {
-                               resolveNode(n.Recv, true)
-                       }
-                       resolveNode(n.Type, true)
-
-               case *syntax.TypeDecl:
-                       resolveNode(n.Type, true)
-
-               case *syntax.VarDecl:
-                       if n.Type != nil {
-                               resolveNode(n.Type, true)
-                       } else {
-                               resolveNode(n.Values, true)
-                       }
-               }
-       }
-
-       resolveObj := func(pos syntax.Pos, obj types2.Object) {
-               switch obj.Pkg() {
-               case nil:
-                       // builtin; nothing to do
-
-               case curpkg:
-                       if decl, ok := decls[obj]; ok {
-                               resolveDecl(decl)
-                       }
-
-               default:
-                       if obj.Parent() == obj.Pkg().Scope() && !seen[obj] {
-                               seen[obj] = true
-                               objs = append(objs, obj)
-                       }
-               }
-       }
-
-       checkdefat := func(pos syntax.Pos, n *syntax.Name) {
-               if n.Value == "_" {
-                       return
-               }
-               obj, ok := info.Uses[n]
-               if !ok {
-                       obj, ok = info.Defs[n]
-                       if !ok {
-                               return
-                       }
-               }
-               if obj == nil {
-                       return
-               }
-               resolveObj(pos, obj)
-       }
-       checkdef := func(n *syntax.Name) { checkdefat(n.Pos(), n) }
-
-       var later []syntax.Node
-
-       resolveNode = func(n syntax.Node, top bool) {
-               if n == nil {
-                       return
-               }
-               syntax.Crawl(n, func(n syntax.Node) bool {
-                       switch n := n.(type) {
-                       case *syntax.Name:
-                               checkdef(n)
-
-                       case *syntax.SelectorExpr:
-                               if name, ok := n.X.(*syntax.Name); ok {
-                                       if _, isPkg := info.Uses[name].(*types2.PkgName); isPkg {
-                                               checkdefat(n.X.Pos(), n.Sel)
-                                               return true
-                                       }
-                               }
-
-                       case *syntax.AssignStmt:
-                               resolveNode(n.Rhs, top)
-                               resolveNode(n.Lhs, top)
-                               return true
-
-                       case *syntax.VarDecl:
-                               resolveNode(n.Values, top)
-
-                       case *syntax.FuncLit:
-                               if top {
-                                       resolveNode(n.Type, top)
-                                       later = append(later, n.Body)
-                                       return true
-                               }
-
-                       case *syntax.BlockStmt:
-                               if phase >= 3 {
-                                       for _, stmt := range n.List {
-                                               resolveNode(stmt, false)
-                                       }
-                               }
-                               return true
-                       }
-
-                       return false
-               })
-       }
-
-       for phase = 1; phase <= 5; phase++ {
-               visited = map[syntax.Decl]bool{}
-
-               for _, p := range noders {
-                       for _, decl := range p.file.DeclList {
-                               switch decl := decl.(type) {
-                               case *syntax.ConstDecl:
-                                       resolveDecl(decl)
-
-                               case *syntax.FuncDecl:
-                                       resolveDecl(decl)
-                                       if phase >= 3 && decl.Body != nil {
-                                               resolveNode(decl.Body, true)
-                                       }
-
-                               case *syntax.TypeDecl:
-                                       if !decl.Alias || phase >= 2 {
-                                               resolveDecl(decl)
-                                       }
-
-                               case *syntax.VarDecl:
-                                       if phase >= 2 {
-                                               resolveNode(decl.Values, true)
-                                               resolveDecl(decl)
-                                       }
-                               }
-                       }
-
-                       if phase >= 5 {
-                               syntax.Crawl(p.file, func(n syntax.Node) bool {
-                                       if name, ok := n.(*syntax.Name); ok {
-                                               if obj, ok := info.Uses[name]; ok {
-                                                       resolveObj(name.Pos(), obj)
-                                               }
-                                       }
-                                       return false
-                               })
-                       }
-               }
-
-               for i := 0; i < len(later); i++ {
-                       resolveNode(later[i], true)
-               }
-               later = nil
-       }
-
-       return objs
-}
-
 // typeExprEndPos returns the position that noder would leave base.Pos
 // after parsing the given type expression.
 func typeExprEndPos(expr0 syntax.Expr) syntax.Pos {
@@ -320,131 +79,3 @@ func lastFieldType(fields []*syntax.Field) syntax.Expr {
        }
        return fields[len(fields)-1].Type
 }
-
-// sumPos returns the position that noder.sum would produce for
-// constant expression x.
-func sumPos(x syntax.Expr) syntax.Pos {
-       orig := x
-       for {
-               switch x1 := x.(type) {
-               case *syntax.BasicLit:
-                       assert(x1.Kind == syntax.StringLit)
-                       return x1.Pos()
-               case *syntax.Operation:
-                       assert(x1.Op == syntax.Add && x1.Y != nil)
-                       if r, ok := x1.Y.(*syntax.BasicLit); ok {
-                               assert(r.Kind == syntax.StringLit)
-                               x = x1.X
-                               continue
-                       }
-               }
-               return orig.Pos()
-       }
-}
-
-// funcParamsEndPos returns the value of base.Pos left by noder after
-// processing a function signature.
-func funcParamsEndPos(fn *ir.Func) src.XPos {
-       sig := fn.Nname.Type()
-
-       fields := sig.Results().FieldSlice()
-       if len(fields) == 0 {
-               fields = sig.Params().FieldSlice()
-               if len(fields) == 0 {
-                       fields = sig.Recvs().FieldSlice()
-                       if len(fields) == 0 {
-                               if fn.OClosure != nil {
-                                       return fn.Nname.Ntype.Pos()
-                               }
-                               return fn.Pos()
-                       }
-               }
-       }
-
-       return fields[len(fields)-1].Pos
-}
-
-type dupTypes struct {
-       origs map[types2.Type]types2.Type
-}
-
-func (d *dupTypes) orig(t types2.Type) types2.Type {
-       if orig, ok := d.origs[t]; ok {
-               return orig
-       }
-       return t
-}
-
-func (d *dupTypes) add(t, orig types2.Type) {
-       if t == orig {
-               return
-       }
-
-       if d.origs == nil {
-               d.origs = make(map[types2.Type]types2.Type)
-       }
-       assert(d.origs[t] == nil)
-       d.origs[t] = orig
-
-       switch t := t.(type) {
-       case *types2.Pointer:
-               orig := orig.(*types2.Pointer)
-               d.add(t.Elem(), orig.Elem())
-
-       case *types2.Slice:
-               orig := orig.(*types2.Slice)
-               d.add(t.Elem(), orig.Elem())
-
-       case *types2.Map:
-               orig := orig.(*types2.Map)
-               d.add(t.Key(), orig.Key())
-               d.add(t.Elem(), orig.Elem())
-
-       case *types2.Array:
-               orig := orig.(*types2.Array)
-               assert(t.Len() == orig.Len())
-               d.add(t.Elem(), orig.Elem())
-
-       case *types2.Chan:
-               orig := orig.(*types2.Chan)
-               assert(t.Dir() == orig.Dir())
-               d.add(t.Elem(), orig.Elem())
-
-       case *types2.Struct:
-               orig := orig.(*types2.Struct)
-               assert(t.NumFields() == orig.NumFields())
-               for i := 0; i < t.NumFields(); i++ {
-                       d.add(t.Field(i).Type(), orig.Field(i).Type())
-               }
-
-       case *types2.Interface:
-               orig := orig.(*types2.Interface)
-               assert(t.NumExplicitMethods() == orig.NumExplicitMethods())
-               assert(t.NumEmbeddeds() == orig.NumEmbeddeds())
-               for i := 0; i < t.NumExplicitMethods(); i++ {
-                       d.add(t.ExplicitMethod(i).Type(), orig.ExplicitMethod(i).Type())
-               }
-               for i := 0; i < t.NumEmbeddeds(); i++ {
-                       d.add(t.EmbeddedType(i), orig.EmbeddedType(i))
-               }
-
-       case *types2.Signature:
-               orig := orig.(*types2.Signature)
-               assert((t.Recv() == nil) == (orig.Recv() == nil))
-               if t.Recv() != nil {
-                       d.add(t.Recv().Type(), orig.Recv().Type())
-               }
-               d.add(t.Params(), orig.Params())
-               d.add(t.Results(), orig.Results())
-
-       case *types2.Tuple:
-               orig := orig.(*types2.Tuple)
-               assert(t.Len() == orig.Len())
-               for i := 0; i < t.Len(); i++ {
-                       d.add(t.At(i).Type(), orig.At(i).Type())
-               }
-
-       default:
-               assert(types2.Identical(t, orig))
-       }
-}
index 5d17c534c10205fafef64282fed7ae48a4aac46e..60b0b7b40a76a28795d2c6901a9a0bcf3ec5fbeb 100644 (file)
@@ -968,11 +968,7 @@ func (r *reader) funcBody(fn *ir.Func) {
 
                body := r.stmts()
                if body == nil {
-                       pos := src.NoXPos
-                       if quirksMode() {
-                               pos = funcParamsEndPos(fn)
-                       }
-                       body = []ir.Node{typecheck.Stmt(ir.NewBlockStmt(pos, nil))}
+                       body = []ir.Node{typecheck.Stmt(ir.NewBlockStmt(src.NoXPos, nil))}
                }
                fn.Body = body
                fn.Endlineno = r.pos()
@@ -1291,18 +1287,6 @@ func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node {
 
        case stmtSwitch:
                return r.switchStmt(label)
-
-       case stmtTypeDeclHack:
-               // fake "type _ = int" declaration to prevent inlining in quirks mode.
-               assert(quirksMode())
-
-               name := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.BlankNode.Sym())
-               name.SetAlias(true)
-               setType(name, types.Types[types.TINT])
-
-               n := ir.NewDecl(src.NoXPos, ir.ODCLTYPE, name)
-               n.SetTypecheck(1)
-               return n
        }
 }
 
@@ -1712,22 +1696,15 @@ func (r *reader) funcLit() ir.Node {
        r.sync(syncFuncLit)
 
        pos := r.pos()
-       typPos := r.pos()
        xtype2 := r.signature(types.LocalPkg, nil)
 
        opos := pos
-       if quirksMode() {
-               opos = r.origPos(pos)
-       }
 
        fn := ir.NewClosureFunc(opos, r.curfn != nil)
        clo := fn.OClosure
        ir.NameClosure(clo, r.curfn)
 
        setType(fn.Nname, xtype2)
-       if quirksMode() {
-               fn.Nname.Ntype = ir.TypeNodeAt(typPos, xtype2)
-       }
        typecheck.Func(fn)
        setType(clo, fn.Type())
 
@@ -1767,23 +1744,6 @@ func (r *reader) op() ir.Op {
 // @@@ Package initialization
 
 func (r *reader) pkgInit(self *types.Pkg, target *ir.Package) {
-       if quirksMode() {
-               for i, n := 0, r.len(); i < n; i++ {
-                       // Eagerly register position bases, so their filenames are
-                       // assigned stable indices.
-                       posBase := r.posBase()
-                       _ = base.Ctxt.PosTable.XPos(src.MakePos(posBase, 0, 0))
-               }
-
-               for i, n := 0, r.len(); i < n; i++ {
-                       // Eagerly resolve imported objects, so any filenames registered
-                       // in the process are assigned stable indices too.
-                       _, sym := r.qualifiedIdent()
-                       typecheck.Resolve(ir.NewIdent(src.NoXPos, sym))
-                       assert(sym.Def != nil)
-               }
-       }
-
        cgoPragmas := make([][]string, r.len())
        for i := range cgoPragmas {
                cgoPragmas[i] = r.strings()
@@ -2027,17 +1987,6 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp
 
        body := ir.Nodes(r.curfn.Body)
 
-       // Quirk: If deadcode elimination turned a non-empty function into
-       // an empty one, we need to set the position for the empty block
-       // left behind to the inlined position for src.NoXPos, so that
-       // an empty string gets added into the DWARF file name listing at
-       // the appropriate index.
-       if quirksMode() && len(body) == 1 {
-               if block, ok := body[0].(*ir.BlockStmt); ok && len(block.List) == 0 {
-                       block.SetPos(r.updatePos(src.NoXPos))
-               }
-       }
-
        // Quirkish: We need to eagerly prune variables added during
        // inlining, but removed by deadcode.FuncBody above. Unused
        // variables will get removed during stack frame layout anyway, but
@@ -2218,8 +2167,8 @@ func (r *reader) importedDef() bool {
 }
 
 func MakeWrappers(target *ir.Package) {
-       // Only unified IR in non-quirks mode emits its own wrappers.
-       if base.Debug.Unified == 0 || quirksMode() {
+       // Only unified IR emits its own wrappers.
+       if base.Debug.Unified == 0 {
                return
        }
 
index ec0012db4cec44bb732597f5843ffb2db863f8b9..57bec438906886d74f62f448375f3edba4292b8f 100644 (file)
@@ -72,11 +72,7 @@ var localPkgReader *pkgReader
 func unified(noders []*noder) {
        inline.NewInline = InlineCall
 
-       if !quirksMode() {
-               writeNewExportFunc = writeNewExport
-       } else if base.Flag.G != 0 {
-               base.Errorf("cannot use -G and -d=quirksmode together")
-       }
+       writeNewExportFunc = writeNewExport
 
        newReadImportFunc = func(data string, pkg1 *types.Pkg, ctxt *types2.Context, packages map[string]*types2.Package) (pkg2 *types2.Package, err error) {
                pr := newPkgDecoder(pkg1.Path, data)
diff --git a/src/cmd/compile/internal/noder/unified_test.go b/src/cmd/compile/internal/noder/unified_test.go
deleted file mode 100644 (file)
index d7334df..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package noder_test
-
-import (
-       "encoding/json"
-       "flag"
-       exec "internal/execabs"
-       "os"
-       "reflect"
-       "runtime"
-       "strings"
-       "testing"
-)
-
-var (
-       flagCmp      = flag.Bool("cmp", false, "enable TestUnifiedCompare")
-       flagPkgs     = flag.String("pkgs", "std", "list of packages to compare (ignored in -short mode)")
-       flagAll      = flag.Bool("all", false, "enable testing of all GOOS/GOARCH targets")
-       flagParallel = flag.Bool("parallel", false, "test GOOS/GOARCH targets in parallel")
-)
-
-// TestUnifiedCompare implements a test similar to running:
-//
-//     $ go build -toolexec="toolstash -cmp" std
-//
-// The -pkgs flag controls the list of packages tested.
-//
-// By default, only the native GOOS/GOARCH target is enabled. The -all
-// flag enables testing of non-native targets. The -parallel flag
-// additionally enables testing of targets in parallel.
-//
-// Caution: Testing all targets is very resource intensive! On an IBM
-// P920 (dual Intel Xeon Gold 6154 CPUs; 36 cores, 192GB RAM), testing
-// all targets in parallel takes about 5 minutes. Using the 'go test'
-// command's -run flag for subtest matching is recommended for less
-// powerful machines.
-func TestUnifiedCompare(t *testing.T) {
-       // TODO(mdempsky): Either re-enable or delete. Disabled for now to
-       // avoid impeding others' forward progress.
-       if !*flagCmp {
-               t.Skip("skipping TestUnifiedCompare (use -cmp to enable)")
-       }
-
-       targets, err := exec.Command("go", "tool", "dist", "list").Output()
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       for _, target := range strings.Fields(string(targets)) {
-               t.Run(target, func(t *testing.T) {
-                       parts := strings.Split(target, "/")
-                       goos, goarch := parts[0], parts[1]
-
-                       if !(*flagAll || goos == runtime.GOOS && goarch == runtime.GOARCH) {
-                               t.Skip("skipping non-native target (use -all to enable)")
-                       }
-                       if *flagParallel {
-                               t.Parallel()
-                       }
-
-                       pkgs1 := loadPackages(t, goos, goarch, "-d=unified=0 -d=inlfuncswithclosures=0 -d=unifiedquirks=1 -G=0")
-                       pkgs2 := loadPackages(t, goos, goarch, "-d=unified=1 -d=inlfuncswithclosures=0 -d=unifiedquirks=1 -G=0")
-
-                       if len(pkgs1) != len(pkgs2) {
-                               t.Fatalf("length mismatch: %v != %v", len(pkgs1), len(pkgs2))
-                       }
-
-                       for i := range pkgs1 {
-                               pkg1 := pkgs1[i]
-                               pkg2 := pkgs2[i]
-
-                               path := pkg1.ImportPath
-                               if path != pkg2.ImportPath {
-                                       t.Fatalf("mismatched paths: %q != %q", path, pkg2.ImportPath)
-                               }
-
-                               // Packages that don't have any source files (e.g., packages
-                               // unsafe, embed/internal/embedtest, and cmd/internal/moddeps).
-                               if pkg1.Export == "" && pkg2.Export == "" {
-                                       continue
-                               }
-
-                               if pkg1.BuildID == pkg2.BuildID {
-                                       t.Errorf("package %q: build IDs unexpectedly matched", path)
-                               }
-
-                               // Unlike toolstash -cmp, we're comparing the same compiler
-                               // binary against itself, just with different flags. So we
-                               // don't need to worry about skipping over mismatched version
-                               // strings, but we do need to account for differing build IDs.
-                               //
-                               // Fortunately, build IDs are cryptographic 256-bit hashes,
-                               // and cmd/go provides us with them up front. So we can just
-                               // use them as delimeters to split the files, and then check
-                               // that the substrings are all equal.
-                               file1 := strings.Split(readFile(t, pkg1.Export), pkg1.BuildID)
-                               file2 := strings.Split(readFile(t, pkg2.Export), pkg2.BuildID)
-                               if !reflect.DeepEqual(file1, file2) {
-                                       t.Errorf("package %q: compile output differs", path)
-                               }
-                       }
-               })
-       }
-}
-
-type pkg struct {
-       ImportPath string
-       Export     string
-       BuildID    string
-       Incomplete bool
-}
-
-func loadPackages(t *testing.T, goos, goarch, gcflags string) []pkg {
-       args := []string{"list", "-e", "-export", "-json", "-gcflags=all=" + gcflags, "--"}
-       if testing.Short() {
-               t.Log("short testing mode; only testing package runtime")
-               args = append(args, "runtime")
-       } else {
-               args = append(args, strings.Fields(*flagPkgs)...)
-       }
-
-       cmd := exec.Command("go", args...)
-       cmd.Env = append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch)
-       cmd.Stderr = os.Stderr
-       t.Logf("running %v", cmd)
-       stdout, err := cmd.StdoutPipe()
-       if err != nil {
-               t.Fatal(err)
-       }
-       if err := cmd.Start(); err != nil {
-               t.Fatal(err)
-       }
-
-       var res []pkg
-       for dec := json.NewDecoder(stdout); dec.More(); {
-               var pkg pkg
-               if err := dec.Decode(&pkg); err != nil {
-                       t.Fatal(err)
-               }
-               if pkg.Incomplete {
-                       t.Fatalf("incomplete package: %q", pkg.ImportPath)
-               }
-               res = append(res, pkg)
-       }
-       if err := cmd.Wait(); err != nil {
-               t.Fatal(err)
-       }
-       return res
-}
-
-func readFile(t *testing.T, name string) string {
-       buf, err := os.ReadFile(name)
-       if err != nil {
-               t.Fatal(err)
-       }
-       return string(buf)
-}
index 46e833912057d158cdbf899a19abff96db95e62e..97b3d878d0165b00b146bbcd3a80573481abc8c8 100644 (file)
@@ -8,7 +8,6 @@ package noder
 
 import (
        "fmt"
-       "go/constant"
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
@@ -33,8 +32,6 @@ type pkgWriter struct {
 
        linknames  map[types2.Object]string
        cgoPragmas [][]string
-
-       dups dupTypes
 }
 
 func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info) *pkgWriter {
@@ -251,10 +248,6 @@ func (w *writer) typInfo(info typeInfo) {
 // typIdx also reports whether typ is a derived type; that is, whether
 // its identity depends on type parameters.
 func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
-       if quirksMode() {
-               typ = pw.dups.orig(typ)
-       }
-
        if idx, ok := pw.typsIdx[typ]; ok {
                return typeInfo{idx: idx, derived: false}
        }
@@ -999,36 +992,9 @@ func (w *writer) declStmt(decl syntax.Decl) {
        default:
                w.p.unexpected("declaration", decl)
 
-       case *syntax.ConstDecl:
-
-       case *syntax.TypeDecl:
-               // Quirk: The legacy inliner doesn't support inlining functions
-               // with type declarations. Unified IR doesn't have any need to
-               // write out type declarations explicitly (they're always looked
-               // up via global index tables instead), so we just write out a
-               // marker so the reader knows to synthesize a fake declaration to
-               // prevent inlining.
-               if quirksMode() {
-                       w.code(stmtTypeDeclHack)
-               }
+       case *syntax.ConstDecl, *syntax.TypeDecl:
 
        case *syntax.VarDecl:
-               values := unpackListExpr(decl.Values)
-
-               // Quirk: When N variables are declared with N initialization
-               // values, we need to decompose that into N interleaved
-               // declarations+initializations, because it leads to different
-               // (albeit semantically equivalent) code generation.
-               if quirksMode() && len(decl.NameList) == len(values) {
-                       for i, name := range decl.NameList {
-                               w.code(stmtAssign)
-                               w.pos(decl)
-                               w.exprList(values[i])
-                               w.assignList(name)
-                       }
-                       break
-               }
-
                w.code(stmtAssign)
                w.pos(decl)
                w.exprList(decl.Values)
@@ -1184,21 +1150,8 @@ func (w *writer) expr(expr syntax.Expr) {
                }
 
                if tv.Value != nil {
-                       pos := expr.Pos()
-                       if quirksMode() {
-                               if obj != nil {
-                                       // Quirk: IR (and thus iexport) doesn't track position
-                                       // information for uses of declared objects.
-                                       pos = syntax.Pos{}
-                               } else if tv.Value.Kind() == constant.String {
-                                       // Quirk: noder.sum picks a particular position for certain
-                                       // string concatenations.
-                                       pos = sumPos(expr)
-                               }
-                       }
-
                        w.code(exprConst)
-                       w.pos(pos)
+                       w.pos(expr.Pos())
                        w.typ(tv.Type)
                        w.value(tv.Value)
 
@@ -1377,15 +1330,11 @@ func (w *writer) funcLit(expr *syntax.FuncLit) {
 
        w.sync(syncFuncLit)
        w.pos(expr)
-       w.pos(expr.Type) // for QuirksMode
        w.signature(sig)
 
        w.len(len(closureVars))
        for _, cv := range closureVars {
                w.pos(cv.pos)
-               if quirksMode() {
-                       cv.pos = expr.Body.Rbrace
-               }
                w.useLocal(cv.pos, cv.obj)
        }
 
@@ -1538,21 +1487,6 @@ func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
                        }
                }
 
-               // Workaround for #46208. For variable declarations that
-               // declare multiple variables and have an explicit type
-               // expression, the type expression is evaluated multiple
-               // times. This affects toolstash -cmp, because iexport is
-               // sensitive to *types.Type pointer identity.
-               if quirksMode() && n.Type != nil {
-                       tv, ok := pw.info.Types[n.Type]
-                       assert(ok)
-                       assert(tv.IsType())
-                       for _, name := range n.NameList {
-                               obj := pw.info.Defs[name].(*types2.Var)
-                               pw.dups.add(obj.Type(), tv.Type)
-                       }
-               }
-
        case *syntax.BlockStmt:
                if !c.withinFunc {
                        copy := *c
@@ -1621,20 +1555,6 @@ func (pw *pkgWriter) checkPragmas(p syntax.Pragma, allowed ir.PragmaFlag, embedO
 }
 
 func (w *writer) pkgInit(noders []*noder) {
-       if quirksMode() {
-               posBases := posBasesOf(noders)
-               w.len(len(posBases))
-               for _, posBase := range posBases {
-                       w.posBase(posBase)
-               }
-
-               objs := importedObjsOf(w.p.curpkg, w.p.info, noders)
-               w.len(len(objs))
-               for _, obj := range objs {
-                       w.qualifiedIdent(obj)
-               }
-       }
-
        w.len(len(w.p.cgoPragmas))
        for _, cgoPragma := range w.p.cgoPragmas {
                w.strings(cgoPragma)
index 42ea7bac46cbcb2226228e5c9ab05a526d4c034c..bd55c91c388f134f62e8d7d477fad0a32d84e42c 100644 (file)
@@ -1826,8 +1826,8 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
        }
        newnam.SetSiggen(true)
 
-       // Except in quirks mode, unified IR creates its own wrappers.
-       if base.Debug.Unified != 0 && base.Debug.UnifiedQuirks == 0 {
+       // Unified IR creates its own wrappers.
+       if base.Debug.Unified != 0 {
                return lsym
        }
 
index 68ab05a538e8fd52e56686892025dab8e59663e1..e9e4f0ba679c2e134eecfb9347e2b2f060ce95da 100644 (file)
@@ -455,13 +455,6 @@ func autotmpname(n int) string {
                // Add a preceding . to avoid clashing with legal names.
                prefix := ".autotmp_%d"
 
-               // In quirks mode, pad out the number to stabilize variable
-               // sorting. This ensures autotmps 8 and 9 sort the same way even
-               // if they get renumbered to 9 and 10, respectively.
-               if base.Debug.UnifiedQuirks != 0 {
-                       prefix = ".autotmp_%06d"
-               }
-
                s = fmt.Sprintf(prefix, n)
                autotmpnames[n] = s
        }
index ae3c41ca04304c9dc99b991c816f80dc35d65ddd..947d029ae2ceb557e63b1c5fef192d2051ce51ae 100644 (file)
@@ -621,12 +621,7 @@ func (p *iexporter) doDecl(n *ir.Name) {
                        break
                }
 
-               // Sort methods, for consistency with types2.
-               methods := append([]*types.Field(nil), t.Methods().Slice()...)
-               if base.Debug.UnifiedQuirks != 0 {
-                       sort.Sort(types.MethodsByName(methods))
-               }
-
+               methods := t.Methods().Slice()
                w.uint64(uint64(len(methods)))
                for _, m := range methods {
                        w.pos(m.Pos)
@@ -1052,14 +1047,6 @@ func (w *exportWriter) doTyp(t *types.Type) {
                        }
                }
 
-               // Sort methods and embedded types, for consistency with types2.
-               // Note: embedded types may be anonymous, and types2 sorts them
-               // with sort.Stable too.
-               if base.Debug.UnifiedQuirks != 0 {
-                       sort.Sort(types.MethodsByName(methods))
-                       sort.Stable(types.EmbeddedsByName(embeddeds))
-               }
-
                w.startType(interfaceType)
                w.setPkg(t.Pkg(), true)
 
index 4d1c5621fec857fe3a9487bf9da3c422367e08d5..68e16803be088f97d7d7db956abec7368bd35e9b 100644 (file)
@@ -227,7 +227,7 @@ func methodValueWrapper(dot *ir.SelectorExpr) *ir.Name {
        }
        sym.SetUniq(true)
 
-       if base.Debug.Unified != 0 && base.Debug.UnifiedQuirks == 0 {
+       if base.Debug.Unified != 0 {
                base.FatalfAt(dot.Pos(), "missing wrapper for %v", meth)
        }