github.com/bir3/gocompiler@v0.9.2202/src/internal/buildcfg/exp.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package buildcfg 6 7 import ( 8 "fmt" 9 "reflect" 10 "strings" 11 12 "github.com/bir3/gocompiler/src/internal/goexperiment" 13 ) 14 15 // ExperimentFlags represents a set of GOEXPERIMENT flags relative to a baseline 16 // (platform-default) experiment configuration. 17 type ExperimentFlags struct { 18 goexperiment.Flags 19 baseline goexperiment.Flags 20 } 21 22 // Experiment contains the toolchain experiments enabled for the 23 // current build. 24 // 25 // (This is not necessarily the set of experiments the compiler itself 26 // was built with.) 27 // 28 // experimentBaseline specifies the experiment flags that are enabled by 29 // default in the current toolchain. This is, in effect, the "control" 30 // configuration and any variation from this is an experiment. 31 var Experiment ExperimentFlags = func() ExperimentFlags { 32 flags, err := ParseGOEXPERIMENT(GOOS, GOARCH, envOr("GOEXPERIMENT", defaultGOEXPERIMENT)) 33 if err != nil { 34 Error = err 35 return ExperimentFlags{} 36 } 37 return *flags 38 }() 39 40 // DefaultGOEXPERIMENT is the embedded default GOEXPERIMENT string. 41 // It is not guaranteed to be canonical. 42 const DefaultGOEXPERIMENT = defaultGOEXPERIMENT 43 44 // FramePointerEnabled enables the use of platform conventions for 45 // saving frame pointers. 46 // 47 // This used to be an experiment, but now it's always enabled on 48 // platforms that support it. 49 // 50 // Note: must agree with runtime.framepointer_enabled. 51 var FramePointerEnabled = GOARCH == "amd64" || GOARCH == "arm64" 52 53 // ParseGOEXPERIMENT parses a (GOOS, GOARCH, GOEXPERIMENT) 54 // configuration tuple and returns the enabled and baseline experiment 55 // flag sets. 56 // 57 // TODO(mdempsky): Move to internal/goexperiment. 58 func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) { 59 // regabiSupported is set to true on platforms where register ABI is 60 // supported and enabled by default. 61 // regabiAlwaysOn is set to true on platforms where register ABI is 62 // always on. 63 var regabiSupported, regabiAlwaysOn bool 64 switch goarch { 65 case "amd64", "arm64", "ppc64le", "ppc64", "riscv64": 66 regabiAlwaysOn = true 67 regabiSupported = true 68 case "loong64": 69 regabiSupported = true 70 } 71 72 baseline := goexperiment.Flags{ 73 RegabiWrappers: regabiSupported, 74 RegabiArgs: regabiSupported, 75 CoverageRedesign: true, 76 AllocHeaders: true, 77 ExecTracer2: true, 78 } 79 80 // Start with the statically enabled set of experiments. 81 flags := &ExperimentFlags{ 82 Flags: baseline, 83 baseline: baseline, 84 } 85 86 // Pick up any changes to the baseline configuration from the 87 // GOEXPERIMENT environment. This can be set at make.bash time 88 // and overridden at build time. 89 if goexp != "" { 90 // Create a map of known experiment names. 91 names := make(map[string]func(bool)) 92 rv := reflect.ValueOf(&flags.Flags).Elem() 93 rt := rv.Type() 94 for i := 0; i < rt.NumField(); i++ { 95 field := rv.Field(i) 96 names[strings.ToLower(rt.Field(i).Name)] = field.SetBool 97 } 98 99 // "regabi" is an alias for all working regabi 100 // subexperiments, and not an experiment itself. Doing 101 // this as an alias make both "regabi" and "noregabi" 102 // do the right thing. 103 names["regabi"] = func(v bool) { 104 flags.RegabiWrappers = v 105 flags.RegabiArgs = v 106 } 107 108 // Parse names. 109 for _, f := range strings.Split(goexp, ",") { 110 if f == "" { 111 continue 112 } 113 if f == "none" { 114 // GOEXPERIMENT=none disables all experiment flags. 115 // This is used by cmd/dist, which doesn't know how 116 // to build with any experiment flags. 117 flags.Flags = goexperiment.Flags{} 118 continue 119 } 120 val := true 121 if strings.HasPrefix(f, "no") { 122 f, val = f[2:], false 123 } 124 set, ok := names[f] 125 if !ok { 126 return nil, fmt.Errorf("unknown GOEXPERIMENT %s", f) 127 } 128 set(val) 129 } 130 } 131 132 if regabiAlwaysOn { 133 flags.RegabiWrappers = true 134 flags.RegabiArgs = true 135 } 136 // regabi is only supported on amd64, arm64, loong64, riscv64, ppc64 and ppc64le. 137 if !regabiSupported { 138 flags.RegabiWrappers = false 139 flags.RegabiArgs = false 140 } 141 // Check regabi dependencies. 142 if flags.RegabiArgs && !flags.RegabiWrappers { 143 return nil, fmt.Errorf("GOEXPERIMENT regabiargs requires regabiwrappers") 144 } 145 return flags, nil 146 } 147 148 // String returns the canonical GOEXPERIMENT string to enable this experiment 149 // configuration. (Experiments in the same state as in the baseline are elided.) 150 func (exp *ExperimentFlags) String() string { 151 return strings.Join(expList(&exp.Flags, &exp.baseline, false), ",") 152 } 153 154 // expList returns the list of lower-cased experiment names for 155 // experiments that differ from base. base may be nil to indicate no 156 // experiments. If all is true, then include all experiment flags, 157 // regardless of base. 158 func expList(exp, base *goexperiment.Flags, all bool) []string { 159 var list []string 160 rv := reflect.ValueOf(exp).Elem() 161 var rBase reflect.Value 162 if base != nil { 163 rBase = reflect.ValueOf(base).Elem() 164 } 165 rt := rv.Type() 166 for i := 0; i < rt.NumField(); i++ { 167 name := strings.ToLower(rt.Field(i).Name) 168 val := rv.Field(i).Bool() 169 baseVal := false 170 if base != nil { 171 baseVal = rBase.Field(i).Bool() 172 } 173 if all || val != baseVal { 174 if val { 175 list = append(list, name) 176 } else { 177 list = append(list, "no"+name) 178 } 179 } 180 } 181 return list 182 } 183 184 // Enabled returns a list of enabled experiments, as 185 // lower-cased experiment names. 186 func (exp *ExperimentFlags) Enabled() []string { 187 return expList(&exp.Flags, nil, false) 188 } 189 190 // All returns a list of all experiment settings. 191 // Disabled experiments appear in the list prefixed by "no". 192 func (exp *ExperimentFlags) All() []string { 193 return expList(&exp.Flags, nil, true) 194 }