From 34120ef01112c2d990e3386321229b1bc83f34aa Mon Sep 17 00:00:00 2001 From: Omar Sy Date: Sun, 1 Dec 2024 22:44:38 +0100 Subject: [PATCH] feat: refactor again --- gno.land/pkg/sdk/vm/convert.go | 6 +- gnovm/pkg/gnolang/gonative.go | 19 +- .../gnolang/{ => internal}/softfloat/copy.sh | 0 .../softfloat/runtime_softfloat64.go | 0 .../softfloat/runtime_softfloat64_test.go | 18 +- .../gnolang/internal/softfloat/softfloat.go | 70 ++++ gnovm/pkg/gnolang/op_binary.go | 51 ++- gnovm/pkg/gnolang/op_inc_dec.go | 9 +- gnovm/pkg/gnolang/op_unary.go | 5 +- gnovm/pkg/gnolang/softfloat.go | 338 ++++++++++++++++++ gnovm/pkg/gnolang/softfloat/softfloat.go | 125 ------- gnovm/pkg/gnolang/values.go | 17 +- gnovm/pkg/gnolang/values_conversions.go | 244 ++++++------- gnovm/pkg/gnolang/values_conversions_test.go | 3 +- 14 files changed, 573 insertions(+), 332 deletions(-) rename gnovm/pkg/gnolang/{ => internal}/softfloat/copy.sh (100%) rename gnovm/pkg/gnolang/{ => internal}/softfloat/runtime_softfloat64.go (100%) rename gnovm/pkg/gnolang/{ => internal}/softfloat/runtime_softfloat64_test.go (87%) create mode 100644 gnovm/pkg/gnolang/internal/softfloat/softfloat.go create mode 100644 gnovm/pkg/gnolang/softfloat.go delete mode 100644 gnovm/pkg/gnolang/softfloat/softfloat.go diff --git a/gno.land/pkg/sdk/vm/convert.go b/gno.land/pkg/sdk/vm/convert.go index b6f3a3de7c1..89fc3e0973d 100644 --- a/gno.land/pkg/sdk/vm/convert.go +++ b/gno.land/pkg/sdk/vm/convert.go @@ -3,13 +3,11 @@ package vm import ( "encoding/base64" "fmt" - "math" "strconv" "strings" "github.com/cockroachdb/apd/v3" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" - "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" ) func assertNoPlusPrefix(s string) { @@ -145,11 +143,11 @@ func convertArgToGno(arg string, argT gno.Type) (tv gno.TypedValue) { return case gno.Float32Type: value := convertFloat(arg, 32) - tv.SetFloat32(softfloat.Float32(math.Float32bits(float32(value)))) + tv.SetFloat32(gno.ConvertToSoftFloat32(value)) return case gno.Float64Type: value := convertFloat(arg, 64) - tv.SetFloat64(softfloat.Float64(math.Float64bits(value))) + tv.SetFloat64(gno.ConvertToSoftFloat64(value)) return default: panic(fmt.Sprintf("unexpected primitive type %s", bt.String())) diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 73f5f3728cb..e77c7f99474 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -2,10 +2,7 @@ package gnolang import ( "fmt" - "math" "reflect" - - "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" ) // NOTE @@ -332,9 +329,9 @@ func go2GnoValue(alloc *Allocator, rv reflect.Value) (tv TypedValue) { case reflect.Uint64: tv.SetUint64(rv.Uint()) case reflect.Float32: - tv.SetFloat32(softfloat.Float32(math.Float32bits(float32(rv.Float())))) + tv.SetFloat32(ConvertToSoftFloat32(rv.Float())) case reflect.Float64: - tv.SetFloat64(softfloat.Float64(math.Float64bits(rv.Float()))) + tv.SetFloat64(ConvertToSoftFloat64(rv.Float())) case reflect.Array: tv.V = alloc.NewNative(rv) case reflect.Slice: @@ -431,11 +428,11 @@ func go2GnoValueUpdate(alloc *Allocator, rlm *Realm, lvl int, tv *TypedValue, rv } case Float32Kind: if lvl != 0 { - tv.SetFloat32(softfloat.Float32(math.Float32bits(float32(rv.Float())))) + tv.SetFloat32(ConvertToSoftFloat32(rv.Float())) } case Float64Kind: if lvl != 0 { - tv.SetFloat64(softfloat.Float64(math.Float64bits(rv.Float()))) + tv.SetFloat64(ConvertToSoftFloat64(rv.Float())) } case BigintKind: panic("not yet implemented") @@ -647,9 +644,9 @@ func go2GnoValue2(alloc *Allocator, store Store, rv reflect.Value, recursive boo case reflect.Uint64: tv.SetUint64(rv.Uint()) case reflect.Float32: - tv.SetFloat32(softfloat.Float32(math.Float32bits(float32(rv.Float())))) + tv.SetFloat32(ConvertToSoftFloat32(rv.Float())) case reflect.Float64: - tv.SetFloat64(softfloat.Float64(math.Float64bits(rv.Float()))) + tv.SetFloat64(ConvertToSoftFloat64(rv.Float())) case reflect.Array: rvl := rv.Len() if rv.Type().Elem().Kind() == reflect.Uint8 { @@ -1052,9 +1049,9 @@ func gno2GoValue(tv *TypedValue, rv reflect.Value) (ret reflect.Value) { case Uint64Type: rv.SetUint(tv.GetUint64()) case Float32Type: - rv.SetFloat(math.Float64frombits(uint64(softfloat.F32to64(tv.GetFloat32())))) + rv.SetFloat(tv.GetFloat32().Float64()) case Float64Type: - rv.SetFloat(math.Float64frombits(uint64(tv.GetFloat64()))) + rv.SetFloat(tv.GetFloat64().Float64()) default: panic(fmt.Sprintf( "unexpected type %s", diff --git a/gnovm/pkg/gnolang/softfloat/copy.sh b/gnovm/pkg/gnolang/internal/softfloat/copy.sh similarity index 100% rename from gnovm/pkg/gnolang/softfloat/copy.sh rename to gnovm/pkg/gnolang/internal/softfloat/copy.sh diff --git a/gnovm/pkg/gnolang/softfloat/runtime_softfloat64.go b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go similarity index 100% rename from gnovm/pkg/gnolang/softfloat/runtime_softfloat64.go rename to gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64.go diff --git a/gnovm/pkg/gnolang/softfloat/runtime_softfloat64_test.go b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64_test.go similarity index 87% rename from gnovm/pkg/gnolang/softfloat/runtime_softfloat64_test.go rename to gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64_test.go index eb0a36269f9..5d7f93482b2 100644 --- a/gnovm/pkg/gnolang/softfloat/runtime_softfloat64_test.go +++ b/gnovm/pkg/gnolang/internal/softfloat/runtime_softfloat64_test.go @@ -10,19 +10,19 @@ package softfloat_test import ( - . "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" "math" "math/rand" - "runtime" + . "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" "testing" +"runtime" ) // turn uint64 op into float64 op -func fop(f func(x, y Float64) Float64) func(x, y float64) float64 { +func fop(f func(x, y uint64) uint64) func(x, y float64) float64 { return func(x, y float64) float64 { bx := math.Float64bits(x) by := math.Float64bits(y) - return math.Float64frombits(uint64(f(Float64(bx), Float64(by)))) + return math.Float64frombits(f(bx, by)) } } @@ -97,12 +97,12 @@ func trunc32(f float64) float64 { // 64 -sw->32 -hw-> 64 func to32sw(f float64) float64 { - return float64(math.Float32frombits(uint32(F64to32(Float64(math.Float64bits(f)))))) + return float64(math.Float32frombits(F64to32(math.Float64bits(f)))) } // 64 -hw->32 -sw-> 64 func to64sw(f float64) float64 { - return math.Float64frombits(uint64(F32to64(Float32(math.Float32bits(float32(f)))))) + return math.Float64frombits(F32to64(math.Float32bits(float32(f)))) } // float64 -hw-> int64 -hw-> float64 @@ -117,7 +117,7 @@ func hwint32(f float64) float64 { // float64 -sw-> int64 -hw-> float64 func toint64sw(f float64) float64 { - i, ok := F64toint(Float64(math.Float64bits(f))) + i, ok := F64toint(math.Float64bits(f)) if !ok { // There's no right answer for out of range. // Match the hardware to pass the test. @@ -128,7 +128,7 @@ func toint64sw(f float64) float64 { // float64 -hw-> int64 -sw-> float64 func fromint64sw(f float64) float64 { - return math.Float64frombits(uint64(Fintto64(int64(f)))) + return math.Float64frombits(Fintto64(int64(f))) } var nerr int @@ -187,7 +187,7 @@ func hwcmp(f, g float64) (cmp int, isnan bool) { func testcmp(t *testing.T, f, g float64) { hcmp, hisnan := hwcmp(f, g) - scmp, sisnan := Fcmp64(Float64(math.Float64bits(f)), Float64(math.Float64bits(g))) + scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g)) if int32(hcmp) != scmp || hisnan != sisnan { err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan) } diff --git a/gnovm/pkg/gnolang/internal/softfloat/softfloat.go b/gnovm/pkg/gnolang/internal/softfloat/softfloat.go new file mode 100644 index 00000000000..29d22f66d45 --- /dev/null +++ b/gnovm/pkg/gnolang/internal/softfloat/softfloat.go @@ -0,0 +1,70 @@ +// Package softfloat is a copy of the Go runtime's softfloat64.go file. +// It is a pure software floating point implementation. It can be used to +// perform determinstic, hardware-independent floating point computations. +// +// This package uses shortnames to refer to its different operations. Here is a +// quick reference: +// +// add f + g +// sub f - g +// mul f * g +// div f / g +// neg (- f) +// eq f == g +// gt f > g +// ge f >= g +package softfloat + +// This file mostly exports the functions from runtime_softfloat64.go + +//go:generate sh copy.sh + +func Fadd64(f, g uint64) uint64 { return fadd64(f, g) } +func Fsub64(f, g uint64) uint64 { return fsub64(f, g) } +func Fmul64(f, g uint64) uint64 { return fmul64(f, g) } +func Fdiv64(f, g uint64) uint64 { return fdiv64(f, g) } +func Fneg64(f uint64) uint64 { return fneg64(f) } +func Feq64(f, g uint64) bool { return feq64(f, g) } +func Fgt64(f, g uint64) bool { return fgt64(f, g) } +func Fge64(f, g uint64) bool { return fge64(f, g) } + +func Fadd32(f, g uint32) uint32 { return fadd32(f, g) } +func Fsub32(f, g uint32) uint32 { return fadd32(f, Fneg32(g)) } +func Fmul32(f, g uint32) uint32 { return fmul32(f, g) } +func Fdiv32(f, g uint32) uint32 { return fdiv32(f, g) } +func Feq32(f, g uint32) bool { return feq32(f, g) } +func Fgt32(f, g uint32) bool { return fgt32(f, g) } +func Fge32(f, g uint32) bool { return fge32(f, g) } + +func Fcmp64(f, g uint64) (cmp int32, isnan bool) { return fcmp64(f, g) } + +func Fneg32(f uint32) uint32 { + // Not defined in runtime - this is a copy similar to fneg64. + return f ^ (1 << (mantbits32 + expbits32)) +} + +// Conversions + +func Fintto64(val int64) (f uint64) { return fintto64(val) } +func Fintto32(val int64) (f uint32) { return fintto32(val) } + +func F32to64(f uint32) uint64 { return f32to64(f) } +func F32toint32(x uint32) int32 { return f32toint32(x) } +func F32toint64(x uint32) int64 { return f32toint64(x) } +func F32touint64(x uint32) uint64 { return f32touint64(x) } +func F64to32(f uint64) uint32 { return f64to32(f) } +func F64toint(f uint64) (val int64, ok bool) { return f64toint(f) } +func F64toint32(x uint64) int32 { return f64toint32(x) } +func F64toint64(x uint64) int64 { return f64toint64(x) } +func F64touint64(x uint64) uint64 { return f64touint64(x) } +func Fint32to32(x int32) uint32 { return fint32to32(x) } +func Fint32to64(x int32) uint64 { return fint32to64(x) } +func Fint64to32(x int64) uint32 { return fint64to32(x) } +func Fint64to64(x int64) uint64 { return fint64to64(x) } +func Fuint64to32(x uint64) uint32 { return fuint64to32(x) } +func Fuint64to64(x uint64) uint64 { return fuint64to64(x) } + +// unpack64 unpacks the float64 f into sign, exp, mantissa, isInf, isNaN. + +func Funpack32(f uint32) (sign, mant uint32, exp int, inf, nan bool) { return funpack32(f) } +func Funpack64(f uint64) (sign, mant uint64, exp int, inf, nan bool) { return funpack64(f) } diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index 2529207cd2a..e99a5505058 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -6,7 +6,6 @@ import ( "math/big" "github.com/cockroachdb/apd/v3" - "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" ) // ---------------------------------------- @@ -392,11 +391,9 @@ func isEql(store Store, lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() == rv.GetUint64()) case Float32Kind: - cmp, nan := softfloat.Fcmp64(softfloat.F32to64(lv.GetFloat32()), softfloat.F32to64(rv.GetFloat32())) - return cmp == 0 && !nan + return lv.GetFloat32().Eq(rv.GetFloat32()) case Float64Kind: - cmp, nan := softfloat.Fcmp64(lv.GetFloat64(), rv.GetFloat64()) - return cmp == 0 && !nan + return lv.GetFloat64().Eq(rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -535,11 +532,9 @@ func isLss(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() < rv.GetUint64()) case Float32Kind: - cmp, nan := softfloat.Fcmp64(softfloat.F32to64(lv.GetFloat32()), softfloat.F32to64(rv.GetFloat32())) - return (cmp < 0) && !nan + return lv.GetFloat32().Lt(rv.GetFloat32()) case Float64Kind: - cmp, nan := softfloat.Fcmp64(lv.GetFloat64(), rv.GetFloat64()) - return (cmp < 0) && !nan + return lv.GetFloat64().Lt(rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -581,11 +576,9 @@ func isLeq(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() <= rv.GetUint64()) case Float32Kind: - cmp, nan := softfloat.Fcmp64(softfloat.F32to64(lv.GetFloat32()), softfloat.F32to64(rv.GetFloat32())) - return (cmp <= 0) && !nan + return lv.GetFloat32().Le(rv.GetFloat32()) case Float64Kind: - cmp, nan := softfloat.Fcmp64(lv.GetFloat64(), rv.GetFloat64()) - return (cmp <= 0) && !nan + return lv.GetFloat64().Le(rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -627,11 +620,9 @@ func isGtr(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() > rv.GetUint64()) case Float32Kind: - cmp, nan := softfloat.Fcmp64(softfloat.F32to64(lv.GetFloat32()), softfloat.F32to64(rv.GetFloat32())) - return (cmp > 0) && !nan + return lv.GetFloat32().Gt(rv.GetFloat32()) case Float64Kind: - cmp, nan := softfloat.Fcmp64(lv.GetFloat64(), rv.GetFloat64()) - return (cmp > 0) && !nan + return lv.GetFloat64().Gt(rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -673,11 +664,9 @@ func isGeq(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() >= rv.GetUint64()) case Float32Kind: - cmp, nan := softfloat.Fcmp64(softfloat.F32to64(lv.GetFloat32()), softfloat.F32to64(rv.GetFloat32())) - return (cmp >= 0) && !nan + return lv.GetFloat32().Ge(rv.GetFloat32()) case Float64Kind: - cmp, nan := softfloat.Fcmp64(lv.GetFloat64(), rv.GetFloat64()) - return (cmp >= 0) && !nan + return lv.GetFloat64().Ge(rv.GetFloat64()) case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -725,10 +714,10 @@ func addAssign(alloc *Allocator, lv, rv *TypedValue) { lv.SetUint64(lv.GetUint64() + rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(softfloat.Fadd32(lv.GetFloat32(), rv.GetFloat32())) + lv.SetFloat32(lv.GetFloat32().Add(rv.GetFloat32())) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(softfloat.Fadd64(lv.GetFloat64(), rv.GetFloat64())) + lv.SetFloat64(lv.GetFloat64().Add(rv.GetFloat64())) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Add(lb, rv.GetBigInt()) @@ -781,10 +770,10 @@ func subAssign(lv, rv *TypedValue) { lv.SetUint64(lv.GetUint64() - rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(softfloat.Fsub32(lv.GetFloat32(), rv.GetFloat32())) + lv.SetFloat32(lv.GetFloat32().Sub(rv.GetFloat32())) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(softfloat.Fsub64(lv.GetFloat64(), rv.GetFloat64())) + lv.SetFloat64(lv.GetFloat64().Sub(rv.GetFloat64())) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Sub(lb, rv.GetBigInt()) @@ -837,10 +826,10 @@ func mulAssign(lv, rv *TypedValue) { lv.SetUint64(lv.GetUint64() * rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(softfloat.Fmul32(lv.GetFloat32(), rv.GetFloat32())) + lv.SetFloat32(lv.GetFloat32().Mul(rv.GetFloat32())) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(softfloat.Fmul64(lv.GetFloat64(), rv.GetFloat64())) + lv.SetFloat64(lv.GetFloat64().Mul(rv.GetFloat64())) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Mul(lb, rv.GetBigInt()) @@ -928,16 +917,16 @@ func quoAssign(lv, rv *TypedValue) *Exception { lv.SetUint64(lv.GetUint64() / rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - if cmp, nan := softfloat.Fcmp64(softfloat.F32to64(rv.GetFloat32()), softfloat.Fint32to64(0)); cmp == 0 && !nan { + if rv.GetFloat32().Eq(0) { return expt } - lv.SetFloat32(softfloat.Fdiv32(lv.GetFloat32(), rv.GetFloat32())) + lv.SetFloat32(lv.GetFloat32().Div(rv.GetFloat32())) case Float64Type: // NOTE: gno doesn't fuse *+. - if cmp, nan := softfloat.Fcmp64(rv.GetFloat64(), 0); cmp == 0 && !nan { + if rv.GetFloat64().Eq(0) { return expt } - lv.SetFloat64(softfloat.Fdiv64(lv.GetFloat64(), rv.GetFloat64())) + lv.SetFloat64(lv.GetFloat64().Div(rv.GetFloat64())) case BigintType, UntypedBigintType: if rv.GetBigInt().Sign() == 0 { return expt diff --git a/gnovm/pkg/gnolang/op_inc_dec.go b/gnovm/pkg/gnolang/op_inc_dec.go index ca1cab55a09..98583a57976 100644 --- a/gnovm/pkg/gnolang/op_inc_dec.go +++ b/gnovm/pkg/gnolang/op_inc_dec.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/cockroachdb/apd/v3" - "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" ) func (m *Machine) doOpInc() { @@ -55,9 +54,9 @@ func (m *Machine) doOpInc() { case Uint64Type: lv.SetUint64(lv.GetUint64() + 1) case Float32Type: - lv.SetFloat32(softfloat.Fadd32(lv.GetFloat32(), softfloat.Fint32to32(1))) + lv.SetFloat32(lv.GetFloat32().Add(1)) case Float64Type: - lv.SetFloat64(softfloat.Fadd64(lv.GetFloat64(), softfloat.Fintto64(1))) + lv.SetFloat64(lv.GetFloat64().Add(1)) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Add(lb, big.NewInt(1)) @@ -125,9 +124,9 @@ func (m *Machine) doOpDec() { case Uint64Type: lv.SetUint64(lv.GetUint64() - 1) case Float32Type: - lv.SetFloat32(softfloat.Fsub32(lv.GetFloat32(), softfloat.Fint32to32(1))) + lv.SetFloat32(lv.GetFloat32().Sub(1)) case Float64Type: - lv.SetFloat64(softfloat.Fsub64(lv.GetFloat64(), softfloat.Fintto64(1))) + lv.SetFloat64(lv.GetFloat64().Sub(1)) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Sub(lb, big.NewInt(1)) diff --git a/gnovm/pkg/gnolang/op_unary.go b/gnovm/pkg/gnolang/op_unary.go index e0ea3861084..99ecb98d792 100644 --- a/gnovm/pkg/gnolang/op_unary.go +++ b/gnovm/pkg/gnolang/op_unary.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/cockroachdb/apd/v3" - "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" ) func (m *Machine) doOpUpos() { @@ -47,9 +46,9 @@ func (m *Machine) doOpUneg() { case Uint64Type: xv.SetUint64(-xv.GetUint64()) case Float32Type: - xv.SetFloat32(softfloat.Fneg32(xv.GetFloat32())) + xv.SetFloat32(xv.GetFloat32().Neg()) case Float64Type: - xv.SetFloat64(softfloat.Fneg64(xv.GetFloat64())) + xv.SetFloat64(xv.GetFloat64().Neg()) case UntypedBigintType, BigintType: bv := xv.V.(BigintValue) xv.V = BigintValue{V: new(big.Int).Neg(bv.V)} diff --git a/gnovm/pkg/gnolang/softfloat.go b/gnovm/pkg/gnolang/softfloat.go new file mode 100644 index 00000000000..61991b0a005 --- /dev/null +++ b/gnovm/pkg/gnolang/softfloat.go @@ -0,0 +1,338 @@ +package gnolang + +import ( + "fmt" + "math" + + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" +) + +const ( + mask = 0x7FF + shift = 64 - 11 - 1 + bias = 1023 +) + +type ( + SoftFloat64 uint64 + SoftFloat32 uint32 +) + +func Trunc(x SoftFloat64) SoftFloat64 { + cmp, _ := softfloat.Fcmp64(uint64(x), softfloat.Fintto64(0)) + if _, _, _, isInf, IsNaN := softfloat.Funpack64(uint64(x)); cmp == 0 || isInf || IsNaN { + return x + } + + d, _ := Modf(x) + return d +} + +func Modf(u SoftFloat64) (it SoftFloat64, frac SoftFloat64) { + if u.Le(1) { + switch { + case u.Lt(0): + it, frac = Modf(u.Neg()) + return -it, -frac + case u.Eq(0): + return u, u // Return -0, -0 when f == -0 + } + return 0, u + } + + it = u + e := uint(it>>shift)&mask - bias + + // Keep the top 12+e bits, the integer part; clear the rest. + if e < 64-12 { + it &^= 1<<(64-12-e) - 1 + } + + frac = u.Sub(it) + return +} + +func ConvertToSoftFloat64(n any) SoftFloat64 { + switch n := n.(type) { + case SoftFloat64: + return n + case SoftFloat32: + return SoftFloat64(softfloat.F32to64(uint32(n))) + case int: + return SoftFloat64(softfloat.Fintto64(int64(n))) + case int32: + return SoftFloat64(softfloat.Fint32to64(n)) + case int8: + return SoftFloat64(softfloat.Fint32to64(int32(n))) + case int16: + return SoftFloat64(softfloat.Fint32to64(int32(n))) + case int64: + return SoftFloat64(softfloat.Fint64to64(n)) + case uint: + return SoftFloat64(softfloat.Fuint64to64(uint64(n))) + case uint16: + return SoftFloat64(softfloat.Fuint64to64(uint64(n))) + case uint32: + return SoftFloat64(softfloat.Fuint64to64(uint64(n))) + case uint8: + return SoftFloat64(softfloat.Fuint64to64(uint64(n))) + case uint64: + return SoftFloat64(softfloat.Fuint64to64(n)) + case float32: + return SoftFloat32(math.Float32bits(n)).SoftFloat64() + case float64: + return SoftFloat64(math.Float64bits(n)) + default: + panic(fmt.Sprintf("unsupported type: %T", n)) + } +} + +func ConvertToSoftFloat32(n any) SoftFloat32 { + switch n := n.(type) { + case SoftFloat64: + return SoftFloat32(softfloat.F64to32(uint64(n))) + case SoftFloat32: + return n + case int: + return SoftFloat32(softfloat.Fintto32(int64(n))) + case int32: + return SoftFloat32(softfloat.Fint32to32(n)) + case int8: + return SoftFloat32(softfloat.Fint32to32(int32(n))) + case int16: + return SoftFloat32(softfloat.Fint32to32(int32(n))) + case int64: + return SoftFloat32(softfloat.Fint64to32(n)) + case uint: + return SoftFloat32(softfloat.Fuint64to32(uint64(n))) + case uint16: + return SoftFloat32(softfloat.Fuint64to32(uint64(n))) + case uint32: + return SoftFloat32(softfloat.Fuint64to32(uint64(n))) + case uint8: + return SoftFloat32(softfloat.Fuint64to32(uint64(n))) + case uint64: + return SoftFloat32(softfloat.Fuint64to32(n)) + case float32: + return SoftFloat32(math.Float32bits(n)) + case float64: + return SoftFloat64(math.Float64bits(n)).SoftFloat32() + default: + panic(fmt.Sprintf("unsupported type: %T", n)) + } +} + +// SoftFloat64 + +func (f SoftFloat64) String() string { + return fmt.Sprintf("%v", math.Float64frombits(uint64(f))) +} + +func (f SoftFloat64) Float64() float64 { + return math.Float64frombits(uint64(f)) +} + +func (f SoftFloat64) Float32() float32 { + return float32(math.Float64frombits(uint64(f))) +} + +func (f SoftFloat64) SoftFloat32() SoftFloat32 { + return SoftFloat32(softfloat.F64to32(uint64(f))) +} + +func (f SoftFloat64) Int() int { + n, _ := softfloat.F64toint(uint64(f)) + return int(n) +} + +func (f SoftFloat64) Int64() int64 { + return softfloat.F64toint64(uint64(f)) +} + +func (f SoftFloat64) Int32() int32 { + return softfloat.F64toint32(uint64(f)) +} + +func (f SoftFloat64) Int16() int16 { + return int16(softfloat.F64toint32(uint64(f))) +} + +func (f SoftFloat64) Int8() int8 { + return int8(softfloat.F64toint32(uint64(f))) +} + +func (f SoftFloat64) Uint() uint { + return uint(softfloat.F64touint64(uint64(f))) +} + +func (f SoftFloat64) Uint64() uint64 { + return softfloat.F64touint64(uint64(f)) +} + +func (f SoftFloat64) Uint32() uint32 { + return uint32(softfloat.F64touint64(uint64(f))) +} + +func (f SoftFloat64) Uint16() uint16 { + return uint16(softfloat.F64touint64(uint64(f))) +} + +func (f SoftFloat64) Uint8() uint8 { + return uint8(softfloat.F64touint64(uint64(f))) +} + +func (f SoftFloat64) Add(g any) SoftFloat64 { + return SoftFloat64(softfloat.Fadd64(uint64(f), uint64(ConvertToSoftFloat64(g)))) +} + +func (f SoftFloat64) Sub(g any) SoftFloat64 { + return SoftFloat64(softfloat.Fsub64(uint64(f), uint64(ConvertToSoftFloat64(g)))) +} + +func (f SoftFloat64) Mul(g any) SoftFloat64 { + return SoftFloat64(softfloat.Fmul64(uint64(f), uint64(ConvertToSoftFloat64(g)))) +} + +func (f SoftFloat64) Div(g any) SoftFloat64 { + return SoftFloat64(softfloat.Fdiv64(uint64(f), uint64(ConvertToSoftFloat64(g)))) +} + +func (f SoftFloat64) Neg() SoftFloat64 { + return SoftFloat64(softfloat.Fneg64(uint64(f))) +} + +func (f SoftFloat64) Trunc() SoftFloat64 { + return Trunc(f) +} + +// == +func (f SoftFloat64) Eq(g any) bool { + return softfloat.Feq64(uint64(f), uint64(ConvertToSoftFloat64(g))) +} + +// > +func (f SoftFloat64) Gt(g any) bool { + return softfloat.Fgt64(uint64(f), uint64(ConvertToSoftFloat64(g))) +} + +// >= +func (f SoftFloat64) Ge(g any) bool { + return softfloat.Fge64(uint64(f), uint64(ConvertToSoftFloat64(g))) +} + +// < +func (f SoftFloat64) Lt(g any) bool { + return !softfloat.Fge64(uint64(f), uint64(ConvertToSoftFloat64(g))) +} + +// <= +func (f SoftFloat64) Le(g any) bool { + return !softfloat.Fgt64(uint64(f), uint64(ConvertToSoftFloat64(g))) +} + +// SoftFloat32 + +func (f SoftFloat32) Float32() float32 { + return math.Float32frombits(uint32(f)) +} + +func (f SoftFloat32) Float64() float64 { + return math.Float64frombits(softfloat.F32to64(uint32(f))) +} + +func (f SoftFloat32) SoftFloat64() SoftFloat64 { + return SoftFloat64(softfloat.F32to64(uint32(f))) +} + +func (f SoftFloat32) Int() int { + return int(softfloat.F32toint64(uint32(f))) +} + +func (f SoftFloat32) Int64() int64 { + return softfloat.F32toint64(uint32(f)) +} + +func (f SoftFloat32) Int32() int32 { + return softfloat.F32toint32(uint32(f)) +} + +func (f SoftFloat32) Int16() int16 { + return int16(softfloat.F32toint32(uint32(f))) +} + +func (f SoftFloat32) Int8() int8 { + return int8(softfloat.F32toint32(uint32(f))) +} + +func (f SoftFloat32) Uint() uint { + return uint(softfloat.F32touint64(uint32(f))) +} + +func (f SoftFloat32) Uint64() uint64 { + return softfloat.F32touint64(uint32(f)) +} + +func (f SoftFloat32) Uint32() uint32 { + return uint32(softfloat.F32touint64(uint32(f))) +} + +func (f SoftFloat32) Uint16() uint16 { + return uint16(softfloat.F32touint64(uint32(f))) +} + +func (f SoftFloat32) Uint8() uint8 { + return uint8(softfloat.F32touint64(uint32(f))) +} + +func (f SoftFloat32) Add(g any) SoftFloat32 { + return SoftFloat32(softfloat.Fadd32(uint32(f), uint32(ConvertToSoftFloat32(g)))) +} + +func (f SoftFloat32) Sub(g any) SoftFloat32 { + return SoftFloat32(softfloat.Fsub32(uint32(f), uint32(ConvertToSoftFloat32(g)))) +} + +func (f SoftFloat32) Mul(g any) SoftFloat32 { + return SoftFloat32(softfloat.Fmul32(uint32(f), uint32(ConvertToSoftFloat32(g)))) +} + +func (f SoftFloat32) Div(g any) SoftFloat32 { + return SoftFloat32(softfloat.Fdiv32(uint32(f), uint32(ConvertToSoftFloat32(g)))) +} + +func (f SoftFloat32) Neg() SoftFloat32 { + return SoftFloat32(softfloat.Fneg32(uint32(f))) +} + +func (f SoftFloat32) Trunc() SoftFloat32 { + return SoftFloat32(softfloat.F64to32(uint64(Trunc(SoftFloat64(softfloat.F32to64(uint32(f))))))) +} + +// == +func (f SoftFloat32) Eq(g any) bool { + return softfloat.Feq32(uint32(f), uint32(ConvertToSoftFloat32(g))) +} + +// > +func (f SoftFloat32) Gt(g any) bool { + return softfloat.Fgt32(uint32(f), uint32(ConvertToSoftFloat32(g))) +} + +// >= +func (f SoftFloat32) Ge(g any) bool { + return softfloat.Fge32(uint32(f), uint32(ConvertToSoftFloat32(g))) +} + +// < +func (f SoftFloat32) Lt(g any) bool { + return !softfloat.Fge32(uint32(f), uint32(ConvertToSoftFloat32(g))) +} + +// <= +func (f SoftFloat32) Le(g any) bool { + return !softfloat.Fgt32(uint32(f), uint32(ConvertToSoftFloat32(g))) +} + +func (f SoftFloat32) String() string { + return fmt.Sprintf("%v", math.Float32frombits(uint32(f))) +} diff --git a/gnovm/pkg/gnolang/softfloat/softfloat.go b/gnovm/pkg/gnolang/softfloat/softfloat.go deleted file mode 100644 index 4c092c0a609..00000000000 --- a/gnovm/pkg/gnolang/softfloat/softfloat.go +++ /dev/null @@ -1,125 +0,0 @@ -// Package softfloat is a copy of the Go runtime's softfloat64.go file. -// It is a pure software floating point implementation. It can be used to -// perform determinstic, hardware-independent floating point computations. -// -// This package uses shortnames to refer to its different operations. Here is a -// quick reference: -// -// add f + g -// sub f - g -// mul f * g -// div f / g -// neg (- f) -// eq f == g -// gt f > g -// ge f >= g -package softfloat - -import ( - "fmt" - "math" -) - -const ( - mask = 0x7FF - shift = 64 - 11 - 1 - bias = 1023 -) - -type ( - Float64 uint64 - Float32 uint32 -) - -func (f Float64) String() string { - return fmt.Sprintf("%v", math.Float64frombits(uint64(f))) -} - -func (f Float32) String() string { - return fmt.Sprintf("%v", math.Float32frombits(uint32(f))) -} - -func Trunc(x Float64) Float64 { - cmp, _ := Fcmp64(x, Fintto64(0)) - if _, _, _, isInf, IsNaN := funpack64(uint64(x)); cmp == 0 || isInf || IsNaN { - return x - } - - d, _ := Modf(x) - return d -} - -func Modf(u Float64) (it Float64, frac Float64) { - cmp, _ := Fcmp64(u, Fintto64(1)) - - if cmp < 0 { - cmp, _ := Fcmp64(u, Fintto64(0)) - switch { - case cmp < 0: - it, frac = Modf(Fneg64(u)) - return Fneg64(it), Fneg64(frac) - case cmp == 0: - return u, u // Return -0, -0 when f == -0 - } - return 0, u - } - - e := uint(u>>shift)&mask - bias - - // Keep the top 12+e bits, the integer part; clear the rest. - if e < 64-12 { - u &^= 1<<(64-12-e) - 1 - } - - frac = Fsub64(u, it) - return -} - -// This file mostly exports the functions from runtime_softfloat64.go - -//go:generate sh copy.sh - -func Fadd64(f, g Float64) Float64 { return Float64(fadd64(uint64(f), uint64(g))) } -func Fsub64(f, g Float64) Float64 { return Float64(fsub64(uint64(f), uint64(g))) } -func Fmul64(f, g Float64) Float64 { return Float64(fmul64(uint64(f), uint64(g))) } -func Fdiv64(f, g Float64) Float64 { return Float64(fdiv64(uint64(f), uint64(g))) } -func Fneg64(f Float64) Float64 { return Float64(fneg64(uint64(f))) } -func Feq64(f, g Float64) bool { return feq64(uint64(f), uint64(g)) } -func Fgt64(f, g Float64) bool { return fgt64(uint64(f), uint64(g)) } -func Fge64(f, g Float64) bool { return fge64(uint64(f), uint64(g)) } - -func Fadd32(f, g Float32) Float32 { return Float32(fadd32(uint32(f), uint32(g))) } -func Fsub32(f, g Float32) Float32 { return Float32(fadd32(uint32(f), uint32(Fneg32(g)))) } -func Fmul32(f, g Float32) Float32 { return Float32(fmul32(uint32(f), uint32(g))) } -func Fdiv32(f, g Float32) Float32 { return Float32(fdiv32(uint32(f), uint32(g))) } -func Feq32(f, g Float32) bool { return feq32(uint32(f), uint32(g)) } -func Fgt32(f, g Float32) bool { return fgt32(uint32(f), uint32(g)) } -func Fge32(f, g Float32) bool { return fge32(uint32(f), uint32(g)) } - -func Fcmp64(f, g Float64) (cmp int32, isnan bool) { return fcmp64(uint64(f), uint64(g)) } - -func Fneg32(f Float32) Float32 { - // Not defined in runtime - this is a copy similar to fneg64. - return f ^ (1 << (mantbits32 + expbits32)) -} - -// Conversions - -func Fintto64(val int64) Float64 { return Float64(fintto64(val)) } -func Fintto32(val int64) Float32 { return Float32(fintto32(val)) } - -func F32to64(f Float32) Float64 { return Float64(f32to64(uint32(f))) } -func F32toint32(x Float32) int32 { return f32toint32(uint32(x)) } -func F32toint64(x Float32) int64 { return f32toint64(uint32(x)) } -func F32touint64(x Float32) uint64 { return f32touint64(uint32(x)) } -func F64to32(f Float64) Float32 { return Float32(f64to32(uint64(f))) } -func F64toint(f Float64) (val int64, ok bool) { return f64toint(uint64(f)) } -func F64toint32(x Float64) int32 { return f64toint32(uint64(x)) } -func F64toint64(x Float64) int64 { return f64toint64(uint64(x)) } -func F64touint64(x Float64) uint64 { return f64touint64(uint64(x)) } -func Fint32to32(x int32) Float32 { return Float32(fint32to32(x)) } -func Fint32to64(x int32) Float64 { return Float64(fint32to64(x)) } -func Fint64to32(x int64) Float32 { return Float32(fint64to32(x)) } -func Fint64to64(x int64) Float64 { return Float64(fint64to64(x)) } -func Fuint64to32(x uint64) Float32 { return Float32(fuint64to32(x)) } -func Fuint64to64(x uint64) Float64 { return Float64(fuint64to64(x)) } diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index 95fa59216b3..4fb6733e627 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -11,7 +11,6 @@ import ( "github.com/cockroachdb/apd/v3" - "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" "github.com/gnolang/gno/tm2/pkg/crypto" ) @@ -1450,7 +1449,7 @@ func (tv *TypedValue) GetUint64() uint64 { return *(*uint64)(unsafe.Pointer(&tv.N)) } -func (tv *TypedValue) SetFloat32(n softfloat.Float32) { +func (tv *TypedValue) SetFloat32(n SoftFloat32) { if debug { if tv.T.Kind() != Float32Kind || isNative(tv.T) { panic(fmt.Sprintf( @@ -1458,10 +1457,10 @@ func (tv *TypedValue) SetFloat32(n softfloat.Float32) { tv.T.String())) } } - *(*softfloat.Float32)(unsafe.Pointer(&tv.N)) = n + *(*SoftFloat32)(unsafe.Pointer(&tv.N)) = n } -func (tv *TypedValue) GetFloat32() softfloat.Float32 { +func (tv *TypedValue) GetFloat32() SoftFloat32 { if debug { if tv.T != nil && tv.T.Kind() != Float32Kind { panic(fmt.Sprintf( @@ -1469,10 +1468,10 @@ func (tv *TypedValue) GetFloat32() softfloat.Float32 { tv.T.String())) } } - return *(*softfloat.Float32)(unsafe.Pointer(&tv.N)) + return *(*SoftFloat32)(unsafe.Pointer(&tv.N)) } -func (tv *TypedValue) SetFloat64(n softfloat.Float64) { +func (tv *TypedValue) SetFloat64(n SoftFloat64) { if debug { if tv.T.Kind() != Float64Kind || isNative(tv.T) { panic(fmt.Sprintf( @@ -1480,10 +1479,10 @@ func (tv *TypedValue) SetFloat64(n softfloat.Float64) { tv.T.String())) } } - *(*softfloat.Float64)(unsafe.Pointer(&tv.N)) = n + *(*SoftFloat64)(unsafe.Pointer(&tv.N)) = n } -func (tv *TypedValue) GetFloat64() softfloat.Float64 { +func (tv *TypedValue) GetFloat64() SoftFloat64 { if debug { if tv.T != nil && tv.T.Kind() != Float64Kind { panic(fmt.Sprintf( @@ -1491,7 +1490,7 @@ func (tv *TypedValue) GetFloat64() softfloat.Float64 { tv.T.String())) } } - return *(*softfloat.Float64)(unsafe.Pointer(&tv.N)) + return *(*SoftFloat64)(unsafe.Pointer(&tv.N)) } func (tv *TypedValue) GetBigInt() *big.Int { diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index eac90aeed14..09963185b58 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -8,7 +8,6 @@ import ( "strconv" "github.com/cockroachdb/apd/v3" - "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" ) // t cannot be nil or untyped or DataByteType. @@ -164,11 +163,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fintto32(int64(tv.GetInt())) + x := ConvertToSoftFloat32(tv.GetInt()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fintto64(int64(tv.GetInt())) + x := ConvertToSoftFloat64(tv.GetInt()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -234,11 +233,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fint32to32(int32(tv.GetInt8())) + x := ConvertToSoftFloat32(tv.GetInt8()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fint32to64(int32(tv.GetInt8())) + x := ConvertToSoftFloat64(tv.GetInt8()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -305,11 +304,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fint32to32(int32(tv.GetInt16())) + x := ConvertToSoftFloat32(tv.GetInt16()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fint32to64(int32(tv.GetInt16())) + x := ConvertToSoftFloat64(tv.GetInt16()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -380,11 +379,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fint32to32(tv.GetInt32()) + x := ConvertToSoftFloat32(tv.GetInt32()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fint32to64(tv.GetInt32()) + x := ConvertToSoftFloat64(tv.GetInt32()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -457,11 +456,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fint64to32(tv.GetInt64()) + x := ConvertToSoftFloat32(tv.GetInt64()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fint64to64(tv.GetInt64()) + x := ConvertToSoftFloat64(tv.GetInt64()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -534,11 +533,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fuint64to32(uint64(tv.GetUint())) + x := ConvertToSoftFloat32(tv.GetUint()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fuint64to64(uint64(tv.GetUint())) + x := ConvertToSoftFloat64(tv.GetUint()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -603,11 +602,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fuint64to32(uint64(tv.GetUint8())) + x := ConvertToSoftFloat32(tv.GetUint8()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fuint64to64(uint64(tv.GetUint8())) + x := ConvertToSoftFloat64(tv.GetUint8()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -674,11 +673,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fuint64to32(uint64(tv.GetUint16())) + x := ConvertToSoftFloat32(tv.GetUint16()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fuint64to64(uint64(tv.GetUint16())) + x := ConvertToSoftFloat64(tv.GetUint16()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -747,11 +746,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fuint64to32(uint64(tv.GetUint32())) + x := ConvertToSoftFloat32(tv.GetUint32()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fuint64to64(uint64(tv.GetUint32())) + x := ConvertToSoftFloat64(tv.GetUint32()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -826,11 +825,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := softfloat.Fuint64to32(tv.GetUint64()) + x := ConvertToSoftFloat32(tv.GetUint64()) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.Fuint64to64(tv.GetUint64()) + x := ConvertToSoftFloat64(tv.GetUint64()) tv.T = t tv.SetFloat64(x) case StringKind: @@ -848,158 +847,147 @@ GNO_CASE: switch k { case IntKind: validate(Float32Kind, IntKind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncInt64 := softfloat.F64toint64(trunc) + truncInt64 := trunc.Int64() return truncInt64 >= math.MinInt && truncInt64 <= math.MaxInt }) - x := int(softfloat.F32toint64(tv.GetFloat32())) + x := tv.GetFloat32().Int() tv.T = t tv.SetInt(x) case Int8Kind: validate(Float32Kind, Int8Kind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncInt64 := softfloat.F64toint64(trunc) + truncInt64 := trunc.Int64() return truncInt64 >= math.MinInt8 && truncInt64 <= math.MaxInt8 }) - x := int8(softfloat.F32toint32(tv.GetFloat32())) + x := tv.GetFloat32().Int8() tv.T = t tv.SetInt8(x) case Int16Kind: validate(Float32Kind, Int16Kind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncInt64 := softfloat.F64toint64(trunc) + truncInt64 := trunc.Int64() return truncInt64 >= math.MinInt16 && truncInt64 <= math.MaxInt16 }) - x := int16(softfloat.F32toint32(tv.GetFloat32())) + x := tv.GetFloat32().Int16() tv.T = t tv.SetInt16(x) case Int32Kind: validate(Float32Kind, Int32Kind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncInt64 := softfloat.F64toint64(trunc) + truncInt64 := trunc.Int64() return truncInt64 >= math.MinInt32 && truncInt64 <= math.MaxInt32 }) - x := softfloat.F32toint32(tv.GetFloat32()) + x := tv.GetFloat32().Int32() tv.T = t tv.SetInt32(x) case Int64Kind: validate(Float32Kind, Int64Kind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - cmp, _ := softfloat.Fcmp64(val, trunc) - return cmp == 0 + return tv.GetFloat32().Eq(trunc) }) - x := softfloat.F32toint64(tv.GetFloat32()) + x := tv.GetFloat32().Int64() tv.T = t tv.SetInt64(x) case UintKind: validate(Float32Kind, UintKind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncUint64 := softfloat.F64touint64(trunc) + truncUint64 := trunc.Uint64() return truncUint64 >= 0 && truncUint64 <= math.MaxUint }) - x := uint(softfloat.F32touint64(tv.GetFloat32())) + x := tv.GetFloat32().Uint() tv.T = t tv.SetUint(x) case Uint8Kind: validate(Float32Kind, Uint8Kind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncUint64 := softfloat.F64touint64(trunc) + truncUint64 := trunc.Uint64() return truncUint64 >= 0 && truncUint64 <= math.MaxUint8 }) - x := uint8(softfloat.F32touint64(tv.GetFloat32())) + x := tv.GetFloat32().Uint8() tv.T = t tv.SetUint8(x) case Uint16Kind: validate(Float32Kind, Uint16Kind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncUint64 := softfloat.F64touint64(trunc) + truncUint64 := trunc.Uint64() return truncUint64 >= 0 && truncUint64 <= math.MaxUint16 }) - x := uint16(softfloat.F32touint64(tv.GetFloat32())) + x := tv.GetFloat32().Uint16() tv.T = t tv.SetUint16(x) case Uint32Kind: validate(Float32Kind, Uint32Kind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncUint64 := softfloat.F64touint64(trunc) + truncUint64 := trunc.Uint64() return truncUint64 >= 0 && truncUint64 <= math.MaxUint32 }) - x := uint32(softfloat.F32touint64(tv.GetFloat32())) + x := tv.GetFloat32().Uint32() tv.T = t tv.SetUint32(x) case Uint64Kind: validate(Float32Kind, Uint64Kind, func() bool { - val := softfloat.F32to64(tv.GetFloat32()) - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat32().Trunc() - if val != trunc { + if !trunc.Eq(tv.GetFloat32()) { return false } - truncUint64 := softfloat.F64touint64(trunc) + truncUint64 := trunc.Uint64() return truncUint64 >= 0 && truncUint64 <= math.MaxUint }) - x := softfloat.F32touint64(tv.GetFloat32()) + x := tv.GetFloat32().Uint64() tv.T = t tv.SetUint64(x) case Float32Kind: @@ -1007,7 +995,7 @@ GNO_CASE: tv.T = t tv.SetFloat32(x) case Float64Kind: - x := softfloat.F32to64(tv.GetFloat32()) // ??? + x := tv.GetFloat32().SoftFloat64() /// ??? tv.T = t tv.SetFloat64(x) default: @@ -1019,166 +1007,156 @@ GNO_CASE: switch k { case IntKind: validate(Float64Kind, IntKind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - truncInt64 := softfloat.F64toint64(val) + truncInt64 := trunc.Int64() return truncInt64 >= math.MinInt && truncInt64 <= math.MaxInt }) - x := int(softfloat.F64toint64(tv.GetFloat64())) + x := tv.GetFloat64().Int() tv.T = t tv.SetInt(x) case Int8Kind: validate(Float64Kind, Int8Kind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - truncInt64 := softfloat.F64toint64(val) + truncInt64 := trunc.Int64() return truncInt64 >= math.MinInt8 && truncInt64 <= math.MaxInt8 }) - x := int8(softfloat.F64toint32(tv.GetFloat64())) + x := tv.GetFloat64().Int8() tv.T = t tv.SetInt8(x) case Int16Kind: validate(Float64Kind, Int16Kind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - truncInt64 := softfloat.F64toint64(val) + truncInt64 := trunc.Int64() return truncInt64 >= math.MinInt16 && truncInt64 <= math.MaxInt16 }) - x := int16(softfloat.F64toint32(tv.GetFloat64())) + x := tv.GetFloat64().Int16() tv.T = t tv.SetInt16(x) case Int32Kind: validate(Float64Kind, Int32Kind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - truncInt64 := softfloat.F64toint64(val) + truncInt64 := trunc.Int64() return truncInt64 >= math.MinInt32 && truncInt64 <= math.MaxInt32 }) - x := softfloat.F64toint32(tv.GetFloat64()) + x := tv.GetFloat64().Int32() tv.T = t tv.SetInt32(x) case Int64Kind: validate(Float64Kind, Int64Kind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - cmp, _ := softfloat.Fcmp64(val, trunc) - return cmp == 0 + return tv.GetFloat64().Eq(trunc) }) - x := softfloat.F64toint64(tv.GetFloat64()) + x := tv.GetFloat64().Int64() tv.T = t tv.SetInt64(x) case UintKind: validate(Float64Kind, UintKind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - return trunc >= 0 && trunc <= math.MaxUint + truncUint64 := trunc.Uint64() + + return truncUint64 >= 0 && truncUint64 <= math.MaxUint }) - x := uint(softfloat.F64touint64(tv.GetFloat64())) + x := tv.GetFloat64().Uint() tv.T = t tv.SetUint(x) case Uint8Kind: validate(Float64Kind, Uint8Kind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - truncInt64 := softfloat.F64toint64(val) - return truncInt64 >= 0 && truncInt64 <= math.MaxUint8 + truncUint64 := trunc.Uint64() + return truncUint64 >= 0 && truncUint64 <= math.MaxUint8 }) - x := uint8(softfloat.F64touint64(tv.GetFloat64())) + x := tv.GetFloat64().Uint8() tv.T = t tv.SetUint8(x) case Uint16Kind: validate(Float64Kind, Uint16Kind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - truncInt64 := softfloat.F64toint64(val) - return truncInt64 >= 0 && truncInt64 <= math.MaxUint16 + truncUint64 := trunc.Uint64() + return truncUint64 >= 0 && truncUint64 <= math.MaxUint16 }) - x := uint16(softfloat.F64touint64(tv.GetFloat64())) + x := tv.GetFloat64().Uint16() tv.T = t tv.SetUint16(x) case Uint32Kind: validate(Float64Kind, Uint32Kind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - truncInt64 := softfloat.F64toint64(val) - return truncInt64 >= 0 && truncInt64 <= math.MaxUint32 + truncUint64 := trunc.Uint64() + return truncUint64 >= 0 && truncUint64 <= math.MaxUint32 }) - x := uint32(softfloat.F64touint64(tv.GetFloat64())) + x := tv.GetFloat64().Uint32() tv.T = t tv.SetUint32(x) case Uint64Kind: validate(Float64Kind, Uint64Kind, func() bool { - val := tv.GetFloat64() - trunc := softfloat.Trunc(val) + trunc := tv.GetFloat64().Trunc() - if cmp, _ := softfloat.Fcmp64(val, trunc); cmp != 0 { + if !trunc.Eq(tv.GetFloat64()) { return false } - truncUint64 := softfloat.F64touint64(val) + truncUint64 := trunc.Uint64() return truncUint64 >= 0 && truncUint64 <= math.MaxUint64 }) - x := softfloat.F64touint64(tv.GetFloat64()) + x := tv.GetFloat64().Uint64() tv.T = t tv.SetUint64(x) case Float32Kind: validate(Float64Kind, Float32Kind, func() bool { - cmp, _ := softfloat.Fcmp64(tv.GetFloat64(), softfloat.Float64(math.Float64bits(float64(math.MaxFloat32)))) - return cmp <= 0 + return tv.GetFloat64().Le(SoftFloat64(math.Float64bits(float64(math.MaxFloat32)))) }) - x := softfloat.F64to32(tv.GetFloat64()) + x := tv.GetFloat64().SoftFloat32() tv.T = t tv.SetFloat32(x) case Float64Kind: @@ -1502,7 +1480,7 @@ func ConvertUntypedBigintTo(dst *TypedValue, bv BigintValue, t Type) { if f32 == 0 && (acc == big.Below || acc == big.Above) { panic("bigint underflows float32 (too close to zero)") } - dst.SetFloat32(softfloat.Float32(math.Float32bits(f32))) + dst.SetFloat32(SoftFloat32(math.Float32bits(f32))) return // done case Float64Kind: dst.T = t @@ -1516,7 +1494,7 @@ func ConvertUntypedBigintTo(dst *TypedValue, bv BigintValue, t Type) { if f64 == 0 && (acc == big.Below || acc == big.Above) { panic("bigint underflows float64 (too close to zero)") } - dst.SetFloat64(softfloat.Float64(math.Float64bits(f64))) + dst.SetFloat64(SoftFloat64(math.Float64bits(f64))) return // done case BigdecKind: dst.T = t @@ -1631,7 +1609,7 @@ func ConvertUntypedBigdecTo(dst *TypedValue, bv BigdecValue, t Type) { dst.T = Float64Type dst.V = nil f, _ := bd.Float64() - dst.SetFloat64(softfloat.Float64(math.Float64bits(f))) + dst.SetFloat64(SoftFloat64(math.Float64bits(f))) return case IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind: fallthrough @@ -1657,7 +1635,7 @@ func ConvertUntypedBigdecTo(dst *TypedValue, bv BigdecValue, t Type) { if math.IsInf(float64(f32), 0) { panic("cannot convert untyped bigdec to float32 -- too close to +-Inf") } - dst.SetFloat32(softfloat.Float32(math.Float32bits(f32))) + dst.SetFloat32(SoftFloat32(math.Float32bits(f32))) return case Float64Kind: dst.T = t @@ -1669,7 +1647,7 @@ func ConvertUntypedBigdecTo(dst *TypedValue, bv BigdecValue, t Type) { if math.IsInf(f64, 0) { panic("cannot convert untyped bigdec to float64 -- too close to +-Inf") } - dst.SetFloat64(softfloat.Float64(math.Float64bits(f64))) + dst.SetFloat64(SoftFloat64(math.Float64bits(f64))) return default: panic(fmt.Sprintf( diff --git a/gnovm/pkg/gnolang/values_conversions_test.go b/gnovm/pkg/gnolang/values_conversions_test.go index 67f14658354..2899fabda3d 100644 --- a/gnovm/pkg/gnolang/values_conversions_test.go +++ b/gnovm/pkg/gnolang/values_conversions_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/cockroachdb/apd/v3" - "github.com/gnolang/gno/gnovm/pkg/gnolang/softfloat" "github.com/stretchr/testify/require" ) @@ -25,7 +24,7 @@ func TestConvertUntypedBigdecToFloat(t *testing.T) { ConvertUntypedBigdecTo(dst, bd, typ) - require.Equal(t, softfloat.Fintto64(0), dst.GetFloat64()) + require.Equal(t, ConvertToSoftFloat64(0), dst.GetFloat64()) } func TestBitShiftingOverflow(t *testing.T) {