Skip to content

Commit ea74770

Browse files
committed
mips: add GOMIPS=softfloat support
Previously, the compiler would default to hardfloat. This is not supported by some MIPS CPUs.
1 parent 6184a6c commit ea74770

File tree

8 files changed

+69
-26
lines changed

8 files changed

+69
-26
lines changed

builder/build.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
745745
ldflags = append(ldflags, dependency.result)
746746
}
747747
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
748+
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
748749
if config.GOOS() == "windows" {
749750
// Options for the MinGW wrapper for the lld COFF linker.
750751
ldflags = append(ldflags,

builder/builder_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ func TestClangAttributes(t *testing.T) {
5757
{GOOS: "linux", GOARCH: "arm", GOARM: "6"},
5858
{GOOS: "linux", GOARCH: "arm", GOARM: "7"},
5959
{GOOS: "linux", GOARCH: "arm64"},
60-
{GOOS: "linux", GOARCH: "mips"},
61-
{GOOS: "linux", GOARCH: "mipsle"},
60+
{GOOS: "linux", GOARCH: "mips", GOMIPS: "hardfloat"},
61+
{GOOS: "linux", GOARCH: "mipsle", GOMIPS: "hardfloat"},
62+
{GOOS: "linux", GOARCH: "mips", GOMIPS: "softfloat"},
63+
{GOOS: "linux", GOARCH: "mipsle", GOMIPS: "softfloat"},
6264
{GOOS: "darwin", GOARCH: "amd64"},
6365
{GOOS: "darwin", GOARCH: "arm64"},
6466
{GOOS: "windows", GOARCH: "amd64"},
@@ -70,6 +72,9 @@ func TestClangAttributes(t *testing.T) {
7072
if options.GOARCH == "arm" {
7173
name += ",GOARM=" + options.GOARM
7274
}
75+
if options.GOARCH == "mips" || options.GOARCH == "mipsle" {
76+
name += ",GOMIPS=" + options.GOMIPS
77+
}
7378
t.Run(name, func(t *testing.T) {
7479
testClangAttributes(t, options)
7580
})

builder/library.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
184184
}
185185
if strings.HasPrefix(target, "mips") {
186186
args = append(args, "-fno-pic")
187+
if config.Target.SoftFloat {
188+
args = append(args, "-msoft-float")
189+
}
187190
}
188191

189192
var once sync.Once

compileopts/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ func (c *Config) GOARM() string {
7272
return c.Options.GOARM
7373
}
7474

75+
// GOMIPS will return the GOMIPS environment variable given to the compiler when
76+
// building a program.
77+
func (c *Config) GOMIPS() string {
78+
return c.Options.GOMIPS
79+
}
80+
7581
// BuildTags returns the complete list of build tags used during this build.
7682
func (c *Config) BuildTags() []string {
7783
tags := append([]string(nil), c.Target.BuildTags...) // copy slice (avoid a race)
@@ -231,6 +237,9 @@ func (c *Config) LibcPath(name string) (path string, precompiled bool) {
231237
if c.ABI() != "" {
232238
archname += "-" + c.ABI()
233239
}
240+
if c.Target.SoftFloat {
241+
archname += "-softfloat"
242+
}
234243

235244
// Try to load a precompiled library.
236245
precompiledDir := filepath.Join(goenv.Get("TINYGOROOT"), "pkg", archname, name)

compileopts/options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Options struct {
2323
GOOS string // environment variable
2424
GOARCH string // environment variable
2525
GOARM string // environment variable (only used with GOARCH=arm)
26+
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
2627
Directory string // working dir, leave it unset to use the current working dir
2728
Target string
2829
Opt string

compileopts/target.go

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type TargetSpec struct {
3030
Features string `json:"features,omitempty"`
3131
GOOS string `json:"goos,omitempty"`
3232
GOARCH string `json:"goarch,omitempty"`
33+
SoftFloat bool // used for non-baremetal systems (GOMIPS=softfloat etc)
3334
BuildTags []string `json:"build-tags,omitempty"`
3435
GC string `json:"gc,omitempty"`
3536
Scheduler string `json:"scheduler,omitempty"`
@@ -86,6 +87,10 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) error {
8687
if src.Uint() != 0 {
8788
dst.Set(src)
8889
}
90+
case reflect.Bool:
91+
if src.Bool() {
92+
dst.Set(src)
93+
}
8994
case reflect.Ptr: // for pointers, copy if not nil
9095
if !src.IsNil() {
9196
dst.Set(src)
@@ -228,7 +233,7 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
228233
} else if options.GOARCH == "arm" {
229234
target += "-gnueabihf"
230235
}
231-
return defaultTarget(options.GOOS, options.GOARCH, target)
236+
return defaultTarget(options, target)
232237
}
233238

234239
// See whether there is a target specification for this target (e.g.
@@ -289,22 +294,22 @@ func GetTargetSpecs() (map[string]*TargetSpec, error) {
289294
return maps, nil
290295
}
291296

292-
func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
297+
func defaultTarget(options *Options, triple string) (*TargetSpec, error) {
293298
// No target spec available. Use the default one, useful on most systems
294299
// with a regular OS.
295300
spec := TargetSpec{
296301
Triple: triple,
297-
GOOS: goos,
298-
GOARCH: goarch,
299-
BuildTags: []string{goos, goarch},
302+
GOOS: options.GOOS,
303+
GOARCH: options.GOARCH,
304+
BuildTags: []string{options.GOOS, options.GOARCH},
300305
GC: "precise",
301306
Scheduler: "tasks",
302307
Linker: "cc",
303308
DefaultStackSize: 1024 * 64, // 64kB
304309
GDB: []string{"gdb"},
305310
PortReset: "false",
306311
}
307-
switch goarch {
312+
switch options.GOARCH {
308313
case "386":
309314
spec.CPU = "pentium4"
310315
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
@@ -324,17 +329,26 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
324329
}
325330
case "arm64":
326331
spec.CPU = "generic"
327-
if goos == "darwin" {
332+
if options.GOOS == "darwin" {
328333
spec.Features = "+fp-armv8,+neon"
329-
} else if goos == "windows" {
334+
} else if options.GOOS == "windows" {
330335
spec.Features = "+fp-armv8,+neon,-fmv"
331336
} else { // linux
332337
spec.Features = "+fp-armv8,+neon,-fmv,-outline-atomics"
333338
}
334339
case "mips", "mipsle":
335340
spec.CPU = "mips32r2"
336-
spec.Features = "+fpxx,+mips32r2,+nooddspreg,-noabicalls"
337341
spec.CFlags = append(spec.CFlags, "-fno-pic")
342+
switch options.GOMIPS {
343+
case "hardfloat":
344+
spec.Features = "+fpxx,+mips32r2,+nooddspreg,-noabicalls"
345+
case "softfloat":
346+
spec.SoftFloat = true
347+
spec.Features = "+mips32r2,+soft-float,-noabicalls"
348+
spec.CFlags = append(spec.CFlags, "-msoft-float")
349+
default:
350+
return nil, errors.New("invalid GOMIPS: must be hardfloat or softfloat")
351+
}
338352
case "wasm":
339353
spec.CPU = "generic"
340354
spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext"
@@ -345,7 +359,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
345359
"-msign-ext",
346360
)
347361
}
348-
if goos == "darwin" {
362+
if options.GOOS == "darwin" {
349363
spec.Linker = "ld.lld"
350364
spec.Libc = "darwin-libSystem"
351365
arch := strings.Split(triple, "-")[0]
@@ -356,12 +370,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
356370
"-arch", arch,
357371
"-platform_version", "macos", platformVersion, platformVersion,
358372
)
359-
} else if goos == "linux" {
373+
} else if options.GOOS == "linux" {
360374
spec.Linker = "ld.lld"
361375
spec.RTLib = "compiler-rt"
362376
spec.Libc = "musl"
363377
spec.LDFlags = append(spec.LDFlags, "--gc-sections")
364-
if goarch == "arm64" {
378+
if options.GOARCH == "arm64" {
365379
// Disable outline atomics. For details, see:
366380
// https://cpufun.substack.com/p/atomics-in-aarch64
367381
// A better way would be to fully support outline atomics, which
@@ -375,7 +389,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
375389
// proper threading.
376390
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
377391
}
378-
} else if goos == "windows" {
392+
} else if options.GOOS == "windows" {
379393
spec.Linker = "ld.lld"
380394
spec.Libc = "mingw-w64"
381395
// Note: using a medium code model, low image base and no ASLR
@@ -384,7 +398,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
384398
// normally present in Go (without explicitly opting in).
385399
// For more discussion:
386400
// https://groups.google.com/g/Golang-nuts/c/Jd9tlNc6jUE/m/Zo-7zIP_m3MJ?pli=1
387-
switch goarch {
401+
switch options.GOARCH {
388402
case "amd64":
389403
spec.LDFlags = append(spec.LDFlags,
390404
"-m", "i386pep",
@@ -401,7 +415,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
401415
"--no-insert-timestamp",
402416
"--no-dynamicbase",
403417
)
404-
} else if goos == "wasip1" {
418+
} else if options.GOOS == "wasip1" {
405419
spec.GC = "" // use default GC
406420
spec.Scheduler = "asyncify"
407421
spec.Linker = "wasm-ld"
@@ -420,25 +434,25 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
420434
} else {
421435
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
422436
}
423-
if goarch != "wasm" {
437+
if options.GOARCH != "wasm" {
424438
suffix := ""
425-
if goos == "windows" && goarch == "amd64" {
439+
if options.GOOS == "windows" && options.GOARCH == "amd64" {
426440
// Windows uses a different calling convention on amd64 from other
427441
// operating systems so we need separate assembly files.
428442
suffix = "_windows"
429443
}
430-
asmGoarch := goarch
431-
if goarch == "mips" || goarch == "mipsle" {
444+
asmGoarch := options.GOARCH
445+
if options.GOARCH == "mips" || options.GOARCH == "mipsle" {
432446
asmGoarch = "mipsx"
433447
}
434448
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+asmGoarch+suffix+".S")
435449
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+asmGoarch+suffix+".S")
436450
}
437-
if goarch != runtime.GOARCH {
451+
if options.GOARCH != runtime.GOARCH {
438452
// Some educated guesses as to how to invoke helper programs.
439453
spec.GDB = []string{"gdb-multiarch"}
440-
if goos == "linux" {
441-
switch goarch {
454+
if options.GOOS == "linux" {
455+
switch options.GOARCH {
442456
case "386":
443457
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
444458
if runtime.GOARCH != "amd64" {
@@ -457,8 +471,8 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
457471
}
458472
}
459473
}
460-
if goos != runtime.GOOS {
461-
if goos == "windows" {
474+
if options.GOOS != runtime.GOOS {
475+
if options.GOOS == "windows" {
462476
spec.Emulator = "wine {}"
463477
}
464478
}

goenv/goenv.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ func Get(name string) string {
128128
// difference between ARMv6 and ARMv7. ARMv6 binaries are much smaller,
129129
// especially when floating point instructions are involved.
130130
return "6"
131+
case "GOMIPS":
132+
gomips := os.Getenv("GOMIPS")
133+
if gomips == "" {
134+
// Default to hardfloat (this matches the Go toolchain).
135+
gomips = "hardfloat"
136+
}
137+
return gomips
131138
case "GOROOT":
132139
readGoEnvVars()
133140
return goEnvVars.GOROOT

main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,7 @@ func main() {
14981498
GOOS: goenv.Get("GOOS"),
14991499
GOARCH: goenv.Get("GOARCH"),
15001500
GOARM: goenv.Get("GOARM"),
1501+
GOMIPS: goenv.Get("GOMIPS"),
15011502
Target: *target,
15021503
StackSize: stackSize,
15031504
Opt: *opt,
@@ -1780,6 +1781,7 @@ func main() {
17801781
GOOS string `json:"goos"`
17811782
GOARCH string `json:"goarch"`
17821783
GOARM string `json:"goarm"`
1784+
GOMIPS string `json:"gomips"`
17831785
BuildTags []string `json:"build_tags"`
17841786
GC string `json:"garbage_collector"`
17851787
Scheduler string `json:"scheduler"`
@@ -1790,6 +1792,7 @@ func main() {
17901792
GOOS: config.GOOS(),
17911793
GOARCH: config.GOARCH(),
17921794
GOARM: config.GOARM(),
1795+
GOMIPS: config.GOMIPS(),
17931796
BuildTags: config.BuildTags(),
17941797
GC: config.GC(),
17951798
Scheduler: config.Scheduler(),

0 commit comments

Comments
 (0)