implement extract_lane and replace_lane

This commit is contained in:
Ilya Rezvov
2023-09-06 21:09:23 -06:00
parent 4302e4b32f
commit 5c6e9b59bc
6 changed files with 243 additions and 201 deletions
+15
View File
@@ -1574,6 +1574,21 @@ eval budget store inst FunctionInstance { funcType, moduleInstance, code = Funct
ByteArray.unsafeFreezeByteArray arr ByteArray.unsafeFreezeByteArray arr
_ -> error "impossible due to validation" _ -> error "impossible due to validation"
return $ Done ctx { stack = VV128 val : rest } return $ Done ctx { stack = VV128 val : rest }
step ctx@EvalCtx{ stack = (VV128 v:rest) } V128AnyTrue =
let w0 = ByteArray.indexByteArray @Word64 v 0 in
let w1 = ByteArray.indexByteArray @Word64 v 1 in
let r = if w0 == 0 && w1 == 0 then 0 else 1 in
return $ Done ctx { stack = VI32 r : rest }
step ctx@EvalCtx{ stack = (VV128 v:rest) } (V128AllTrue shape) =
let r = case shape of
I8x16 -> all (/= 0) $ ByteArray.indexByteArray @Word8 v <$> [0..15]
I16x8 -> all (/= 0) $ ByteArray.indexByteArray @Word16 v <$> [0..8]
I32x4 -> all (/= 0) $ ByteArray.indexByteArray @Word32 v <$> [0..4]
I64x2 -> all (/= 0) $ ByteArray.indexByteArray @Word64 v <$> [0..2]
F32x4 -> all (/= 0) $ wordToFloat . ByteArray.indexByteArray @Word32 v <$> [0..4]
F64x2 -> all (/= 0) $ wordToDouble . ByteArray.indexByteArray @Word64 v <$> [0..2]
in
return $ Done ctx { stack = VI32 (if r then 1 else 0) : rest }
step EvalCtx{ stack } instr = error $ "Error during evaluation of instruction: " ++ show instr ++ ". Stack " ++ show stack step EvalCtx{ stack } instr = error $ "Error during evaluation of instruction: " ++ show instr ++ ". Stack " ++ show stack
eval _ _ _ HostInstance { funcType, hostCode } args = Just <$> hostCode args eval _ _ _ HostInstance { funcType, hostCode } args = Just <$> hostCode args
+11 -9
View File
@@ -80,8 +80,10 @@ tokens :-
<0> @id { tokenStr TId } <0> @id { tokenStr TId }
<0> "(" { constToken TOpenBracket } <0> "(" { constToken TOpenBracket }
<0> ")" { constToken TCloseBracket } <0> ")" { constToken TCloseBracket }
<0> $sign? @num { parseDecimalSignedInt } <0> @num { parseDecimalSignedInt True }
<0> $sign? "0x" @hexnum { parseHexalSignedInt } <0> "0x" @hexnum { parseHexalSignedInt True }
<0> $sign @num { parseDecimalSignedInt False }
<0> $sign "0x" @hexnum { parseHexalSignedInt False }
<0> $sign? @float { parseDecFloat } <0> $sign? @float { parseDecFloat }
<0> $sign? @hexfloat { parseHexFloat } <0> $sign? @hexfloat { parseHexFloat }
<0, blockComment> @startblockcomment { startBlockComment } <0, blockComment> @startblockcomment { startBlockComment }
@@ -130,11 +132,11 @@ parseSign str =
{-# SPECIALIZE parseSign :: LBS.ByteString -> ((Integer -> Integer), Int64) #-} {-# SPECIALIZE parseSign :: LBS.ByteString -> ((Integer -> Integer), Int64) #-}
{-# SPECIALIZE parseSign :: LBS.ByteString -> ((Double -> Double), Int64) #-} {-# SPECIALIZE parseSign :: LBS.ByteString -> ((Double -> Double), Int64) #-}
parseHexalSignedInt :: AlexAction Lexeme parseHexalSignedInt :: Bool -> AlexAction Lexeme
parseHexalSignedInt = token $ \(pos, _, s, _) len -> parseHexalSignedInt nat = token $ \(pos, _, s, _) len ->
let (sign, slen) = parseSign s in let (sign, slen) = parseSign s in
let num = readHexFromPrefix (len - 2 - slen) $ LBSUtf8.drop (2 + slen) s in let num = readHexFromPrefix (len - 2 - slen) $ LBSUtf8.drop (2 + slen) s in
Lexeme (Just pos) $ TIntLit $ sign num Lexeme (Just pos) $ TIntLit nat $ sign num
parseNanSigned :: AlexAction Lexeme parseNanSigned :: AlexAction Lexeme
parseNanSigned = token $ \(pos, _, s, _) len -> parseNanSigned = token $ \(pos, _, s, _) len ->
@@ -146,11 +148,11 @@ parseNanSigned = token $ \(pos, _, s, _) len ->
let num = readHexFromPrefix (len - 6 - slen) $ LBSUtf8.drop (6 + slen) s in let num = readHexFromPrefix (len - 6 - slen) $ LBSUtf8.drop (6 + slen) s in
Lexeme (Just pos) $ TFloatLit $ NanRep $ NanHex sign $ fromIntegral num Lexeme (Just pos) $ TFloatLit $ NanRep $ NanHex sign $ fromIntegral num
parseDecimalSignedInt :: AlexAction Lexeme parseDecimalSignedInt :: Bool -> AlexAction Lexeme
parseDecimalSignedInt = token $ \(pos, _, s, _) len -> parseDecimalSignedInt nat = token $ \(pos, _, s, _) len ->
let (sign, slen) = parseSign s in let (sign, slen) = parseSign s in
let num = readDecFromPrefix (len - slen) $ LBSUtf8.drop slen s in let num = readDecFromPrefix (len - slen) $ LBSUtf8.drop slen s in
Lexeme (Just pos) $ TIntLit $ sign num Lexeme (Just pos) $ TIntLit nat $ sign num
parseDecFloat :: AlexAction Lexeme parseDecFloat :: AlexAction Lexeme
parseDecFloat = token $ \(pos, _, s, _) len -> parseDecFloat = token $ \(pos, _, s, _) len ->
@@ -364,7 +366,7 @@ data NaN
deriving (Show, Eq) deriving (Show, Eq)
data Token = TKeyword LBS.ByteString data Token = TKeyword LBS.ByteString
| TIntLit Integer | TIntLit {- Natural -} Bool Integer
| TFloatLit FloatRep | TFloatLit FloatRep
| TStringLit LBS.ByteString | TStringLit LBS.ByteString
| TId LBS.ByteString | TId LBS.ByteString
+28 -18
View File
@@ -408,7 +408,8 @@ import Language.Wasm.Lexer (
'output' { Lexeme _ (TKeyword "output") } 'output' { Lexeme _ (TKeyword "output") }
-- script extension end -- script extension end
id { Lexeme _ (TId $$) } id { Lexeme _ (TId $$) }
int { Lexeme _ (TIntLit $$) } signed { Lexeme _ (TIntLit False $$) }
nat { Lexeme _ (TIntLit True $$) }
f64 { Lexeme _ (TFloatLit $$) } f64 { Lexeme _ (TFloatLit $$) }
offset { Lexeme _ (TKeyword (asOffset -> Just $$)) } offset { Lexeme _ (TKeyword (asOffset -> Just $$)) }
align { Lexeme _ (TKeyword (asAlign -> Just $$)) } align { Lexeme _ (TKeyword (asAlign -> Just $$)) }
@@ -439,6 +440,10 @@ valtype :: { ValueType }
| 'funcref' { Func } | 'funcref' { Func }
| 'externref' { Extern } | 'externref' { Extern }
int :: {Integer}
: signed { $1 }
| nat { $1 }
index :: { Index } index :: { Index }
: u32 { Index $1 } : u32 { Index $1 }
| ident { Named $1 } | ident { Named $1 }
@@ -524,6 +529,9 @@ v128_const :: { V128Rep }
F64x2Const [$2, $3] F64x2Const [$2, $3]
} }
lane_index :: { Natural }
: nat {% if $1 < 256 then Right $ fromIntegral $1 else Left "malformed lane index"}
plaininstr :: { PlainInstr } plaininstr :: { PlainInstr }
-- control instructions -- control instructions
: 'unreachable' { Unreachable } : 'unreachable' { Unreachable }
@@ -733,9 +741,11 @@ plaininstr :: { PlainInstr }
| 'f32.reinterpret_i32' { FReinterpretI BS32 } | 'f32.reinterpret_i32' { FReinterpretI BS32 }
| 'f64.reinterpret_i64' { FReinterpretI BS64 } | 'f64.reinterpret_i64' { FReinterpretI BS64 }
-- simd -- simd
| 'i8x16.shuffle' i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 { | 'i8x16.shuffle' u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 {%
I8x16Shuffle $ map fromIntegral let idxs = [$2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17] in
[$2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17] if any (\i -> i < 0 || i > 0xFF) idxs
then Left "malformed lane index"
else Right $ I8x16Shuffle $ map fromIntegral idxs
} }
| 'i8x16.swizzle' { I8x16Swizzle } | 'i8x16.swizzle' { I8x16Swizzle }
| 'v128.any_true' { V128AnyTrue } | 'v128.any_true' { V128AnyTrue }
@@ -751,20 +761,20 @@ plaininstr :: { PlainInstr }
| 'i64x2.all_true' { V128AllTrue I64x2 } | 'i64x2.all_true' { V128AllTrue I64x2 }
| 'f32x4.all_true' { V128AllTrue F32x4 } | 'f32x4.all_true' { V128AllTrue F32x4 }
| 'f64x2.all_true' { V128AllTrue F64x2 } | 'f64x2.all_true' { V128AllTrue F64x2 }
| 'i8x16.extract_lane_s' u32 { V128ExtractLane I8x16 $2 True } | 'i8x16.extract_lane_s' lane_index { V128ExtractLane I8x16 $2 True }
| 'i16x8.extract_lane_s' u32 { V128ExtractLane I16x8 $2 True } | 'i16x8.extract_lane_s' lane_index { V128ExtractLane I16x8 $2 True }
| 'i8x16.extract_lane_u' u32 { V128ExtractLane I8x16 $2 False } | 'i8x16.extract_lane_u' lane_index { V128ExtractLane I8x16 $2 False }
| 'i16x8.extract_lane_u' u32 { V128ExtractLane I16x8 $2 False } | 'i16x8.extract_lane_u' lane_index { V128ExtractLane I16x8 $2 False }
| 'i32x4.extract_lane' u32 { V128ExtractLane I32x4 $2 False } | 'i32x4.extract_lane' lane_index { V128ExtractLane I32x4 $2 False }
| 'i64x2.extract_lane' u32 { V128ExtractLane I64x2 $2 False } | 'i64x2.extract_lane' lane_index { V128ExtractLane I64x2 $2 False }
| 'f32x4.extract_lane' u32 { V128ExtractLane F32x4 $2 False } | 'f32x4.extract_lane' lane_index { V128ExtractLane F32x4 $2 False }
| 'f64x2.extract_lane' u32 { V128ExtractLane F64x2 $2 False } | 'f64x2.extract_lane' lane_index { V128ExtractLane F64x2 $2 False }
| 'i8x16.replace_lane' u32 { V128ReplaceLane I8x16 $2 } | 'i8x16.replace_lane' lane_index { V128ReplaceLane I8x16 $2 }
| 'i16x8.replace_lane' u32 { V128ReplaceLane I16x8 $2 } | 'i16x8.replace_lane' lane_index { V128ReplaceLane I16x8 $2 }
| 'i32x4.replace_lane' u32 { V128ReplaceLane I32x4 $2 } | 'i32x4.replace_lane' lane_index { V128ReplaceLane I32x4 $2 }
| 'i64x2.replace_lane' u32 { V128ReplaceLane I64x2 $2 } | 'i64x2.replace_lane' lane_index { V128ReplaceLane I64x2 $2 }
| 'f32x4.replace_lane' u32 { V128ReplaceLane F32x4 $2 } | 'f32x4.replace_lane' lane_index { V128ReplaceLane F32x4 $2 }
| 'f64x2.replace_lane' u32 { V128ReplaceLane F64x2 $2 } | 'f64x2.replace_lane' lane_index { V128ReplaceLane F64x2 $2 }
| 'i8x16.add' { IBinOp (BS128 I8x16) IAdd } | 'i8x16.add' { IBinOp (BS128 I8x16) IAdd }
| 'i16x8.add' { IBinOp (BS128 I16x8) IAdd } | 'i16x8.add' { IBinOp (BS128 I16x8) IAdd }
| 'i32x4.add' { IBinOp (BS128 I32x4) IAdd } | 'i32x4.add' { IBinOp (BS128 I32x4) IAdd }
+1
View File
@@ -188,6 +188,7 @@ runScript onAssertFail script = do
getFailureString (Validate.FunctionIndexOutOfRange idx) = ["unknown function", "unknown function " <> TL.pack (show idx)] getFailureString (Validate.FunctionIndexOutOfRange idx) = ["unknown function", "unknown function " <> TL.pack (show idx)]
getFailureString (Validate.GlobalIndexOutOfRange idx) = ["unknown global", "unknown global " <> TL.pack (show idx)] getFailureString (Validate.GlobalIndexOutOfRange idx) = ["unknown global", "unknown global " <> TL.pack (show idx)]
getFailureString Validate.LabelIndexOutOfRange = ["unknown label"] getFailureString Validate.LabelIndexOutOfRange = ["unknown label"]
getFailureString Validate.LaneIndexOutOfRange = ["invalid lane index"]
getFailureString Validate.TypeIndexOutOfRange = ["unknown type"] getFailureString Validate.TypeIndexOutOfRange = ["unknown type"]
getFailureString Validate.MinMoreThanMaxInMemoryLimit = ["size minimum must not be greater than maximum"] getFailureString Validate.MinMoreThanMaxInMemoryLimit = ["size minimum must not be greater than maximum"]
getFailureString Validate.MemoryLimitExceeded = ["memory size must be at most 65536 pages (4GiB)"] getFailureString Validate.MemoryLimitExceeded = ["memory size must be at most 65536 pages (4GiB)"]
+17 -3
View File
@@ -40,6 +40,7 @@ data ValidationError =
| ElemIndexOutOfRange Natural | ElemIndexOutOfRange Natural
| DataIndexOutOfRange Natural | DataIndexOutOfRange Natural
| LabelIndexOutOfRange | LabelIndexOutOfRange
| LaneIndexOutOfRange
| TypeIndexOutOfRange | TypeIndexOutOfRange
| ResultTypeDoesntMatch | ResultTypeDoesntMatch
| TypeMismatch { actual :: Arrow, expected :: Arrow } | TypeMismatch { actual :: Arrow, expected :: Arrow }
@@ -524,13 +525,16 @@ getInstrType _ (FReinterpretI BS32) = return $ I32 ==> F32
getInstrType _ (FReinterpretI BS64) = return $ I64 ==> F64 getInstrType _ (FReinterpretI BS64) = return $ I64 ==> F64
getInstrType _ I8x16Swizzle = getInstrType _ I8x16Swizzle =
return $ [V128, V128] ==> V128 return $ [V128, V128] ==> V128
getInstrType _ (I8x16Shuffle _) = getInstrType _ (I8x16Shuffle idxs) = do
when (any (>= 32) idxs) $ throwError LaneIndexOutOfRange
return $ [V128, V128] ==> V128 return $ [V128, V128] ==> V128
getInstrType _ (V128Splat shape) = getInstrType _ (V128Splat shape) =
return $ getShapeElemType shape ==> V128 return $ getShapeElemType shape ==> V128
getInstrType _ (V128ExtractLane shape _ _) = getInstrType _ (V128ExtractLane shape idx _) = do
when (idx >= lanesCount shape) $ throwError LaneIndexOutOfRange
return $ V128 ==> getShapeElemType shape return $ V128 ==> getShapeElemType shape
getInstrType _ (V128ReplaceLane shape _) = getInstrType _ (V128ReplaceLane shape idx) = do
when (idx >= lanesCount shape) $ throwError LaneIndexOutOfRange
return $ [V128, getShapeElemType shape] ==> V128 return $ [V128, getShapeElemType shape] ==> V128
getInstrType _ (V128AllTrue _) = getInstrType _ (V128AllTrue _) =
return $ V128 ==> I32 return $ V128 ==> I32
@@ -545,6 +549,16 @@ getShapeElemType I64x2 = I64
getShapeElemType F32x4 = F32 getShapeElemType F32x4 = F32
getShapeElemType F64x2 = F64 getShapeElemType F64x2 = F64
lanesCount :: SimdShape -> Natural
lanesCount shape = case shape of
I8x16 -> 16
I16x8 -> 8
I32x4 -> 4
I64x2 -> 2
F32x4 -> 4
F64x2 -> 2
I128x1 -> 1
replace :: (Eq a) => a -> a -> [a] -> [a] replace :: (Eq a) => a -> a -> [a] -> [a]
replace _ _ [] = [] replace _ _ [] = []
replace x y (v:r) = (if x == v then y else v) : replace x y r replace x y (v:r) = (if x == v then y else v) : replace x y r
+1 -1
View File
@@ -20,7 +20,7 @@ main = do
filter (List.isPrefixOf "simd") . filter (List.isPrefixOf "simd") .
filter (List.isSuffixOf ".wast") filter (List.isSuffixOf ".wast")
<$> Directory.listDirectory "tests/spec" <$> Directory.listDirectory "tests/spec"
let files = ["simd_lane.wast"] -- let files = ["simd_lane.wast"]
scriptTestCases <- (`mapM` files) $ \file -> do scriptTestCases <- (`mapM` files) $ \file -> do
test <- LBS.readFile ("tests/spec/" ++ file) test <- LBS.readFile ("tests/spec/" ++ file)
return $ testCase file $ do return $ testCase file $ do