go/src/cmd/compile/internal/ssa/softfloat.go
Cherry Mui 656f0888b7 [dev.typeparams] cmd/compile: make softfloat mode work with register ABI
Previously, softfloat mode does not work with register ABI, mainly
because the compiler doesn't know how to pass floating point
arguments and results. According to the ABI it should be passed in
FP registers, but there isn't any in softfloat mode.

This CL makes it work. When softfloat is used, we define the ABI
as having 0 floating point registers (because there aren't any).
The integer registers are unchanged. So floating point arguments
and results are passed in memory.

Another option is to pass (the bit representation of) floating
point values in integer registers. But this complicates things
because it'd need to reorder integer argument registers.

Change-Id: Ibecbeccb658c10a868fa7f2dcf75138f719cc809
Reviewed-on: https://go-review.googlesource.com/c/go/+/327274
Trust: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2021-08-03 16:14:24 +00:00

80 lines
2 KiB
Go

// 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 (
"cmd/compile/internal/types"
"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() {
f.unCache(v)
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(auxTo32F(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
} else if (v.Op == OpStore || v.Op == OpZero || v.Op == OpMove) && v.Aux.(*types.Type).IsFloat() {
switch size := v.Aux.(*types.Type).Size(); size {
case 4:
v.Aux = f.Config.Types.UInt32
case 8:
v.Aux = f.Config.Types.UInt64
newInt64 = true
default:
v.Fatalf("bad float type with size %d", size)
}
}
}
}
if newInt64 && f.Config.RegSize == 4 {
// On 32bit arch, decompose Uint64 introduced in the switch above.
decomposeBuiltIn(f)
applyRewrite(f, rewriteBlockdec64, rewriteValuedec64, removeDeadValues)
}
}