diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go index 5b7612429eb..a55c402c442 100644 --- a/src/cmd/internal/obj/ppc64/obj9.go +++ b/src/cmd/internal/obj/ppc64/obj9.go @@ -37,6 +37,7 @@ import ( "internal/abi" "internal/buildcfg" "log" + "math" "math/bits" "strings" ) @@ -90,6 +91,29 @@ func isNOTOCfunc(name string) bool { } } +// Try converting FMOVD/FMOVS to XXSPLTIDP. If it is converted, +// return true. +func convertFMOVtoXXSPLTIDP(p *obj.Prog) bool { + if p.From.Type != obj.TYPE_FCONST || buildcfg.GOPPC64 < 10 { + return false + } + v := p.From.Val.(float64) + if float64(float32(v)) != v { + return false + } + // Secondly, is this value a normal value? + ival := int64(math.Float32bits(float32(v))) + isDenorm := ival&0x7F800000 == 0 && ival&0x007FFFFF != 0 + if !isDenorm { + p.As = AXXSPLTIDP + p.From.Type = obj.TYPE_CONST + p.From.Offset = ival + // Convert REG_Fx into equivalent REG_VSx + p.To.Reg = REG_VS0 + (p.To.Reg & 31) + } + return !isDenorm +} + func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { p.From.Class = 0 p.To.Class = 0 @@ -111,7 +135,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { // Rewrite float constants to values stored in memory. switch p.As { case AFMOVS: - if p.From.Type == obj.TYPE_FCONST { + if p.From.Type == obj.TYPE_FCONST && !convertFMOVtoXXSPLTIDP(p) { f32 := float32(p.From.Val.(float64)) p.From.Type = obj.TYPE_MEM p.From.Sym = ctxt.Float32Sym(f32) @@ -123,7 +147,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { if p.From.Type == obj.TYPE_FCONST { f64 := p.From.Val.(float64) // Constant not needed in memory for float +/- 0 - if f64 != 0 { + if f64 != 0 && !convertFMOVtoXXSPLTIDP(p) { p.From.Type = obj.TYPE_MEM p.From.Sym = ctxt.Float64Sym(f64) p.From.Name = obj.NAME_EXTERN diff --git a/test/codegen/floats.go b/test/codegen/floats.go index d5c54755678..baa745bdeec 100644 --- a/test/codegen/floats.go +++ b/test/codegen/floats.go @@ -196,3 +196,34 @@ func Float32Max(a, b float32) float32 { // ppc64/power10:"XSMAXJDP" return max(a, b) } + +// ------------------------ // +// Constant Optimizations // +// ------------------------ // + +func Float32Constant() float32 { + // ppc64x/power8:"FMOVS\t[$]f32\\.42440000\\(SB\\)" + // ppc64x/power9:"FMOVS\t[$]f32\\.42440000\\(SB\\)" + // ppc64x/power10:"XXSPLTIDP\t[$]1111752704," + return 49.0 +} + +func Float64Constant() float64 { + // ppc64x/power8:"FMOVD\t[$]f64\\.4048800000000000\\(SB\\)" + // ppc64x/power9:"FMOVD\t[$]f64\\.4048800000000000\\(SB\\)" + // ppc64x/power10:"XXSPLTIDP\t[$]1111752704," + return 49.0 +} + +func Float32DenormalConstant() float32 { + // ppc64x:"FMOVS\t[$]f32\\.00400000\\(SB\\)" + return 0x1p-127 +} + +// A float64 constant which can be exactly represented as a +// denormal float32 value. On ppc64x, denormal values cannot +// be used with XXSPLTIDP. +func Float64DenormalFloat32Constant() float64 { + // ppc64x:"FMOVD\t[$]f64\\.3800000000000000\\(SB\\)" + return 0x1p-127 +} diff --git a/test/codegen/math.go b/test/codegen/math.go index 331ebbe6094..eb6e927dec9 100644 --- a/test/codegen/math.go +++ b/test/codegen/math.go @@ -204,7 +204,9 @@ func constantCheck32() bool { func constantConvert32(x float32) float32 { // amd64:"MOVSS\t[$]f32.3f800000\\(SB\\)" // s390x:"FMOVS\t[$]f32.3f800000\\(SB\\)" - // ppc64x:"FMOVS\t[$]f32.3f800000\\(SB\\)" + // ppc64x/power8:"FMOVS\t[$]f32.3f800000\\(SB\\)" + // ppc64x/power9:"FMOVS\t[$]f32.3f800000\\(SB\\)" + // ppc64x/power10:"XXSPLTIDP\t[$]1065353216, VS0" // arm64:"FMOVS\t[$]\\(1.0\\)" if x > math.Float32frombits(0x3f800000) { return -x