]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/base/flag.go
1eb46e2369168a98137818a0a39d28778518159c
[gostls13.git] / src / cmd / compile / internal / base / flag.go
1 // Copyright 2009 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 base
6
7 import (
8         "encoding/json"
9         "flag"
10         "fmt"
11         "internal/buildcfg"
12         "internal/coverage/covcmd"
13         "internal/platform"
14         "log"
15         "os"
16         "reflect"
17         "runtime"
18         "strings"
19
20         "cmd/internal/obj"
21         "cmd/internal/objabi"
22         "cmd/internal/sys"
23 )
24
25 func usage() {
26         fmt.Fprintf(os.Stderr, "usage: compile [options] file.go...\n")
27         objabi.Flagprint(os.Stderr)
28         Exit(2)
29 }
30
31 // Flag holds the parsed command-line flags.
32 // See ParseFlag for non-zero defaults.
33 var Flag CmdFlags
34
35 // A CountFlag is a counting integer flag.
36 // It accepts -name=value to set the value directly,
37 // but it also accepts -name with no =value to increment the count.
38 type CountFlag int
39
40 // CmdFlags defines the command-line flags (see var Flag).
41 // Each struct field is a different flag, by default named for the lower-case of the field name.
42 // If the flag name is a single letter, the default flag name is left upper-case.
43 // If the flag name is "Lower" followed by a single letter, the default flag name is the lower-case of the last letter.
44 //
45 // If this default flag name can't be made right, the `flag` struct tag can be used to replace it,
46 // but this should be done only in exceptional circumstances: it helps everyone if the flag name
47 // is obvious from the field name when the flag is used elsewhere in the compiler sources.
48 // The `flag:"-"` struct tag makes a field invisible to the flag logic and should also be used sparingly.
49 //
50 // Each field must have a `help` struct tag giving the flag help message.
51 //
52 // The allowed field types are bool, int, string, pointers to those (for values stored elsewhere),
53 // CountFlag (for a counting flag), and func(string) (for a flag that uses special code for parsing).
54 type CmdFlags struct {
55         // Single letters
56         B CountFlag    "help:\"disable bounds checking\""
57         C CountFlag    "help:\"disable printing of columns in error messages\""
58         D string       "help:\"set relative `path` for local imports\""
59         E CountFlag    "help:\"debug symbol export\""
60         I func(string) "help:\"add `directory` to import search path\""
61         K CountFlag    "help:\"debug missing line numbers\""
62         L CountFlag    "help:\"also show actual source file names in error messages for positions affected by //line directives\""
63         N CountFlag    "help:\"disable optimizations\""
64         S CountFlag    "help:\"print assembly listing\""
65         // V is added by objabi.AddVersionFlag
66         W CountFlag "help:\"debug parse tree after type checking\""
67
68         LowerC int        "help:\"concurrency during compilation (1 means no concurrency)\""
69         LowerD flag.Value "help:\"enable debugging settings; try -d help\""
70         LowerE CountFlag  "help:\"no limit on number of errors reported\""
71         LowerH CountFlag  "help:\"halt on error\""
72         LowerJ CountFlag  "help:\"debug runtime-initialized variables\""
73         LowerL CountFlag  "help:\"disable inlining\""
74         LowerM CountFlag  "help:\"print optimization decisions\""
75         LowerO string     "help:\"write output to `file`\""
76         LowerP *string    "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
77         LowerR CountFlag  "help:\"debug generated wrappers\""
78         LowerT bool       "help:\"enable tracing for debugging the compiler\""
79         LowerW CountFlag  "help:\"debug type checking\""
80         LowerV *bool      "help:\"increase debug verbosity\""
81
82         // Special characters
83         Percent          CountFlag "flag:\"%\" help:\"debug non-static initializers\""
84         CompilingRuntime bool      "flag:\"+\" help:\"compiling runtime\""
85
86         // Longer names
87         AsmHdr             string       "help:\"write assembly header to `file`\""
88         ASan               bool         "help:\"build code compatible with C/C++ address sanitizer\""
89         Bench              string       "help:\"append benchmark times to `file`\""
90         BlockProfile       string       "help:\"write block profile to `file`\""
91         BuildID            string       "help:\"record `id` as the build id in the export metadata\""
92         CPUProfile         string       "help:\"write cpu profile to `file`\""
93         Complete           bool         "help:\"compiling complete package (no C or assembly)\""
94         ClobberDead        bool         "help:\"clobber dead stack slots (for debugging)\""
95         ClobberDeadReg     bool         "help:\"clobber dead registers (for debugging)\""
96         Dwarf              bool         "help:\"generate DWARF symbols\""
97         DwarfBASEntries    *bool        "help:\"use base address selection entries in DWARF\""                        // &Ctxt.UseBASEntries, set below
98         DwarfLocationLists *bool        "help:\"add location lists to DWARF in optimized mode\""                      // &Ctxt.Flag_locationlists, set below
99         Dynlink            *bool        "help:\"support references to Go symbols defined in other shared libraries\"" // &Ctxt.Flag_dynlink, set below
100         EmbedCfg           func(string) "help:\"read go:embed configuration from `file`\""
101         Env                func(string) "help:\"add `definition` of the form key=value to environment\""
102         GenDwarfInl        int          "help:\"generate DWARF inline info records\"" // 0=disabled, 1=funcs, 2=funcs+formals/locals
103         GoVersion          string       "help:\"required version of the runtime\""
104         ImportCfg          func(string) "help:\"read import configuration from `file`\""
105         InstallSuffix      string       "help:\"set pkg directory `suffix`\""
106         JSON               string       "help:\"version,file for JSON compiler/optimizer detail output\""
107         Lang               string       "help:\"Go language version source code expects\""
108         LinkObj            string       "help:\"write linker-specific object to `file`\""
109         LinkShared         *bool        "help:\"generate code that will be linked against Go shared libraries\"" // &Ctxt.Flag_linkshared, set below
110         Live               CountFlag    "help:\"debug liveness analysis\""
111         MSan               bool         "help:\"build code compatible with C/C++ memory sanitizer\""
112         MemProfile         string       "help:\"write memory profile to `file`\""
113         MemProfileRate     int          "help:\"set runtime.MemProfileRate to `rate`\""
114         MutexProfile       string       "help:\"write mutex profile to `file`\""
115         NoLocalImports     bool         "help:\"reject local (relative) imports\""
116         CoverageCfg        func(string) "help:\"read coverage configuration from `file`\""
117         Pack               bool         "help:\"write to file.a instead of file.o\""
118         Race               bool         "help:\"enable race detector\""
119         Shared             *bool        "help:\"generate code that can be linked into a shared library\"" // &Ctxt.Flag_shared, set below
120         SmallFrames        bool         "help:\"reduce the size limit for stack allocated objects\""      // small stacks, to diagnose GC latency; see golang.org/issue/27732
121         Spectre            string       "help:\"enable spectre mitigations in `list` (all, index, ret)\""
122         Std                bool         "help:\"compiling standard library\""
123         SymABIs            string       "help:\"read symbol ABIs from `file`\""
124         TraceProfile       string       "help:\"write an execution trace to `file`\""
125         TrimPath           string       "help:\"remove `prefix` from recorded source file paths\""
126         WB                 bool         "help:\"enable write barrier\"" // TODO: remove
127         PgoProfile         string       "help:\"read profile from `file`\""
128         ErrorURL           bool         "help:\"print explanatory URL with error message if applicable\""
129
130         // Configuration derived from flags; not a flag itself.
131         Cfg struct {
132                 Embed struct { // set by -embedcfg
133                         Patterns map[string][]string
134                         Files    map[string]string
135                 }
136                 ImportDirs   []string                 // appended to by -I
137                 ImportMap    map[string]string        // set by -importcfg
138                 PackageFile  map[string]string        // set by -importcfg; nil means not in use
139                 CoverageInfo *covcmd.CoverFixupConfig // set by -coveragecfg
140                 SpectreIndex bool                     // set by -spectre=index or -spectre=all
141                 // Whether we are adding any sort of code instrumentation, such as
142                 // when the race detector is enabled.
143                 Instrumenting bool
144         }
145 }
146
147 func addEnv(s string) {
148         i := strings.Index(s, "=")
149         if i < 0 {
150                 log.Fatal("-env argument must be of the form key=value")
151         }
152         os.Setenv(s[:i], s[i+1:])
153 }
154
155 // ParseFlags parses the command-line flags into Flag.
156 func ParseFlags() {
157         Flag.I = addImportDir
158
159         Flag.LowerC = runtime.GOMAXPROCS(0)
160         Flag.LowerD = objabi.NewDebugFlag(&Debug, DebugSSA)
161         Flag.LowerP = &Ctxt.Pkgpath
162         Flag.LowerV = &Ctxt.Debugvlog
163
164         Flag.Dwarf = buildcfg.GOARCH != "wasm"
165         Flag.DwarfBASEntries = &Ctxt.UseBASEntries
166         Flag.DwarfLocationLists = &Ctxt.Flag_locationlists
167         *Flag.DwarfLocationLists = true
168         Flag.Dynlink = &Ctxt.Flag_dynlink
169         Flag.EmbedCfg = readEmbedCfg
170         Flag.Env = addEnv
171         Flag.GenDwarfInl = 2
172         Flag.ImportCfg = readImportCfg
173         Flag.CoverageCfg = readCoverageCfg
174         Flag.LinkShared = &Ctxt.Flag_linkshared
175         Flag.Shared = &Ctxt.Flag_shared
176         Flag.WB = true
177
178         Debug.ConcurrentOk = true
179         Debug.InlFuncsWithClosures = 1
180         Debug.InlStaticInit = 1
181         Debug.PGOInline = 1
182         Debug.PGODevirtualize = 1
183         Debug.SyncFrames = -1 // disable sync markers by default
184
185         Debug.Checkptr = -1 // so we can tell whether it is set explicitly
186
187         Flag.Cfg.ImportMap = make(map[string]string)
188
189         objabi.AddVersionFlag() // -V
190         registerFlags()
191         objabi.Flagparse(usage)
192
193         if gcd := os.Getenv("GOCOMPILEDEBUG"); gcd != "" {
194                 // This will only override the flags set in gcd;
195                 // any others set on the command line remain set.
196                 Flag.LowerD.Set(gcd)
197         }
198
199         if Debug.Gossahash != "" {
200                 hashDebug = NewHashDebug("gossahash", Debug.Gossahash, nil)
201         }
202
203         // Three inputs govern loop iteration variable rewriting, hash, experiment, flag.
204         // The loop variable rewriting is:
205         // IF non-empty hash, then hash determines behavior (function+line match) (*)
206         // ELSE IF experiment and flag==0, then experiment (set flag=1)
207         // ELSE flag (note that build sets flag per-package), with behaviors:
208         //  -1 => no change to behavior.
209         //   0 => no change to behavior (unless non-empty hash, see above)
210         //   1 => apply change to likely-iteration-variable-escaping loops
211         //   2 => apply change, log results
212         //   11 => apply change EVERYWHERE, do not log results (for debugging/benchmarking)
213         //   12 => apply change EVERYWHERE, log results (for debugging/benchmarking)
214         //
215         // The expected uses of the these inputs are, in believed most-likely to least likely:
216         //  GOEXPERIMENT=loopvar -- apply change to entire application
217         //  -gcflags=some_package=-d=loopvar=1 -- apply change to some_package (**)
218         //  -gcflags=some_package=-d=loopvar=2 -- apply change to some_package, log it
219         //  GOEXPERIMENT=loopvar -gcflags=some_package=-d=loopvar=-1 -- apply change to all but one package
220         //  GOCOMPILEDEBUG=loopvarhash=... -- search for failure cause
221         //
222         //  (*) For debugging purposes, providing loopvar flag >= 11 will expand the hash-eligible set of loops to all.
223         // (**) Loop semantics, changed or not, follow code from a package when it is inlined; that is, the behavior
224         //      of an application compiled with partially modified loop semantics does not depend on inlining.
225
226         if Debug.LoopVarHash != "" {
227                 // This first little bit controls the inputs for debug-hash-matching.
228                 mostInlineOnly := true
229                 if strings.HasPrefix(Debug.LoopVarHash, "IL") {
230                         // When hash-searching on a position that is an inline site, default is to use the
231                         // most-inlined position only.  This makes the hash faster, plus there's no point
232                         // reporting a problem with all the inlining; there's only one copy of the source.
233                         // However, if for some reason you wanted it per-site, you can get this.  (The default
234                         // hash-search behavior for compiler debugging is at an inline site.)
235                         Debug.LoopVarHash = Debug.LoopVarHash[2:]
236                         mostInlineOnly = false
237                 }
238                 // end of testing trickiness
239                 LoopVarHash = NewHashDebug("loopvarhash", Debug.LoopVarHash, nil)
240                 if Debug.LoopVar < 11 { // >= 11 means all loops are rewrite-eligible
241                         Debug.LoopVar = 1 // 1 means those loops that syntactically escape their dcl vars are eligible.
242                 }
243                 LoopVarHash.SetInlineSuffixOnly(mostInlineOnly)
244         } else if buildcfg.Experiment.LoopVar && Debug.LoopVar == 0 {
245                 Debug.LoopVar = 1
246         }
247
248         if Debug.Fmahash != "" {
249                 FmaHash = NewHashDebug("fmahash", Debug.Fmahash, nil)
250         }
251
252         if Flag.MSan && !platform.MSanSupported(buildcfg.GOOS, buildcfg.GOARCH) {
253                 log.Fatalf("%s/%s does not support -msan", buildcfg.GOOS, buildcfg.GOARCH)
254         }
255         if Flag.ASan && !platform.ASanSupported(buildcfg.GOOS, buildcfg.GOARCH) {
256                 log.Fatalf("%s/%s does not support -asan", buildcfg.GOOS, buildcfg.GOARCH)
257         }
258         if Flag.Race && !platform.RaceDetectorSupported(buildcfg.GOOS, buildcfg.GOARCH) {
259                 log.Fatalf("%s/%s does not support -race", buildcfg.GOOS, buildcfg.GOARCH)
260         }
261         if (*Flag.Shared || *Flag.Dynlink || *Flag.LinkShared) && !Ctxt.Arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.Loong64, sys.MIPS64, sys.PPC64, sys.RISCV64, sys.S390X) {
262                 log.Fatalf("%s/%s does not support -shared", buildcfg.GOOS, buildcfg.GOARCH)
263         }
264         parseSpectre(Flag.Spectre) // left as string for RecordFlags
265
266         Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared
267         Ctxt.Flag_optimize = Flag.N == 0
268         Ctxt.Debugasm = int(Flag.S)
269         Ctxt.Flag_maymorestack = Debug.MayMoreStack
270         Ctxt.Flag_noRefName = Debug.NoRefName != 0
271
272         if flag.NArg() < 1 {
273                 usage()
274         }
275
276         if Flag.GoVersion != "" && Flag.GoVersion != runtime.Version() {
277                 fmt.Printf("compile: version %q does not match go tool version %q\n", runtime.Version(), Flag.GoVersion)
278                 Exit(2)
279         }
280
281         if *Flag.LowerP == "" {
282                 *Flag.LowerP = obj.UnlinkablePkg
283         }
284
285         if Flag.LowerO == "" {
286                 p := flag.Arg(0)
287                 if i := strings.LastIndex(p, "/"); i >= 0 {
288                         p = p[i+1:]
289                 }
290                 if runtime.GOOS == "windows" {
291                         if i := strings.LastIndex(p, `\`); i >= 0 {
292                                 p = p[i+1:]
293                         }
294                 }
295                 if i := strings.LastIndex(p, "."); i >= 0 {
296                         p = p[:i]
297                 }
298                 suffix := ".o"
299                 if Flag.Pack {
300                         suffix = ".a"
301                 }
302                 Flag.LowerO = p + suffix
303         }
304         switch {
305         case Flag.Race && Flag.MSan:
306                 log.Fatal("cannot use both -race and -msan")
307         case Flag.Race && Flag.ASan:
308                 log.Fatal("cannot use both -race and -asan")
309         case Flag.MSan && Flag.ASan:
310                 log.Fatal("cannot use both -msan and -asan")
311         }
312         if Flag.Race || Flag.MSan || Flag.ASan {
313                 // -race, -msan and -asan imply -d=checkptr for now.
314                 if Debug.Checkptr == -1 { // if not set explicitly
315                         Debug.Checkptr = 1
316                 }
317         }
318
319         if Flag.CompilingRuntime && Flag.N != 0 {
320                 log.Fatal("cannot disable optimizations while compiling runtime")
321         }
322         if Flag.LowerC < 1 {
323                 log.Fatalf("-c must be at least 1, got %d", Flag.LowerC)
324         }
325         if !concurrentBackendAllowed() {
326                 Flag.LowerC = 1
327         }
328
329         if Flag.CompilingRuntime {
330                 // Runtime can't use -d=checkptr, at least not yet.
331                 Debug.Checkptr = 0
332
333                 // Fuzzing the runtime isn't interesting either.
334                 Debug.Libfuzzer = 0
335         }
336
337         if Debug.Checkptr == -1 { // if not set explicitly
338                 Debug.Checkptr = 0
339         }
340
341         // set via a -d flag
342         Ctxt.Debugpcln = Debug.PCTab
343 }
344
345 // registerFlags adds flag registrations for all the fields in Flag.
346 // See the comment on type CmdFlags for the rules.
347 func registerFlags() {
348         var (
349                 boolType      = reflect.TypeOf(bool(false))
350                 intType       = reflect.TypeOf(int(0))
351                 stringType    = reflect.TypeOf(string(""))
352                 ptrBoolType   = reflect.TypeOf(new(bool))
353                 ptrIntType    = reflect.TypeOf(new(int))
354                 ptrStringType = reflect.TypeOf(new(string))
355                 countType     = reflect.TypeOf(CountFlag(0))
356                 funcType      = reflect.TypeOf((func(string))(nil))
357         )
358
359         v := reflect.ValueOf(&Flag).Elem()
360         t := v.Type()
361         for i := 0; i < t.NumField(); i++ {
362                 f := t.Field(i)
363                 if f.Name == "Cfg" {
364                         continue
365                 }
366
367                 var name string
368                 if len(f.Name) == 1 {
369                         name = f.Name
370                 } else if len(f.Name) == 6 && f.Name[:5] == "Lower" && 'A' <= f.Name[5] && f.Name[5] <= 'Z' {
371                         name = string(rune(f.Name[5] + 'a' - 'A'))
372                 } else {
373                         name = strings.ToLower(f.Name)
374                 }
375                 if tag := f.Tag.Get("flag"); tag != "" {
376                         name = tag
377                 }
378
379                 help := f.Tag.Get("help")
380                 if help == "" {
381                         panic(fmt.Sprintf("base.Flag.%s is missing help text", f.Name))
382                 }
383
384                 if k := f.Type.Kind(); (k == reflect.Ptr || k == reflect.Func) && v.Field(i).IsNil() {
385                         panic(fmt.Sprintf("base.Flag.%s is uninitialized %v", f.Name, f.Type))
386                 }
387
388                 switch f.Type {
389                 case boolType:
390                         p := v.Field(i).Addr().Interface().(*bool)
391                         flag.BoolVar(p, name, *p, help)
392                 case intType:
393                         p := v.Field(i).Addr().Interface().(*int)
394                         flag.IntVar(p, name, *p, help)
395                 case stringType:
396                         p := v.Field(i).Addr().Interface().(*string)
397                         flag.StringVar(p, name, *p, help)
398                 case ptrBoolType:
399                         p := v.Field(i).Interface().(*bool)
400                         flag.BoolVar(p, name, *p, help)
401                 case ptrIntType:
402                         p := v.Field(i).Interface().(*int)
403                         flag.IntVar(p, name, *p, help)
404                 case ptrStringType:
405                         p := v.Field(i).Interface().(*string)
406                         flag.StringVar(p, name, *p, help)
407                 case countType:
408                         p := (*int)(v.Field(i).Addr().Interface().(*CountFlag))
409                         objabi.Flagcount(name, help, p)
410                 case funcType:
411                         f := v.Field(i).Interface().(func(string))
412                         objabi.Flagfn1(name, help, f)
413                 default:
414                         if val, ok := v.Field(i).Interface().(flag.Value); ok {
415                                 flag.Var(val, name, help)
416                         } else {
417                                 panic(fmt.Sprintf("base.Flag.%s has unexpected type %s", f.Name, f.Type))
418                         }
419                 }
420         }
421 }
422
423 // concurrentFlagOk reports whether the current compiler flags
424 // are compatible with concurrent compilation.
425 func concurrentFlagOk() bool {
426         // TODO(rsc): Many of these are fine. Remove them.
427         return Flag.Percent == 0 &&
428                 Flag.E == 0 &&
429                 Flag.K == 0 &&
430                 Flag.L == 0 &&
431                 Flag.LowerH == 0 &&
432                 Flag.LowerJ == 0 &&
433                 Flag.LowerM == 0 &&
434                 Flag.LowerR == 0
435 }
436
437 func concurrentBackendAllowed() bool {
438         if !concurrentFlagOk() {
439                 return false
440         }
441
442         // Debug.S by itself is ok, because all printing occurs
443         // while writing the object file, and that is non-concurrent.
444         // Adding Debug_vlog, however, causes Debug.S to also print
445         // while flushing the plist, which happens concurrently.
446         if Ctxt.Debugvlog || !Debug.ConcurrentOk || Flag.Live > 0 {
447                 return false
448         }
449         // TODO: Test and delete this condition.
450         if buildcfg.Experiment.FieldTrack {
451                 return false
452         }
453         // TODO: fix races and enable the following flags
454         if Ctxt.Flag_dynlink || Flag.Race {
455                 return false
456         }
457         return true
458 }
459
460 func addImportDir(dir string) {
461         if dir != "" {
462                 Flag.Cfg.ImportDirs = append(Flag.Cfg.ImportDirs, dir)
463         }
464 }
465
466 func readImportCfg(file string) {
467         if Flag.Cfg.ImportMap == nil {
468                 Flag.Cfg.ImportMap = make(map[string]string)
469         }
470         Flag.Cfg.PackageFile = map[string]string{}
471         data, err := os.ReadFile(file)
472         if err != nil {
473                 log.Fatalf("-importcfg: %v", err)
474         }
475
476         for lineNum, line := range strings.Split(string(data), "\n") {
477                 lineNum++ // 1-based
478                 line = strings.TrimSpace(line)
479                 if line == "" || strings.HasPrefix(line, "#") {
480                         continue
481                 }
482
483                 verb, args, found := strings.Cut(line, " ")
484                 if found {
485                         args = strings.TrimSpace(args)
486                 }
487                 before, after, hasEq := strings.Cut(args, "=")
488
489                 switch verb {
490                 default:
491                         log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
492                 case "importmap":
493                         if !hasEq || before == "" || after == "" {
494                                 log.Fatalf(`%s:%d: invalid importmap: syntax is "importmap old=new"`, file, lineNum)
495                         }
496                         Flag.Cfg.ImportMap[before] = after
497                 case "packagefile":
498                         if !hasEq || before == "" || after == "" {
499                                 log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
500                         }
501                         Flag.Cfg.PackageFile[before] = after
502                 }
503         }
504 }
505
506 func readCoverageCfg(file string) {
507         var cfg covcmd.CoverFixupConfig
508         data, err := os.ReadFile(file)
509         if err != nil {
510                 log.Fatalf("-coveragecfg: %v", err)
511         }
512         if err := json.Unmarshal(data, &cfg); err != nil {
513                 log.Fatalf("error reading -coveragecfg file %q: %v", file, err)
514         }
515         Flag.Cfg.CoverageInfo = &cfg
516 }
517
518 func readEmbedCfg(file string) {
519         data, err := os.ReadFile(file)
520         if err != nil {
521                 log.Fatalf("-embedcfg: %v", err)
522         }
523         if err := json.Unmarshal(data, &Flag.Cfg.Embed); err != nil {
524                 log.Fatalf("%s: %v", file, err)
525         }
526         if Flag.Cfg.Embed.Patterns == nil {
527                 log.Fatalf("%s: invalid embedcfg: missing Patterns", file)
528         }
529         if Flag.Cfg.Embed.Files == nil {
530                 log.Fatalf("%s: invalid embedcfg: missing Files", file)
531         }
532 }
533
534 // parseSpectre parses the spectre configuration from the string s.
535 func parseSpectre(s string) {
536         for _, f := range strings.Split(s, ",") {
537                 f = strings.TrimSpace(f)
538                 switch f {
539                 default:
540                         log.Fatalf("unknown setting -spectre=%s", f)
541                 case "":
542                         // nothing
543                 case "all":
544                         Flag.Cfg.SpectreIndex = true
545                         Ctxt.Retpoline = true
546                 case "index":
547                         Flag.Cfg.SpectreIndex = true
548                 case "ret":
549                         Ctxt.Retpoline = true
550                 }
551         }
552
553         if Flag.Cfg.SpectreIndex {
554                 switch buildcfg.GOARCH {
555                 case "amd64":
556                         // ok
557                 default:
558                         log.Fatalf("GOARCH=%s does not support -spectre=index", buildcfg.GOARCH)
559                 }
560         }
561 }