diff --git a/examples/euler2.fs b/examples/euler2.fs new file mode 100644 index 0000000..93f452d --- /dev/null +++ b/examples/euler2.fs @@ -0,0 +1,20 @@ +module Euler2 + +let main () = + let mutable first = 1 + let mutable second = 2 + + let mutable sum = 2 + + while second <= 4_000_000 do + let temp = first + second + first <- second + second <- temp + + sum <- + if second % 2 = 0 then + sum + second + else + sum + + sum diff --git a/src/AstToWasm.fs b/src/AstToWasm.fs index 6d309b3..9713c7c 100644 --- a/src/AstToWasm.fs +++ b/src/AstToWasm.fs @@ -92,7 +92,7 @@ let getBlockType (typ: Types option) = | Bool | Int32 -> i32_VAL_TYPE | Int64 -> i64_VAL_TYPE - //| F32 -> f32_VAL_TYPE + | Float32 -> f32_VAL_TYPE | Float64 -> f64_VAL_TYPE | _ -> tinyfail (sprintf "Currently do not support a '%s' block type" (vall.ToString())) @@ -103,6 +103,7 @@ let getResultType typ = | Types.Int16 | Types.Int32 -> i32_VAL_TYPE | Types.Int64 -> i64_VAL_TYPE + | Types.Float32 -> f32_VAL_TYPE | Types.Float64 -> f64_VAL_TYPE | _ -> tinyfail (sprintf "Currently does not support '%s' result type" (typ.ToString())) @@ -113,6 +114,7 @@ let getType (strType) = | FS_INT | FS_INT32 -> Types.Int32 | FS_INT64 -> Types.Int64 + | FS_FLOAT32 -> Types.Float32 | FS_FLOAT64 -> Types.Float64 | FS_BOOL -> Types.Bool | FS_UNIT -> Types.Unit @@ -125,6 +127,7 @@ let getOperatorType typ = | Types.Int16 | Types.Int32 -> Types.Int32 | Types.Int64 -> Types.Int64 + | Types.Float32 -> Types.Float32 | Types.Float64 -> Types.Float64 | _ -> tinyfail (sprintf "Currently does not support '%s' operator type" (typ.ToString())) @@ -143,36 +146,46 @@ let operatorToWasm (op: string) (typ: Types) = //arithmetic | FS_OP_ADDITION, Int32 -> INSTR_i32_ADD | FS_OP_ADDITION, Int64 -> INSTR_i64_ADD + | FS_OP_ADDITION, Float32 -> INSTR_f32_ADD | FS_OP_ADDITION, Float64 -> INSTR_f64_ADD | FS_OP_SUBTRACTION, Int32 -> INSTR_i32_SUB | FS_OP_SUBTRACTION, Int64 -> INSTR_i64_SUB + | FS_OP_SUBTRACTION, Float32 -> INSTR_f32_SUB | FS_OP_SUBTRACTION, Float64 -> INSTR_f64_SUB | FS_OP_MULTIPLY, Int32 -> INSTR_i32_MUL | FS_OP_MULTIPLY, Int64 -> INSTR_i64_MUL + | FS_OP_MULTIPLY, Float32 -> INSTR_f32_MUL | FS_OP_MULTIPLY, Float64 -> INSTR_f64_MUL | FS_OP_DIVISION, Int32 -> INSTR_i32_DIV_S | FS_OP_DIVISION, Int64 -> INSTR_i64_DIV_S + | FS_OP_DIVISION, Float32 -> INSTR_f32_DIV | FS_OP_DIVISION, Float64 -> INSTR_f64_DIV | FS_OP_MODULUS, Int32 -> INSTR_i32_MOD_S | FS_OP_MODULUS, Int64 -> INSTR_i64_MOD_S //comparison | FS_OP_EQUALITY, Int32 -> INSTR_i32_EQ | FS_OP_EQUALITY, Int64 -> INSTR_i64_EQ + | FS_OP_EQUALITY, Float32 -> INSTR_f32_EQ | FS_OP_EQUALITY, Float64 -> INSTR_f64_EQ | FS_OP_INEQUALITY, Int32 -> INSTR_i32_NE | FS_OP_INEQUALITY, Int64 -> INSTR_i64_NE + | FS_OP_INEQUALITY, Float32 -> INSTR_f32_NE | FS_OP_INEQUALITY, Float64 -> INSTR_f64_NE | FS_OP_LESSTHAN, Int32 -> INSTR_i32_LT_S | FS_OP_LESSTHAN, Int64 -> INSTR_i64_LT_S + | FS_OP_LESSTHAN, Float32 -> INSTR_f32_LT | FS_OP_LESSTHAN, Float64 -> INSTR_f64_LT | FS_OP_LESSTHANOREQUAL, Int32 -> INSTR_i32_LE_S | FS_OP_LESSTHANOREQUAL, Int64 -> INSTR_i64_LE_S + | FS_OP_LESSTHANOREQUAL, Float32 -> INSTR_f32_LE | FS_OP_LESSTHANOREQUAL, Float64 -> INSTR_f64_LE | FS_OP_GREATERTHAN, Int32 -> INSTR_i32_GT_S | FS_OP_GREATERTHAN, Int64 -> INSTR_i64_GT_S + | FS_OP_GREATERTHAN, Float32 -> INSTR_f32_GT | FS_OP_GREATERTHAN, Float64 -> INSTR_f64_GT | FS_OP_GREATERTHANOREQUAL, Int32 -> INSTR_i32_GE_S | FS_OP_GREATERTHANOREQUAL, Int64 -> INSTR_i64_GE_S + | FS_OP_GREATERTHANOREQUAL, Float32 -> INSTR_f32_GE | FS_OP_GREATERTHANOREQUAL, Float64 -> INSTR_f64_GE ////logic //| "and" -> INSTR_i32_AND @@ -334,6 +347,12 @@ let rec exprToWasm match convertInt64 value with | Some vall -> (Types.Int64, (appendSinList i64_CONST (i64 vall))) | None -> tinyfail (sprintf "Cannot convert '%s' to Int64" (value.ToString())) + | Types.Float32 -> + match convertFloat32 value with + | Some vall -> + let floatBytes = BitConverter.GetBytes(vall) |> Array.toList + (Types.Float32, (appendSinList f32_CONST floatBytes)) + | None -> tinyfail (sprintf "Cannot convert '%s' to Float32" (value.ToString())) | Types.Float64 -> match convertFloat64 value with | Some vall -> diff --git a/src/TypeInfos.fs b/src/TypeInfos.fs index dfbe578..981098c 100644 --- a/src/TypeInfos.fs +++ b/src/TypeInfos.fs @@ -24,6 +24,9 @@ let FS_INT = "Microsoft.FSharp.Core.int" [] let FS_BOOL = "Microsoft.FSharp.Core.bool" +[] +let FS_FLOAT32 = "Microsoft.FSharp.Core.float32" + [] let FS_FLOAT64 = "Microsoft.FSharp.Core.float" diff --git a/src/Utils.fs b/src/Utils.fs index 1543b0d..820d0c2 100644 --- a/src/Utils.fs +++ b/src/Utils.fs @@ -41,6 +41,11 @@ let convertInt64 (o: obj) = | true, int -> Some int | _ -> None +let convertFloat32 (o: obj) = + match System.Single.TryParse(o.ToString()) with + | true, flt -> Some flt + | _ -> None + let convertFloat64 (o: obj) = match System.Double.TryParse(o.ToString()) with | true, flt -> Some flt diff --git a/src/WasmLiterals.fs b/src/WasmLiterals.fs index 44703a2..aaeef40 100644 --- a/src/WasmLiterals.fs +++ b/src/WasmLiterals.fs @@ -1,5 +1,6 @@ module TinyFS.Core.WasmLiterals +//https://webassembly.github.io/spec/core/appendix/index-instructions.html module Section = [] let SECTION_ID_TYPE = 0x1uy @@ -221,6 +222,18 @@ module Instructions = [] let INSTR_i64_MOD_U = 0x82uy + [] + let INSTR_f32_ADD = 0x92uy + + [] + let INSTR_f32_SUB = 0x93uy + + [] + let INSTR_f32_MUL = 0x94uy + + [] + let INSTR_f32_DIV = 0x95uy + [] let INSTR_f64_ADD = 0xA0uy diff --git a/test/Helpers.fs b/test/Helpers.fs index b6f688a..d6dc62f 100644 --- a/test/Helpers.fs +++ b/test/Helpers.fs @@ -28,16 +28,22 @@ let runFuncInt32Return (funcName: string) (wasmBytes: byte list) = let func = instance.GetFunction(funcName) func.Invoke() +let runFuncInt64Return (funcName: string) (wasmBytes: byte list) = + let instance = buildInstance wasmBytes + + let func = instance.GetFunction(funcName) + func.Invoke() + let runFuncFloat64Return (funcName: string) (wasmBytes: byte list) = let instance = buildInstance wasmBytes let func = instance.GetFunction(funcName) func.Invoke() -let runFuncInt64Return (funcName: string) (wasmBytes: byte list) = +let runFuncFloat32Return (funcName: string) (wasmBytes: byte list) = let instance = buildInstance wasmBytes - let func = instance.GetFunction(funcName) + let func = instance.GetFunction(funcName) func.Invoke() let runInt32FuncInt32 (funcName: string) (param1: int32) (wasmBytes: byte list) = @@ -52,6 +58,12 @@ let runInt64FuncInt64 (funcName: string) (param1: int64) (wasmBytes: byte list) let func = instance.GetFunction(funcName) func.Invoke(param1) +let runFloat32FuncFloat32 (funcName: string) (param1: float32) (wasmBytes: byte list) = + let instance = buildInstance wasmBytes + + let func = instance.GetFunction(funcName) + func.Invoke(param1) + let runFloat64FuncFloat64 (funcName: string) (param1: float) (wasmBytes: byte list) = let instance = buildInstance wasmBytes diff --git a/test/WasmBoolOperatorTests.fs b/test/WasmBoolOperatorTests.fs index b7c430b..5f641b5 100644 --- a/test/WasmBoolOperatorTests.fs +++ b/test/WasmBoolOperatorTests.fs @@ -171,6 +171,46 @@ let main () = 0 let response = wasmBytes |> runInt64FuncInt64 "x" param response.Should().Be(expected) +[] +[ 0.0f", 3.0f, 10.0f)>] +[ 0.0f", -3.0f, -10.0f)>] +[] +[] +[] +[] +[] +[ 3.0f", 3.0f, -10.0f)>] +[ 3.0f", -3.0f, 10.0f)>] +[ 3.0f", 6.0f, 10.0f)>] +[] +[] +[] +[= 3.0f", 3.0f, 10.0f)>] +[= 3.0f", -3.0f, -10.0f)>] +[= 3.0f", 6.0f, 10.0f)>] +let ``Can support float32 boolean operator expressions`` expr param expected = + let input = + $"""module Test + +let x (y: float32) = + let z = + if {expr} then + 10.0f + else + -10.0f + z + +let main () = 0 +""" + + let declarations = getDeclarations checker input + let wasmBytes = astToWasm declarations + + //printWasm wasmBytes + + let response = wasmBytes |> runFloat32FuncFloat32 "x" param + response.Should().Be(expected) + [] [ 0.0", 3.0, 10.0)>] [ 0.0", -3.0, -10.0)>] @@ -458,6 +498,118 @@ let main () = let response = wasmBytes |> runFuncInt64Return "main" response.Should().Be(10L) +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``Can support float32 boolean expressions`` nValue mValue expr expected = + let input = + $"""module Test + +let main () = + let n: float32 = {nValue} + let m: float32 = {mValue} + if {expr} then + 10.0f + else + 20.0f +""" + + let declarations = getDeclarations checker input + let wasmBytes = astToWasm declarations + + //printWasm wasmBytes + + let response = wasmBytes |> runFuncFloat32Return "main" + response.Should().Be(expected) + +[] +let ``Can support complicated float32 boolean expression`` () = + let input = + $"""module Test + +let main () = + let num1 = 1.0f + let num2 = 2.0f + let num3 = 3.0f + let num4 = 4.0f + let num5 = 5.0f + let num6 = 6.0f + if num1 = 1.0f && num2 = 2.0f && num3 = 3.0f && num4 > 2.0f && (num5 < 10.0f || num6 <= 6.0f) then + 10.0f + else + 20.0f +""" + + let declarations = getDeclarations checker input + let wasmBytes = astToWasm declarations + + //printWasm wasmBytes + + let response = wasmBytes |> runFuncFloat32Return "main" + response.Should().Be(10.0f) + +[] +[] +[] +[] +[] +[] +[] +[] +[] +let ``Can support float64 boolean expressions`` nValue mValue expr expected = + let input = + $"""module Test + +let main () = + let n: float = {nValue} + let m: float = {mValue} + if {expr} then + 10.0 + else + 20.0 +""" + + let declarations = getDeclarations checker input + let wasmBytes = astToWasm declarations + + //printWasm wasmBytes + + let response = wasmBytes |> runFuncFloat64Return "main" + response.Should().Be(expected) + +[] +let ``Can support complicated float64 boolean expression`` () = + let input = + $"""module Test + +let main () = + let num1 = 1.0 + let num2 = 2.0 + let num3 = 3.0 + let num4 = 4.0 + let num5 = 5.0 + let num6 = 6.0 + if num1 = 1.0 && num2 = 2.0 && num3 = 3.0 && num4 > 2.0 && (num5 < 10.0 || num6 <= 6.0) then + 10.0 + else + 20.0 +""" + + let declarations = getDeclarations checker input + let wasmBytes = astToWasm declarations + + //printWasm wasmBytes + + let response = wasmBytes |> runFuncFloat64Return "main" + response.Should().Be(10.0) + [] let ``Can support boolean types`` () = let input = diff --git a/test/WasmMathOperatorTests.fs b/test/WasmMathOperatorTests.fs index 699c4fd..934caa8 100644 --- a/test/WasmMathOperatorTests.fs +++ b/test/WasmMathOperatorTests.fs @@ -131,6 +131,35 @@ let main () = {expr} let response = wasmBytes |> runFuncInt64Return "main" response.Should().Be(expected) +[] +[] +[] +[] +[] +[] +[] +[] +//[] //don't know about modulo +//[] //don't know about modulo +[] +[] +[] +let ``Can support float32 expressions`` expr expected = + let input = + $""" +module Test + +let main () = {expr} +""" + + let declarations = getDeclarations checker input + let wasmBytes = astToWasm declarations + + //printWasm wasmBytes + + let response = wasmBytes |> runFuncFloat32Return "main" + response.Should().Be(expected) + [] [] []