@@ -980,26 +980,26 @@ func addStr(n *ir.AddStringExpr) ir.Node {
980
980
981
981
const wrapGlobalMapInitSizeThreshold = 20
982
982
983
- // tryWrapGlobalMapInit examines the node 'n' to see if it is a map
984
- // variable initialization, and if so, possibly returns the mapvar
985
- // being assigned, a new function containing the init code, and a call
986
- // to the function passing the mapvar. Returns will be nil if the
987
- // assignment is not to a map, or the map init is not big enough ,
988
- // or if the expression being assigned to the map has side effects .
989
- func tryWrapGlobalMapInit (n ir.Node ) ( mapvar * ir.Name , genfn * ir. Func , call ir. Node ) {
983
+ // tryWrapGlobalInit returns a new outlined function to contain global
984
+ // initializer statement n, if possible and worthwhile. Otherwise, it
985
+ // returns nil.
986
+ //
987
+ // Currently, it outlines map assignment statements with large ,
988
+ // side-effect-free RHS expressions .
989
+ func tryWrapGlobalInit (n ir.Node ) * ir.Func {
990
990
// Look for "X = ..." where X has map type.
991
991
// FIXME: might also be worth trying to look for cases where
992
992
// the LHS is of interface type but RHS is map type.
993
993
if n .Op () != ir .OAS {
994
- return nil , nil , nil
994
+ return nil
995
995
}
996
996
as := n .(* ir.AssignStmt )
997
997
if ir .IsBlank (as .X ) || as .X .Op () != ir .ONAME {
998
- return nil , nil , nil
998
+ return nil
999
999
}
1000
1000
nm := as .X .(* ir.Name )
1001
1001
if ! nm .Type ().IsMap () {
1002
- return nil , nil , nil
1002
+ return nil
1003
1003
}
1004
1004
1005
1005
// Determine size of RHS.
@@ -1019,15 +1019,15 @@ func tryWrapGlobalMapInit(n ir.Node) (mapvar *ir.Name, genfn *ir.Func, call ir.N
1019
1019
fmt .Fprintf (os .Stderr , "=-= skipping %v size too small at %d\n " ,
1020
1020
nm , rsiz )
1021
1021
}
1022
- return nil , nil , nil
1022
+ return nil
1023
1023
}
1024
1024
1025
1025
// Reject right hand sides with side effects.
1026
1026
if AnySideEffects (as .Y ) {
1027
1027
if base .Debug .WrapGlobalMapDbg > 0 {
1028
1028
fmt .Fprintf (os .Stderr , "=-= rejected %v due to side effects\n " , nm )
1029
1029
}
1030
- return nil , nil , nil
1030
+ return nil
1031
1031
}
1032
1032
1033
1033
if base .Debug .WrapGlobalMapDbg > 1 {
@@ -1036,42 +1036,37 @@ func tryWrapGlobalMapInit(n ir.Node) (mapvar *ir.Name, genfn *ir.Func, call ir.N
1036
1036
1037
1037
// Create a new function that will (eventually) have this form:
1038
1038
//
1039
- // func map.init.%d() {
1040
- // globmapvar = <map initialization>
1041
- // }
1039
+ // func map.init.%d() {
1040
+ // globmapvar = <map initialization>
1041
+ // }
1042
1042
//
1043
+ // Note: cmd/link expects the function name to contain "map.init".
1043
1044
minitsym := typecheck .LookupNum ("map.init." , mapinitgen )
1044
1045
mapinitgen ++
1045
1046
1046
- newfn := ir .NewFunc (base .Pos , base .Pos , minitsym , types .NewSignature (nil , nil , nil ))
1047
- typecheck .DeclFunc (newfn )
1047
+ fn := ir .NewFunc (n .Pos (), n .Pos (), minitsym , types .NewSignature (nil , nil , nil ))
1048
+ fn .SetInlinabilityChecked (true ) // suppress inlining (which would defeat the point)
1049
+ typecheck .DeclFunc (fn )
1048
1050
if base .Debug .WrapGlobalMapDbg > 0 {
1049
- fmt .Fprintf (os .Stderr , "=-= generated func is %v\n " , newfn )
1051
+ fmt .Fprintf (os .Stderr , "=-= generated func is %v\n " , fn )
1050
1052
}
1051
1053
1052
1054
// NB: we're relying on this phase being run before inlining;
1053
1055
// if for some reason we need to move it after inlining, we'll
1054
1056
// need code here that relocates or duplicates inline temps.
1055
1057
1056
1058
// Insert assignment into function body; mark body finished.
1057
- newfn .Body = append ( newfn . Body , as )
1059
+ fn .Body = []ir. Node { as }
1058
1060
typecheck .FinishFuncBody ()
1059
1061
1060
- const no = `
1061
- // Register new function with decls.
1062
- typecheck.Target.Decls = append(typecheck.Target.Decls, newfn)
1063
- `
1064
-
1065
- // Create call to function, passing mapvar.
1066
- fncall := ir .NewCallExpr (n .Pos (), ir .OCALL , newfn .Nname , nil )
1067
-
1068
1062
if base .Debug .WrapGlobalMapDbg > 1 {
1069
1063
fmt .Fprintf (os .Stderr , "=-= mapvar is %v\n " , nm )
1070
- fmt .Fprintf (os .Stderr , "=-= newfunc is %+v\n " , newfn )
1071
- fmt .Fprintf (os .Stderr , "=-= call is %+v\n " , fncall )
1064
+ fmt .Fprintf (os .Stderr , "=-= newfunc is %+v\n " , fn )
1072
1065
}
1073
1066
1074
- return nm , newfn , typecheck .Stmt (fncall )
1067
+ recordFuncForVar (nm , fn )
1068
+
1069
+ return fn
1075
1070
}
1076
1071
1077
1072
// mapinitgen is a counter used to uniquify compiler-generated
@@ -1108,31 +1103,28 @@ func AddKeepRelocations() {
1108
1103
varToMapInit = nil
1109
1104
}
1110
1105
1111
- // OutlineMapInits walks through a list of init statements (candidates
1112
- // for inclusion in the package "init" function) and returns an
1113
- // updated list in which items corresponding to map variable
1114
- // initializations have been replaced with calls to outline "map init"
1115
- // functions (if legal/profitable). Return value is an updated list
1116
- // and a list of any newly generated "map init" functions.
1117
- func OutlineMapInits (stmts []ir.Node ) ([]ir.Node , []* ir.Func ) {
1106
+ // OutlineMapInits replaces global map initializers with outlined
1107
+ // calls to separate "map init" functions (where possible and
1108
+ // profitable), to facilitate better dead-code elimination by the
1109
+ // linker.
1110
+ func OutlineMapInits (fn * ir.Func ) {
1118
1111
if base .Debug .WrapGlobalMapCtl == 1 {
1119
- return stmts , nil
1112
+ return
1120
1113
}
1121
- newfuncs := []* ir.Func {}
1122
- for i := range stmts {
1123
- s := stmts [i ]
1124
- // Call the helper tryWrapGlobalMapInit to see if the LHS of
1125
- // this assignment is to a map var, and if so whether the RHS
1126
- // should be outlined into a separate init function. If the
1127
- // outline goes through, then replace the original init
1128
- // statement with the call to the outlined func, and append
1129
- // the new outlined func to our return list.
1130
- if mapvar , genfn , call := tryWrapGlobalMapInit (s ); call != nil {
1131
- stmts [i ] = call
1132
- newfuncs = append (newfuncs , genfn )
1133
- recordFuncForVar (mapvar , genfn )
1114
+
1115
+ outlined := 0
1116
+ for i , stmt := range fn .Body {
1117
+ // Attempt to outline stmt. If successful, replace it with a call
1118
+ // to the returned wrapper function.
1119
+ if wrapperFn := tryWrapGlobalInit (stmt ); wrapperFn != nil {
1120
+ ir .WithFunc (fn , func () {
1121
+ fn .Body [i ] = typecheck .Call (stmt .Pos (), wrapperFn .Nname , nil , false )
1122
+ })
1123
+ outlined ++
1134
1124
}
1135
1125
}
1136
1126
1137
- return stmts , newfuncs
1127
+ if base .Debug .WrapGlobalMapDbg > 1 {
1128
+ fmt .Fprintf (os .Stderr , "=-= outlined %v map initializations\n " , outlined )
1129
+ }
1138
1130
}
0 commit comments