diff --git a/gnovm/pkg/gnolang/internal/softfloat/softfloat.go b/gnovm/pkg/gnolang/internal/softfloat/softfloat.go index 96ac86f6053..06f4bd8d7e9 100644 --- a/gnovm/pkg/gnolang/internal/softfloat/softfloat.go +++ b/gnovm/pkg/gnolang/internal/softfloat/softfloat.go @@ -61,3 +61,5 @@ 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) } diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index a541a7da8b5..321e197ad4b 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -2,9 +2,11 @@ package gnolang import ( "fmt" + "math" "math/big" "github.com/cockroachdb/apd/v3" + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" ) // ---------------------------------------- @@ -335,6 +337,18 @@ func (m *Machine) doOpBandn() { bandnAssign(lv, rv) } +func compFloat32(lv, rv *TypedValue) (int32, bool) { + lvf := softfloat.F32to64(math.Float32bits(lv.GetFloat32())) + rvf := softfloat.F32to64(math.Float32bits(rv.GetFloat32())) + return softfloat.Fcmp64(lvf, rvf) +} + +func compFloat64(lv, rv *TypedValue) (int32, bool) { + lvf := math.Float64bits(lv.GetFloat64()) + rvf := math.Float64bits(rv.GetFloat64()) + return softfloat.Fcmp64(lvf, rvf) +} + // ---------------------------------------- // logic functions @@ -390,9 +404,11 @@ func isEql(store Store, lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() == rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() == rv.GetFloat32()) // XXX determinism? + cmp, nan := compFloat32(lv, rv) + return cmp == 0 && !nan case Float64Kind: - return (lv.GetFloat64() == rv.GetFloat64()) // XXX determinism? + cmp, nan := compFloat64(lv, rv) + return cmp == 0 && !nan case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -531,9 +547,11 @@ func isLss(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() < rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() < rv.GetFloat32()) // XXX determinism? + cmp, nan := compFloat32(lv, rv) + return (cmp < 0) && !nan case Float64Kind: - return (lv.GetFloat64() < rv.GetFloat64()) // XXX determinism? + cmp, nan := compFloat64(lv, rv) + return (cmp < 0) && !nan case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -575,9 +593,11 @@ func isLeq(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() <= rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() <= rv.GetFloat32()) // XXX determinism? + cmp, nan := compFloat32(lv, rv) + return (cmp <= 0) && !nan case Float64Kind: - return (lv.GetFloat64() <= rv.GetFloat64()) // XXX determinism? + cmp, nan := compFloat64(lv, rv) + return (cmp <= 0) && !nan case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -619,9 +639,11 @@ func isGtr(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() > rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() > rv.GetFloat32()) // XXX determinism? + cmp, nan := compFloat32(lv, rv) + return (cmp > 0) && !nan case Float64Kind: - return (lv.GetFloat64() > rv.GetFloat64()) // XXX determinism? + cmp, nan := compFloat64(lv, rv) + return (cmp > 0) && !nan case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -663,9 +685,11 @@ func isGeq(lv, rv *TypedValue) bool { case Uint64Kind: return (lv.GetUint64() >= rv.GetUint64()) case Float32Kind: - return (lv.GetFloat32() >= rv.GetFloat32()) // XXX determinism? + cmp, nan := compFloat32(lv, rv) + return (cmp >= 0) && !nan case Float64Kind: - return (lv.GetFloat64() >= rv.GetFloat64()) // XXX determinism? + cmp, nan := compFloat64(lv, rv) + return (cmp >= 0) && !nan case BigintKind: lb := lv.V.(BigintValue).V rb := rv.V.(BigintValue).V @@ -713,10 +737,14 @@ func addAssign(alloc *Allocator, lv, rv *TypedValue) { lv.SetUint64(lv.GetUint64() + rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(lv.GetFloat32() + rv.GetFloat32()) // XXX determinism? + lvf := math.Float32bits(lv.GetFloat32()) + rvf := math.Float32bits(rv.GetFloat32()) + lv.SetFloat32(math.Float32frombits(softfloat.Fadd32(lvf, rvf))) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(lv.GetFloat64() + rv.GetFloat64()) // XXX determinism? + lvf := math.Float64bits(lv.GetFloat64()) + rvf := math.Float64bits(rv.GetFloat64()) + lv.SetFloat64(math.Float64frombits(softfloat.Fadd64(lvf, rvf))) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Add(lb, rv.GetBigInt()) @@ -769,10 +797,14 @@ func subAssign(lv, rv *TypedValue) { lv.SetUint64(lv.GetUint64() - rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(lv.GetFloat32() - rv.GetFloat32()) // XXX determinism? + lvf := math.Float32bits(lv.GetFloat32()) + rvf := math.Float32bits(rv.GetFloat32()) + lv.SetFloat32(math.Float32frombits(softfloat.Fsub32(lvf, rvf))) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(lv.GetFloat64() - rv.GetFloat64()) // XXX determinism? + lvf := math.Float64bits(lv.GetFloat64()) + rvf := math.Float64bits(rv.GetFloat64()) + lv.SetFloat64(math.Float64frombits(softfloat.Fsub64(lvf, rvf))) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Sub(lb, rv.GetBigInt()) @@ -825,10 +857,14 @@ func mulAssign(lv, rv *TypedValue) { lv.SetUint64(lv.GetUint64() * rv.GetUint64()) case Float32Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat32(lv.GetFloat32() * rv.GetFloat32()) // XXX determinism? + lvf := math.Float32bits(lv.GetFloat32()) + rvf := math.Float32bits(rv.GetFloat32()) + lv.SetFloat32(math.Float32frombits(softfloat.Fmul32(lvf, rvf))) case Float64Type: // NOTE: gno doesn't fuse *+. - lv.SetFloat64(lv.GetFloat64() * rv.GetFloat64()) // XXX determinism? + lvf := math.Float64bits(lv.GetFloat64()) + rvf := math.Float64bits(rv.GetFloat64()) + lv.SetFloat64(math.Float64frombits(softfloat.Fmul64(lvf, rvf))) case BigintType, UntypedBigintType: lb := lv.GetBigInt() lb = big.NewInt(0).Mul(lb, rv.GetBigInt()) diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index df93144b4e7..b34de05f289 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/cockroachdb/apd/v3" + "github.com/gnolang/gno/gnovm/pkg/gnolang/internal/softfloat" ) // t cannot be nil or untyped or DataByteType. @@ -163,11 +164,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt()) // XXX determinism? + x := math.Float32frombits(softfloat.Fintto32(int64(tv.GetInt()))) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt()) // XXX determinism? + x := math.Float64frombits(softfloat.Fintto64(int64(tv.GetInt()))) tv.T = t tv.SetFloat64(x) case StringKind: @@ -233,11 +234,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt8()) // XXX determinism? + x := math.Float32frombits(softfloat.Fint32to32(int32(tv.GetInt8()))) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt8()) // XXX determinism? + x := math.Float64frombits(softfloat.Fint32to64(int32(tv.GetInt8()))) tv.T = t tv.SetFloat64(x) case StringKind: @@ -304,11 +305,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt16()) // XXX determinism? + x := math.Float32frombits(softfloat.Fint32to32(int32(tv.GetInt16()))) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt16()) // XXX determinism? + x := math.Float64frombits(softfloat.Fint32to64(int32(tv.GetInt16()))) tv.T = t tv.SetFloat64(x) case StringKind: @@ -379,11 +380,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt32()) // XXX determinism? + x := math.Float32frombits(softfloat.Fint32to32(tv.GetInt32())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt32()) // XXX determinism? + x := math.Float64frombits(softfloat.Fint32to64(tv.GetInt32())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -456,11 +457,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetInt64()) // XXX determinism? + x := math.Float32frombits(softfloat.Fint64to32(tv.GetInt64())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetInt64()) // XXX determinism? + x := math.Float64frombits(softfloat.Fint64to64(tv.GetInt64())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -533,11 +534,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint()) // XXX determinism? + x := math.Float32frombits(softfloat.Fuint64to32(uint64(tv.GetUint()))) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint()) // XXX determinism? + x := math.Float64frombits(softfloat.Fuint64to64(uint64(tv.GetUint()))) tv.T = t tv.SetFloat64(x) case StringKind: @@ -602,11 +603,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint8()) // XXX determinism? + x := math.Float32frombits(softfloat.Fuint64to32(uint64(tv.GetUint8()))) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint8()) // XXX determinism? + x := math.Float64frombits(softfloat.Fuint64to64(uint64(tv.GetUint8()))) tv.T = t tv.SetFloat64(x) case StringKind: @@ -673,11 +674,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint16()) // XXX determinism? + x := math.Float32frombits(softfloat.Fuint64to32(uint64(tv.GetUint16()))) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint16()) // XXX determinism? + x := math.Float64frombits(softfloat.Fuint64to64(uint64(tv.GetUint16()))) tv.T = t tv.SetFloat64(x) case StringKind: @@ -746,11 +747,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint32()) // XXX determinism? + x := math.Float32frombits(softfloat.Fuint64to32(uint64(tv.GetUint32()))) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint32()) // XXX determinism? + x := math.Float64frombits(softfloat.Fuint64to64(uint64(tv.GetUint32()))) tv.T = t tv.SetFloat64(x) case StringKind: @@ -825,11 +826,11 @@ GNO_CASE: tv.T = t tv.SetUint64(x) case Float32Kind: - x := float32(tv.GetUint64()) // XXX determinism? + x := math.Float32frombits(softfloat.Fuint64to32(tv.GetUint64())) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetUint64()) // XXX determinism? + x := math.Float64frombits(softfloat.Fuint64to64(tv.GetUint64())) tv.T = t tv.SetFloat64(x) case StringKind: @@ -857,7 +858,7 @@ GNO_CASE: return int64(trunc) >= math.MinInt && int64(trunc) <= math.MaxInt }) - x := int(tv.GetFloat32()) // XXX determinism? + x := int(softfloat.F32toint64(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetInt(x) case Int8Kind: @@ -872,7 +873,7 @@ GNO_CASE: return int64(trunc) >= math.MinInt8 && int64(trunc) <= math.MaxInt8 }) - x := int8(tv.GetFloat32()) // XXX determinism? + x := int8(softfloat.F32toint32(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetInt8(x) case Int16Kind: @@ -887,7 +888,7 @@ GNO_CASE: return int64(trunc) >= math.MinInt16 && int64(trunc) <= math.MaxInt16 }) - x := int16(tv.GetFloat32()) // XXX determinism? + x := int16(softfloat.F32toint32(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetInt16(x) case Int32Kind: @@ -902,7 +903,7 @@ GNO_CASE: return int64(trunc) >= math.MinInt32 && int64(trunc) <= math.MaxInt32 }) - x := int32(tv.GetFloat32()) // XXX determinism? + x := int32(softfloat.F32toint32(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetInt32(x) case Int64Kind: @@ -913,7 +914,7 @@ GNO_CASE: return val == trunc }) - x := int64(tv.GetFloat32()) // XXX determinism? + x := int64(softfloat.F32toint64(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetInt64(x) case UintKind: @@ -928,7 +929,7 @@ GNO_CASE: return trunc >= 0 && trunc <= math.MaxUint }) - x := uint(tv.GetFloat32()) // XXX determinism? + x := uint(softfloat.F32touint64(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetUint(x) case Uint8Kind: @@ -943,7 +944,7 @@ GNO_CASE: return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint8 }) - x := uint8(tv.GetFloat32()) // XXX determinism? + x := uint8(softfloat.F32touint64(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetUint8(x) case Uint16Kind: @@ -958,7 +959,7 @@ GNO_CASE: return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint16 }) - x := uint16(tv.GetFloat32()) // XXX determinism? + x := uint16(softfloat.F32touint64(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetUint16(x) case Uint32Kind: @@ -973,7 +974,7 @@ GNO_CASE: return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint32 }) - x := uint32(tv.GetFloat32()) // XXX determinism? + x := uint32(softfloat.F32touint64(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetUint32(x) case Uint64Kind: @@ -988,15 +989,15 @@ GNO_CASE: return trunc >= 0 && trunc <= math.MaxUint }) - x := uint64(tv.GetFloat32()) // XXX determinism? + x := uint64(softfloat.F32touint64(math.Float32bits(tv.GetFloat32()))) tv.T = t tv.SetUint64(x) case Float32Kind: - x := tv.GetFloat32() // XXX determinism? + x := math.Float32frombits(math.Float32bits(tv.GetFloat32())) // ??? tv.T = t tv.SetFloat32(x) case Float64Kind: - x := float64(tv.GetFloat32()) // XXX determinism? + x := math.Float64frombits(softfloat.F32to64(math.Float32bits(tv.GetFloat32()))) // ??? tv.T = t tv.SetFloat64(x) default: @@ -1018,7 +1019,7 @@ GNO_CASE: return int64(trunc) >= math.MinInt && int64(trunc) <= math.MaxInt }) - x := int(tv.GetFloat64()) // XXX determinism? + x := int(softfloat.F64toint64(math.Float64bits(tv.GetFloat64()))) tv.T = t tv.SetInt(x) case Int8Kind: @@ -1033,7 +1034,7 @@ GNO_CASE: return int64(trunc) >= math.MinInt8 && int64(trunc) <= math.MaxInt8 }) - x := int8(tv.GetFloat64()) // XXX determinism? + x := int8(softfloat.F64toint32(math.Float64bits(tv.GetFloat64()))) tv.T = t tv.SetInt8(x) case Int16Kind: @@ -1048,7 +1049,7 @@ GNO_CASE: return int64(trunc) >= math.MinInt16 && int64(trunc) <= math.MaxInt16 }) - x := int16(tv.GetFloat64()) // XXX determinism? + x := int16(softfloat.F64toint32(math.Float64bits(tv.GetFloat64()))) tv.T = t tv.SetInt16(x) case Int32Kind: @@ -1063,7 +1064,7 @@ GNO_CASE: return int64(trunc) >= math.MinInt32 && int64(trunc) <= math.MaxInt32 }) - x := int32(tv.GetFloat64()) // XXX determinism? + x := softfloat.F64toint32(math.Float64bits(tv.GetFloat64())) tv.T = t tv.SetInt32(x) case Int64Kind: @@ -1074,7 +1075,7 @@ GNO_CASE: return val == trunc }) - x := int64(tv.GetFloat64()) // XXX determinism? + x := softfloat.F64toint64(math.Float64bits(tv.GetFloat64())) tv.T = t tv.SetInt64(x) case UintKind: @@ -1089,7 +1090,7 @@ GNO_CASE: return trunc >= 0 && trunc <= math.MaxUint }) - x := uint(tv.GetFloat64()) // XXX determinism? + x := uint(softfloat.F64touint64(math.Float64bits(tv.GetFloat64()))) tv.T = t tv.SetUint(x) case Uint8Kind: @@ -1104,7 +1105,7 @@ GNO_CASE: return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint8 }) - x := uint8(tv.GetFloat64()) // XXX determinism? + x := uint8(softfloat.F64touint64(math.Float64bits(tv.GetFloat64()))) tv.T = t tv.SetUint8(x) case Uint16Kind: @@ -1119,7 +1120,7 @@ GNO_CASE: return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint16 }) - x := uint16(tv.GetFloat64()) // XXX determinism? + x := uint16(softfloat.F64touint64(math.Float64bits(tv.GetFloat64()))) tv.T = t tv.SetUint16(x) case Uint32Kind: @@ -1134,7 +1135,7 @@ GNO_CASE: return int64(trunc) >= 0 && int64(trunc) <= math.MaxUint32 }) - x := uint32(tv.GetFloat64()) // XXX determinism? + x := uint32(softfloat.F64touint64(math.Float64bits(tv.GetFloat64()))) tv.T = t tv.SetUint32(x) case Uint64Kind: @@ -1149,7 +1150,7 @@ GNO_CASE: return trunc >= 0 && trunc <= math.MaxUint64 }) - x := uint64(tv.GetFloat64()) // XXX determinism? + x := softfloat.F64touint64(math.Float64bits(tv.GetFloat64())) tv.T = t tv.SetUint64(x) case Float32Kind: @@ -1157,11 +1158,11 @@ GNO_CASE: return tv.GetFloat64() <= math.MaxFloat32 }) - x := float32(tv.GetFloat64()) // XXX determinism? + x := math.Float32frombits(softfloat.F64to32(math.Float64bits(tv.GetFloat64()))) tv.T = t tv.SetFloat32(x) case Float64Kind: - x := tv.GetFloat64() // XXX determinism? + x := math.Float64frombits(math.Float64bits(tv.GetFloat64())) // ??? tv.T = t tv.SetFloat64(x) default: