From d406776095866b9aac2bcf8380b449c86a46abe0 Mon Sep 17 00:00:00 2001 From: Ilya Rezvov Date: Fri, 8 Sep 2023 10:29:30 -0600 Subject: [PATCH] implement v128.load[8|16|32|64]_splat --- src/Language/Wasm/Interpreter.hs | 16 ++++++++++++++++ src/Language/Wasm/Parser.y | 16 ++++++++++++++++ src/Language/Wasm/Structure.hs | 4 ++++ src/Language/Wasm/Validate.hs | 12 ++++++++++++ tests/Test.hs | 2 +- 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/Language/Wasm/Interpreter.hs b/src/Language/Wasm/Interpreter.hs index 124c2f3..b6620c8 100644 --- a/src/Language/Wasm/Interpreter.hs +++ b/src/Language/Wasm/Interpreter.hs @@ -879,6 +879,22 @@ eval budget store inst FunctionInstance { funcType, moduleInstance, code = Funct else do val <- ByteArray.freezeByteArray memory addr 16 return $ Done ctx { stack = VV128 val : rest } + step ctx (V128Load8Splat MemArg { offset }) = + makeLoadInstr @Word8 ctx offset 1 $ \rest val -> + let v = ByteArray.byteArrayFromListN 16 $ replicate 16 val in + Done ctx { stack = VV128 v : rest } + step ctx (V128Load16Splat MemArg { offset }) = + makeLoadInstr @Word16 ctx offset 2 $ \rest val -> + let v = ByteArray.byteArrayFromListN 8 $ replicate 8 val in + Done ctx { stack = VV128 v : rest } + step ctx (V128Load32Splat MemArg { offset }) = + makeLoadInstr @Word32 ctx offset 4 $ \rest val -> + let v = ByteArray.byteArrayFromListN 4 $ replicate 4 val in + Done ctx { stack = VV128 v : rest } + step ctx (V128Load64Splat MemArg { offset }) = + makeLoadInstr @Word64 ctx offset 8 $ \rest val -> + let v = ByteArray.byteArrayFromListN 2 [val, val] in + Done ctx { stack = VV128 v : rest } step ctx (I32Load8U MemArg { offset }) = makeLoadInstr @Word8 ctx offset 1 $ (\rest val -> Done ctx { stack = VI32 (fromIntegral val) : rest }) step ctx (I32Load8S MemArg { offset }) = diff --git a/src/Language/Wasm/Parser.y b/src/Language/Wasm/Parser.y index 8b88f34..cca9e14 100644 --- a/src/Language/Wasm/Parser.y +++ b/src/Language/Wasm/Parser.y @@ -151,6 +151,10 @@ import Language.Wasm.Lexer ( 'f32.load' { Lexeme _ (TKeyword "f32.load") } 'f64.load' { Lexeme _ (TKeyword "f64.load") } 'v128.load' { Lexeme _ (TKeyword "v128.load") } +'v128.load8_splat' { Lexeme _ (TKeyword "v128.load8_splat") } +'v128.load16_splat' { Lexeme _ (TKeyword "v128.load16_splat") } +'v128.load32_splat' { Lexeme _ (TKeyword "v128.load32_splat") } +'v128.load64_splat' { Lexeme _ (TKeyword "v128.load64_splat") } 'i32.load8_s' { Lexeme _ (TKeyword "i32.load8_s") } 'i32.load8_u' { Lexeme _ (TKeyword "i32.load8_u") } 'i32.load16_s' { Lexeme _ (TKeyword "i32.load16_s") } @@ -563,6 +567,10 @@ plaininstr :: { PlainInstr } | 'f32.load' memarg4 { F32Load $2 } | 'f64.load' memarg8 { F64Load $2 } | 'v128.load' memarg16 { V128Load $2 } + | 'v128.load8_splat' memarg1 { V128Load8Splat $2 } + | 'v128.load16_splat' memarg2 { V128Load16Splat $2 } + | 'v128.load32_splat' memarg4 { V128Load32Splat $2 } + | 'v128.load64_splat' memarg8 { V128Load64Splat $2 } | 'i32.load8_s' memarg1 { I32Load8S $2 } | 'i32.load8_u' memarg1 { I32Load8U $2 } | 'i32.load16_s' memarg2 { I32Load16S $2 } @@ -1429,6 +1437,10 @@ data PlainInstr = | F32Load MemArg | F64Load MemArg | V128Load MemArg + | V128Load8Splat MemArg + | V128Load16Splat MemArg + | V128Load32Splat MemArg + | V128Load64Splat MemArg | I32Load8S MemArg | I32Load8U MemArg | I32Load16S MemArg @@ -1952,6 +1964,10 @@ desugarize fields = do synInstrToStruct _ (PlainInstr (F32Load memArg)) = return $ S.F32Load memArg synInstrToStruct _ (PlainInstr (F64Load memArg)) = return $ S.F64Load memArg synInstrToStruct _ (PlainInstr (V128Load memArg)) = return $ S.V128Load memArg + synInstrToStruct _ (PlainInstr (V128Load8Splat memArg)) = return $ S.V128Load8Splat memArg + synInstrToStruct _ (PlainInstr (V128Load16Splat memArg)) = return $ S.V128Load16Splat memArg + synInstrToStruct _ (PlainInstr (V128Load32Splat memArg)) = return $ S.V128Load32Splat memArg + synInstrToStruct _ (PlainInstr (V128Load64Splat memArg)) = return $ S.V128Load64Splat memArg synInstrToStruct _ (PlainInstr (I32Load8S memArg)) = return $ S.I32Load8S memArg synInstrToStruct _ (PlainInstr (I32Load8U memArg)) = return $ S.I32Load8U memArg synInstrToStruct _ (PlainInstr (I32Load16S memArg)) = return $ S.I32Load16S memArg diff --git a/src/Language/Wasm/Structure.hs b/src/Language/Wasm/Structure.hs index f9d89a5..f7d0964 100644 --- a/src/Language/Wasm/Structure.hs +++ b/src/Language/Wasm/Structure.hs @@ -165,6 +165,10 @@ data Instruction index = | F32Load MemArg | F64Load MemArg | V128Load MemArg + | V128Load8Splat MemArg + | V128Load16Splat MemArg + | V128Load32Splat MemArg + | V128Load64Splat MemArg | I32Load8S MemArg | I32Load8U MemArg | I32Load16S MemArg diff --git a/src/Language/Wasm/Validate.hs b/src/Language/Wasm/Validate.hs index f571c3d..596d587 100644 --- a/src/Language/Wasm/Validate.hs +++ b/src/Language/Wasm/Validate.hs @@ -340,6 +340,18 @@ getInstrType _ (F64Load memarg) = do getInstrType _ (V128Load memarg) = do checkMemoryInstr 16 memarg return $ I32 ==> V128 +getInstrType _ (V128Load8Splat memarg) = do + checkMemoryInstr 1 memarg + return $ I32 ==> V128 +getInstrType _ (V128Load16Splat memarg) = do + checkMemoryInstr 2 memarg + return $ I32 ==> V128 +getInstrType _ (V128Load32Splat memarg) = do + checkMemoryInstr 4 memarg + return $ I32 ==> V128 +getInstrType _ (V128Load64Splat memarg) = do + checkMemoryInstr 8 memarg + return $ I32 ==> V128 getInstrType _ (I32Load8S memarg) = do checkMemoryInstr 1 memarg return $ I32 ==> I32 diff --git a/tests/Test.hs b/tests/Test.hs index 713f721..253f0cb 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_store64_lane.wast"] + let files = ["simd_load_splat.wast"] scriptTestCases <- (`mapM` files) $ \file -> do test <- LBS.readFile ("tests/spec/" ++ file) return $ testCase file $ do