diff --git a/src/cmd/compile/internal/gc/embed.go b/src/cmd/compile/internal/gc/embed.go
index 103949c..f45796c 100644
--- a/src/cmd/compile/internal/gc/embed.go
+++ b/src/cmd/compile/internal/gc/embed.go
@@ -47,9 +47,7 @@
 	embedFiles
 )
 
-var numLocalEmbed int
-
-func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []PragmaEmbed) (newExprs []*Node) {
+func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []PragmaEmbed) {
 	haveEmbed := false
 	for _, decl := range p.file.DeclList {
 		imp, ok := decl.(*syntax.ImportDecl)
@@ -67,44 +65,48 @@
 	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
+		return
 	}
 	if len(names) > 1 {
 		p.yyerrorpos(pos, "go:embed cannot apply to multiple vars")
-		return exprs
+		return
 	}
 	if len(exprs) > 0 {
 		p.yyerrorpos(pos, "go:embed cannot apply to var with initializer")
-		return exprs
+		return
 	}
 	if typ == nil {
 		// Should not happen, since len(exprs) == 0 now.
 		p.yyerrorpos(pos, "go:embed cannot apply to var without type")
-		return exprs
+		return
+	}
+	if dclcontext != PEXTERN {
+		p.yyerrorpos(pos, "go:embed cannot apply to var inside func")
+		return
 	}
 
-	kind := embedKindApprox(typ)
-	if kind == embedUnknown {
-		p.yyerrorpos(pos, "go:embed cannot apply to var of type %v", typ)
-		return exprs
+	var list []irEmbed
+	for _, e := range embeds {
+		list = append(list, irEmbed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns})
 	}
+	v := names[0]
+	v.Name.Param.SetEmbedList(list)
+	embedlist = append(embedlist, v)
+}
 
+func embedFileList(v *Node, kind int) []string {
 	// Build list of files to store.
 	have := make(map[string]bool)
 	var list []string
-	for _, e := range embeds {
+	for _, e := range v.Name.Param.EmbedList() {
 		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)
+				yyerrorl(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)
+					yyerrorl(e.Pos, "invalid go:embed: build system did not map file: %s", file)
 					continue
 				}
 				if !have[file] {
@@ -126,46 +128,12 @@
 
 	if kind == embedString || kind == embedBytes {
 		if len(list) > 1 {
-			p.yyerrorpos(pos, "invalid go:embed: multiple files for type %v", typ)
-			return exprs
+			yyerrorl(v.Pos, "invalid go:embed: multiple files for type %v", v.Type)
+			return nil
 		}
 	}
 
-	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
+	return list
 }
 
 // embedKind determines the kind of embedding variable.
@@ -173,10 +141,10 @@
 	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] {
+	if typ.Etype == types.TSTRING {
 		return embedString
 	}
-	if typ.Sym == nil && typ.IsSlice() && typ.Elem() == types.Bytetype {
+	if typ.Etype == types.TSLICE && typ.Elem().Etype == types.TUINT8 {
 		return embedBytes
 	}
 	return embedUnknown
@@ -214,11 +182,26 @@
 // 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:
+	commentPos := v.Name.Param.EmbedList()[0].Pos
+	if !langSupported(1, 16, localpkg) {
+		lno := lineno
+		lineno = commentPos
+		yyerrorv("go1.16", "go:embed")
+		lineno = lno
+		return
+	}
+	if embedCfg.Patterns == nil {
+		yyerrorl(commentPos, "invalid go:embed: build system did not supply embed configuration")
+		return
+	}
+	kind := embedKind(v.Type)
+	if kind == embedUnknown {
 		yyerrorl(v.Pos, "go:embed cannot apply to var of type %v", v.Type)
+		return
+	}
 
+	files := embedFileList(v, kind)
+	switch kind {
 	case embedString, embedBytes:
 		file := files[0]
 		fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], kind == embedString, nil)
diff --git a/src/cmd/compile/internal/gc/initorder.go b/src/cmd/compile/internal/gc/initorder.go
index 41f1349..e2084fd 100644
--- a/src/cmd/compile/internal/gc/initorder.go
+++ b/src/cmd/compile/internal/gc/initorder.go
@@ -108,7 +108,7 @@
 					errorexit()
 				}
 
-				findInitLoopAndExit(firstLHS(n), new([]*Node))
+				findInitLoopAndExit(firstLHS(n), new([]*Node), make(map[*Node]bool))
 				Fatalf("initialization unfinished, but failed to identify loop")
 			}
 		}
@@ -181,10 +181,7 @@
 // path points to a slice used for tracking the sequence of
 // variables/functions visited. Using a pointer to a slice allows the
 // slice capacity to grow and limit reallocations.
-func findInitLoopAndExit(n *Node, path *[]*Node) {
-	// We implement a simple DFS loop-finding algorithm. This
-	// could be faster, but initialization cycles are rare.
-
+func findInitLoopAndExit(n *Node, path *[]*Node, ok map[*Node]bool) {
 	for i, x := range *path {
 		if x == n {
 			reportInitLoopAndExit((*path)[i:])
@@ -201,12 +198,18 @@
 	*path = append(*path, n)
 	for _, ref := range refers {
 		// Short-circuit variables that were initialized.
-		if ref.Class() == PEXTERN && ref.Name.Defn.Initorder() == InitDone {
+		if ref.Class() == PEXTERN && ref.Name.Defn.Initorder() == InitDone || ok[ref] {
 			continue
 		}
-
-		findInitLoopAndExit(ref, path)
+		findInitLoopAndExit(ref, path, ok)
 	}
+
+	// n is not involved in a cycle.
+	// Record that fact to avoid checking it again when reached another way,
+	// or else this traversal will take exponential time traversing all paths
+	// through the part of the package's call graph implicated in the cycle.
+	ok[n] = true
+
 	*path = (*path)[:len(*path)-1]
 }
 
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index 67d24ef..7494c3e 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -397,7 +397,7 @@
 					p.yyerrorpos(e.Pos, "//go:embed only allowed in Go files that import \"embed\"")
 				}
 			} else {
-				exprs = varEmbed(p, names, typ, exprs, pragma.Embeds)
+				varEmbed(p, names, typ, exprs, pragma.Embeds)
 			}
 			pragma.Embeds = nil
 		}
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index 4335833..7b4a315 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -499,7 +499,12 @@
 	alias bool
 }
 
-type embedFileList []string
+type irEmbed struct {
+	Pos      src.XPos
+	Patterns []string
+}
+
+type embedList []irEmbed
 
 // Pragma returns the PragmaFlag for p, which must be for an OTYPE.
 func (p *Param) Pragma() PragmaFlag {
@@ -547,28 +552,28 @@
 	(*p.Extra).(*paramType).alias = alias
 }
 
-// EmbedFiles returns the list of embedded files for p,
+// EmbedList returns the list of embedded files for p,
 // which must be for an ONAME var.
-func (p *Param) EmbedFiles() []string {
+func (p *Param) EmbedList() []irEmbed {
 	if p.Extra == nil {
 		return nil
 	}
-	return *(*p.Extra).(*embedFileList)
+	return *(*p.Extra).(*embedList)
 }
 
-// SetEmbedFiles sets the list of embedded files for p,
+// SetEmbedList sets the list of embedded files for p,
 // which must be for an ONAME var.
-func (p *Param) SetEmbedFiles(list []string) {
+func (p *Param) SetEmbedList(list []irEmbed) {
 	if p.Extra == nil {
 		if len(list) == 0 {
 			return
 		}
-		f := embedFileList(list)
+		f := embedList(list)
 		p.Extra = new(interface{})
 		*p.Extra = &f
 		return
 	}
-	*(*p.Extra).(*embedFileList) = list
+	*(*p.Extra).(*embedList) = list
 }
 
 // Functions