Skip to content

Commit 4270bae

Browse files
committed
Implement a new Prim type, which is used for implementing primitives.
This simplifies somewhat the process of implementing primitives, and also gives the simulator a more graceful way to handle errors that occur when primtives expect values to have specific forms, but they do not.
1 parent c8edab3 commit 4270bae

File tree

8 files changed

+848
-835
lines changed

8 files changed

+848
-835
lines changed

saw-core-aig/src/Verifier/SAW/Simulator/BitBlast.hs

+62-49
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ type instance VInt (BitBlast l) = Integer
9999
type instance Extra (BitBlast l) = BExtra l
100100

101101
type BValue l = Value (BitBlast l)
102+
type BPrim l = Prims.Prim (BitBlast l)
102103
type BThunk l = Thunk (BitBlast l)
103104

104105
data BExtra l
@@ -137,19 +138,16 @@ flattenBValue (VRecordValue elems) = do
137138
AIG.concat <$> mapM (flattenBValue <=< force . snd) elems
138139
flattenBValue _ = error $ unwords ["Verifier.SAW.Simulator.BitBlast.flattenBValue: unsupported value"]
139140

140-
wordFun :: (LitVector l -> IO (BValue l)) -> BValue l
141-
wordFun f = strictFun (\x -> toWord x >>= f)
142-
143141
------------------------------------------------------------
144142

145143
-- | op : (n : Nat) -> Vec n Bool -> Nat -> Vec n Bool
146144
bvShiftOp :: (LitVector l -> LitVector l -> IO (LitVector l))
147145
-> (LitVector l -> Natural -> LitVector l)
148-
-> BValue l
146+
-> BPrim l
149147
bvShiftOp bvOp natOp =
150-
constFun $
151-
wordFun $ \x -> return $
152-
strictFun $ \y ->
148+
Prims.constFun $
149+
Prims.wordFun (pure1 lvFromV) $ \x ->
150+
Prims.strictFun $ \y -> Prims.Prim $
153151
case y of
154152
VNat n -> return (vWord (natOp x n))
155153
VBVToNat _ v -> fmap vWord (bvOp x =<< toWord v)
@@ -258,7 +256,7 @@ prims be =
258256
unsupportedAIGPrimitive :: String -> a
259257
unsupportedAIGPrimitive = Prim.unsupportedPrimitive "AIG"
260258

261-
beConstMap :: AIG.IsAIG l g => g s -> Map Ident (BValue (l s))
259+
beConstMap :: AIG.IsAIG l g => g s -> Map Ident (BPrim (l s))
262260
beConstMap be =
263261
Map.union (Prims.constMap (prims be)) $
264262
Map.fromList
@@ -330,78 +328,86 @@ bitblastLogBase2 g x = do
330328
-- Integer/bitvector conversions
331329

332330
-- primitive bvToInt : (n : Nat) -> Vec n Bool -> Integer;
333-
bvToIntOp :: AIG.IsAIG l g => g s -> BValue (l s)
334-
bvToIntOp g = constFun $ wordFun $ \v ->
331+
bvToIntOp :: AIG.IsAIG l g => g s -> BPrim (l s)
332+
bvToIntOp g =
333+
Prims.constFun $
334+
Prims.wordFun (pure1 lvFromV) $ \v ->
335+
Prims.Prim $
335336
case AIG.asUnsigned g v of
336337
Just i -> return $ VInt i
337338
Nothing -> fail "Cannot convert symbolic bitvector to integer"
338339

339340
-- primitive sbvToInt : (n : Nat) -> Vec n Bool -> Integer;
340-
sbvToIntOp :: AIG.IsAIG l g => g s -> BValue (l s)
341-
sbvToIntOp g = constFun $ wordFun $ \v ->
341+
sbvToIntOp :: AIG.IsAIG l g => g s -> BPrim (l s)
342+
sbvToIntOp g =
343+
Prims.constFun $
344+
Prims.wordFun (pure1 lvFromV) $ \v ->
345+
Prims.Prim $
342346
case AIG.asSigned g v of
343347
Just i -> return $ VInt i
344348
Nothing -> fail "Cannot convert symbolic bitvector to integer"
345349

346350
-- primitive intToBv : (n : Nat) -> Integer -> Vec n Bool;
347-
intToBvOp :: AIG.IsAIG l g => g s -> BValue (l s)
351+
intToBvOp :: AIG.IsAIG l g => g s -> BPrim (l s)
348352
intToBvOp g =
349-
Prims.natFun' "intToBv n" $ \n -> return $
350-
Prims.intFun "intToBv x" $ \x ->
351-
VWord <$>
353+
Prims.natFun $ \n ->
354+
Prims.intFun $ \x -> Prims.Prim
355+
(VWord <$>
352356
if n >= 0 then return (AIG.bvFromInteger g (fromIntegral n) x)
353-
else AIG.neg g (AIG.bvFromInteger g (fromIntegral n) (negate x))
357+
else AIG.neg g (AIG.bvFromInteger g (fromIntegral n) (negate x)))
354358

355359
------------------------------------------------------------
356360

357-
toIntModOp :: BValue l
361+
toIntModOp :: BPrim l
358362
toIntModOp =
359-
Prims.natFun $ \n -> return $
360-
Prims.intFun "toIntModOp" $ \x -> return $
361-
VIntMod n (x `mod` toInteger n)
363+
Prims.natFun $ \n ->
364+
Prims.intFun $ \x ->
365+
Prims.PrimValue (VIntMod n (x `mod` toInteger n))
362366

363-
fromIntModOp :: BValue l
367+
fromIntModOp :: BPrim l
364368
fromIntModOp =
365-
constFun $
366-
Prims.intModFun "fromIntModOp" $ \x -> return $
367-
VInt x
369+
Prims.constFun $
370+
Prims.intModFun $ \x ->
371+
Prims.PrimValue (VInt x)
368372

369-
intModEqOp :: AIG.IsAIG l g => g s -> BValue (l s)
373+
intModEqOp :: AIG.IsAIG l g => g s -> BPrim (l s)
370374
intModEqOp be =
371-
constFun $
372-
Prims.intModFun "intModEqOp" $ \x -> return $
373-
Prims.intModFun "intModEqOp" $ \y -> return $
374-
VBool (AIG.constant be (x == y))
375+
Prims.constFun $
376+
Prims.intModFun $ \x ->
377+
Prims.intModFun $ \y ->
378+
Prims.PrimValue (VBool (AIG.constant be (x == y)))
375379

376-
intModBinOp :: (Integer -> Integer -> Integer) -> BValue l
380+
intModBinOp :: (Integer -> Integer -> Integer) -> BPrim l
377381
intModBinOp f =
378-
Prims.natFun $ \n -> return $
379-
Prims.intModFun "intModBinOp x" $ \x -> return $
380-
Prims.intModFun "intModBinOp y" $ \y -> return $
381-
VIntMod n (f x y `mod` toInteger n)
382+
Prims.natFun $ \n ->
383+
Prims.intModFun $ \x ->
384+
Prims.intModFun $ \y ->
385+
Prims.PrimValue (VIntMod n (f x y `mod` toInteger n))
382386

383-
intModUnOp :: (Integer -> Integer) -> BValue l
387+
intModUnOp :: (Integer -> Integer) -> BPrim l
384388
intModUnOp f =
385-
Prims.natFun $ \n -> return $
386-
Prims.intModFun "intModUnOp" $ \x -> return $
387-
VIntMod n (f x `mod` toInteger n)
389+
Prims.natFun $ \n ->
390+
Prims.intModFun $ \x ->
391+
Prims.PrimValue (VIntMod n (f x `mod` toInteger n))
388392

389393
----------------------------------------
390394

391395
-- MkStream :: (a :: sort 0) -> (Nat -> a) -> Stream a;
392-
mkStreamOp :: BValue l
396+
mkStreamOp :: BPrim l
393397
mkStreamOp =
394-
constFun $
395-
strictFun $ \f -> do
396-
r <- newIORef Map.empty
397-
return $ VExtra (BStream (\n -> apply f (ready (VNat n))) r)
398+
Prims.constFun $
399+
Prims.strictFun $ \f ->
400+
Prims.Prim $
401+
do r <- newIORef Map.empty
402+
return $ VExtra (BStream (\n -> apply f (ready (VNat n))) r)
398403

399404
-- streamGet :: (a :: sort 0) -> Stream a -> Nat -> a;
400-
streamGetOp :: AIG.IsAIG l g => g s -> BValue (l s)
405+
streamGetOp :: AIG.IsAIG l g => g s -> BPrim (l s)
401406
streamGetOp be =
402-
strictFun $ \(toTValue -> tp) -> return $
403-
strictFun $ \xs -> return $
404-
strictFun $ \case
407+
Prims.tvalFun $ \tp ->
408+
Prims.strictFun $ \xs ->
409+
Prims.strictFun $ \ix ->
410+
Prims.Prim $ case ix of
405411
VNat n -> lookupBStream xs n
406412
VBVToNat _ w ->
407413
do bs <- toWord w
@@ -439,7 +445,7 @@ newVars' be shape = ready <$> newVars be shape
439445
-- own bit engine internally, instead of receiving it from the caller,
440446
-- and pass it to the caller-provided continuation.
441447

442-
type PrimMap l g = forall s. g s -> Map Ident (BValue (l s))
448+
type PrimMap l g = forall s. g s -> Map Ident (BPrim (l s))
443449

444450
bitBlastBasic :: AIG.IsAIG l g
445451
=> g s
@@ -450,10 +456,17 @@ bitBlastBasic :: AIG.IsAIG l g
450456
-> IO (BValue (l s))
451457
bitBlastBasic be m addlPrims ecMap t = do
452458
let neutral _env nt = fail ("bitBlastBasic: could not evaluate neutral term: " ++ show nt)
459+
let primHandler pn msg env _tv =
460+
fail $ unlines
461+
[ "Could not evaluate primitive " ++ show (primName pn)
462+
, "On argument " ++ show (length env)
463+
, Text.unpack msg
464+
]
453465
cfg <- Sim.evalGlobal m (Map.union (beConstMap be) (addlPrims be))
454466
(bitBlastExtCns ecMap)
455467
(const Nothing)
456468
neutral
469+
primHandler
457470
Sim.evalSharedTerm cfg t
458471

459472
bitBlastExtCns ::

0 commit comments

Comments
 (0)