diff --git a/src/Language/Wasm/Interpreter.hs b/src/Language/Wasm/Interpreter.hs index 82ee06f..099a970 100644 --- a/src/Language/Wasm/Interpreter.hs +++ b/src/Language/Wasm/Interpreter.hs @@ -1528,6 +1528,45 @@ eval budget store inst FunctionInstance { funcType, moduleInstance, code = Funct _ -> error "impossible due to validation" in return $ Done ctx { stack = VV128 r : rest } + step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (IBinOp (BS128 shape) IAvgrU) = + let r = case shape of + I8x16 -> lanewise @Word8 shape v1 v2 $ \a b -> fromIntegral $ (fromIntegral a + fromIntegral b + 1) `div` 2 + I16x8 -> lanewise @Word16 shape v1 v2 $ \a b -> fromIntegral $ (fromIntegral a + fromIntegral b + 1) `div` 2 + _ -> error "impossible due to validation" + in + return $ Done ctx { stack = VV128 r : rest } + step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (IBinOp (BS128 shape) IMinU) = + let r = case shape of + I8x16 -> lanewise @Word8 shape v1 v2 min + I16x8 -> lanewise @Word16 shape v1 v2 min + I32x4 -> lanewise @Word32 shape v1 v2 min + _ -> error "impossible due to validation" + in + return $ Done ctx { stack = VV128 r : rest } + step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (IBinOp (BS128 shape) IMinS) = + let r = case shape of + I8x16 -> lanewise @Word8 shape v1 v2 $ \a b -> asWord8 $ min (asInt8 a) (asInt8 b) + I16x8 -> lanewise @Word16 shape v1 v2 $ \a b -> asWord16 $ min (asInt16 a) (asInt16 b) + I32x4 -> lanewise @Word32 shape v1 v2 $ \a b -> asWord32 $ min (asInt32 a) (asInt32 b) + _ -> error "impossible due to validation" + in + return $ Done ctx { stack = VV128 r : rest } + step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (IBinOp (BS128 shape) IMaxU) = + let r = case shape of + I8x16 -> lanewise @Word8 shape v1 v2 max + I16x8 -> lanewise @Word16 shape v1 v2 max + I32x4 -> lanewise @Word32 shape v1 v2 max + _ -> error "impossible due to validation" + in + return $ Done ctx { stack = VV128 r : rest } + step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (IBinOp (BS128 shape) IMaxS) = + let r = case shape of + I8x16 -> lanewise @Word8 shape v1 v2 $ \a b -> asWord8 $ max (asInt8 a) (asInt8 b) + I16x8 -> lanewise @Word16 shape v1 v2 $ \a b -> asWord16 $ max (asInt16 a) (asInt16 b) + I32x4 -> lanewise @Word32 shape v1 v2 $ \a b -> asWord32 $ max (asInt32 a) (asInt32 b) + _ -> error "impossible due to validation" + in + return $ Done ctx { stack = VV128 r : rest } step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (IBinOp (BS128 _) IAnd) = let r = lanewise @Word64 I64x2 v1 v2 (.&.) in return $ Done ctx { stack = VV128 r : rest } @@ -1682,6 +1721,17 @@ eval budget store inst FunctionInstance { funcType, moduleInstance, code = Funct return $ Done ctx { stack = VF64 (nearest v) : rest } step ctx@EvalCtx{ stack = (VF64 v:rest) } (FUnOp BS64 FSqrt) = return $ Done ctx { stack = VF64 (sqrt v) : rest } + step ctx@EvalCtx{ stack = (VV128 v:rest) } (FUnOp (BS128 shape) FAbs) = + let r = case shape of + F32x4 -> ByteArray.byteArrayFromList + $ floatToWord . abs . wordToFloat . ByteArray.indexByteArray @Word32 v + <$> [0..3] + F64x2 -> ByteArray.byteArrayFromList + $ doubleToWord . abs . wordToDouble . ByteArray.indexByteArray @Word64 v + <$> [0..1] + _ -> error "impossible due to validation" + in + return $ Done ctx { stack = VV128 r : rest } step ctx@EvalCtx{ stack = (VV128 v:rest) } (FUnOp (BS128 shape) FNeg) = let r = case shape of F32x4 -> ByteArray.byteArrayFromList @@ -1760,6 +1810,20 @@ eval budget store inst FunctionInstance { funcType, moduleInstance, code = Funct _ -> error "impossible due to validation" in return $ Done ctx { stack = VV128 r : rest } + step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (FBinOp (BS128 shape) FMin) = + let r = case shape of + F32x4 -> lanewise @Word32 shape v1 v2 $ \a b -> floatToWord $ zeroAwareMin (wordToFloat a) (wordToFloat b) + F64x2 -> lanewise @Word64 shape v1 v2 $ \a b -> doubleToWord $ zeroAwareMin (wordToDouble a) (wordToDouble b) + _ -> error "impossible due to validation" + in + return $ Done ctx { stack = VV128 r : rest } + step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (FBinOp (BS128 shape) FMax) = + let r = case shape of + F32x4 -> lanewise @Word32 shape v1 v2 $ \a b -> floatToWord $ zeroAwareMax (wordToFloat a) (wordToFloat b) + F64x2 -> lanewise @Word64 shape v1 v2 $ \a b -> doubleToWord $ zeroAwareMax (wordToDouble a) (wordToDouble b) + _ -> error "impossible due to validation" + in + return $ Done ctx { stack = VV128 r : rest } step ctx@EvalCtx{ stack = (VF32 v2:VF32 v1:rest) } (FRelOp BS32 FEq) = return $ Done ctx { stack = VI32 (if v1 == v2 then 1 else 0) : rest } step ctx@EvalCtx{ stack = (VF32 v2:VF32 v1:rest) } (FRelOp BS32 FNe) = diff --git a/src/Language/Wasm/Parser.y b/src/Language/Wasm/Parser.y index 8708555..9bab426 100644 --- a/src/Language/Wasm/Parser.y +++ b/src/Language/Wasm/Parser.y @@ -422,6 +422,20 @@ import Language.Wasm.Lexer ( 'i16x8.add_sat_u' { Lexeme _ (TKeyword "i16x8.add_sat_u") } 'i8x16.sub_sat_u' { Lexeme _ (TKeyword "i8x16.sub_sat_u") } 'i16x8.sub_sat_u' { Lexeme _ (TKeyword "i16x8.sub_sat_u") } +'i8x16.avgr_u' { Lexeme _ (TKeyword "i8x16.avgr_u") } +'i16x8.avgr_u' { Lexeme _ (TKeyword "i16x8.avgr_u") } +'i8x16.min_s' { Lexeme _ (TKeyword "i8x16.min_s") } +'i16x8.min_s' { Lexeme _ (TKeyword "i16x8.min_s") } +'i32x4.min_s' { Lexeme _ (TKeyword "i32x4.min_s") } +'i8x16.min_u' { Lexeme _ (TKeyword "i8x16.min_u") } +'i16x8.min_u' { Lexeme _ (TKeyword "i16x8.min_u") } +'i32x4.min_u' { Lexeme _ (TKeyword "i32x4.min_u") } +'i8x16.max_s' { Lexeme _ (TKeyword "i8x16.max_s") } +'i16x8.max_s' { Lexeme _ (TKeyword "i16x8.max_s") } +'i32x4.max_s' { Lexeme _ (TKeyword "i32x4.max_s") } +'i8x16.max_u' { Lexeme _ (TKeyword "i8x16.max_u") } +'i16x8.max_u' { Lexeme _ (TKeyword "i16x8.max_u") } +'i32x4.max_u' { Lexeme _ (TKeyword "i32x4.max_u") } 'i16x8.mul' { Lexeme _ (TKeyword "i16x8.mul") } 'i32x4.mul' { Lexeme _ (TKeyword "i32x4.mul") } 'i64x2.mul' { Lexeme _ (TKeyword "i64x2.mul") } @@ -497,6 +511,12 @@ import Language.Wasm.Lexer ( 'f64x2.mul' { Lexeme _ (TKeyword "f64x2.mul") } 'f32x4.div' { Lexeme _ (TKeyword "f32x4.div") } 'f64x2.div' { Lexeme _ (TKeyword "f64x2.div") } +'f32x4.min' { Lexeme _ (TKeyword "f32x4.min") } +'f64x2.min' { Lexeme _ (TKeyword "f64x2.min") } +'f32x4.max' { Lexeme _ (TKeyword "f32x4.max") } +'f64x2.max' { Lexeme _ (TKeyword "f64x2.max") } +'f32x4.abs' { Lexeme _ (TKeyword "f32x4.abs") } +'f64x2.abs' { Lexeme _ (TKeyword "f64x2.abs") } 'f32x4.neg' { Lexeme _ (TKeyword "f32x4.neg") } 'f64x2.neg' { Lexeme _ (TKeyword "f64x2.neg") } 'f32x4.sqrt' { Lexeme _ (TKeyword "f32x4.sqrt") } @@ -967,6 +987,20 @@ plaininstr :: { PlainInstr } | 'i16x8.add_sat_u' { IBinOp (BS128 I16x8) IAddSatU } | 'i8x16.sub_sat_u' { IBinOp (BS128 I8x16) ISubSatU } | 'i16x8.sub_sat_u' { IBinOp (BS128 I16x8) ISubSatU } + | 'i8x16.avgr_u' { IBinOp (BS128 I8x16) IAvgrU } + | 'i16x8.avgr_u' { IBinOp (BS128 I16x8) IAvgrU } + | 'i8x16.min_s' { IBinOp (BS128 I8x16) IMinS } + | 'i16x8.min_s' { IBinOp (BS128 I16x8) IMinS } + | 'i32x4.min_s' { IBinOp (BS128 I32x4) IMinS } + | 'i8x16.min_u' { IBinOp (BS128 I8x16) IMinU } + | 'i16x8.min_u' { IBinOp (BS128 I16x8) IMinU } + | 'i32x4.min_u' { IBinOp (BS128 I32x4) IMinU } + | 'i8x16.max_s' { IBinOp (BS128 I8x16) IMaxS } + | 'i16x8.max_s' { IBinOp (BS128 I16x8) IMaxS } + | 'i32x4.max_s' { IBinOp (BS128 I32x4) IMaxS } + | 'i8x16.max_u' { IBinOp (BS128 I8x16) IMaxU } + | 'i16x8.max_u' { IBinOp (BS128 I16x8) IMaxU } + | 'i32x4.max_u' { IBinOp (BS128 I32x4) IMaxU } | 'i16x8.mul' { IBinOp (BS128 I16x8) IMul } | 'i32x4.mul' { IBinOp (BS128 I32x4) IMul } | 'i64x2.mul' { IBinOp (BS128 I64x2) IMul } @@ -1042,6 +1076,12 @@ plaininstr :: { PlainInstr } | 'f64x2.mul' { FBinOp (BS128 F64x2) FMul } | 'f32x4.div' { FBinOp (BS128 F32x4) FDiv } | 'f64x2.div' { FBinOp (BS128 F64x2) FDiv } + | 'f32x4.min' { FBinOp (BS128 F32x4) FMin } + | 'f64x2.min' { FBinOp (BS128 F64x2) FMin } + | 'f32x4.max' { FBinOp (BS128 F32x4) FMax } + | 'f64x2.max' { FBinOp (BS128 F64x2) FMax } + | 'f32x4.abs' { FUnOp (BS128 F32x4) FAbs } + | 'f64x2.abs' { FUnOp (BS128 F64x2) FAbs } | 'f32x4.neg' { FUnOp (BS128 F32x4) FNeg } | 'f64x2.neg' { FUnOp (BS128 F64x2) FNeg } | 'f32x4.sqrt' { FUnOp (BS128 F32x4) FSqrt } diff --git a/src/Language/Wasm/Structure.hs b/src/Language/Wasm/Structure.hs index d4fb402..7faba32 100644 --- a/src/Language/Wasm/Structure.hs +++ b/src/Language/Wasm/Structure.hs @@ -83,6 +83,7 @@ data IBinOp = | ISubSatS | IAddSatU | ISubSatU + | IAvgrU | IMul | IDivU | IDivS @@ -97,6 +98,10 @@ data IBinOp = | IShrS | IRotl | IRotr + | IMinU + | IMinS + | IMaxU + | IMaxS deriving (Show, Eq, Generic, NFData) data IRelOp = IEq | INe | ILtU | ILtS | IGtU | IGtS | ILeU | ILeS | IGeU | IGeS deriving (Show, Eq, Generic, NFData) diff --git a/tests/Test.hs b/tests/Test.hs index 0eb5717..98298e7 100644 --- a/tests/Test.hs +++ b/tests/Test.hs @@ -20,7 +20,7 @@ main = do filter (List.isPrefixOf "simd") . filter (List.isSuffixOf ".wast") <$> Directory.listDirectory "tests/spec" - -- let files = ["simd_f64x2_cmp.wast"] + -- let files = ["simd_i16x8_arith2.wast"] scriptTestCases <- (`mapM` files) $ \file -> do test <- LBS.readFile ("tests/spec/" ++ file) return $ testCase file $ do