Open qizhou opened 1 year ago
CC @golang/wasm
This would presumably need to be an option in the GOWASM
environment variable.
Have we introduced a GOWASM
variable or are you proposing a new variable?
It seems truly ironic for a WASM implementation not to support floating point.
It seems truly ironic for a WASM implementation not to support floating point.
ZK technology that supports floating point instructions is much harder than integer ones - especially since most ZK/blockchain applications use high-resolution integers (mostly 256-bit) to perform financial applications such as balance transfer, token swap, compound rate, etc.
Hi there, I am working with @qizhou trying to deliver a provable WASM program. It would be greatly appreciated if we could be guided the pointers or links which implement f32/f64 as software float simulation (i.e. how the softfloat takes effect, it seems right now that the support is partially), thus we might do some handcraft change ourselves : )
Plus can confirm f32 is gone after using -d=softfloat fp.go
func main() {
a := float32(3.5)
b := float32(2.7)
println(a / b)
}
commands
% env GO111MODULE=on GOOS=wasip1 GOARCH=wasm go build -gcflags=all=-d=softfloat fp.go
% wasmtime fp
+1.296296e+000
% wasm2wat fp | grep 'f32\.' | wc -l
0
% wasm2wat fp | grep 'f64\.' | wc -l
0
I think this is a problem caused by the incompatibility of the math library with the softfloat compilation option. Take math.Floor
in (src/math/floor.go) as an example.
// src/math/floor.go Line 14
func Floor(x float64) float64 {
if haveArchFloor {
return archFloor(x)
}
return floor(x)
}
When the compilation architecture is WASM , it will directly uses the corresponding underlying instructions of WASM (src/math/floor_wasm.s). Therefore, softfloat does not work!
// src/math/floor_asm.go
//go:build 386 || amd64 || arm64 || ppc64 || ppc64le || s390x || wasm
package math
const haveArchFloor = true
Okay now it looks more like a bug to me.
Is there a way to pass the gcflag into math package in runtime? Or a build flag could help this.
-gcflags=all=-d=softfloat
only affects the compiler (gc
= Go Compiler). It does not affect any assembly code in the math package or elsewhere. Thus it isn't the equivalent of a GOWASM=softfloat
build option.
@randall77 Thanks. That makes sense.
I agree the proposal of adding GOWASM=softfloat
would be an elegant way to implement that.
https://github.com/golang/go/blob/06138963a2a16e0ac982ac85877092920a21e60f/src/internal/buildcfg/cfg.go#L137
Is this something we need a build option for, or could it just be the default behavior?
Based on what I learned from Qi's proposal and conversation, my understanding is to, add a new build option. Default behavior should (consistently) be using hardware floating point arithmetic for sake of performance, plus all modern browsers supporting it. This pr empowers users who are operating on weird platform(for example, zkWASM) which may be hard handling floating point.
We have temporarily solved the issue by replacing f64.floor and f64.ceil using the following code (by @0x1cc ):
+// golang issue: https://github.com/golang/go/issues/62470
+
+package math
+
+import "math"
+
+// Borrow from `src/math/floor.go`
+func Floor(x float64) float64 {
+ if x == 0 || math.IsNaN(x) || math.IsInf(x, 0) {
+ return x
+ }
+ if x < 0 {
+ d, fract := math.Modf(-x)
+ if fract != 0.0 {
+ d = d + 1
+ }
+ return -d
+ }
+ d, _ := math.Modf(x)
+ return d
+}
+
+func Ceil(x float64) float64 {
+ return -Floor(-x)
+}
Should this be something we add a wasm arch build tagged file for in the math package?
Not only for WASM, indeed, math package does not support softfloat well for all platform.
In the example (fp.go) provided by Qi, even GO386=softfloat
does not work in the math package. This looks like a bug.
$ GOOS=linux GOARCH=386 GO386=softfloat go build fp.go
$ go tool objdump -S fp | grep FRNDINT
0x80a56be d9fc FRNDINT
0x80a56ee d9fc FRNDINT
FRNDINT (Round to Integer) requires hardware support FPU.
If we want to support softfloat for all platform (even for architectures that in general would have FPU), we need to modify the math package. In the current math package, when the architecture has an FPU, it will by default accelerate the computation using assembling code that takes advantage of the architecture's FPU. But this will lead to incompatibility with softfloat. As shown in the example above, GO386=softfloat
does not work in the math package.
@0x1cc : that is not a bug. FRNDINT
is used by the 387 coprocessor to implement floating point operations. It is not an SSE instruction.
We assume that 386 chips have at least Pentium MMX or better. See https://github.com/golang/go/wiki/MinimumRequirements#386 . That includes MMX instructions like FRNDINT but not SSE instructions.
But in any case, that's a separate issue than this one. @0x1cc Please open an new issue if you disagree with how softfloat is implemented on 386 (this issue is about wasm).
@randall77 Thanks! Regarding the softfloat support for WASM, using -gcflags=all=-d=softfloat
can convert floating-point calculations to softfloat within the compiler, but it doesn't impact any assembly code in the math package. To incorporate softfloat support for WASM, or possibly other architectures, should we consider introducing a new build option that disables the math package from utilizing FPU-related assembly code for performance optimization?
The math package can leverage assembly code for performance optimization by default. However, when we require softfloat support, we can utilize an option to deactivate this feature. This option will enable softfloat support with -gcflags=all=-d=softfloat
for WASM and potentially all platforms.
Hi Go community 👋,
By reusing this thread, I would like to introduce zkGo - a minimum modified Go compiler to produce Wasm code compatible with ZK prover. To prove the Wasm code generated by the Go compiler with ZK, we found some additional issues besides the support issue of floating point instruction as follows.
proc_exit
: The compiled Wasm code employs an unclean proc_exit
approach, while zkWasm requires a normal program exit by returning from the main function.We create the zkGo compiler to address these issues with
The article with details (and motivation) can be found here https://perfect-amphibian-929.notion.site/Advancing-Towards-ZF-Fraud-Proof-zkGo-Compiling-L2-Geth-into-ZK-Compatible-Wasm-315a878af5754c549e5003568e1ee124?pvs=4
The repo of zkGo is here: https://github.com/ethstorage/go/tree/zkGo
This seems irrelevant to this issue, and I don't think this an appropriate forum for this sort of announcement.
To support softfloat in the Go math package, we propose adding a new build tag, let's call it math_pure_go
, that users can apply to disable the use of FPU-specific assembly code in the math package. We can use the math_pure_go
build tag to disable the assembly in math
package. With the build tag -tags=math_pure_go
and -gcflags=all=-d=softfloat
, we can support softfloat for all platforms.
go build -gcflags=all=-d=softfloat -tags=math_pure_go
For additional details, please refer to the corresponding issue: GitHub Issue #63270.
Can we close this issue in favor of the new proposal?
the current zkWASM prover cannot support floating point instructions (f32.xxx/f64.xxx)
Can you give more detail as to why you would prefer to add another Go platform variant rather than implement support in zkWASM for the necessary floating-point instructions?
It seems like either way you'd be emulating floating-point arithmetic using a framework designed for integers.
@johanbrandhorst Using a GOWASM=softfloat
variable seems more consistent with how other targets behave than the approach described in #63270. I don't think we should close this proposal yet.
Like others, I also don't understand how many people need this feature. Is there enough need here that this is a platform that we ought to support?
There are two separate questions, as I could think up: First, is there necessary to support softfloat on golang? This is subtle. As many reply states modern browser and other archs should have hardware support for fp. But there is always exception ---- as Qi points out, if you want to do calculation on an elliptic curve group using a generic programming language, it requires to set up a large prime field (see a rust implementation here https://github.com/zcash/pasta_curves). It is generally dealing with a large int, you might imagine, but not any float number. For such applications, it is hard for developers to think about fp support because they do not really need it. Again, I DO NOT think this MUST BE DONE in upstream, which is go community. But I do want to demonstrate the (maybe niche) demand from users. Second, without any background, when I use -gcflags=all=-d=softfloat I naively believe this could help me eliminate all fp in target asm. This is quite confusing that the code written by customers could be fp-free but the standard library like math still holds quite an amount of them. Personally I don't think it is intuitive. And this inconsistency concerns users (at least me). Again, I hold same question about "should golang support softfloat" but I strongly believe that the 'inconsistency' (forgive me if you have a better wording) must be solved -- at least a note stating that, so that people with same demand might not encounter the situation again, hopefully.
Note that -gcflags=all=-d=softfloat
isn't documented at all. We make no promise that we will retain that feature.
The closest thing I can find to documentation is from go tool compile -d help
which says, for softfloat
: force compiler to emit soft-float code
. It doesn't say anything about assembly code. It may not be intuitive but I don't think that very short comment about an undocumented feature needs to say anything about assembly code.
Where did you see a mention of -d=softfloat
? Perhaps we could mention assembly code there.
I find -d=softfloat
in https://github.com/golang/go/issues/61588#issuecomment-1652120941, which faces the same issue for GOARM=6, 7.
We are working on proving the execution of go-compiled WASM code using zero-knowledge (ZK) (see https://github.com/DelphinusLab/zkWasm). However, the current zkWASM prover cannot support floating point instructions (f32.xxx/f64.xxx). We tried to use
go build -gcflags=all=-d=softfloat
and we found most of the FP instructions are translated to INT ones exceptf64.load
,f64.store
,f64.ceil
,f64.floor
.Q: Is there a way to support softfloat explicitly for WASM or any flags to fully support softfloat?
Test code (fp.go):
Commands