diff --git a/src/Language/Wasm/Interpreter.hs b/src/Language/Wasm/Interpreter.hs index b21b467..a45b543 100644 --- a/src/Language/Wasm/Interpreter.hs +++ b/src/Language/Wasm/Interpreter.hs @@ -1428,6 +1428,11 @@ 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 v:rest) } (IUnOp (BS128 _) IPopcnt) = + let r = ByteArray.byteArrayFromList @Word8 + $ (fromIntegral . popCount) . ByteArray.indexByteArray @Word8 v <$> [0..15] + in + return $ Done ctx { stack = VV128 r : rest } step ctx@EvalCtx{ stack = (VV128 v2:VV128 v1:rest) } (IBinOp (BS128 shape) IAdd) = let r = case shape of I8x16 -> lanewise @Word8 shape v1 v2 (+) @@ -1454,6 +1459,39 @@ 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) (IExtMul signed high)) = + let count = case shape of + I16x8 -> 8 + I32x4 -> 4 + I64x2 -> 2 + _ -> error "impossible due to validation" + in + let proto = if high then [1,3..2*(count - 1) + 1] else [0,2..2 *(count-1)] in + let r = case shape of + I16x8 -> + let op = if signed + then \a b -> asWord16 $ fromIntegral (asInt8 a) * fromIntegral (asInt8 b) + else \a b -> fromIntegral a * fromIntegral b + in + ByteArray.byteArrayFromListN count + $ zipWith op (ByteArray.indexByteArray v1 <$> proto) (ByteArray.indexByteArray v2 <$> proto) + I32x4 -> + let op = if signed + then \a b -> asWord32 $ fromIntegral (asInt16 a) * fromIntegral (asInt16 b) + else \a b -> fromIntegral a * fromIntegral b + in + ByteArray.byteArrayFromListN count + $ zipWith op (ByteArray.indexByteArray v1 <$> proto) (ByteArray.indexByteArray v2 <$> proto) + I64x2 -> + let op = if signed + then \a b -> asWord64 $ fromIntegral (asInt32 a) * fromIntegral (asInt32 b) + else \a b -> fromIntegral a * fromIntegral b + in + ByteArray.byteArrayFromListN count + $ zipWith op (ByteArray.indexByteArray v1 <$> proto) (ByteArray.indexByteArray v2 <$> proto) + _ -> 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) IAddSatU) = let r = case shape of I8x16 -> lanewise @Word8 shape v1 v2 $ \a b -> diff --git a/src/Language/Wasm/Parser.y b/src/Language/Wasm/Parser.y index b5b0bc3..19edab5 100644 --- a/src/Language/Wasm/Parser.y +++ b/src/Language/Wasm/Parser.y @@ -399,6 +399,7 @@ import Language.Wasm.Lexer ( 'i16x8.all_true' { Lexeme _ (TKeyword "i16x8.all_true") } 'i32x4.all_true' { Lexeme _ (TKeyword "i32x4.all_true") } 'i64x2.all_true' { Lexeme _ (TKeyword "i64x2.all_true") } +'i8x16.popcnt' { Lexeme _ (TKeyword "i8x16.popcnt") } 'v128.not' { Lexeme _ (TKeyword "v128.not") } 'v128.and' { Lexeme _ (TKeyword "v128.and") } 'v128.andnot' { Lexeme _ (TKeyword "v128.andnot") } @@ -424,6 +425,18 @@ import Language.Wasm.Lexer ( '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") } +'i16x8.extmul_low_i8x16_s' { Lexeme _ (TKeyword "i16x8.extmul_low_i8x16_s") } +'i32x4.extmul_low_i16x8_s' { Lexeme _ (TKeyword "i32x4.extmul_low_i16x8_s") } +'i64x2.extmul_low_i32x4_s' { Lexeme _ (TKeyword "i64x2.extmul_low_i32x4_s") } +'i16x8.extmul_low_i8x16_u' { Lexeme _ (TKeyword "i16x8.extmul_low_i8x16_u") } +'i32x4.extmul_low_i16x8_u' { Lexeme _ (TKeyword "i32x4.extmul_low_i16x8_u") } +'i64x2.extmul_low_i32x4_u' { Lexeme _ (TKeyword "i64x2.extmul_low_i32x4_u") } +'i16x8.extmul_high_i8x16_s' { Lexeme _ (TKeyword "i16x8.extmul_high_i8x16_s") } +'i32x4.extmul_high_i16x8_s' { Lexeme _ (TKeyword "i32x4.extmul_high_i16x8_s") } +'i64x2.extmul_high_i32x4_s' { Lexeme _ (TKeyword "i64x2.extmul_high_i32x4_s") } +'i16x8.extmul_high_i8x16_u' { Lexeme _ (TKeyword "i16x8.extmul_high_i8x16_u") } +'i32x4.extmul_high_i16x8_u' { Lexeme _ (TKeyword "i32x4.extmul_high_i16x8_u") } +'i64x2.extmul_high_i32x4_u' { Lexeme _ (TKeyword "i64x2.extmul_high_i32x4_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") } @@ -1009,6 +1022,18 @@ plaininstr :: { PlainInstr } | 'i8x16.max_u' { IBinOp (BS128 I8x16) IMaxU } | 'i16x8.max_u' { IBinOp (BS128 I16x8) IMaxU } | 'i32x4.max_u' { IBinOp (BS128 I32x4) IMaxU } + | 'i16x8.extmul_low_i8x16_s' { IBinOp (BS128 I16x8) (IExtMul True False) } + | 'i32x4.extmul_low_i16x8_s' { IBinOp (BS128 I32x4) (IExtMul True False) } + | 'i64x2.extmul_low_i32x4_s' { IBinOp (BS128 I64x2) (IExtMul True False) } + | 'i16x8.extmul_low_i8x16_u' { IBinOp (BS128 I16x8) (IExtMul False False) } + | 'i32x4.extmul_low_i16x8_u' { IBinOp (BS128 I32x4) (IExtMul False False) } + | 'i64x2.extmul_low_i32x4_u' { IBinOp (BS128 I64x2) (IExtMul False False) } + | 'i16x8.extmul_high_i8x16_s' { IBinOp (BS128 I16x8) (IExtMul True True) } + | 'i32x4.extmul_high_i16x8_s' { IBinOp (BS128 I32x4) (IExtMul True True) } + | 'i64x2.extmul_high_i32x4_s' { IBinOp (BS128 I64x2) (IExtMul True True) } + | 'i16x8.extmul_high_i8x16_u' { IBinOp (BS128 I16x8) (IExtMul False True) } + | 'i32x4.extmul_high_i16x8_u' { IBinOp (BS128 I32x4) (IExtMul False True) } + | 'i64x2.extmul_high_i32x4_u' { IBinOp (BS128 I64x2) (IExtMul False True) } | 'i16x8.mul' { IBinOp (BS128 I16x8) IMul } | 'i32x4.mul' { IBinOp (BS128 I32x4) IMul } | 'i64x2.mul' { IBinOp (BS128 I64x2) IMul } @@ -1024,6 +1049,7 @@ plaininstr :: { PlainInstr } | 'i16x8.shr_s' { IBinOp (BS128 I16x8) IShrS } | 'i32x4.shr_s' { IBinOp (BS128 I32x4) IShrS } | 'i64x2.shr_s' { IBinOp (BS128 I64x2) IShrS } + | 'i8x16.popcnt' { IUnOp (BS128 I8x16) IPopcnt } | 'i8x16.abs' { IUnOp (BS128 I8x16) IAbs } | 'i16x8.abs' { IUnOp (BS128 I16x8) IAbs } | 'i32x4.abs' { IUnOp (BS128 I32x4) IAbs } diff --git a/src/Language/Wasm/Structure.hs b/src/Language/Wasm/Structure.hs index 7faba32..b1ee60b 100644 --- a/src/Language/Wasm/Structure.hs +++ b/src/Language/Wasm/Structure.hs @@ -102,6 +102,7 @@ data IBinOp = | IMinS | IMaxU | IMaxS + | IExtMul {- Signed -} Bool {- High -} Bool 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 cb27f4b..fb0a8fc 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_rounding.wast"] + -- let files = ["simd_i64x2_extmul_i32x4.wast"] scriptTestCases <- (`mapM` files) $ \file -> do test <- LBS.readFile ("tests/spec/" ++ file) return $ testCase file $ do