Commit 6be1c09e authored by Vladimir Stefanovic's avatar Vladimir Stefanovic Committed by Brad Fitzpatrick

cmd/compile: use soft-float routines for soft-float targets

Updates #18162 (mostly fixes)

Change-Id: I35bcb8a688bdaa432adb0ddbb73a2f7adda47b9e
Reviewed-on: https://go-review.googlesource.com/37958
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent f0f62fcc
......@@ -246,6 +246,7 @@ type Arch struct {
REGSP int
MAXWIDTH int64
Use387 bool // should 386 backend use 387 FP instructions instead of sse2.
SoftFloat bool
PadFrame func(int64) int64
ZeroRange func(*Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog
......
......@@ -49,6 +49,7 @@ var (
Debug_locationlist int
Debug_typecheckinl int
Debug_gendwarfinl int
Debug_softfloat int
)
// Debug arguments.
......@@ -78,6 +79,7 @@ var debugtab = []struct {
{"locationlists", "print information about DWARF location list creation", &Debug_locationlist},
{"typecheckinl", "eager typechecking of inline function bodies", &Debug_typecheckinl},
{"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl},
{"softfloat", "force compiler to emit soft-float code", &Debug_softfloat},
}
const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
......@@ -393,6 +395,10 @@ func Main(archInit func(*Arch)) {
dwarf.EnableLogging(Debug_gendwarfinl != 0)
}
if Debug_softfloat != 0 {
thearch.SoftFloat = true
}
// enable inlining. for now:
// default: inlining on. (debug['l'] == 1)
// -l: inlining off (debug['l'] == 0)
......
This diff is collapsed.
......@@ -18,20 +18,27 @@ import (
// TODO: move all these tests elsewhere?
// Perhaps teach test/run.go how to run them with a new action verb.
func runTest(t *testing.T, filename string) {
func runTest(t *testing.T, filename string, flags ...string) {
t.Parallel()
doTest(t, filename, "run")
doTest(t, filename, "run", flags...)
}
func buildTest(t *testing.T, filename string) {
func buildTest(t *testing.T, filename string, flags ...string) {
t.Parallel()
doTest(t, filename, "build")
doTest(t, filename, "build", flags...)
}
func doTest(t *testing.T, filename string, kind string) {
func doTest(t *testing.T, filename string, kind string, flags ...string) {
testenv.MustHaveGoBuild(t)
gotool := testenv.GoToolPath(t)
var stdout, stderr bytes.Buffer
cmd := exec.Command(gotool, kind, "-gcflags=-d=ssa/check/on", filepath.Join("testdata", filename))
args := []string{kind}
if len(flags) == 0 {
args = append(args, "-gcflags=-d=ssa/check/on")
} else {
args = append(args, flags...)
}
args = append(args, filepath.Join("testdata", filename))
cmd := exec.Command(gotool, args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
......@@ -113,6 +120,10 @@ func TestArithmetic(t *testing.T) { runTest(t, "arith.go") }
// TestFP tests that both backends have the same result for floating point expressions.
func TestFP(t *testing.T) { runTest(t, "fp.go") }
func TestFPSoftFloat(t *testing.T) {
runTest(t, "fp.go", "-gcflags=-d=softfloat,ssa/check/on")
}
// TestArithmeticBoundary tests boundary results for arithmetic operations.
func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary.go") }
......
......@@ -1165,6 +1165,21 @@ func calcHasCall(n *Node) bool {
// These ops might panic, make sure they are done
// before we start marshaling args for a call. See issue 16760.
return true
// When using soft-float, these ops might be rewritten to function calls
// so we ensure they are evaluated first.
case OADD, OSUB, OMINUS:
if thearch.SoftFloat && (isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) {
return true
}
case OLT, OEQ, ONE, OLE, OGE, OGT:
if thearch.SoftFloat && (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype]) {
return true
}
case OCONV:
if thearch.SoftFloat && ((isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) || (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype])) {
return true
}
}
if n.Left != nil && n.Left.HasCall() {
......
......@@ -988,6 +988,10 @@ opswitch:
n = walkexpr(n, init)
case OCONV, OCONVNOP:
if thearch.SoftFloat {
// For the soft-float case, ssa.go handles these conversions.
goto oconv_walkexpr
}
switch thearch.LinkArch.Family {
case sys.ARM, sys.MIPS:
if n.Left.Type.IsFloat() {
......@@ -1041,6 +1045,7 @@ opswitch:
}
}
oconv_walkexpr:
n.Left = walkexpr(n.Left, init)
case OANDNOT:
......
......@@ -18,6 +18,7 @@ func Init(arch *gc.Arch) {
}
arch.REGSP = mips.REGSP
arch.MAXWIDTH = (1 << 31) - 1
arch.SoftFloat = (objabi.GOMIPS == "softfloat")
arch.ZeroRange = zerorange
arch.ZeroAuto = zeroAuto
arch.Ginsnop = ginsnop
......
......@@ -203,6 +203,10 @@ func checkFunc(f *Func) {
}
}
if f.RegAlloc != nil && f.Config.SoftFloat && v.Type.IsFloat() {
f.Fatalf("unexpected floating-point type %v", v.LongString())
}
// TODO: check for cycles in values
// TODO: check type
}
......
......@@ -344,6 +344,7 @@ var passes = [...]pass{
{name: "prove", fn: prove},
{name: "loopbce", fn: loopbce},
{name: "decompose builtin", fn: decomposeBuiltIn, required: true},
{name: "softfloat", fn: softfloat, required: true},
{name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
{name: "generic deadcode", fn: deadcode},
{name: "check bce", fn: checkbce},
......@@ -413,6 +414,8 @@ var passOrder = [...]constraint{
{"generic deadcode", "check bce"},
// don't run optimization pass until we've decomposed builtin objects
{"decompose builtin", "late opt"},
// decompose builtin is the last pass that may introduce new float ops, so run softfloat after it
{"decompose builtin", "softfloat"},
// don't layout blocks until critical edges have been removed
{"critical", "layout"},
// regalloc requires the removal of all critical edges
......
......@@ -36,6 +36,7 @@ type Config struct {
useSSE bool // Use SSE for non-float operations
nacl bool // GOOS=nacl
use387 bool // GO386=387
SoftFloat bool //
NeedsFpScratch bool // No direct move between GP and FP register sets
BigEndian bool //
sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
......
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssa
import "math"
func softfloat(f *Func) {
if !f.Config.SoftFloat {
return
}
newInt64 := false
for _, b := range f.Blocks {
for _, v := range b.Values {
if v.Type.IsFloat() {
switch v.Op {
case OpPhi, OpLoad, OpArg:
if v.Type.Size() == 4 {
v.Type = f.Config.Types.UInt32
} else {
v.Type = f.Config.Types.UInt64
}
case OpConst32F:
v.Op = OpConst32
v.Type = f.Config.Types.UInt32
v.AuxInt = int64(int32(math.Float32bits(i2f32(v.AuxInt))))
case OpConst64F:
v.Op = OpConst64
v.Type = f.Config.Types.UInt64
case OpNeg32F:
arg0 := v.Args[0]
v.reset(OpXor32)
v.Type = f.Config.Types.UInt32
v.AddArg(arg0)
mask := v.Block.NewValue0(v.Pos, OpConst32, v.Type)
mask.AuxInt = -0x80000000
v.AddArg(mask)
case OpNeg64F:
arg0 := v.Args[0]
v.reset(OpXor64)
v.Type = f.Config.Types.UInt64
v.AddArg(arg0)
mask := v.Block.NewValue0(v.Pos, OpConst64, v.Type)
mask.AuxInt = -0x8000000000000000
v.AddArg(mask)
case OpRound32F:
v.Op = OpCopy
v.Type = f.Config.Types.UInt32
case OpRound64F:
v.Op = OpCopy
v.Type = f.Config.Types.UInt64
}
newInt64 = newInt64 || v.Type.Size() == 8
}
}
}
if newInt64 && f.Config.RegSize == 4 {
// On 32bit arch, decompose Uint64 introduced in the switch above.
decomposeBuiltIn(f)
applyRewrite(f, rewriteBlockdec64, rewriteValuedec64)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment